<commit_before># vim:ts=4:sw=4:expandtab
'''Core implementation/handling of generators, including
the various yield tokens.
'''
import socket
import traceback
import errno
import sys
import itertools
from OpenSSL import SSL
from greenlet import greenlet

from diesel import pipeline
from diesel import buffer
from diesel.security import ssl_async_handshake
from diesel import runtime
from diesel import log

class ConnectionClosed(socket.error):
    '''Raised if the client closes the connection.
    '''
    def __init__(self, msg, buffer=None):
        socket.error.__init__(self, msg)
        self.buffer = buffer

class ClientConnectionError(socket.error):
    '''Raised if a client cannot connect.
    '''

class ClientConnectionTimeout(socket.error):
    '''Raised if the client connection timed out before succeeding.
    '''

class LoopKeepAlive(Exception):
    '''Raised when an exception occurs that causes a loop to terminate;
    allows the app to re-schedule keep_alive loops.
    '''

class ParentDiedException(Exception):
    '''Raised when the parent (assigned via fork_child) has died.
    '''

class TerminateLoop(Exception):
    '''Raised to terminate the current loop, closing the socket if there
    is one associated with the loop.
    '''

CRLF = '\r\n'
BUFSIZ = 2 ** 14

def until(*args, **kw):
    return current_loop.input_op(*args, **kw)

def until_eol():
    return until("\r\n")

def receive(*args, **kw):
    return current_loop.input_op(*args, **kw)

def send(*args, **kw):
    return current_loop.send(*args, **kw)

def wait(*args, **kw):
    return current_loop.wait(*args, **kw)

def fire(*args, **kw):
    return current_loop.fire(*args, **kw)

def sleep(*args, **kw):
    return current_loop.sleep(*args, **kw)

def thread(*args, **kw):
    return current_loop.thread(*args, **kw)

def _private_connect(*args, **kw):
    return current_loop.connect(*args, **kw)

def first(*args, **kw):
    return current_loop.first(*args, **kw)

def label(*args, **kw):
    return current_loop.label(*args, **kw)

def fork(*args, **kw):
    return current_loop.fork(False, *args, **kw)

def fork_child(*args, **kw):
    return current_loop.fork(True, *args, **kw)

class call(object):
    def __init__(self, f, inst=None):
        self.f = f
        self.client = inst

    def __get__(self, inst, cls):
        return call(self.f, inst)

    def __call__(self, *args, **kw):
        if not self.client.connected:
            raise RuntimeError("Client call failed: client is not connected")
        if self.client.is_closed:
            raise RuntimeError("Client call failed: client connection was closed")
        current_loop.connection_stack.append(self.client.conn)
        try:
            r = self.f(self.client, *args, **kw)
        finally:
            current_loop.connection_stack.pop()
        return r

current_loop = None

class ContinueNothing(object): pass

def identity(cb): return cb

ids = itertools.count(1)

class Loop(object):
    def __init__(self, loop_callable, *args, **kw):
        self.loop_callable = loop_callable
        self.loop_label = str(self.loop_callable)
        self.args = args
        self.kw = kw
        self.keep_alive = False
        self.hub = runtime.current_app.hub
        self.app = runtime.current_app
        self.id = ids.next()
        self.children = set()
        self.parent = None
        self.reset()

    def reset(self):
        self.running = False
        self._wakeup_timer = None
        self.fire_handlers = {}
        self.connection_stack = []
        self.coroutine = None

    def run(self):
        from diesel.app import ApplicationEnd
        self.running = True
        self.app.running.add(self)
        try:
            self.loop_callable(*self.args, **self.kw)
        except TerminateLoop:
            pass
        except (SystemExit, KeyboardInterrupt, ApplicationEnd):
            raise
        except:
            log.error("-- Unhandled Exception in local loop <%s> --" % self.loop_label)
            log.error(traceback.format_exc())
        finally:
            if self.connection_stack:
                assert len(self.connection_stack) == 1
                self.connection_stack.pop().close()
        self.running = False
        self.app.running.remove(self)
        self.notify_children()
        if self.parent and self in self.parent.children:
            self.parent.children.remove(self)
            self.parent = None

        if self.keep_alive:
            log.warn("(Keep-Alive loop %s died; restarting)" % self)
            self.reset()
            self.hub.call_later(0.5, self.wake)

    def notify_children(self):
        for c in self.children:
            c.parent_died()

    def __hash__(self):
        return self.id

    def __str__(self):
        return '<Loop id=%s callable=%s>' % (self.id,
        str(self.loop_callable))

    def clear_pending_events(self):
        '''When a loop is rescheduled, cancel any other timers or waits.
        '''
        if self._wakeup_timer and self._wakeup_timer.pending:
            self._wakeup_timer.cancel()
        if self.connection_stack:
            self.connection_stack[-1].buffer.clear_term()
            self.connection_stack[-1].waiting_callback = None
        self.fire_handlers = {}
        self.app.waits.clear(self)

    def thread(self, f, *args, **kw):
        self.hub.run_in_thread(self.wake, f, *args, **kw)
        return self.dispatch()

    def fork(self, make_child, f, *args, **kw):
        def wrap():
            return f(*args, **kw)
        l = Loop(wrap)
        if make_child:
            self.children.add(l)
            l.parent = self
        self.app.add_loop(l)
        return l

    def parent_died(self):
        if self.running:
            self.hub.schedule(lambda: self.wake(ParentDiedException()))

    def label(self, label):
        self.loop_label = label

    def first(self, sleep=None, waits=None,
            receive=None, until=None, until_eol=None):
        def marked_cb(kw):
            def deco(f):
                def mark(d):
                    if isinstance(d, Exception):
                        return f(d)
                    return f((kw, d))
                return mark
            return deco

        f_sent = filter(None, (receive, until, until_eol))
        assert len(f_sent) <= 1,(
        "only 1 of (receive, until, until_eol) may be provided")
        sentinel = None
        if receive:
            sentinel = receive
            tok = 'receive'
        elif until:
            sentinel = until
            tok = 'until'
        elif until_eol:
            sentinel = "\r\n"
            tok = 'until_eol'
        if sentinel:
            early_val = self._input_op(sentinel, marked_cb(tok))
            if early_val:
                return tok, early_val
            # othewise.. process others and dispatch

        if sleep is not None:
            self._sleep(sleep, marked_cb('sleep'))

        if waits:
            for w in waits:
                self._wait(w, marked_cb('wait-' + w))
        return self.dispatch()

    def connect(self, client, ip, sock, timeout=None):
        def cancel_callback(sock):
            self.hub.unregister(sock)
            sock.close()
            self.hub.schedule(lambda: self.wake(
                ClientConnectionTimeout("connection timeout")
                ))

        def connect_callback():
            if cancel_timer is not None:
                cancel_timer.cancel()
            self.hub.unregister(sock)
            def finish():
                client.conn = Connection(fsock, ip)
                client.connected = True
                self.hub.schedule(
                lambda: self.wake()
                )

            if client.ssl_ctx:
                fsock = SSL.Connection(client.ssl_ctx, sock)
                fsock.setblocking(0)
                fsock.set_connect_state()
                ssl_async_handshake(fsock, self.hub, finish)
            else:
                fsock = sock
                finish()

        def error_callback():
            if cancel_timer is not None:
                cancel_timer.cancel()
            self.hub.unregister(sock)
            self.hub.schedule(
            lambda: self.wake(
                    ClientConnectionError("odd error on connect()!")
                ))

        def read_callback():
            self.hub.unregister(sock)
            try:
                s = sock.recv(100)
            except socket.error, e:
                self.hub.schedule(
                    lambda: self.wake(
                        ClientConnectionError(str(e))
                    ))

        cancel_timer = None
        if timeout is not None:
            cancel_timer = self.hub.call_later(timeout, cancel_callback, sock)

        self.hub.register(sock, read_callback, connect_callback, error_callback)
        self.hub.enable_write(sock)
        try:
            return self.dispatch()
        except ClientConnectionError:
            if cancel_timer is not None:
                cancel_timer.cancel()
            raise

    def sleep(self, v=0):
        self._sleep(v)
        return self.dispatch()

    def _sleep(self, v, cb_maker=identity):
        cb = lambda: cb_maker(self.wake)(True)
        assert v >= 0

        if v > 0:
            self._wakeup_timer = self.hub.call_later(v, cb)
        else:
            self.hub.schedule(cb)

    def fire_in(self, what, value):
        if what in self.fire_handlers:
            handler = self.fire_handlers.pop(what)
            self.fire_handlers = {}
            handler(value)

    def wait(self, event):
        self._wait(event)
        return self.dispatch()

    def _wait(self, event, cb_maker=identity):
        rcb = cb_maker(self.wake)
        def cb(d):
            def call_in():
                rcb(d)
            self.hub.schedule(call_in)
        self.fire_handlers[event] = cb
        self.app.waits.wait(self, event)

    def fire(self, event, value=None):
        self.app.waits.fire(event, value)

    def dispatch(self):
        r = self.app.runhub.switch()
        return r

    def wake(self, value=ContinueNothing):
        '''Wake up this loop.  Called by the main hub to resume a loop
        when it is rescheduled.
        '''
        global current_loop
        if self.coroutine is None:
            self.coroutine = greenlet(self.run)
            assert self.coroutine.parent == runtime.current_app.runhub
        self.clear_pending_events()
        current_loop = self
        if isinstance(value, Exception):
            self.coroutine.throw(value)
        elif value != ContinueNothing:
            self.coroutine.switch(value)
        else:
            self.coroutine.switch()

    def input_op(self, sentinel_or_receive):
        v = self._input_op(sentinel_or_receive)
        if v:
            return v
        else:
            return self.dispatch()

    def _input_op(self, sentinel, cb_maker=identity):
        conn = self.check_connection()
        cb = cb_maker(self.wake)
        res = conn.buffer.set_term(sentinel)
        return self.check_buffer(conn, cb)

    def check_buffer(self, conn, cb):
        res = conn.buffer.check()
        if res:
            return res
        conn.waiting_callback = cb
        return None

    def check_connection(self):
        try:
            conn = self.connection_stack[-1]
        except IndexError:
            raise RuntimeError("Cannot complete socket operation: no associated connection")
        if conn.closed:
            raise ConnectionClosed("Cannot complete socket operation: associated connection is closed")
        return conn

    def send(self, o, priority=5):
        conn = self.check_connection()
        conn.pipeline.add(o, priority)
        conn.set_writable(True)

class Connection(object):
    def __init__(self, sock, addr):
        self.hub = runtime.current_app.hub
        self.pipeline = pipeline.Pipeline()
        self.buffer = buffer.Buffer()
        self.sock = sock
        self.addr = addr
        self.hub.register(sock, self.handle_read, self.handle_write, self.handle_error)
        self._writable = False
        self.closed = False
        self.waiting_callback = None

    def set_writable(self, val):
        '''Set the associated socket writable.  Called when there is
        data on the outgoing pipeline ready to be delivered to the
        remote host.
        '''
        if self.closed:
            return
        if val and not self._writable:
            self.hub.enable_write(self.sock)
            self._writable = True
            return
        if not val and self._writable:
            self.hub.disable_write(self.sock)
            self._writable = False

    def close(self):
        self.set_writable(True)
        self.pipeline.close_request()

    def shutdown(self, remote_closed=False):
        '''Clean up after a client disconnects or after
        the connection_handler ends (and we disconnect).
        '''
        self.hub.unregister(self.sock)
        self.closed = True
        self.sock.close()

        if remote_closed and self.waiting_callback:
            self.waiting_callback(
            ConnectionClosed('Connection closed by remote host',
            self.buffer.pop()))

    def handle_write(self):
        '''The low-level handler called by the event hub
        when the socket is ready for writing.
        '''
        if not self.pipeline.empty and not self.closed:
            try:
                data = self.pipeline.read(BUFSIZ)
            except pipeline.PipelineCloseRequest:
                self.shutdown()
            else:
                try:
                    bsent = self.sock.send(data)
                except socket.error, e:
                    code, s = e
                    if code in (errno.EAGAIN, errno.EINTR):
                        self.pipeline.backup(data)
                        return
                    self.shutdown(True)
                except (SSL.WantReadError, SSL.WantWriteError, SSL.WantX509LookupError):
                    self.pipeline.backup(data)
                    return
                except SSL.ZeroReturnError:
                    self.shutdown(True)
                except SSL.SysCallError:
                    self.shutdown(True)
                except:
                    sys.stderr.write("Unknown Error on send():\n%s"
                    % traceback.format_exc())
                    self.shutdown(True)

                else:
                    if bsent != len(data):
                        self.pipeline.backup(data[bsent:])

                    if not self.pipeline.empty:
                        return
                    else:
                        self.set_writable(False)

    def handle_read(self):
        '''The low-level handler called by the event hub
        when the socket is ready for reading.
        '''
        if self.closed:
            return
        try:
            data = self.sock.recv(BUFSIZ)
        except socket.error, e:
            code, s = e
            if code in (errno.EAGAIN, errno.EINTR):
                return
            data = ''
        except (SSL.WantReadError, SSL.WantWriteError, SSL.WantX509LookupError):
            return
        except SSL.ZeroReturnError:
            data = ''
        except SSL.SysCallError:
            data = ''
        except:
            sys.stderr.write("Unknown Error on recv():\n%s"
            % traceback.format_exc())
            data = ''

        if not data:
            self.shutdown(True)
        else:
            res = self.buffer.feed(data)
            if res:
                self.waiting_callback(res)

    def handle_error(self):
        self.shutdown(True)
<commit_msg>Use ConnectionClosed exception instead of RuntimeError in call<commit_after># vim:ts=4:sw=4:expandtab
'''Core implementation/handling of generators, including
the various yield tokens.
'''
import socket
import traceback
import errno
import sys
import itertools
from OpenSSL import SSL
from greenlet import greenlet

from diesel import pipeline
from diesel import buffer
from diesel.security import ssl_async_handshake
from diesel import runtime
from diesel import log

class ConnectionClosed(socket.error):
    '''Raised if the client closes the connection.
    '''
    def __init__(self, msg, buffer=None):
        socket.error.__init__(self, msg)
        self.buffer = buffer

class ClientConnectionError(socket.error):
    '''Raised if a client cannot connect.
    '''

class ClientConnectionTimeout(socket.error):
    '''Raised if the client connection timed out before succeeding.
    '''

class LoopKeepAlive(Exception):
    '''Raised when an exception occurs that causes a loop to terminate;
    allows the app to re-schedule keep_alive loops.
    '''

class ParentDiedException(Exception):
    '''Raised when the parent (assigned via fork_child) has died.
    '''

class TerminateLoop(Exception):
    '''Raised to terminate the current loop, closing the socket if there
    is one associated with the loop.
    '''

CRLF = '\r\n'
BUFSIZ = 2 ** 14

def until(*args, **kw):
    return current_loop.input_op(*args, **kw)

def until_eol():
    return until("\r\n")

def receive(*args, **kw):
    return current_loop.input_op(*args, **kw)

def send(*args, **kw):
    return current_loop.send(*args, **kw)

def wait(*args, **kw):
    return current_loop.wait(*args, **kw)

def fire(*args, **kw):
    return current_loop.fire(*args, **kw)

def sleep(*args, **kw):
    return current_loop.sleep(*args, **kw)

def thread(*args, **kw):
    return current_loop.thread(*args, **kw)

def _private_connect(*args, **kw):
    return current_loop.connect(*args, **kw)

def first(*args, **kw):
    return current_loop.first(*args, **kw)

def label(*args, **kw):
    return current_loop.label(*args, **kw)

def fork(*args, **kw):
    return current_loop.fork(False, *args, **kw)

def fork_child(*args, **kw):
    return current_loop.fork(True, *args, **kw)

class call(object):
    def __init__(self, f, inst=None):
        self.f = f
        self.client = inst

    def __get__(self, inst, cls):
        return call(self.f, inst)

    def __call__(self, *args, **kw):
        if not self.client.connected:
            raise ConnectionClosed(
                    "ClientNotConnected: client is not connected")
        if self.client.is_closed:
            raise ConnectionClosed(
                    "Client call failed: client connection was closed")
        current_loop.connection_stack.append(self.client.conn)
        try:
            r = self.f(self.client, *args, **kw)
        finally:
            current_loop.connection_stack.pop()
        return r

current_loop = None

class ContinueNothing(object): pass

def identity(cb): return cb

ids = itertools.count(1)

class Loop(object):
    def __init__(self, loop_callable, *args, **kw):
        self.loop_callable = loop_callable
        self.loop_label = str(self.loop_callable)
        self.args = args
        self.kw = kw
        self.keep_alive = False
        self.hub = runtime.current_app.hub
        self.app = runtime.current_app
        self.id = ids.next()
        self.children = set()
        self.parent = None
        self.reset()

    def reset(self):
        self.running = False
        self._wakeup_timer = None
        self.fire_handlers = {}
        self.connection_stack = []
        self.coroutine = None

    def run(self):
        from diesel.app import ApplicationEnd
        self.running = True
        self.app.running.add(self)
        try:
            self.loop_callable(*self.args, **self.kw)
        except TerminateLoop:
            pass
        except (SystemExit, KeyboardInterrupt, ApplicationEnd):
            raise
        except:
            log.error("-- Unhandled Exception in local loop <%s> --" % self.loop_label)
            log.error(traceback.format_exc())
        finally:
            if self.connection_stack:
                assert len(self.connection_stack) == 1
                self.connection_stack.pop().close()
        self.running = False
        self.app.running.remove(self)
        self.notify_children()
        if self.parent and self in self.parent.children:
            self.parent.children.remove(self)
            self.parent = None

        if self.keep_alive:
            log.warn("(Keep-Alive loop %s died; restarting)" % self)
            self.reset()
            self.hub.call_later(0.5, self.wake)

    def notify_children(self):
        for c in self.children:
            c.parent_died()

    def __hash__(self):
        return self.id

    def __str__(self):
        return '<Loop id=%s callable=%s>' % (self.id,
        str(self.loop_callable))

    def clear_pending_events(self):
        '''When a loop is rescheduled, cancel any other timers or waits.
        '''
        if self._wakeup_timer and self._wakeup_timer.pending:
            self._wakeup_timer.cancel()
        if self.connection_stack:
            self.connection_stack[-1].buffer.clear_term()
            self.connection_stack[-1].waiting_callback = None
        self.fire_handlers = {}
        self.app.waits.clear(self)

    def thread(self, f, *args, **kw):
        self.hub.run_in_thread(self.wake, f, *args, **kw)
        return self.dispatch()

    def fork(self, make_child, f, *args, **kw):
        def wrap():
            return f(*args, **kw)
        l = Loop(wrap)
        if make_child:
            self.children.add(l)
            l.parent = self
        self.app.add_loop(l)
        return l

    def parent_died(self):
        if self.running:
            self.hub.schedule(lambda: self.wake(ParentDiedException()))

    def label(self, label):
        self.loop_label = label

    def first(self, sleep=None, waits=None,
            receive=None, until=None, until_eol=None):
        def marked_cb(kw):
            def deco(f):
                def mark(d):
                    if isinstance(d, Exception):
                        return f(d)
                    return f((kw, d))
                return mark
            return deco

        f_sent = filter(None, (receive, until, until_eol))
        assert len(f_sent) <= 1,(
        "only 1 of (receive, until, until_eol) may be provided")
        sentinel = None
        if receive:
            sentinel = receive
            tok = 'receive'
        elif until:
            sentinel = until
            tok = 'until'
        elif until_eol:
            sentinel = "\r\n"
            tok = 'until_eol'
        if sentinel:
            early_val = self._input_op(sentinel, marked_cb(tok))
            if early_val:
                return tok, early_val
            # othewise.. process others and dispatch

        if sleep is not None:
            self._sleep(sleep, marked_cb('sleep'))

        if waits:
            for w in waits:
                self._wait(w, marked_cb('wait-' + w))
        return self.dispatch()

    def connect(self, client, ip, sock, timeout=None):
        def cancel_callback(sock):
            self.hub.unregister(sock)
            sock.close()
            self.hub.schedule(lambda: self.wake(
                ClientConnectionTimeout("connection timeout")
                ))

        def connect_callback():
            if cancel_timer is not None:
                cancel_timer.cancel()
            self.hub.unregister(sock)
            def finish():
                client.conn = Connection(fsock, ip)
                client.connected = True
                self.hub.schedule(
                lambda: self.wake()
                )

            if client.ssl_ctx:
                fsock = SSL.Connection(client.ssl_ctx, sock)
                fsock.setblocking(0)
                fsock.set_connect_state()
                ssl_async_handshake(fsock, self.hub, finish)
            else:
                fsock = sock
                finish()

        def error_callback():
            if cancel_timer is not None:
                cancel_timer.cancel()
            self.hub.unregister(sock)
            self.hub.schedule(
            lambda: self.wake(
                    ClientConnectionError("odd error on connect()!")
                ))

        def read_callback():
            self.hub.unregister(sock)
            try:
                s = sock.recv(100)
            except socket.error, e:
                self.hub.schedule(
                    lambda: self.wake(
                        ClientConnectionError(str(e))
                    ))

        cancel_timer = None
        if timeout is not None:
            cancel_timer = self.hub.call_later(timeout, cancel_callback, sock)

        self.hub.register(sock, read_callback, connect_callback, error_callback)
        self.hub.enable_write(sock)
        try:
            return self.dispatch()
        except ClientConnectionError:
            if cancel_timer is not None:
                cancel_timer.cancel()
            raise

    def sleep(self, v=0):
        self._sleep(v)
        return self.dispatch()

    def _sleep(self, v, cb_maker=identity):
        cb = lambda: cb_maker(self.wake)(True)
        assert v >= 0

        if v > 0:
            self._wakeup_timer = self.hub.call_later(v, cb)
        else:
            self.hub.schedule(cb)

    def fire_in(self, what, value):
        if what in self.fire_handlers:
            handler = self.fire_handlers.pop(what)
            self.fire_handlers = {}
            handler(value)

    def wait(self, event):
        self._wait(event)
        return self.dispatch()

    def _wait(self, event, cb_maker=identity):
        rcb = cb_maker(self.wake)
        def cb(d):
            def call_in():
                rcb(d)
            self.hub.schedule(call_in)
        self.fire_handlers[event] = cb
        self.app.waits.wait(self, event)

    def fire(self, event, value=None):
        self.app.waits.fire(event, value)

    def dispatch(self):
        r = self.app.runhub.switch()
        return r

    def wake(self, value=ContinueNothing):
        '''Wake up this loop.  Called by the main hub to resume a loop
        when it is rescheduled.
        '''
        global current_loop
        if self.coroutine is None:
            self.coroutine = greenlet(self.run)
            assert self.coroutine.parent == runtime.current_app.runhub
        self.clear_pending_events()
        current_loop = self
        if isinstance(value, Exception):
            self.coroutine.throw(value)
        elif value != ContinueNothing:
            self.coroutine.switch(value)
        else:
            self.coroutine.switch()

    def input_op(self, sentinel_or_receive):
        v = self._input_op(sentinel_or_receive)
        if v:
            return v
        else:
            return self.dispatch()

    def _input_op(self, sentinel, cb_maker=identity):
        conn = self.check_connection()
        cb = cb_maker(self.wake)
        res = conn.buffer.set_term(sentinel)
        return self.check_buffer(conn, cb)

    def check_buffer(self, conn, cb):
        res = conn.buffer.check()
        if res:
            return res
        conn.waiting_callback = cb
        return None

    def check_connection(self):
        try:
            conn = self.connection_stack[-1]
        except IndexError:
            raise RuntimeError("Cannot complete socket operation: no associated connection")
        if conn.closed:
            raise ConnectionClosed("Cannot complete socket operation: associated connection is closed")
        return conn

    def send(self, o, priority=5):
        conn = self.check_connection()
        conn.pipeline.add(o, priority)
        conn.set_writable(True)

class Connection(object):
    def __init__(self, sock, addr):
        self.hub = runtime.current_app.hub
        self.pipeline = pipeline.Pipeline()
        self.buffer = buffer.Buffer()
        self.sock = sock
        self.addr = addr
        self.hub.register(sock, self.handle_read, self.handle_write, self.handle_error)
        self._writable = False
        self.closed = False
        self.waiting_callback = None

    def set_writable(self, val):
        '''Set the associated socket writable.  Called when there is
        data on the outgoing pipeline ready to be delivered to the
        remote host.
        '''
        if self.closed:
            return
        if val and not self._writable:
            self.hub.enable_write(self.sock)
            self._writable = True
            return
        if not val and self._writable:
            self.hub.disable_write(self.sock)
            self._writable = False

    def close(self):
        self.set_writable(True)
        self.pipeline.close_request()

    def shutdown(self, remote_closed=False):
        '''Clean up after a client disconnects or after
        the connection_handler ends (and we disconnect).
        '''
        self.hub.unregister(self.sock)
        self.closed = True
        self.sock.close()

        if remote_closed and self.waiting_callback:
            self.waiting_callback(
            ConnectionClosed('Connection closed by remote host',
            self.buffer.pop()))

    def handle_write(self):
        '''The low-level handler called by the event hub
        when the socket is ready for writing.
        '''
        if not self.pipeline.empty and not self.closed:
            try:
                data = self.pipeline.read(BUFSIZ)
            except pipeline.PipelineCloseRequest:
                self.shutdown()
            else:
                try:
                    bsent = self.sock.send(data)
                except socket.error, e:
                    code, s = e
                    if code in (errno.EAGAIN, errno.EINTR):
                        self.pipeline.backup(data)
                        return
                    self.shutdown(True)
                except (SSL.WantReadError, SSL.WantWriteError, SSL.WantX509LookupError):
                    self.pipeline.backup(data)
                    return
                except SSL.ZeroReturnError:
                    self.shutdown(True)
                except SSL.SysCallError:
                    self.shutdown(True)
                except:
                    sys.stderr.write("Unknown Error on send():\n%s"
                    % traceback.format_exc())
                    self.shutdown(True)

                else:
                    if bsent != len(data):
                        self.pipeline.backup(data[bsent:])

                    if not self.pipeline.empty:
                        return
                    else:
                        self.set_writable(False)

    def handle_read(self):
        '''The low-level handler called by the event hub
        when the socket is ready for reading.
        '''
        if self.closed:
            return
        try:
            data = self.sock.recv(BUFSIZ)
        except socket.error, e:
            code, s = e
            if code in (errno.EAGAIN, errno.EINTR):
                return
            data = ''
        except (SSL.WantReadError, SSL.WantWriteError, SSL.WantX509LookupError):
            return
        except SSL.ZeroReturnError:
            data = ''
        except SSL.SysCallError:
            data = ''
        except:
            sys.stderr.write("Unknown Error on recv():\n%s"
            % traceback.format_exc())
            data = ''

        if not data:
            self.shutdown(True)
        else:
            res = self.buffer.feed(data)
            if res:
                self.waiting_callback(res)

    def handle_error(self):
        self.shutdown(True)
<|endoftext|>


<commit_before># vim:ts=4:sw=4:expandtab
'''Core implementation/handling of generators, including
the various yield tokens.
'''
import socket
import traceback
import errno
import sys
import ssl
from types import GeneratorType
from collections import deque, defaultdict

from diesel import pipeline
from diesel import buffer
from diesel.client import call, message, response, connect
from diesel.security import ssl_async_handshake

class ConnectionClosed(socket.error):
    '''Raised if the client closes the connection.
    '''
    pass

CRLF = '\r\n'
BUFSIZ = 2 ** 14

class until(object):
    '''A yield token that indicates the generator wants
    a string sent back from the socket stream when a
    certain `sentinel` is encountered.
    '''
    def __init__(self, sentinel):
        self.sentinel = sentinel

def until_eol():
    '''Macro for `until("\r\n")`.
    '''
    return until(CRLF)

class bytes(object):
    '''A yield token that indicates the generator wants
    a string sent back from the socket stream when a
    certain number of bytes are available.
    '''
    def __init__(self, sentinel):
        self.sentinel = sentinel

class sleep(object):
    '''A yield token that indicates the generator wants
    a callback in `duration` seconds.

    If no argument is passed, the generator will be called
    again during the next iteration of the main loop.  It
    can act as a way to yield control to other loops, with
    the intention of taking control back as soon as they've
    had a pass.
    '''
    def __init__(self, duration=0):
        self.duration = duration

class up(object):
    '''For nested generators, a yield token that indicates this value is
    being passed "up" the stack to the "calling" generator, and isn't intended
    as a message for diesel itself.
    '''
    def __init__(self, value):
        self.value = value

class wait(object):
    '''A yield token that indicates a generators desire to wait until a
    certain event is `fire`d.
    '''
    def __init__(self, event):
        self.event = event

class fire(object):
    '''A yield token that fires an event to any appropriate `wait`ers.
    '''
    def __init__(self, event, value=None):
        self.event = event
        self.value = value

class catch(object):
    '''A yield token that indicates a "calling" generator's willingness
    to handle certain types of failures in "called" generators.. must be
    paired with another generator.
    '''
    def __init__(self, call, *exc_types):
        self.call = call
        self.exc_types = set(exc_types)

class WaitPool(object):
    '''A structure that manages all `wait`ers, makes sure fired events
    get to the right places, and that all other waits are canceled when
    a one event is passed back to a generator.
    '''
    def __init__(self):
        self.waits = defaultdict(set)
        self.loop_refs = defaultdict(set)

    def wait(self, who, what):
        self.waits[what].add(who)
        self.loop_refs[who].add(what)

    def fire(self, what, value):
        for handler in self.waits[what].copy():
            handler.fire(what, value)

    def clear(self, who):
        for what in self.loop_refs[who]:
            self.waits[what].remove(who)
        del self.loop_refs[who]

waits = WaitPool()

class NoPipeline(object):
    '''Fake pipeline for Loops that aren't managing a connection and have no
    I/O stream.
    '''
    def __getattr__(self, *args, **kw):
        return ValueError("Cannot write to the outgoing pipeline for socketless Loops (yield string, file)")
    empty = True

class NoBuffer(object):
    '''Fake buffer for loops that aren't managing a connection and have no
    I/O stream.
    '''
    def __getattr__(self, *args, **kw):
        return ValueError("Cannot check incoming buffer on socketless Loops (yield until, bytes, etc)")

def id_gen():
    x = 1
    while True:
        yield x
        x += 1
ids = id_gen()

def print_errstack(stack, e):
    eout = lambda s: sys.stderr.write(str(s) + "\n")
    eout("=== DIESEL ERROR ===")
    if stack:
        eout("")
        eout(" Generator stack at time of error:")
        eout("")
        for g, c in stack:
            eout(g.gi_code,)
            if c:
                eout("catches %r" % c.exc_types)
            else:
                eout("")
        eout("")
    eout("")
    eout(" Standard Traceback:")
    eout("")
    traceback.print_exception(*e)

class Loop(object):
    '''A cooperative generator that represents an arbitrary piece of
    logic.
    '''
    def __init__(self, loop_callable, *callable_args):
        self.g = self.cycle_all(loop_callable(*callable_args))
        self.pipeline = NoPipeline()
        self.buffer = NoBuffer()
        from diesel.app import current_app
        self.hub = current_app.hub
        self.id = ids.next()
        self._wakeup_timer = None
        self.fire_handlers = {}

    def __hash__(self):
        return self.id

    def __eq__(self, other):
        return other.id == self.id

    def fire(self, what, value):
        '''Fire an event back into this generator.
        '''
        if what in self.fire_handlers:
            handler = self.fire_handlers.pop(what)
            self.fire_handlers = {}
            handler(value)

    def cycle_all(self, current, error=None):
        '''Effectively flattens all iterators, providing the
        "generator stack" effect.
        '''
        last = None
        in_self_call = False
        stack = []
        while True:
            try:
                if error != None:
                    item = current.throw(*error)
                elif last != None:
                    item = current.send(last)
                else:
                    item = current.next()
            except StopIteration:
                if stack:
                    current, _ = stack.pop()
                else:
                    raise
            except Exception, e:
                errstack = stack[:] + [(current, None)]
                error = None
                while stack:
                    current, level_catch = stack.pop()
                    if level_catch and \
                    filter(None, map(lambda x: isinstance(e, x),
                    level_catch.exc_types)):

                        error = tuple(sys.exc_info()[:2])
                        break
                    else:
                        current.close()
                if not error: # no one claims to handle it
                    print_errstack(errstack, sys.exc_info())
                    raise StopIteration()
            else:
                level_catch = None
                error = None

                if type(item) is catch:
                    level_catch = item
                    item = item.call

                if type(item) is GeneratorType:
                    stack.append((current, level_catch))
                    current = item
                    last = None
                elif type(item) is call and item.client.conn == self:
                    in_self_call = True
                    stack.append((current, level_catch))
                    current = item.gen
                    last = None
                else:
                    if type(item) is response:
                        assert stack, "Cannot return a response from main handler"
                        current, _ = stack.pop()
                        if in_self_call:
                            in_self_call = False
                            item = up(item.value)
                    elif type(item) is up:
                        assert stack, "Cannot return an up from main handler"
                        current, _ = stack.pop()
                    try:
                        last = (yield item)
                    except ConnectionClosed, e:
                        error = (ConnectionClosed, str(e))

    def multi_callin(self, pos, tot, real_f=None):
        '''Provide a callable that will pass `None` in all spots
        that aren't the event that triggered the rescheduling of the
        generator.  For yield groups.
        '''
        real_f = real_f or self.wake
        if tot == 1:
            return real_f
        def f(res):
            real_arg = [None] * tot
            real_arg[pos] = res
            return real_f(tuple(real_arg))
        return f

    def iterate(self, n_val=None):
        '''The algorithm that represents iterating over all items
        in the nested generator that represents this Loop or
        Connection.  Run whenever a generator is (re-)scheduled.
        Handles all the `yield` tokens.
        '''
        if self.g is None:
            return

        while True:
            try:
                if isinstance(n_val, Exception):
                    self.g.throw(n_val)
                elif n_val is not None:
                    rets = self.g.send(n_val)
                else:
                    rets = self.g.next()
            except StopIteration:
                if hasattr(self, 'sock'):
                    self.pipeline.close_request()
                break
            n_val = None
            if type(rets) != tuple:
                rets = (rets,)

            exit = False
            used_term = False
            nrets = len(rets)
            for pos, ret in enumerate(rets):

                if type(ret) is str or hasattr(ret, 'seek'):
                    assert nrets == 1, "a string or file cannot be paired with any other yield token"
                    self.pipeline.add(ret)
                elif type(ret) is until or type(ret) is bytes:
                    assert used_term == False, "only one terminal specifier (bytes, until) per yield"
                    used_term = True
                    self.buffer.set_term(ret.sentinel)
                    n_val = self.buffer.check()
                    if n_val == None:
                        exit = True
                        self.new_data = self.multi_callin(pos, nrets)
                    else:
                        if nrets > 1:
                            t = [None] * nrets
                            t[pos] = n_val
                            n_val = tuple(t)
                        self.clear_pending_events()
                        exit = False
                        break
                elif type(ret) is connect:
                    assert nrets == 1, "connect cannot be paired with any other yield token"
                    def connect_callback():
                        self.hub.unregister(ret.sock)
                        def finish():
                            ret.callback()
                            self.multi_callin(pos, nrets)()
                        if ret.security:
                            ret.sock = ret.security.wrap(ret.sock)
                            ssl_async_handshake(ret.sock, self.hub, finish)
                        else:
                            finish()

                    def error_callback():
                        self.hub.unregister(ret.sock)
                        raise ConnectionClosed("odd error on connect()!")

                    def read_callback():
                        self.hub.unregister(ret.sock)
                        try:
                            s = ret.sock.recv(100)
                        except socket.error, e:
                            self.multi_callin(pos, nrets)(ConnectionClosed(str(e)))

                    self.hub.register(ret.sock, read_callback, connect_callback, error_callback)
                    self.hub.enable_write(ret.sock)
                    exit = True

                elif type(ret) is sleep:
                    self._wakeup_timer = self.hub.call_later(ret.duration, self.multi_callin(pos, nrets), True)
                    exit = True

                elif type(ret) is up:
                    assert nrets == 1, "up cannot be paired with any other yield token"
                    n_val = ret.value

                elif type(ret) is fire:
                    assert nrets == 1, "fire cannot be paired with any other yield token"
                    waits.fire(ret.event, ret.value)

                elif type(ret) is wait:
                    self.fire_handlers[ret.event] = self.multi_callin(pos, nrets, self.schedule)
                    waits.wait(self, ret.event)
                    exit = True

                elif type(ret) is response:
                    assert nrets == 1, "response cannot be paired with any other yield token"
                    c = self.callbacks.popleft()
                    c(ret.value)
                    exit = True

                elif type(ret) is call:
                    assert nrets == 1, "call cannot be paired with any other yield token"
                    ret.go(self.iterate)
                    exit = True

                elif type(ret) is message:
                    assert nrets == 1, "message cannot be paired with any other yield token"
                    ret.go()

                else:
                    raise ValueError("Unknown yield token %s" % ret)
            if exit:
                break

        if not self.pipeline.empty:
            self.set_writable(True)

    def clear_pending_events(self):
        '''When a loop is rescheduled, cancel any other timers or waits.
        '''
        if self._wakeup_timer and self._wakeup_timer.pending:
            self._wakeup_timer.cancel()
        self.fire_handlers = {}
        waits.clear(self)

    def schedule(self, value=None):
        '''Called by another Loop--reschedule this loop so the hub will run
        it.  Used in `response` and `fire` situations.
        '''
        self.hub.schedule(lambda: self.wake(value))

    def wake(self, value=None):
        '''Wake up this loop.  Called by the main hub to resume a loop
        when it is rescheduled.
        '''
        self.clear_pending_events()
        self.iterate(value)

class Connection(Loop):
    '''A `Loop` with an associated socket and I/O stream.
    '''
    def __init__(self, sock, addr, connection_handler):
        Loop.__init__(self, connection_handler, addr)
        self.pipeline = pipeline.Pipeline()
        self.buffer = buffer.Buffer()
        self.sock = sock
        self.addr = addr
        self.hub.register(sock, self.handle_read, self.handle_write, self.handle_error)
        self._wakeup_timer = None
        self._writable = False
        self.callbacks = deque()
        self.closed = False

    def set_writable(self, val):
        '''Set the associated socket writable.  Called when there is
        data on the outgoing pipeline ready to be delivered to the
        remote host.
        '''
        if self.closed:
            return
        if val and not self._writable:
            self.hub.enable_write(self.sock)
            self._writable = True
            return
        if not val and self._writable:
            self.hub.disable_write(self.sock)
            self._writable = False

    def shutdown(self, remote_closed=False):
        '''Clean up after a client disconnects or after
        the connection_handler ends (and we disconnect).
        '''
        self.hub.unregister(self.sock)
        self.closed = True
        try:
            if not remote_closed:
                self.sock.close()
            else:
                try:
                    self.g.throw(ConnectionClosed)
                except StopIteration:
                    pass
        finally:
            self.g = None

    def handle_write(self):
        '''The low-level handler called by the event hub
        when the socket is ready for writing.
        '''
        if not self.pipeline.empty:
            try:
                data = self.pipeline.read(BUFSIZ)
            except pipeline.PipelineCloseRequest:
                self.shutdown()
            else:
                try:
                    bsent = self.sock.send(data)
                except socket.error, s:
                    code, s = e
                    if code in (errno.EAGAIN, errno.EINTR):
                        self.pipeline.backup(data)
                        return True
                    g = self.g
                    self.shutdown(True)
                else:
                    if bsent != len(data):
                        self.pipeline.backup(data[bsent:])

                    if not self.pipeline.empty:
                        return True
                    else:
                        self.set_writable(False)

    def handle_read(self):
        '''The low-level handler called by the event hub
        when the socket is ready for reading.
        '''
        disconnect_reason = None
        try:
            data = self.sock.recv(BUFSIZ)
        except socket.error, e:
            code, s = e
            if code in (errno.EAGAIN, errno.EINTR):
                return
            data = ''
            disconnect_reason = str(e)

        if not data:
            g = self.g
            self.shutdown(True)
        else:
            res = self.buffer.feed(data)
            if res:
                self.new_data(res)

    def handle_error(self):
        self.shutdown(True)
<commit_msg>Use repr() instead of str() for unknown yield token, and make sure you don't get bitten (str formatting error) if it's a tuple.<commit_after># vim:ts=4:sw=4:expandtab
'''Core implementation/handling of generators, including
the various yield tokens.
'''
import socket
import traceback
import errno
import sys
import ssl
from types import GeneratorType
from collections import deque, defaultdict

from diesel import pipeline
from diesel import buffer
from diesel.client import call, message, response, connect
from diesel.security import ssl_async_handshake

class ConnectionClosed(socket.error):
    '''Raised if the client closes the connection.
    '''
    pass

CRLF = '\r\n'
BUFSIZ = 2 ** 14

class until(object):
    '''A yield token that indicates the generator wants
    a string sent back from the socket stream when a
    certain `sentinel` is encountered.
    '''
    def __init__(self, sentinel):
        self.sentinel = sentinel

def until_eol():
    '''Macro for `until("\r\n")`.
    '''
    return until(CRLF)

class bytes(object):
    '''A yield token that indicates the generator wants
    a string sent back from the socket stream when a
    certain number of bytes are available.
    '''
    def __init__(self, sentinel):
        self.sentinel = sentinel

class sleep(object):
    '''A yield token that indicates the generator wants
    a callback in `duration` seconds.

    If no argument is passed, the generator will be called
    again during the next iteration of the main loop.  It
    can act as a way to yield control to other loops, with
    the intention of taking control back as soon as they've
    had a pass.
    '''
    def __init__(self, duration=0):
        self.duration = duration

class up(object):
    '''For nested generators, a yield token that indicates this value is
    being passed "up" the stack to the "calling" generator, and isn't intended
    as a message for diesel itself.
    '''
    def __init__(self, value):
        self.value = value

class wait(object):
    '''A yield token that indicates a generators desire to wait until a
    certain event is `fire`d.
    '''
    def __init__(self, event):
        self.event = event

class fire(object):
    '''A yield token that fires an event to any appropriate `wait`ers.
    '''
    def __init__(self, event, value=None):
        self.event = event
        self.value = value

class catch(object):
    '''A yield token that indicates a "calling" generator's willingness
    to handle certain types of failures in "called" generators.. must be
    paired with another generator.
    '''
    def __init__(self, call, *exc_types):
        self.call = call
        self.exc_types = set(exc_types)

class WaitPool(object):
    '''A structure that manages all `wait`ers, makes sure fired events
    get to the right places, and that all other waits are canceled when
    a one event is passed back to a generator.
    '''
    def __init__(self):
        self.waits = defaultdict(set)
        self.loop_refs = defaultdict(set)

    def wait(self, who, what):
        self.waits[what].add(who)
        self.loop_refs[who].add(what)

    def fire(self, what, value):
        for handler in self.waits[what].copy():
            handler.fire(what, value)

    def clear(self, who):
        for what in self.loop_refs[who]:
            self.waits[what].remove(who)
        del self.loop_refs[who]

waits = WaitPool()

class NoPipeline(object):
    '''Fake pipeline for Loops that aren't managing a connection and have no
    I/O stream.
    '''
    def __getattr__(self, *args, **kw):
        return ValueError("Cannot write to the outgoing pipeline for socketless Loops (yield string, file)")
    empty = True

class NoBuffer(object):
    '''Fake buffer for loops that aren't managing a connection and have no
    I/O stream.
    '''
    def __getattr__(self, *args, **kw):
        return ValueError("Cannot check incoming buffer on socketless Loops (yield until, bytes, etc)")

def id_gen():
    x = 1
    while True:
        yield x
        x += 1
ids = id_gen()

def print_errstack(stack, e):
    eout = lambda s: sys.stderr.write(str(s) + "\n")
    eout("=== DIESEL ERROR ===")
    if stack:
        eout("")
        eout(" Generator stack at time of error:")
        eout("")
        for g, c in stack:
            eout(g.gi_code,)
            if c:
                eout("catches %r" % c.exc_types)
            else:
                eout("")
        eout("")
    eout("")
    eout(" Standard Traceback:")
    eout("")
    traceback.print_exception(*e)

class Loop(object):
    '''A cooperative generator that represents an arbitrary piece of
    logic.
    '''
    def __init__(self, loop_callable, *callable_args):
        self.g = self.cycle_all(loop_callable(*callable_args))
        self.pipeline = NoPipeline()
        self.buffer = NoBuffer()
        from diesel.app import current_app
        self.hub = current_app.hub
        self.id = ids.next()
        self._wakeup_timer = None
        self.fire_handlers = {}

    def __hash__(self):
        return self.id

    def __eq__(self, other):
        return other.id == self.id

    def fire(self, what, value):
        '''Fire an event back into this generator.
        '''
        if what in self.fire_handlers:
            handler = self.fire_handlers.pop(what)
            self.fire_handlers = {}
            handler(value)

    def cycle_all(self, current, error=None):
        '''Effectively flattens all iterators, providing the
        "generator stack" effect.
        '''
        last = None
        in_self_call = False
        stack = []
        while True:
            try:
                if error != None:
                    item = current.throw(*error)
                elif last != None:
                    item = current.send(last)
                else:
                    item = current.next()
            except StopIteration:
                if stack:
                    current, _ = stack.pop()
                else:
                    raise
            except Exception, e:
                errstack = stack[:] + [(current, None)]
                error = None
                while stack:
                    current, level_catch = stack.pop()
                    if level_catch and \
                    filter(None, map(lambda x: isinstance(e, x),
                    level_catch.exc_types)):

                        error = tuple(sys.exc_info()[:2])
                        break
                    else:
                        current.close()
                if not error: # no one claims to handle it
                    print_errstack(errstack, sys.exc_info())
                    raise StopIteration()
            else:
                level_catch = None
                error = None

                if type(item) is catch:
                    level_catch = item
                    item = item.call

                if type(item) is GeneratorType:
                    stack.append((current, level_catch))
                    current = item
                    last = None
                elif type(item) is call and item.client.conn == self:
                    in_self_call = True
                    stack.append((current, level_catch))
                    current = item.gen
                    last = None
                else:
                    if type(item) is response:
                        assert stack, "Cannot return a response from main handler"
                        current, _ = stack.pop()
                        if in_self_call:
                            in_self_call = False
                            item = up(item.value)
                    elif type(item) is up:
                        assert stack, "Cannot return an up from main handler"
                        current, _ = stack.pop()
                    try:
                        last = (yield item)
                    except ConnectionClosed, e:
                        error = (ConnectionClosed, str(e))

    def multi_callin(self, pos, tot, real_f=None):
        '''Provide a callable that will pass `None` in all spots
        that aren't the event that triggered the rescheduling of the
        generator.  For yield groups.
        '''
        real_f = real_f or self.wake
        if tot == 1:
            return real_f
        def f(res):
            real_arg = [None] * tot
            real_arg[pos] = res
            return real_f(tuple(real_arg))
        return f

    def iterate(self, n_val=None):
        '''The algorithm that represents iterating over all items
        in the nested generator that represents this Loop or
        Connection.  Run whenever a generator is (re-)scheduled.
        Handles all the `yield` tokens.
        '''
        if self.g is None:
            return

        while True:
            try:
                if isinstance(n_val, Exception):
                    self.g.throw(n_val)
                elif n_val is not None:
                    rets = self.g.send(n_val)
                else:
                    rets = self.g.next()
            except StopIteration:
                if hasattr(self, 'sock'):
                    self.pipeline.close_request()
                break
            n_val = None
            if type(rets) != tuple:
                rets = (rets,)

            exit = False
            used_term = False
            nrets = len(rets)
            for pos, ret in enumerate(rets):

                if type(ret) is str or hasattr(ret, 'seek'):
                    assert nrets == 1, "a string or file cannot be paired with any other yield token"
                    self.pipeline.add(ret)
                elif type(ret) is until or type(ret) is bytes:
                    assert used_term == False, "only one terminal specifier (bytes, until) per yield"
                    used_term = True
                    self.buffer.set_term(ret.sentinel)
                    n_val = self.buffer.check()
                    if n_val == None:
                        exit = True
                        self.new_data = self.multi_callin(pos, nrets)
                    else:
                        if nrets > 1:
                            t = [None] * nrets
                            t[pos] = n_val
                            n_val = tuple(t)
                        self.clear_pending_events()
                        exit = False
                        break
                elif type(ret) is connect:
                    assert nrets == 1, "connect cannot be paired with any other yield token"
                    def connect_callback():
                        self.hub.unregister(ret.sock)
                        def finish():
                            ret.callback()
                            self.multi_callin(pos, nrets)()
                        if ret.security:
                            ret.sock = ret.security.wrap(ret.sock)
                            ssl_async_handshake(ret.sock, self.hub, finish)
                        else:
                            finish()

                    def error_callback():
                        self.hub.unregister(ret.sock)
                        raise ConnectionClosed("odd error on connect()!")

                    def read_callback():
                        self.hub.unregister(ret.sock)
                        try:
                            s = ret.sock.recv(100)
                        except socket.error, e:
                            self.multi_callin(pos, nrets)(ConnectionClosed(str(e)))

                    self.hub.register(ret.sock, read_callback, connect_callback, error_callback)
                    self.hub.enable_write(ret.sock)
                    exit = True

                elif type(ret) is sleep:
                    self._wakeup_timer = self.hub.call_later(ret.duration, self.multi_callin(pos, nrets), True)
                    exit = True

                elif type(ret) is up:
                    assert nrets == 1, "up cannot be paired with any other yield token"
                    n_val = ret.value

                elif type(ret) is fire:
                    assert nrets == 1, "fire cannot be paired with any other yield token"
                    waits.fire(ret.event, ret.value)

                elif type(ret) is wait:
                    self.fire_handlers[ret.event] = self.multi_callin(pos, nrets, self.schedule)
                    waits.wait(self, ret.event)
                    exit = True

                elif type(ret) is response:
                    assert nrets == 1, "response cannot be paired with any other yield token"
                    c = self.callbacks.popleft()
                    c(ret.value)
                    exit = True

                elif type(ret) is call:
                    assert nrets == 1, "call cannot be paired with any other yield token"
                    ret.go(self.iterate)
                    exit = True

                elif type(ret) is message:
                    assert nrets == 1, "message cannot be paired with any other yield token"
                    ret.go()

                else:
                    raise ValueError("Unknown yield token %r" % (ret,))
            if exit:
                break

        if not self.pipeline.empty:
            self.set_writable(True)

    def clear_pending_events(self):
        '''When a loop is rescheduled, cancel any other timers or waits.
        '''
        if self._wakeup_timer and self._wakeup_timer.pending:
            self._wakeup_timer.cancel()
        self.fire_handlers = {}
        waits.clear(self)

    def schedule(self, value=None):
        '''Called by another Loop--reschedule this loop so the hub will run
        it.  Used in `response` and `fire` situations.
        '''
        self.hub.schedule(lambda: self.wake(value))

    def wake(self, value=None):
        '''Wake up this loop.  Called by the main hub to resume a loop
        when it is rescheduled.
        '''
        self.clear_pending_events()
        self.iterate(value)

class Connection(Loop):
    '''A `Loop` with an associated socket and I/O stream.
    '''
    def __init__(self, sock, addr, connection_handler):
        Loop.__init__(self, connection_handler, addr)
        self.pipeline = pipeline.Pipeline()
        self.buffer = buffer.Buffer()
        self.sock = sock
        self.addr = addr
        self.hub.register(sock, self.handle_read, self.handle_write, self.handle_error)
        self._wakeup_timer = None
        self._writable = False
        self.callbacks = deque()
        self.closed = False

    def set_writable(self, val):
        '''Set the associated socket writable.  Called when there is
        data on the outgoing pipeline ready to be delivered to the
        remote host.
        '''
        if self.closed:
            return
        if val and not self._writable:
            self.hub.enable_write(self.sock)
            self._writable = True
            return
        if not val and self._writable:
            self.hub.disable_write(self.sock)
            self._writable = False

    def shutdown(self, remote_closed=False):
        '''Clean up after a client disconnects or after
        the connection_handler ends (and we disconnect).
        '''
        self.hub.unregister(self.sock)
        self.closed = True
        try:
            if not remote_closed:
                self.sock.close()
            else:
                try:
                    self.g.throw(ConnectionClosed)
                except StopIteration:
                    pass
        finally:
            self.g = None

    def handle_write(self):
        '''The low-level handler called by the event hub
        when the socket is ready for writing.
        '''
        if not self.pipeline.empty:
            try:
                data = self.pipeline.read(BUFSIZ)
            except pipeline.PipelineCloseRequest:
                self.shutdown()
            else:
                try:
                    bsent = self.sock.send(data)
                except socket.error, s:
                    code, s = e
                    if code in (errno.EAGAIN, errno.EINTR):
                        self.pipeline.backup(data)
                        return True
                    g = self.g
                    self.shutdown(True)
                else:
                    if bsent != len(data):
                        self.pipeline.backup(data[bsent:])

                    if not self.pipeline.empty:
                        return True
                    else:
                        self.set_writable(False)

    def handle_read(self):
        '''The low-level handler called by the event hub
        when the socket is ready for reading.
        '''
        disconnect_reason = None
        try:
            data = self.sock.recv(BUFSIZ)
        except socket.error, e:
            code, s = e
            if code in (errno.EAGAIN, errno.EINTR):
                return
            data = ''
            disconnect_reason = str(e)

        if not data:
            g = self.g
            self.shutdown(True)
        else:
            res = self.buffer.feed(data)
            if res:
                self.new_data(res)

    def handle_error(self):
        self.shutdown(True)
<|endoftext|>


<commit_before>#!/usr/bin/env python
"""
This script introspects the RTF unit tests and generates the files that are
used for comparison when running those tests.

Note that this script intentionally only writes to a pending directory. You
must manually verify that the generated files are what you expect (I recommend
using OpenOffice for this). Aftwards, copy the good files over to the
sources/rtfng directory.

Once verified and copied, the docs generated will be used in the unit tests
against which test output will be checked. Thus any changes introduced into the
codebase that affect how these generated RTF files are rendered may cause the
tests to fail. For buggy code, this is exactly what we want, so that we can see
the error(s) happening in our tests and write new ones when our fixes are in
place. For new features, we need to update the unit tests, verify that they
create the correct output, and then regenerate the reference RTF files with
this script.
"""
import os
from unittest import TestCase

from rtfng.utils import findTests, importModule

from test.test_all import searchDirs, skipFiles

base = ['test', 'sources', 'rtfng']
pending = base + ['pending']
baseDir = os.path.join(*base)
pendingDir = os.path.join(*pending)

# iterate through the test files
for startDir in searchDirs:
    for testFile in findTests(startDir, skipFiles):
            modBase = os.path.splitext(testFile)[0]
            name = modBase.replace(os.path.sep, '.')
            # import the testFile as a module
            mod = importModule(name)
            # iterate through module objects, checking for TestCases
            for objName in dir(mod):
                if not objName.endswith('TestCase'):
                    continue
                obj = getattr(mod, objName)
                if not issubclass(obj, TestCase):
                    continue
                # iterate through the TestCase attrs, looking for make_*
                # methods
                for attrName in dir(obj):
                    if attrName.startswith('make_'):
                        filename = attrName.split('make_')[1] + '.rtf'
                        doc = getattr(obj, attrName)()
                        fh = open(os.path.join(pendingDir, filename), 'w+')
                        print "Writing %s ..." % filename
                        doc.write(fh)
                        fh.close()

<commit_msg>complain on duplicate test method names<commit_after>#!/usr/bin/env python
"""
This script introspects the RTF unit tests and generates the files that are
used for comparison when running those tests.

Note that this script intentionally only writes to a pending directory. You
must manually verify that the generated files are what you expect (I recommend
using OpenOffice for this). Aftwards, copy the good files over to the
sources/rtfng directory.

Once verified and copied, the docs generated will be used in the unit tests
against which test output will be checked. Thus any changes introduced into the
codebase that affect how these generated RTF files are rendered may cause the
tests to fail. For buggy code, this is exactly what we want, so that we can see
the error(s) happening in our tests and write new ones when our fixes are in
place. For new features, we need to update the unit tests, verify that they
create the correct output, and then regenerate the reference RTF files with
this script.
"""
import os
from unittest import TestCase

from rtfng.utils import findTests, importModule

from test.test_all import searchDirs, skipFiles

base = ['test', 'sources', 'rtfng']
pending = base + ['pending']
baseDir = os.path.join(*base)
pendingDir = os.path.join(*pending)
doneList = []

# iterate through the test files
for startDir in searchDirs:
    for testFile in findTests(startDir, skipFiles):
            modBase = os.path.splitext(testFile)[0]
            name = modBase.replace(os.path.sep, '.')
            # import the testFile as a module
            mod = importModule(name)
            # iterate through module objects, checking for TestCases
            for objName in dir(mod):
                if not objName.endswith('TestCase'):
                    continue
                obj = getattr(mod, objName)
                if not issubclass(obj, TestCase):
                    continue
                # iterate through the TestCase attrs, looking for make_*
                # methods
                for attrName in dir(obj):
                    if attrName.startswith('make_'):
                        if attrName in doneList:
                            raise Exception('Duplicate test method found: %s' % attrName)
                        else:
                            doneList.append(attrName)
                        filename = attrName.split('make_')[1] + '.rtf'
                        doc = getattr(obj, attrName)()
                        fh = open(os.path.join(pendingDir, filename), 'w+')
                        print "Writing %s ..." % filename
                        doc.write(fh)
                        fh.close()

<|endoftext|>


<commit_before>#!/usr/bin/env python
"""
This script introspects the RTF unit tests and generates the files that are
used for comparison when running those tests.

Note that this script intentionally only writes to a pending directory. You
must manually verify that the generated files are what you expect (I recommend
using OpenOffice for this). Aftwards, copy the good files over to the
sources/rtfng directory.

Once verified and copied, the docs generated will be used in the unit tests
against which test output will be checked. Thus any changes introduced into the
codebase that affect how these generated RTF files are rendered may cause the
tests to fail. For buggy code, this is exactly what we want, so that we can see
the error(s) happening in our tests and write new ones when our fixes are in
place. For new features, we need to update the unit tests, verify that they
create the correct output, and then regenerate the reference RTF files with
this script.
"""
import os, sys
from unittest import TestCase

from rtfng.utils import findTests, importModule

from test.test_all import searchDirs, skipFiles

base = ['test', 'sources', 'rtfng']
pending = base + ['pending']
baseDir = os.path.join(*base)
pendingDir = os.path.join(*pending)
doneList = []

requestedList = sys.argv[1:]
if requestedList:
    print 'Only writing these methods: %s' % ', '.join(requestedList)

# iterate through the test files
for startDir in searchDirs:
    for testFile in findTests(startDir, skipFiles):
            modBase = os.path.splitext(testFile)[0]
            name = modBase.replace(os.path.sep, '.')
            # import the testFile as a module
            mod = importModule(name)
            # iterate through module objects, checking for TestCases
            for objName in dir(mod):
                if not objName.endswith('TestCase'):
                    continue
                obj = getattr(mod, objName)
                if not issubclass(obj, TestCase):
                    continue
                # iterate through the TestCase attrs, looking for make_*
                # methods
                for attrName in dir(obj):
                    if attrName.startswith('make_'):

                        # Make sure this is not a duplicate.
                        if attrName in doneList:
                            raise Exception('Duplicate test method found: %s' % attrName)
                        else:
                            doneList.append(attrName)

                        # Skip if not requested.
                        rootName = attrName.split('make_')[1]
                        if requestedList:
                            # Make sure this is requested.
                            if rootName not in requestedList:
                                continue

                        # Save file.
                        filename = '%s.rtf' % rootName
                        doc = getattr(obj, attrName)()
                        fh = open(os.path.join(pendingDir, filename), 'w+')
                        print "Writing %s ..." % filename
                        doc.write(fh)
                        fh.close()

<commit_msg>simplify nested if condition to one if condition<commit_after>#!/usr/bin/env python
"""
This script introspects the RTF unit tests and generates the files that are
used for comparison when running those tests.

Note that this script intentionally only writes to a pending directory. You
must manually verify that the generated files are what you expect (I recommend
using OpenOffice for this). Aftwards, copy the good files over to the
sources/rtfng directory.

Once verified and copied, the docs generated will be used in the unit tests
against which test output will be checked. Thus any changes introduced into the
codebase that affect how these generated RTF files are rendered may cause the
tests to fail. For buggy code, this is exactly what we want, so that we can see
the error(s) happening in our tests and write new ones when our fixes are in
place. For new features, we need to update the unit tests, verify that they
create the correct output, and then regenerate the reference RTF files with
this script.
"""
import os, sys
from unittest import TestCase

from rtfng.utils import findTests, importModule

from test.test_all import searchDirs, skipFiles

base = ['test', 'sources', 'rtfng']
pending = base + ['pending']
baseDir = os.path.join(*base)
pendingDir = os.path.join(*pending)
doneList = []

requestedList = sys.argv[1:]
if requestedList:
    print 'Only writing these methods: %s' % ', '.join(requestedList)

# iterate through the test files
for startDir in searchDirs:
    for testFile in findTests(startDir, skipFiles):
            modBase = os.path.splitext(testFile)[0]
            name = modBase.replace(os.path.sep, '.')
            # import the testFile as a module
            mod = importModule(name)
            # iterate through module objects, checking for TestCases
            for objName in dir(mod):
                if not objName.endswith('TestCase'):
                    continue
                obj = getattr(mod, objName)
                if not issubclass(obj, TestCase):
                    continue
                # iterate through the TestCase attrs, looking for make_*
                # methods
                for attrName in dir(obj):
                    if attrName.startswith('make_'):

                        # Make sure this is not a duplicate.
                        if attrName in doneList:
                            raise Exception('Duplicate test method found: %s' % attrName)
                        else:
                            doneList.append(attrName)

                        # Skip if not requested.
                        rootName = attrName.split('make_')[1]
                        if requestedList and rootName not in requestedList:
                            continue

                        # Save file.
                        filename = '%s.rtf' % rootName
                        doc = getattr(obj, attrName)()
                        fh = open(os.path.join(pendingDir, filename), 'w+')
                        print "Writing %s ..." % filename
                        doc.write(fh)
                        fh.close()

<|endoftext|>


<commit_before>from __future__ import unicode_literals

from django.conf import settings
from django.utils.encoding import python_2_unicode_compatible
from django.utils.six import iteritems

from ..settings import (
    cache,
    VERSATILEIMAGEFIELD_CACHE_LENGTH
)
from ..utils import get_filtered_path

from .base import ProcessedImage
from .mixins import DeleteAndClearCacheMixIn

class InvalidFilter(Exception):
    pass

@python_2_unicode_compatible
class FilteredImage(DeleteAndClearCacheMixIn, ProcessedImage):
    """
    A ProcessedImage subclass that applies a filter to an image.

    Constructor arguments:
        * `path_to_image`: The path within `storage` of the image
                           to filter.
        * `storage`: A django storage class.
        * `filename_key`: A string that is included in the filtered
                          filename to identify it. This should be short
                          and descriptive (i.e. 'grayscale' or 'invert')

    Subclasses must implement a process_image method.
    """

    def __init__(self, path_to_image, storage, create_on_demand, filename_key):
        super(FilteredImage, self).__init__(
            path_to_image, storage, create_on_demand
        )
        self.name = get_filtered_path(
            path_to_image=self.path_to_image,
            filename_key=filename_key,
            storage=storage
        )

        self.url = storage.url(self.name)

    def create_filtered_image(self, path_to_image, save_path_on_storage):
        """
        Creates a filtered image.
        `path_to_image`: The path to the image with the media directory
                         to resize.
        `save_path_on_storage`: Where on self.storage to save the filtered
                                image
        """

        image, file_ext, image_format, mime_type = self.retrieve_image(
            path_to_image
        )
        image, save_kwargs = self.preprocess(image, image_format)
        imagefile = self.process_image(image, image_format, save_kwargs)
        self.save_image(imagefile, save_path_on_storage, file_ext, mime_type)

    def __str__(self):
        return self.url

class DummyFilter(object):
    """
    A 'dummy' version of FilteredImage which is only used if
    settings.VERSATILEIMAGEFIELD_USE_PLACEHOLDIT is True
    """
    name = ''
    url = ''

class FilterLibrary(dict):
    """
    Exposes all filters registered with the sizedimageregistry
    (via sizedimageregistry.register_filter) to each VersatileImageField.

    Each filter also has access to each 'sizer' registered with
    sizedimageregistry (via sizedimageregistry.register_sizer)
    """

    def __init__(self, original_file_location,
                 storage, registry, ppoi, create_on_demand):
        self.original_file_location = original_file_location
        self.storage = storage
        self.registry = registry
        self.ppoi = ppoi
        self.create_on_demand = create_on_demand

    def __getattr__(self, key):
        return self[key]

    def __getitem__(self, key):
        """
        Returns a FilteredImage instance built from the FilteredImage subclass
        associated with self.registry[key]

        If no FilteredImage subclass is associated with self.registry[key],
        InvalidFilter will raise.
        """
        try:
            # FilteredImage instances are not built until they're accessed for
            # the first time (in order to cut down on memory usage and disk
            # space) However, once built, they can be accessed directly by
            # calling the dict superclass's __getitem__ (which avoids the
            # infinite loop that would be caused by using self[key]
            # or self.get(key))
            prepped_filter = dict.__getitem__(self, key)
        except KeyError:
            # See if `key` is associated with a valid filter.
            if key not in self.registry._filter_registry:
                raise InvalidFilter('`%s` is an invalid filter.' % key)
            else:
                # Handling 'empty' fields.
                if not self.original_file_location and getattr(
                    settings, 'VERSATILEIMAGEFIELD_USE_PLACEHOLDIT', False
                ):
                    # If VERSATILEIMAGEFIELD_USE_PLACEHOLDIT is True (i.e.
                    # settings.VERSATILEIMAGEFIELD_PLACEHOLDER_IMAGE is unset)
                    # use DummyFilter (so sized renditions can still return
                    # valid http://placehold.it URLs).
                    filtered_path = None
                    prepped_filter = DummyFilter()
                else:
                    filtered_path = get_filtered_path(
                        path_to_image=self.original_file_location,
                        filename_key=key,
                        storage=self.storage
                    )

                    filtered_url = self.storage.url(filtered_path)

                    filter_cls = self.registry._filter_registry[key]
                    prepped_filter = filter_cls(
                        path_to_image=self.original_file_location,
                        storage=self.storage,
                        create_on_demand=self.create_on_demand,
                        filename_key=key
                    )
                    if self.create_on_demand is True:
                        if cache.get(filtered_url):
                            # The filtered_url exists in the cache so the image
                            # already exists. So we `pass` to skip directly to
                            # the return statement.
                            pass
                        else:
                            if not self.storage.exists(filtered_path):
                                prepped_filter.create_filtered_image(
                                    path_to_image=self.original_file_location,
                                    save_path_on_storage=filtered_path
                                )

                            # Setting a super-long cache for the newly created
                            # image
                            cache.set(
                                filtered_url,
                                1,
                                VERSATILEIMAGEFIELD_CACHE_LENGTH
                            )

                # 'Bolting' all image sizers within
                # `self.registry._sizedimage_registry` onto
                # the prepped_filter instance
                for (
                        attr_name, sizedimage_cls
                ) in iteritems(self.registry._sizedimage_registry):
                    setattr(
                        prepped_filter,
                        attr_name,
                        sizedimage_cls(
                            path_to_image=filtered_path,
                            storage=self.storage,
                            create_on_demand=self.create_on_demand,
                            ppoi=self.ppoi
                        )
                    )
                # Assigning `prepped_filter` to `key` so future access
                # is fast/cheap
                self[key] = prepped_filter

        return dict.__getitem__(self, key)
<commit_msg>fixing formatting<commit_after>from __future__ import unicode_literals

from django.conf import settings
from django.utils.encoding import python_2_unicode_compatible
from django.utils.six import iteritems

from ..settings import (
    cache,
    VERSATILEIMAGEFIELD_CACHE_LENGTH
)
from ..utils import get_filtered_path

from .base import ProcessedImage
from .mixins import DeleteAndClearCacheMixIn

class InvalidFilter(Exception):
    pass

@python_2_unicode_compatible
class FilteredImage(DeleteAndClearCacheMixIn, ProcessedImage):
    """
    A ProcessedImage subclass that applies a filter to an image.

    Constructor arguments:
        * `path_to_image`: The path within `storage` of the image
                           to filter.
        * `storage`: A django storage class.
        * `filename_key`: A string that is included in the filtered
                          filename to identify it. This should be short
                          and descriptive (i.e. 'grayscale' or 'invert')

    Subclasses must implement a process_image method.
    """

    def __init__(self, path_to_image, storage, create_on_demand, filename_key):
        super(FilteredImage, self).__init__(
            path_to_image, storage, create_on_demand
        )
        self.name = get_filtered_path(
            path_to_image=self.path_to_image,
            filename_key=filename_key,
            storage=storage
        )

        self.url = storage.url(self.name)

    def create_filtered_image(self, path_to_image, save_path_on_storage):
        """
        Creates a filtered image.
        `path_to_image`: The path to the image with the media directory
                         to resize.
        `save_path_on_storage`: Where on self.storage to save the filtered
                                image
        """

        image, file_ext, image_format, mime_type = self.retrieve_image(
            path_to_image
        )
        image, save_kwargs = self.preprocess(image, image_format)
        imagefile = self.process_image(image, image_format, save_kwargs)
        self.save_image(imagefile, save_path_on_storage, file_ext, mime_type)

    def __str__(self):
        return self.url

class DummyFilter(object):
    """
    A 'dummy' version of FilteredImage which is only used if
    settings.VERSATILEIMAGEFIELD_USE_PLACEHOLDIT is True
    """
    name = ''
    url = ''

class FilterLibrary(dict):
    """
    Exposes all filters registered with the sizedimageregistry
    (via sizedimageregistry.register_filter) to each VersatileImageField.

    Each filter also has access to each 'sizer' registered with
    sizedimageregistry (via sizedimageregistry.register_sizer)
    """

    def __init__(self, original_file_location,
                 storage, registry, ppoi, create_on_demand):
        self.original_file_location = original_file_location
        self.storage = storage
        self.registry = registry
        self.ppoi = ppoi
        self.create_on_demand = create_on_demand

    def __getattr__(self, key):
        return self[key]

    def __getitem__(self, key):
        """
        Returns a FilteredImage instance built from the FilteredImage subclass
        associated with self.registry[key]

        If no FilteredImage subclass is associated with self.registry[key],
        InvalidFilter will raise.
        """
        try:
            # FilteredImage instances are not built until they're accessed for
            # the first time (in order to cut down on memory usage and disk
            # space) However, once built, they can be accessed directly by
            # calling the dict superclass's __getitem__ (which avoids the
            # infinite loop that would be caused by using self[key]
            # or self.get(key))
            prepped_filter = dict.__getitem__(self, key)
        except KeyError:
            # See if `key` is associated with a valid filter.
            if key not in self.registry._filter_registry:
                raise InvalidFilter('`%s` is an invalid filter.' % key)
            else:
                # Handling 'empty' fields.
                if not self.original_file_location and getattr(
                    settings, 'VERSATILEIMAGEFIELD_USE_PLACEHOLDIT', False
                ):
                    # If VERSATILEIMAGEFIELD_USE_PLACEHOLDIT is True (i.e.
                    # settings.VERSATILEIMAGEFIELD_PLACEHOLDER_IMAGE is unset)
                    # use DummyFilter (so sized renditions can still return
                    # valid http://placehold.it URLs).
                    filtered_path = None
                    prepped_filter = DummyFilter()
                else:
                    filtered_path = get_filtered_path(
                        path_to_image=self.original_file_location,
                        filename_key=key,
                        storage=self.storage
                    )

                    filtered_url = self.storage.url(filtered_path)

                    filter_cls = self.registry._filter_registry[key]
                    prepped_filter = filter_cls(
                        path_to_image=self.original_file_location,
                        storage=self.storage,
                        create_on_demand=self.create_on_demand,
                        filename_key=key
                    )
                    if self.create_on_demand is True:
                        if cache.get(filtered_url):
                            # The filtered_url exists in the cache so the image
                            # already exists. So we `pass` to skip directly to
                            # the return statement.
                            pass
                        else:
                            if not self.storage.exists(filtered_path):
                                prepped_filter.create_filtered_image(
                                    path_to_image=self.original_file_location,
                                    save_path_on_storage=filtered_path
                                )

                            # Setting a super-long cache for the newly created
                            # image
                            cache.set(
                                filtered_url,
                                1,
                                VERSATILEIMAGEFIELD_CACHE_LENGTH
                            )

                # 'Bolting' all image sizers within
                # `self.registry._sizedimage_registry` onto
                # the prepped_filter instance
                for (
                        attr_name, sizedimage_cls
                ) in iteritems(self.registry._sizedimage_registry):
                    setattr(
                        prepped_filter,
                        attr_name,
                        sizedimage_cls(
                            path_to_image=filtered_path,
                            storage=self.storage,
                            create_on_demand=self.create_on_demand,
                            ppoi=self.ppoi
                        )
                    )
                # Assigning `prepped_filter` to `key` so future access
                # is fast/cheap
                self[key] = prepped_filter

        return dict.__getitem__(self, key)
<|endoftext|>


<commit_before>import RPi.GPIO as GPIO
from time import sleep

#Times in ns
E_CYCLE = 500
E_RISE_FALL = 20
E_PULSE_WIDTH = 230

DATA = [0 for x in range(0, 7)]

'''
Anslutningar till GPIO-portar. Alla portar ar i board-numbering
GPIO 	29, 31, 32, 33, 35, 36, 37, 38
GROUND 	30
5V/VCC 	02
E		40
A		02
K		06
'''

#29 is MSB, 38 LSB
pins = [29, 31, 32, 33, 35, 36, 37, 38]
RS = 22
E = 40

FUNCTION_SET = [0, 0, 1, 1, 0, 0, 0, 0]
DISPLAY_ONOFF_CONTROL = [0, 0, 0, 0, 1, 1, 1, 1] #display, cursor, blink on
DISPLAY_CLEAR = [0, 0, 0, 0, 0, 0, 0, 1]
ENTRY_MODE_SET = [0, 0, 0, 0, 0, 1, 1, 0] #increment mode, entire shift off
DISPLAY_ON = [0, 0, 0, 0, 1, 1, 0, 0]

BIT_PATTERN = {
    'A': '01000001',
    'B': '01000010',
    'C': '01000011',
    'D': '01000100',
    'E': '01000101',
    'F': '01000110',
    'G': '01000111',
    'H': '01001000',
    'I': '01001001',
    'J': '01001010',
    'K': '01001011',
    'L': '01001100',
    'M': '01001101',
    'N': '01001110',
    'O': '01001111',
    'P': '01010000',
    'Q': '01010001',
    'R': '01010010',
    'S': '01010011',
    'T': '01010100',
    'U': '01010101',
    'V': '01010110',
    'W': '01010111',
    'X': '01011000',
    'Y': '01011001',
    'Z': '01011010',
    'Å': '11110100',
    'Ö': '11100001',
    '0': '11101111',
    '1': '00110001',
    '2': '00110010',
    '3': '00110011',
    '4': '00110100',
    '5': '00110101',
    '6': '00110110',
    '7': '00110111',
    '8': '00111000',
    '9': '00111001',
    '.': '00101110',
    ' ': '00100000'
}

class LCD:

    def initialize(self):
        #Use board numbering
        GPIO.setmode(GPIO.BOARD)

        #Configure output pins
        GPIO.setup(RS, GPIO.OUT)
        GPIO.setup(E, GPIO.OUT)
        GPIO.setup(pins, GPIO.OUT)

        sleep_ms(100)				#Make sure at least 30 ms has passed since power on

        #Power up sequence
        GPIO.output(RS, 0)		    #Select instruction register
        sleep_us(80)
        self._send(FUNCTION_SET)
        sleep_us(80)				#Make super sure that 39 us has passed
        self._send(DISPLAY_ONOFF_CONTROL)
        sleep_us(80)				#Make super sure that 39 us has passed again
        self._send(DISPLAY_CLEAR)
        sleep_ms(4)				    #Make sure that 1.53 ms has passed
        self._send(ENTRY_MODE_SET)
        sleep_ms(10)
        #End of power up sequence. Display is off

        #Turn on display
        #self._send(DISPLAY_ON)
        sleep_us(80)				#Wait a lot

    def clear(self):
        self._send(DISPLAY_CLEAR)

    def send(self, data):
        for d in data:
            self._send(bit_pattern(d))

    def bit_pattern(self, char):
        return BIT_PATTERN[data.upper()]

    def _send(self, data):
        GPIO.output(E, 0) 		#Make sure E is initially low
        GPIO.output(RS, 1)		#Select data register

        #Put the data on the pins
        for d, p in zip(data, pins):
            GPIO.output(p, int(d))

        #Write the data
        GPIO.output(E, 1)
        sleep_us(1)				#Larger than recommended wait
        GPIO.output(E, 0)
        sleep_us(1)				#Larger than recommended wait

    def cleanup(self):
        GPIO.cleanup()

#Sleep in ms
def sleep_ms(t):
    sleep(t / 1000)

#Sleep in us
def sleep_us(t):
    sleep(t / 10000)
<commit_msg>missed self<commit_after>import RPi.GPIO as GPIO
from time import sleep

#Times in ns
E_CYCLE = 500
E_RISE_FALL = 20
E_PULSE_WIDTH = 230

DATA = [0 for x in range(0, 7)]

'''
Anslutningar till GPIO-portar. Alla portar ar i board-numbering
GPIO 	29, 31, 32, 33, 35, 36, 37, 38
GROUND 	30
5V/VCC 	02
E		40
A		02
K		06
'''

#29 is MSB, 38 LSB
pins = [29, 31, 32, 33, 35, 36, 37, 38]
RS = 22
E = 40

FUNCTION_SET = [0, 0, 1, 1, 0, 0, 0, 0]
DISPLAY_ONOFF_CONTROL = [0, 0, 0, 0, 1, 1, 1, 1] #display, cursor, blink on
DISPLAY_CLEAR = [0, 0, 0, 0, 0, 0, 0, 1]
ENTRY_MODE_SET = [0, 0, 0, 0, 0, 1, 1, 0] #increment mode, entire shift off
DISPLAY_ON = [0, 0, 0, 0, 1, 1, 0, 0]

BIT_PATTERN = {
    'A': '01000001',
    'B': '01000010',
    'C': '01000011',
    'D': '01000100',
    'E': '01000101',
    'F': '01000110',
    'G': '01000111',
    'H': '01001000',
    'I': '01001001',
    'J': '01001010',
    'K': '01001011',
    'L': '01001100',
    'M': '01001101',
    'N': '01001110',
    'O': '01001111',
    'P': '01010000',
    'Q': '01010001',
    'R': '01010010',
    'S': '01010011',
    'T': '01010100',
    'U': '01010101',
    'V': '01010110',
    'W': '01010111',
    'X': '01011000',
    'Y': '01011001',
    'Z': '01011010',
    'Å': '11110100',
    'Ö': '11100001',
    '0': '11101111',
    '1': '00110001',
    '2': '00110010',
    '3': '00110011',
    '4': '00110100',
    '5': '00110101',
    '6': '00110110',
    '7': '00110111',
    '8': '00111000',
    '9': '00111001',
    '.': '00101110',
    ' ': '00100000'
}

class LCD:

    def initialize(self):
        #Use board numbering
        GPIO.setmode(GPIO.BOARD)

        #Configure output pins
        GPIO.setup(RS, GPIO.OUT)
        GPIO.setup(E, GPIO.OUT)
        GPIO.setup(pins, GPIO.OUT)

        sleep_ms(100)				#Make sure at least 30 ms has passed since power on

        #Power up sequence
        GPIO.output(RS, 0)		    #Select instruction register
        sleep_us(80)
        self._send(FUNCTION_SET)
        sleep_us(80)				#Make super sure that 39 us has passed
        self._send(DISPLAY_ONOFF_CONTROL)
        sleep_us(80)				#Make super sure that 39 us has passed again
        self._send(DISPLAY_CLEAR)
        sleep_ms(4)				    #Make sure that 1.53 ms has passed
        self._send(ENTRY_MODE_SET)
        sleep_ms(10)
        #End of power up sequence. Display is off

        #Turn on display
        #self._send(DISPLAY_ON)
        sleep_us(80)				#Wait a lot

    def clear(self):
        self._send(DISPLAY_CLEAR)

    def send(self, data):
        for d in data:
            self._send(self.bit_pattern(d))

    def bit_pattern(self, char):
        return BIT_PATTERN[data.upper()]

    def _send(self, data):
        GPIO.output(E, 0) 		#Make sure E is initially low
        GPIO.output(RS, 1)		#Select data register

        #Put the data on the pins
        for d, p in zip(data, pins):
            GPIO.output(p, int(d))

        #Write the data
        GPIO.output(E, 1)
        sleep_us(1)				#Larger than recommended wait
        GPIO.output(E, 0)
        sleep_us(1)				#Larger than recommended wait

    def cleanup(self):
        GPIO.cleanup()

#Sleep in ms
def sleep_ms(t):
    sleep(t / 1000)

#Sleep in us
def sleep_us(t):
    sleep(t / 10000)
<|endoftext|>