<commit_before># -*- Mode: Python -*-
#   Id: asyncore.py,v 2.51 2000/09/07 22:29:26 rushing Exp
#   Author: Sam Rushing <rushing@nightmare.com>

# ======================================================================
# Copyright 1996 by Sam Rushing
#
#                         All Rights Reserved
#
# Permission to use, copy, modify, and distribute this software and
# its documentation for any purpose and without fee is hereby
# granted, provided that the above copyright notice appear in all
# copies and that both that copyright notice and this permission
# notice appear in supporting documentation, and that the name of Sam
# Rushing not be used in advertising or publicity pertaining to
# distribution of the software without specific, written prior
# permission.
#
# SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
# NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR
# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# ======================================================================

"""Basic infrastructure for asynchronous socket service clients and servers.

There are only two ways to have a program on a single processor do "more
than one thing at a time".  Multi-threaded programming is the simplest and
most popular way to do it, but there is another very different technique,
that lets you have nearly all the advantages of multi-threading, without
actually using multiple threads. it's really only practical if your program
is largely I/O bound. If your program is CPU bound, then pre-emptive
scheduled threads are probably what you really need. Network servers are
rarely CPU-bound, however.

If your operating system supports the select() system call in its I/O
library (and nearly all do), then you can use it to juggle multiple
communication channels at once; doing other work while your I/O is taking
place in the "background."  Although this strategy can seem strange and
complex, especially at first, it is in many ways easier to understand and
control than multi-threaded programming. The module documented here solves
many of the difficult problems for you, making the task of building
sophisticated high-performance network servers and clients a snap.
"""

import exceptions
import select
import socket
import sys
import types

import os
from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, \
     ENOTCONN, ESHUTDOWN

try:
    socket_map
except NameError:
    socket_map = {}

class ExitNow (exceptions.Exception):
    pass

DEBUG = 0

def poll (timeout=0.0, map=None):
    global DEBUG
    if map is None:
        map = socket_map
    if map:
        r = []; w = []; e = []
        for fd, obj in map.items():
            if obj.readable():
                r.append (fd)
            if obj.writable():
                w.append (fd)
        r,w,e = select.select (r,w,e, timeout)

        if DEBUG:
            print r,w,e

        for fd in r:
            try:
                obj = map[fd]
                try:
                    obj.handle_read_event()
                except ExitNow:
                    raise ExitNow
                except:
                    obj.handle_error()
            except KeyError:
                pass

        for fd in w:
            try:
                obj = map[fd]
                try:
                    obj.handle_write_event()
                except ExitNow:
                    raise ExitNow
                except:
                    obj.handle_error()
            except KeyError:
                pass

def poll2 (timeout=0.0, map=None):
    import poll
    if map is None:
        map=socket_map
    if timeout is not None:
        # timeout is in milliseconds
        timeout = int(timeout*1000)
    if map:
        l = []
        for fd, obj in map.items():
            flags = 0
            if obj.readable():
                flags = poll.POLLIN
            if obj.writable():
                flags = flags | poll.POLLOUT
            if flags:
                l.append ((fd, flags))
        r = poll.poll (l, timeout)
        for fd, flags in r:
            try:
                obj = map[fd]
                try:
                    if (flags  & poll.POLLIN):
                        obj.handle_read_event()
                    if (flags & poll.POLLOUT):
                        obj.handle_write_event()
                except ExitNow:
                    raise ExitNow
                except:
                    obj.handle_error()
            except KeyError:
                pass

def poll3 (timeout=0.0, map=None):
    # Use the poll() support added to the select module in Python 2.0
    if map is None:
        map=socket_map
    if timeout is not None:
        # timeout is in milliseconds
        timeout = int(timeout*1000)
    pollster = select.poll()
    if map:
        for fd, obj in map.items():
            flags = 0
            if obj.readable():
                flags = select.POLLIN
            if obj.writable():
                flags = flags | select.POLLOUT
            if flags:
                pollster.register(fd, flags)
        r = pollster.poll (timeout)
        for fd, flags in r:
            try:
                obj = map[fd]
                try:
                    if (flags  & select.POLLIN):
                        obj.handle_read_event()
                    if (flags & select.POLLOUT):
                        obj.handle_write_event()
                except ExitNow:
                    raise ExitNow
                except:
                    obj.handle_error()
            except KeyError:
                pass

def loop (timeout=30.0, use_poll=0, map=None):

    if map is None:
        map=socket_map

    if use_poll:
        if hasattr (select, 'poll'):
            poll_fun = poll3
        else:
            poll_fun = poll2
    else:
        poll_fun = poll

    while map:
        poll_fun (timeout, map)

class dispatcher:
    debug = 0
    connected = 0
    accepting = 0
    closing = 0
    addr = None

    def __init__ (self, sock=None, map=None):
        if sock:
            self.set_socket (sock, map)
            # I think it should inherit this anyway
            self.socket.setblocking (0)
            self.connected = 1
            self.addr = sock.getpeername()

    def __repr__ (self):
        try:
            status = []
            if self.accepting and self.addr:
                status.append ('listening')
            elif self.connected:
                status.append ('connected')
            if self.addr:
                if type(self.addr) == types.TupleType:
                    status.append ('%s:%d' % self.addr)
                else:
                    status.append (self.addr)
            return '<%s %s at %x>' % (self.__class__.__name__,
                                      ' '.join (status), id (self))
        except:
            pass

        try:
            ar = repr (self.addr)
        except AttributeError:
            ar = 'no self.addr!'

        return '<__repr__() failed for %s instance at %x (addr=%s)>' % \
               (self.__class__.__name__, id (self), ar)

    def add_channel (self, map=None):
        #self.log_info ('adding channel %s' % self)
        if map is None:
            map=socket_map
        map [self._fileno] = self

    def del_channel (self, map=None):
        fd = self._fileno
        if map is None:
            map=socket_map
        if map.has_key (fd):
            #self.log_info ('closing channel %d:%s' % (fd, self))
            del map [fd]

    def create_socket (self, family, type):
        self.family_and_type = family, type
        self.socket = socket.socket (family, type)
        self.socket.setblocking(0)
        self._fileno = self.socket.fileno()
        self.add_channel()

    def set_socket (self, sock, map=None):
        self.__dict__['socket'] = sock
        self._fileno = sock.fileno()
        self.add_channel (map)

    def set_reuse_addr (self):
        # try to re-use a server port if possible
        try:
            self.socket.setsockopt (
                socket.SOL_SOCKET, socket.SO_REUSEADDR,
                self.socket.getsockopt (socket.SOL_SOCKET,
                                        socket.SO_REUSEADDR) | 1
                )
        except socket.error:
            pass

    # ==================================================
    # predicates for select()
    # these are used as filters for the lists of sockets
    # to pass to select().
    # ==================================================

    def readable (self):
        return 1

    if os.name == 'mac':
        # The macintosh will select a listening socket for
        # write if you let it.  What might this mean?
        def writable (self):
            return not self.accepting
    else:
        def writable (self):
            return 1

    # ==================================================
    # socket object methods.
    # ==================================================

    def listen (self, num):
        self.accepting = 1
        if os.name == 'nt' and num > 5:
            num = 1
        return self.socket.listen (num)

    def bind (self, addr):
        self.addr = addr
        return self.socket.bind (addr)

    def connect (self, address):
        self.connected = 0
        # XXX why not use connect_ex?
        try:
            self.socket.connect (address)
        except socket.error, why:
            if why[0] in (EINPROGRESS, EALREADY, EWOULDBLOCK):
                return
            else:
                raise socket.error, why
        self.addr = address
        self.connected = 1
        self.handle_connect()

    def accept (self):
        try:
            conn, addr = self.socket.accept()
            return conn, addr
        except socket.error, why:
            if why[0] == EWOULDBLOCK:
                pass
            else:
                raise socket.error, why

    def send (self, data):
        try:
            result = self.socket.send (data)
            return result
        except socket.error, why:
            if why[0] == EWOULDBLOCK:
                return 0
            else:
                raise socket.error, why
            return 0

    def recv (self, buffer_size):
        try:
            data = self.socket.recv (buffer_size)
            if not data:
                # a closed connection is indicated by signaling
                # a read condition, and having recv() return 0.
                self.handle_close()
                return ''
            else:
                return data
        except socket.error, why:
            # winsock sometimes throws ENOTCONN
            if why[0] in [ECONNRESET, ENOTCONN, ESHUTDOWN]:
                self.handle_close()
                return ''
            else:
                raise socket.error, why

    def close (self):
        self.del_channel()
        self.socket.close()

    # cheap inheritance, used to pass all other attribute
    # references to the underlying socket object.
    def __getattr__ (self, attr):
        return getattr (self.socket, attr)

    # log and log_info maybe overriden to provide more sophisitcated
    # logging and warning methods. In general, log is for 'hit' logging
    # and 'log_info' is for informational, warning and error logging.

    def log (self, message):
        sys.stderr.write ('log: %s\n' % str(message))

    def log_info (self, message, type='info'):
        if __debug__ or type != 'info':
            print '%s: %s' % (type, message)

    def handle_read_event (self):
        if self.accepting:
            # for an accepting socket, getting a read implies
            # that we are connected
            if not self.connected:
                self.connected = 1
            self.handle_accept()
        elif not self.connected:
            self.handle_connect()
            self.connected = 1
            self.handle_read()
        else:
            self.handle_read()

    def handle_write_event (self):
        # getting a write implies that we are connected
        if not self.connected:
            self.handle_connect()
            self.connected = 1
        self.handle_write()

    def handle_expt_event (self):
        self.handle_expt()

    def handle_error (self):
        nil, t, v, tbinfo = compact_traceback()

        # sometimes a user repr method will crash.
        try:
            self_repr = repr (self)
        except:
            self_repr = '<__repr__ (self) failed for object at %0x>' % id(self)

        self.log_info (
            'uncaptured python exception, closing channel %s (%s:%s %s)' % (
                self_repr,
                t,
                v,
                tbinfo
                ),
            'error'
            )
        self.close()

    def handle_expt (self):
        self.log_info ('unhandled exception', 'warning')

    def handle_read (self):
        self.log_info ('unhandled read event', 'warning')

    def handle_write (self):
        self.log_info ('unhandled write event', 'warning')

    def handle_connect (self):
        self.log_info ('unhandled connect event', 'warning')

    def handle_accept (self):
        self.log_info ('unhandled accept event', 'warning')

    def handle_close (self):
        self.log_info ('unhandled close event', 'warning')
        self.close()

# ---------------------------------------------------------------------------
# adds simple buffered output capability, useful for simple clients.
# [for more sophisticated usage use asynchat.async_chat]
# ---------------------------------------------------------------------------

class dispatcher_with_send (dispatcher):
    def __init__ (self, sock=None):
        dispatcher.__init__ (self, sock)
        self.out_buffer = ''

    def initiate_send (self):
        num_sent = 0
        num_sent = dispatcher.send (self, self.out_buffer[:512])
        self.out_buffer = self.out_buffer[num_sent:]

    def handle_write (self):
        self.initiate_send()

    def writable (self):
        return (not self.connected) or len(self.out_buffer)

    def send (self, data):
        if self.debug:
            self.log_info ('sending %s' % repr(data))
        self.out_buffer = self.out_buffer + data
        self.initiate_send()

# ---------------------------------------------------------------------------
# used for debugging.
# ---------------------------------------------------------------------------

def compact_traceback ():
    t,v,tb = sys.exc_info()
    tbinfo = []
    while 1:
        tbinfo.append ((
            tb.tb_frame.f_code.co_filename,
            tb.tb_frame.f_code.co_name,
            str(tb.tb_lineno)
            ))
        tb = tb.tb_next
        if not tb:
            break

    # just to be safe
    del tb

    file, function, line = tbinfo[-1]
    info = '[' + '] ['.join(map(lambda x: '|'.join(x), tbinfo)) + ']'
    return (file, function, line), t, v, info

def close_all (map=None):
    if map is None:
        map=socket_map
    for x in map.values():
        x.socket.close()
    map.clear()

# Asynchronous File I/O:
#
# After a little research (reading man pages on various unixen, and
# digging through the linux kernel), I've determined that select()
# isn't meant for doing doing asynchronous file i/o.
# Heartening, though - reading linux/mm/filemap.c shows that linux
# supports asynchronous read-ahead.  So _MOST_ of the time, the data
# will be sitting in memory for us already when we go to read it.
#
# What other OS's (besides NT) support async file i/o?  [VMS?]
#
# Regardless, this is useful for pipes, and stdin/stdout...

import os
if os.name == 'posix':
    import fcntl

    class file_wrapper:
        # here we override just enough to make a file
        # look like a socket for the purposes of asyncore.
        def __init__ (self, fd):
            self.fd = fd

        def recv (self, *args):
            return apply (os.read, (self.fd,)+args)

        def send (self, *args):
            return apply (os.write, (self.fd,)+args)

        read = recv
        write = send

        def close (self):
            return os.close (self.fd)

        def fileno (self):
            return self.fd

    class file_dispatcher (dispatcher):
        def __init__ (self, fd):
            dispatcher.__init__ (self)
            self.connected = 1
            # set it to non-blocking mode
            flags = fcntl.fcntl (fd, fcntl.F_GETFL, 0)
            flags = flags | os.O_NONBLOCK
            fcntl.fcntl (fd, fcntl.F_SETFL, flags)
            self.set_file (fd)

        def set_file (self, fd):
            self._fileno = fd
            self.socket = file_wrapper (fd)
            self.add_channel()
<commit_msg>Patch #468647: Fix exception propagation in asyncore.<commit_after># -*- Mode: Python -*-
#   Id: asyncore.py,v 2.51 2000/09/07 22:29:26 rushing Exp
#   Author: Sam Rushing <rushing@nightmare.com>

# ======================================================================
# Copyright 1996 by Sam Rushing
#
#                         All Rights Reserved
#
# Permission to use, copy, modify, and distribute this software and
# its documentation for any purpose and without fee is hereby
# granted, provided that the above copyright notice appear in all
# copies and that both that copyright notice and this permission
# notice appear in supporting documentation, and that the name of Sam
# Rushing not be used in advertising or publicity pertaining to
# distribution of the software without specific, written prior
# permission.
#
# SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
# NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR
# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# ======================================================================

"""Basic infrastructure for asynchronous socket service clients and servers.

There are only two ways to have a program on a single processor do "more
than one thing at a time".  Multi-threaded programming is the simplest and
most popular way to do it, but there is another very different technique,
that lets you have nearly all the advantages of multi-threading, without
actually using multiple threads. it's really only practical if your program
is largely I/O bound. If your program is CPU bound, then pre-emptive
scheduled threads are probably what you really need. Network servers are
rarely CPU-bound, however.

If your operating system supports the select() system call in its I/O
library (and nearly all do), then you can use it to juggle multiple
communication channels at once; doing other work while your I/O is taking
place in the "background."  Although this strategy can seem strange and
complex, especially at first, it is in many ways easier to understand and
control than multi-threaded programming. The module documented here solves
many of the difficult problems for you, making the task of building
sophisticated high-performance network servers and clients a snap.
"""

import exceptions
import select
import socket
import sys
import types

import os
from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, \
     ENOTCONN, ESHUTDOWN

try:
    socket_map
except NameError:
    socket_map = {}

class ExitNow (exceptions.Exception):
    pass

DEBUG = 0

def poll (timeout=0.0, map=None):
    global DEBUG
    if map is None:
        map = socket_map
    if map:
        r = []; w = []; e = []
        for fd, obj in map.items():
            if obj.readable():
                r.append (fd)
            if obj.writable():
                w.append (fd)
        r,w,e = select.select (r,w,e, timeout)

        if DEBUG:
            print r,w,e

        for fd in r:
            try:
                obj = map[fd]
            except KeyError:
                continue

            try:
                obj.handle_read_event()
            except ExitNow:
                raise ExitNow
            except:
                obj.handle_error()

        for fd in w:
            try:
                obj = map[fd]
            except KeyError:
                continue

            try:
                obj.handle_write_event()
            except ExitNow:
                raise ExitNow
            except:
                obj.handle_error()

def poll2 (timeout=0.0, map=None):
    import poll
    if map is None:
        map=socket_map
    if timeout is not None:
        # timeout is in milliseconds
        timeout = int(timeout*1000)
    if map:
        l = []
        for fd, obj in map.items():
            flags = 0
            if obj.readable():
                flags = poll.POLLIN
            if obj.writable():
                flags = flags | poll.POLLOUT
            if flags:
                l.append ((fd, flags))
        r = poll.poll (l, timeout)
        for fd, flags in r:
            try:
                obj = map[fd]
            except KeyError:
                continue

            try:
                if (flags  & poll.POLLIN):
                    obj.handle_read_event()
                if (flags & poll.POLLOUT):
                    obj.handle_write_event()
            except ExitNow:
                raise ExitNow
            except:
                obj.handle_error()

def poll3 (timeout=0.0, map=None):
    # Use the poll() support added to the select module in Python 2.0
    if map is None:
        map=socket_map
    if timeout is not None:
        # timeout is in milliseconds
        timeout = int(timeout*1000)
    pollster = select.poll()
    if map:
        for fd, obj in map.items():
            flags = 0
            if obj.readable():
                flags = select.POLLIN
            if obj.writable():
                flags = flags | select.POLLOUT
            if flags:
                pollster.register(fd, flags)
        r = pollster.poll (timeout)
        for fd, flags in r:
            try:
                obj = map[fd]
            except KeyError:
                continue

            try:
                if (flags  & select.POLLIN):
                    obj.handle_read_event()
                if (flags & select.POLLOUT):
                    obj.handle_write_event()
            except ExitNow:
                raise ExitNow
            except:
                obj.handle_error()

def loop (timeout=30.0, use_poll=0, map=None):

    if map is None:
        map=socket_map

    if use_poll:
        if hasattr (select, 'poll'):
            poll_fun = poll3
        else:
            poll_fun = poll2
    else:
        poll_fun = poll

    while map:
        poll_fun (timeout, map)

class dispatcher:
    debug = 0
    connected = 0
    accepting = 0
    closing = 0
    addr = None

    def __init__ (self, sock=None, map=None):
        if sock:
            self.set_socket (sock, map)
            # I think it should inherit this anyway
            self.socket.setblocking (0)
            self.connected = 1
            self.addr = sock.getpeername()

    def __repr__ (self):
        try:
            status = []
            if self.accepting and self.addr:
                status.append ('listening')
            elif self.connected:
                status.append ('connected')
            if self.addr:
                if type(self.addr) == types.TupleType:
                    status.append ('%s:%d' % self.addr)
                else:
                    status.append (self.addr)
            return '<%s %s at %x>' % (self.__class__.__name__,
                                      ' '.join (status), id (self))
        except:
            pass

        try:
            ar = repr (self.addr)
        except AttributeError:
            ar = 'no self.addr!'

        return '<__repr__() failed for %s instance at %x (addr=%s)>' % \
               (self.__class__.__name__, id (self), ar)

    def add_channel (self, map=None):
        #self.log_info ('adding channel %s' % self)
        if map is None:
            map=socket_map
        map [self._fileno] = self

    def del_channel (self, map=None):
        fd = self._fileno
        if map is None:
            map=socket_map
        if map.has_key (fd):
            #self.log_info ('closing channel %d:%s' % (fd, self))
            del map [fd]

    def create_socket (self, family, type):
        self.family_and_type = family, type
        self.socket = socket.socket (family, type)
        self.socket.setblocking(0)
        self._fileno = self.socket.fileno()
        self.add_channel()

    def set_socket (self, sock, map=None):
        self.__dict__['socket'] = sock
        self._fileno = sock.fileno()
        self.add_channel (map)

    def set_reuse_addr (self):
        # try to re-use a server port if possible
        try:
            self.socket.setsockopt (
                socket.SOL_SOCKET, socket.SO_REUSEADDR,
                self.socket.getsockopt (socket.SOL_SOCKET,
                                        socket.SO_REUSEADDR) | 1
                )
        except socket.error:
            pass

    # ==================================================
    # predicates for select()
    # these are used as filters for the lists of sockets
    # to pass to select().
    # ==================================================

    def readable (self):
        return 1

    if os.name == 'mac':
        # The macintosh will select a listening socket for
        # write if you let it.  What might this mean?
        def writable (self):
            return not self.accepting
    else:
        def writable (self):
            return 1

    # ==================================================
    # socket object methods.
    # ==================================================

    def listen (self, num):
        self.accepting = 1
        if os.name == 'nt' and num > 5:
            num = 1
        return self.socket.listen (num)

    def bind (self, addr):
        self.addr = addr
        return self.socket.bind (addr)

    def connect (self, address):
        self.connected = 0
        # XXX why not use connect_ex?
        try:
            self.socket.connect (address)
        except socket.error, why:
            if why[0] in (EINPROGRESS, EALREADY, EWOULDBLOCK):
                return
            else:
                raise socket.error, why
        self.addr = address
        self.connected = 1
        self.handle_connect()

    def accept (self):
        try:
            conn, addr = self.socket.accept()
            return conn, addr
        except socket.error, why:
            if why[0] == EWOULDBLOCK:
                pass
            else:
                raise socket.error, why

    def send (self, data):
        try:
            result = self.socket.send (data)
            return result
        except socket.error, why:
            if why[0] == EWOULDBLOCK:
                return 0
            else:
                raise socket.error, why
            return 0

    def recv (self, buffer_size):
        try:
            data = self.socket.recv (buffer_size)
            if not data:
                # a closed connection is indicated by signaling
                # a read condition, and having recv() return 0.
                self.handle_close()
                return ''
            else:
                return data
        except socket.error, why:
            # winsock sometimes throws ENOTCONN
            if why[0] in [ECONNRESET, ENOTCONN, ESHUTDOWN]:
                self.handle_close()
                return ''
            else:
                raise socket.error, why

    def close (self):
        self.del_channel()
        self.socket.close()

    # cheap inheritance, used to pass all other attribute
    # references to the underlying socket object.
    def __getattr__ (self, attr):
        return getattr (self.socket, attr)

    # log and log_info maybe overriden to provide more sophisitcated
    # logging and warning methods. In general, log is for 'hit' logging
    # and 'log_info' is for informational, warning and error logging.

    def log (self, message):
        sys.stderr.write ('log: %s\n' % str(message))

    def log_info (self, message, type='info'):
        if __debug__ or type != 'info':
            print '%s: %s' % (type, message)

    def handle_read_event (self):
        if self.accepting:
            # for an accepting socket, getting a read implies
            # that we are connected
            if not self.connected:
                self.connected = 1
            self.handle_accept()
        elif not self.connected:
            self.handle_connect()
            self.connected = 1
            self.handle_read()
        else:
            self.handle_read()

    def handle_write_event (self):
        # getting a write implies that we are connected
        if not self.connected:
            self.handle_connect()
            self.connected = 1
        self.handle_write()

    def handle_expt_event (self):
        self.handle_expt()

    def handle_error (self):
        nil, t, v, tbinfo = compact_traceback()

        # sometimes a user repr method will crash.
        try:
            self_repr = repr (self)
        except:
            self_repr = '<__repr__ (self) failed for object at %0x>' % id(self)

        self.log_info (
            'uncaptured python exception, closing channel %s (%s:%s %s)' % (
                self_repr,
                t,
                v,
                tbinfo
                ),
            'error'
            )
        self.close()

    def handle_expt (self):
        self.log_info ('unhandled exception', 'warning')

    def handle_read (self):
        self.log_info ('unhandled read event', 'warning')

    def handle_write (self):
        self.log_info ('unhandled write event', 'warning')

    def handle_connect (self):
        self.log_info ('unhandled connect event', 'warning')

    def handle_accept (self):
        self.log_info ('unhandled accept event', 'warning')

    def handle_close (self):
        self.log_info ('unhandled close event', 'warning')
        self.close()

# ---------------------------------------------------------------------------
# adds simple buffered output capability, useful for simple clients.
# [for more sophisticated usage use asynchat.async_chat]
# ---------------------------------------------------------------------------

class dispatcher_with_send (dispatcher):
    def __init__ (self, sock=None):
        dispatcher.__init__ (self, sock)
        self.out_buffer = ''

    def initiate_send (self):
        num_sent = 0
        num_sent = dispatcher.send (self, self.out_buffer[:512])
        self.out_buffer = self.out_buffer[num_sent:]

    def handle_write (self):
        self.initiate_send()

    def writable (self):
        return (not self.connected) or len(self.out_buffer)

    def send (self, data):
        if self.debug:
            self.log_info ('sending %s' % repr(data))
        self.out_buffer = self.out_buffer + data
        self.initiate_send()

# ---------------------------------------------------------------------------
# used for debugging.
# ---------------------------------------------------------------------------

def compact_traceback ():
    t,v,tb = sys.exc_info()
    tbinfo = []
    while 1:
        tbinfo.append ((
            tb.tb_frame.f_code.co_filename,
            tb.tb_frame.f_code.co_name,
            str(tb.tb_lineno)
            ))
        tb = tb.tb_next
        if not tb:
            break

    # just to be safe
    del tb

    file, function, line = tbinfo[-1]
    info = '[' + '] ['.join(map(lambda x: '|'.join(x), tbinfo)) + ']'
    return (file, function, line), t, v, info

def close_all (map=None):
    if map is None:
        map=socket_map
    for x in map.values():
        x.socket.close()
    map.clear()

# Asynchronous File I/O:
#
# After a little research (reading man pages on various unixen, and
# digging through the linux kernel), I've determined that select()
# isn't meant for doing doing asynchronous file i/o.
# Heartening, though - reading linux/mm/filemap.c shows that linux
# supports asynchronous read-ahead.  So _MOST_ of the time, the data
# will be sitting in memory for us already when we go to read it.
#
# What other OS's (besides NT) support async file i/o?  [VMS?]
#
# Regardless, this is useful for pipes, and stdin/stdout...

import os
if os.name == 'posix':
    import fcntl

    class file_wrapper:
        # here we override just enough to make a file
        # look like a socket for the purposes of asyncore.
        def __init__ (self, fd):
            self.fd = fd

        def recv (self, *args):
            return apply (os.read, (self.fd,)+args)

        def send (self, *args):
            return apply (os.write, (self.fd,)+args)

        read = recv
        write = send

        def close (self):
            return os.close (self.fd)

        def fileno (self):
            return self.fd

    class file_dispatcher (dispatcher):
        def __init__ (self, fd):
            dispatcher.__init__ (self)
            self.connected = 1
            # set it to non-blocking mode
            flags = fcntl.fcntl (fd, fcntl.F_GETFL, 0)
            flags = flags | os.O_NONBLOCK
            fcntl.fcntl (fd, fcntl.F_SETFL, flags)
            self.set_file (fd)

        def set_file (self, fd):
            self._fileno = fd
            self.socket = file_wrapper (fd)
            self.add_channel()
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""
===============================================================================
Atom class for KDTree analysis (:mod:`sknano.core.atoms._kdtree_atom`)
===============================================================================

An `XAtom` class for structure analysis.

.. currentmodule:: sknano.core.atoms._kdtree_atom

"""
from __future__ import absolute_import, division, print_function
__docformat__ = 'restructuredtext en'

import numbers

from ._bonds import Bonds
from ._extended_atom import XAtom
from ._neighbor_atoms import NeighborAtoms

__all__ = ['KDTAtom']

class KDTAtom(XAtom):
    """An `Atom` class for KDTree analysis.

    Parameters
    ----------
    CN : int, optional
        `KDTAtom` coordination number.
    NN : sequence, optional
        List of nearest-neighbor `KDTAtom` objects instances

    """

    def __init__(self, **kwargs):
        super(KDTAtom, self).__init__(**kwargs)

        self._CN = 0
        self._NN = NeighborAtoms()
        self._bonds = Bonds()
        self.poav = None
        self.poav_misalignment_angles = []
        self._pyramidalization_angle = None
        self._sigma_bond_angle = None

    def __str__(self):
        """Return a nice string representation of `KDTAtom`."""
        strrep = "Atom(element={element!r}, atomID={atomID!r}, " + \
            "moleculeID={moleculeID!r}, atomtype={atomtype!r}, " + \
            "q={q!r}, m={m!r}, x={x:.6f}, y={y:.6f}, z={z:.6f}, " + \
            "CN={CN!r}, NN={NN!s}, bonds={bonds!s})"

        parameters = dict(element=self.element, atomID=self.atomID,
                          moleculeID=self.moleculeID, atomtype=self.atomtype,
                          q=self.q, m=self.m, x=self.x, y=self.y, z=self.z,
                          CN=self.CN, NN=self.NN, bonds=self.bonds)

        return strrep.format(**parameters)

    def __repr__(self):
        """Return canonical string representation of `KDTAtom`."""
        #strrep = "Atom(element={element!r}, atomID={atomID!r}, " + \
        #    "moleculeID={moleculeID!r}, atomtype={atomtype!r}, " + \
        #    "q={q!r}, m={m!r}, x={x:.6f}, y={y:.6f}, z={z:.6f}, " + \
        #    "CN={CN!r}, NN={NN!r})"
        #parameters = dict(element=self.element, atomID=self.atomID,
        #                  moleculeID=self.moleculeID, atomtype=self.atomtype,
        #                  q=self.q, m=self.m, x=self.x, y=self.y, z=self.z,
        #                  CN=self.CN, NN=self.NN)
        #return strrep.format(**parameters)
        return super(KDTAtom, self).__repr__()

    @property
    def CN(self):
        """Return `KDTAtom` coordination number."""
        return self._CN

    @CN.setter
    def CN(self, value):
        """Set `KDTAtom` coordination number."""
        if not isinstance(value, numbers.Number):
            raise TypeError('Expected a number.')
        self._CN = int(value)

    @property
    def NN(self):
        """Return `KDTAtom` `NeighborAtoms` object."""
        return self._NN

    @NN.setter
    def NN(self, value):
        """Set `KDTAtom` `NeighborAtoms`."""
        if not isinstance(value, NeighborAtoms):
            raise TypeError('Expected `NeighborAtoms`.')
        self._NN = value

    @property
    def bonds(self):
        return self._bonds

    @bonds.setter
    def bonds(self, value):
        if not isinstance(value, Bonds):
            raise TypeError('Expected a `Bonds` object.')
        self._bonds = value

    @property
    def sigma_bond_angle(self):
        return self._sigma_bond_angle

    @sigma_bond_angle.setter
    def sigma_bond_angle(self, value):
        if not isinstance(value, numbers.Number):
            raise TypeError('Expected a number')
        self._sigma_bond_angle = value

    @property
    def pyramidalization_angle(self):
        return self._pyramidalization_angle

    @pyramidalization_angle.setter
    def pyramidalization_angle(self, value):
        if not isinstance(value, numbers.Number):
            raise TypeError('Expected a number')
        self._pyramidalization_angle = value

    #@property
    #def poav_misalignment_angle(self):
    #    return self._poav_misalignment_angle

    #@poav_misalignment_angle.setter
    #def poav_misalignment_angle(self, value):
    #    if not isinstance(value, ):
    #        raise TypeError('Expected a number')
    #    self._poav_misalignment_angle = value
<commit_msg>adding `mean_misalignment_angle` attribute.<commit_after># -*- coding: utf-8 -*-
"""
===============================================================================
Atom class for KDTree analysis (:mod:`sknano.core.atoms._kdtree_atom`)
===============================================================================

An `XAtom` class for structure analysis.

.. currentmodule:: sknano.core.atoms._kdtree_atom

"""
from __future__ import absolute_import, division, print_function
__docformat__ = 'restructuredtext en'

import numbers

from ._bonds import Bonds
from ._extended_atom import XAtom
from ._neighbor_atoms import NeighborAtoms

__all__ = ['KDTAtom']

class KDTAtom(XAtom):
    """An `Atom` class for KDTree analysis.

    Parameters
    ----------
    CN : int, optional
        `KDTAtom` coordination number.
    NN : sequence, optional
        List of nearest-neighbor `KDTAtom` objects instances

    """

    def __init__(self, **kwargs):
        super(KDTAtom, self).__init__(**kwargs)

        self._CN = 0
        self._NN = NeighborAtoms()
        self._bonds = Bonds()
        self.poav = None
        self.poav_misalignment_angles = []
        self.mean_misalignment_angle = None
        self._pyramidalization_angle = None
        self._sigma_bond_angle = None

    def __str__(self):
        """Return a nice string representation of `KDTAtom`."""
        strrep = "Atom(element={element!r}, atomID={atomID!r}, " + \
            "moleculeID={moleculeID!r}, atomtype={atomtype!r}, " + \
            "q={q!r}, m={m!r}, x={x:.6f}, y={y:.6f}, z={z:.6f}, " + \
            "CN={CN!r}, NN={NN!s}, bonds={bonds!s})"

        parameters = dict(element=self.element, atomID=self.atomID,
                          moleculeID=self.moleculeID, atomtype=self.atomtype,
                          q=self.q, m=self.m, x=self.x, y=self.y, z=self.z,
                          CN=self.CN, NN=self.NN, bonds=self.bonds)

        return strrep.format(**parameters)

    def __repr__(self):
        """Return canonical string representation of `KDTAtom`."""
        #strrep = "Atom(element={element!r}, atomID={atomID!r}, " + \
        #    "moleculeID={moleculeID!r}, atomtype={atomtype!r}, " + \
        #    "q={q!r}, m={m!r}, x={x:.6f}, y={y:.6f}, z={z:.6f}, " + \
        #    "CN={CN!r}, NN={NN!r})"
        #parameters = dict(element=self.element, atomID=self.atomID,
        #                  moleculeID=self.moleculeID, atomtype=self.atomtype,
        #                  q=self.q, m=self.m, x=self.x, y=self.y, z=self.z,
        #                  CN=self.CN, NN=self.NN)
        #return strrep.format(**parameters)
        return super(KDTAtom, self).__repr__()

    @property
    def CN(self):
        """Return `KDTAtom` coordination number."""
        return self._CN

    @CN.setter
    def CN(self, value):
        """Set `KDTAtom` coordination number."""
        if not isinstance(value, numbers.Number):
            raise TypeError('Expected a number.')
        self._CN = int(value)

    @property
    def NN(self):
        """Return `KDTAtom` `NeighborAtoms` object."""
        return self._NN

    @NN.setter
    def NN(self, value):
        """Set `KDTAtom` `NeighborAtoms`."""
        if not isinstance(value, NeighborAtoms):
            raise TypeError('Expected `NeighborAtoms`.')
        self._NN = value

    @property
    def bonds(self):
        return self._bonds

    @bonds.setter
    def bonds(self, value):
        if not isinstance(value, Bonds):
            raise TypeError('Expected a `Bonds` object.')
        self._bonds = value

    @property
    def sigma_bond_angle(self):
        return self._sigma_bond_angle

    @sigma_bond_angle.setter
    def sigma_bond_angle(self, value):
        if not isinstance(value, numbers.Number):
            raise TypeError('Expected a number')
        self._sigma_bond_angle = value

    @property
    def pyramidalization_angle(self):
        return self._pyramidalization_angle

    @pyramidalization_angle.setter
    def pyramidalization_angle(self, value):
        if not isinstance(value, numbers.Number):
            raise TypeError('Expected a number')
        self._pyramidalization_angle = value

    #@property
    #def poav_misalignment_angle(self):
    #    return self._poav_misalignment_angle

    #@poav_misalignment_angle.setter
    #def poav_misalignment_angle(self, value):
    #    if not isinstance(value, ):
    #        raise TypeError('Expected a number')
    #    self._poav_misalignment_angle = value
<|endoftext|>


<commit_before>import sys
import glob
import time
import os
import subprocess
import collections

# add user bin to path!
BUILD_DIR = ''
# add user bin to path!
try:
    BUILD_DIR = os.environ["TRAVIS_BUILD_DIR"]
except KeyError:
    pass # ok maybe we're on actions?
try:
    BUILD_DIR = os.environ["GITHUB_WORKSPACE"]
except KeyError:
    pass # ok maybe we're on travis?

os.environ["PATH"] += os.pathsep + BUILD_DIR + "/bin"
print("build dir:", BUILD_DIR)
#os.system('pwd')
#os.system('ls -lA')

CROSS = u'\N{cross mark}'
CHECK = u'\N{check mark}'

ALL_PLATFORMS={
    # classic Arduino AVR
    "uno" : "arduino:avr:uno",
    "leonardo" : "arduino:avr:leonardo",
    "mega2560" : "arduino:avr:mega:cpu=atmega2560",
    # Arduino SAMD
    "zero" : "arduino:samd:arduino_zero_native",
    "cpx" : "arduino:samd:adafruit_circuitplayground_m0",
    # Espressif
    "esp8266" : "esp8266:esp8266:huzzah:eesz=4M3M,xtal=80",
    "esp32" : "esp32:esp32:featheresp32:FlashFreq=80",
    # Adafruit AVR
    "trinket" : "adafruit:avr:trinket5",
    "gemma" : "arduino:avr:gemma",
    "cpc" : "arduino:avr:circuitplay32u4cat",
    # Adafruit SAMD
    "metro_m0" : "adafruit:samd:adafruit_metro_m0",
    "metro_m4" : "adafruit:samd:adafruit_metro_m4:speed=120",
    "pybadge" : "adafruit:samd:adafruit_pybadge_m4:speed=120",
    "pygamer" : "adafruit:samd:adafruit_pygamer_m4:speed=120",
    "hallowing_m0" : "adafruit:samd:adafruit_hallowing",
    "hallowing_m4" : "adafruit:samd:adafruit_hallowing_m4:speed=120",
    "monster_m4sk" : "adafruit:samd:adafruit_monster_m4sk:speed=120",
    "pyportal" : "adafruit:samd:adafruit_pyportal_m4:speed=120",
    "pyportal_titano" : "adafruit:samd:adafruit_pyportal_m4_titano:speed=120",
    "cpx_ada" : "adafruit:samd:adafruit_circuitplayground_m0",
    # Arduino nRF
    "microbit" : "sandeepmistry:nRF5:BBCmicrobit:softdevice=s130",
    # Adafruit nRF
    "nrf52840" : "adafruit:nrf52:feather52840:softdevice=s140v6,debug=l0",
    "cpb" : "adafruit:nrf52:cplaynrf52840:softdevice=s140v6,debug=l0",
    # groupings
    "main_platforms" : ("uno", "leonardo", "mega2560", "zero",
                        "esp8266", "esp32", "metro_m4", "nrf52840"),
    "arcada_platforms" : ("pybadge", "pygamer", "hallowing_m4",
                          "cpb", "cpx_ada"),
}

BSP_URLS = "https://adafruit.github.io/arduino-board-index/package_adafruit_index.json,http://arduino.esp8266.com/stable/package_esp8266com_index.json,https://dl.espressif.com/dl/package_esp32_index.json,https://sandeepmistry.github.io/arduino-nRF5/package_nRF5_boards_index.json"

class ColorPrint:

    @staticmethod
    def print_fail(message, end = '\n'):
        sys.stdout.write('\x1b[1;31m' + message.strip() + '\x1b[0m' + end)

    @staticmethod
    def print_pass(message, end = '\n'):
        sys.stdout.write('\x1b[1;32m' + message.strip() + '\x1b[0m' + end)

    @staticmethod
    def print_warn(message, end = '\n'):
        sys.stdout.write('\x1b[1;33m' + message.strip() + '\x1b[0m' + end)

    @staticmethod
    def print_info(message, end = '\n'):
        sys.stdout.write('\x1b[1;34m' + message.strip() + '\x1b[0m' + end)

    @staticmethod
    def print_bold(message, end = '\n'):
        sys.stdout.write('\x1b[1;37m' + message.strip() + '\x1b[0m' + end)

def install_platform(platform):
    print("Installing", platform, end=" ")
    if platform == "adafruit:samd":   # we have a platform dep
        install_platform("arduino:samd")
    if os.system("arduino-cli core install "+platform+" --additional-urls "+BSP_URLS+" > /dev/null") != 0:
        ColorPrint.print_fail("FAILED to install "+platform)
        exit(-1)
    ColorPrint.print_pass(CHECK)

def run_or_die(cmd, error):
    print(cmd)
    if os.system(cmd) != 0:
        ColorPrint.print_fail(error)
        exit(-1)

################################ Install Arduino IDE
print()
ColorPrint.print_info('#'*40)
print("INSTALLING ARDUINO IDE")
ColorPrint.print_info('#'*40)

run_or_die('curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh 2>&1', "FAILED to install arduino CLI")
run_or_die('arduino-cli config init > /dev/null',
           "FAILED to configure arduino CLI")
run_or_die('arduino-cli core update-index > /dev/null',
           "FAILED to update arduino core")
run_or_die("arduino-cli core update-index --additional-urls "+BSP_URLS+
           " > /dev/null", "FAILED to update core indecies")
print()

# link test library folder to the arduino libraries folder
os.symlink(BUILD_DIR, os.environ['HOME']+'/Arduino/libraries/Adafruit_Test_Library')

################################ Install dependancies
our_name=None
try:
    libprop = open(BUILD_DIR+'/library.properties')
    for line in libprop:
        if line.startswith("name="):
            our_name = line.replace("depends=", "").strip()
        if line.startswith("depends="):
            deps = line.replace("depends=", "").split(",")
            for dep in deps:
                dep = dep.strip()
                print("Installing "+dep)
                run_or_die('arduino-cli lib install "'+dep+'" > /dev/null',
                           "FAILED to install dependancy "+dep)
except OSError:
    pass  # no library properties

# Delete the existing library if we somehow downloaded
# due to dependancies
if our_name:
    run_or_die("arduino-cli lib uninstall \""+our_name+"\"", "Could not uninstall")

print("Libraries installed: ", glob.glob(os.environ['HOME']+'/Arduino/libraries/*'))

################################ Test platforms
platforms = []
success = 0

# expand groups:
for arg in sys.argv[1:]:
    platform = ALL_PLATFORMS.get(arg, None)
    if isinstance(platform, str):
        platforms.append(arg)
    elif isinstance(platform, collections.Iterable):
        for p in platform:
            platforms.append(p)
    else:
        print("Unknown platform: ", arg)
        exit(-1)

def test_examples_in_folder(folderpath):
    global success
    for example in os.listdir(folderpath):
        examplepath = folderpath+"/"+example
        if os.path.isdir(examplepath):
            test_examples_in_folder(examplepath)
            continue
        if not examplepath.endswith(".ino"):
            continue

        print('\t'+example, end=' ')
        # check if we should SKIP
        skipfilename = folderpath+"/."+platform+".test.skip"
        onlyfilename = folderpath+"/."+platform+".test.only"
        if os.path.exists(skipfilename):
            ColorPrint.print_warn("skipping")
            continue
        if glob.glob(folderpath+"/.*.test.only") and not os.path.exists(onlyfilename):
            ColorPrint.print_warn("skipping")
            continue

        cmd = ['arduino-cli', 'compile', '--fqbn', fqbn, examplepath]
        proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
        r = proc.wait()
        out = proc.stdout.read()
        err = proc.stderr.read()
        if r == 0:
            ColorPrint.print_pass(CHECK)
        else:
            ColorPrint.print_fail(CROSS)
            ColorPrint.print_fail(out.decode("utf-8"))
            ColorPrint.print_fail(err.decode("utf-8"))
            success = 1

for platform in platforms:
    fqbn = ALL_PLATFORMS[platform]
    print('#'*80)
    ColorPrint.print_info("SWITCHING TO "+fqbn)
    install_platform(":".join(fqbn.split(':', 2)[0:2])) # take only first two elements
    print('#'*80)
    test_examples_in_folder(BUILD_DIR+"/examples")

exit(success)
<commit_msg>fix replace<commit_after>import sys
import glob
import time
import os
import subprocess
import collections

# add user bin to path!
BUILD_DIR = ''
# add user bin to path!
try:
    BUILD_DIR = os.environ["TRAVIS_BUILD_DIR"]
except KeyError:
    pass # ok maybe we're on actions?
try:
    BUILD_DIR = os.environ["GITHUB_WORKSPACE"]
except KeyError:
    pass # ok maybe we're on travis?

os.environ["PATH"] += os.pathsep + BUILD_DIR + "/bin"
print("build dir:", BUILD_DIR)
#os.system('pwd')
#os.system('ls -lA')

CROSS = u'\N{cross mark}'
CHECK = u'\N{check mark}'

ALL_PLATFORMS={
    # classic Arduino AVR
    "uno" : "arduino:avr:uno",
    "leonardo" : "arduino:avr:leonardo",
    "mega2560" : "arduino:avr:mega:cpu=atmega2560",
    # Arduino SAMD
    "zero" : "arduino:samd:arduino_zero_native",
    "cpx" : "arduino:samd:adafruit_circuitplayground_m0",
    # Espressif
    "esp8266" : "esp8266:esp8266:huzzah:eesz=4M3M,xtal=80",
    "esp32" : "esp32:esp32:featheresp32:FlashFreq=80",
    # Adafruit AVR
    "trinket" : "adafruit:avr:trinket5",
    "gemma" : "arduino:avr:gemma",
    "cpc" : "arduino:avr:circuitplay32u4cat",
    # Adafruit SAMD
    "metro_m0" : "adafruit:samd:adafruit_metro_m0",
    "metro_m4" : "adafruit:samd:adafruit_metro_m4:speed=120",
    "pybadge" : "adafruit:samd:adafruit_pybadge_m4:speed=120",
    "pygamer" : "adafruit:samd:adafruit_pygamer_m4:speed=120",
    "hallowing_m0" : "adafruit:samd:adafruit_hallowing",
    "hallowing_m4" : "adafruit:samd:adafruit_hallowing_m4:speed=120",
    "monster_m4sk" : "adafruit:samd:adafruit_monster_m4sk:speed=120",
    "pyportal" : "adafruit:samd:adafruit_pyportal_m4:speed=120",
    "pyportal_titano" : "adafruit:samd:adafruit_pyportal_m4_titano:speed=120",
    "cpx_ada" : "adafruit:samd:adafruit_circuitplayground_m0",
    # Arduino nRF
    "microbit" : "sandeepmistry:nRF5:BBCmicrobit:softdevice=s130",
    # Adafruit nRF
    "nrf52840" : "adafruit:nrf52:feather52840:softdevice=s140v6,debug=l0",
    "cpb" : "adafruit:nrf52:cplaynrf52840:softdevice=s140v6,debug=l0",
    # groupings
    "main_platforms" : ("uno", "leonardo", "mega2560", "zero",
                        "esp8266", "esp32", "metro_m4", "nrf52840"),
    "arcada_platforms" : ("pybadge", "pygamer", "hallowing_m4",
                          "cpb", "cpx_ada"),
}

BSP_URLS = "https://adafruit.github.io/arduino-board-index/package_adafruit_index.json,http://arduino.esp8266.com/stable/package_esp8266com_index.json,https://dl.espressif.com/dl/package_esp32_index.json,https://sandeepmistry.github.io/arduino-nRF5/package_nRF5_boards_index.json"

class ColorPrint:

    @staticmethod
    def print_fail(message, end = '\n'):
        sys.stdout.write('\x1b[1;31m' + message.strip() + '\x1b[0m' + end)

    @staticmethod
    def print_pass(message, end = '\n'):
        sys.stdout.write('\x1b[1;32m' + message.strip() + '\x1b[0m' + end)

    @staticmethod
    def print_warn(message, end = '\n'):
        sys.stdout.write('\x1b[1;33m' + message.strip() + '\x1b[0m' + end)

    @staticmethod
    def print_info(message, end = '\n'):
        sys.stdout.write('\x1b[1;34m' + message.strip() + '\x1b[0m' + end)

    @staticmethod
    def print_bold(message, end = '\n'):
        sys.stdout.write('\x1b[1;37m' + message.strip() + '\x1b[0m' + end)

def install_platform(platform):
    print("Installing", platform, end=" ")
    if platform == "adafruit:samd":   # we have a platform dep
        install_platform("arduino:samd")
    if os.system("arduino-cli core install "+platform+" --additional-urls "+BSP_URLS+" > /dev/null") != 0:
        ColorPrint.print_fail("FAILED to install "+platform)
        exit(-1)
    ColorPrint.print_pass(CHECK)

def run_or_die(cmd, error):
    print(cmd)
    if os.system(cmd) != 0:
        ColorPrint.print_fail(error)
        exit(-1)

################################ Install Arduino IDE
print()
ColorPrint.print_info('#'*40)
print("INSTALLING ARDUINO IDE")
ColorPrint.print_info('#'*40)

run_or_die('curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh 2>&1', "FAILED to install arduino CLI")
run_or_die('arduino-cli config init > /dev/null',
           "FAILED to configure arduino CLI")
run_or_die('arduino-cli core update-index > /dev/null',
           "FAILED to update arduino core")
run_or_die("arduino-cli core update-index --additional-urls "+BSP_URLS+
           " > /dev/null", "FAILED to update core indecies")
print()

# link test library folder to the arduino libraries folder
os.symlink(BUILD_DIR, os.environ['HOME']+'/Arduino/libraries/Adafruit_Test_Library')

################################ Install dependancies
our_name=None
try:
    libprop = open(BUILD_DIR+'/library.properties')
    for line in libprop:
        if line.startswith("name="):
            our_name = line.replace("name=", "").strip()
        if line.startswith("depends="):
            deps = line.replace("depends=", "").split(",")
            for dep in deps:
                dep = dep.strip()
                print("Installing "+dep)
                run_or_die('arduino-cli lib install "'+dep+'" > /dev/null',
                           "FAILED to install dependancy "+dep)
except OSError:
    pass  # no library properties

# Delete the existing library if we somehow downloaded
# due to dependancies
if our_name:
    run_or_die("arduino-cli lib uninstall \""+our_name+"\"", "Could not uninstall")

print("Libraries installed: ", glob.glob(os.environ['HOME']+'/Arduino/libraries/*'))

################################ Test platforms
platforms = []
success = 0

# expand groups:
for arg in sys.argv[1:]:
    platform = ALL_PLATFORMS.get(arg, None)
    if isinstance(platform, str):
        platforms.append(arg)
    elif isinstance(platform, collections.Iterable):
        for p in platform:
            platforms.append(p)
    else:
        print("Unknown platform: ", arg)
        exit(-1)

def test_examples_in_folder(folderpath):
    global success
    for example in os.listdir(folderpath):
        examplepath = folderpath+"/"+example
        if os.path.isdir(examplepath):
            test_examples_in_folder(examplepath)
            continue
        if not examplepath.endswith(".ino"):
            continue

        print('\t'+example, end=' ')
        # check if we should SKIP
        skipfilename = folderpath+"/."+platform+".test.skip"
        onlyfilename = folderpath+"/."+platform+".test.only"
        if os.path.exists(skipfilename):
            ColorPrint.print_warn("skipping")
            continue
        if glob.glob(folderpath+"/.*.test.only") and not os.path.exists(onlyfilename):
            ColorPrint.print_warn("skipping")
            continue

        cmd = ['arduino-cli', 'compile', '--fqbn', fqbn, examplepath]
        proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
        r = proc.wait()
        out = proc.stdout.read()
        err = proc.stderr.read()
        if r == 0:
            ColorPrint.print_pass(CHECK)
        else:
            ColorPrint.print_fail(CROSS)
            ColorPrint.print_fail(out.decode("utf-8"))
            ColorPrint.print_fail(err.decode("utf-8"))
            success = 1

for platform in platforms:
    fqbn = ALL_PLATFORMS[platform]
    print('#'*80)
    ColorPrint.print_info("SWITCHING TO "+fqbn)
    install_platform(":".join(fqbn.split(':', 2)[0:2])) # take only first two elements
    print('#'*80)
    test_examples_in_folder(BUILD_DIR+"/examples")

exit(success)
<|endoftext|>


<commit_before># Python
import random
import string
from PIL import Image as PILImage
import zlib

# Django
from django.conf import settings
from django.core.cache import cache
from django.core.urlresolvers import reverse
from django.template import Library, Node
from django.template.loader import render_to_string
from django.utils.translation import ugettext as _

# AstroBin
from astrobin.models import CommercialGear, Gear
from astrobin.models import Image

# Third party
from haystack.query import SearchQuerySet

register = Library()

# Returns the URL of an image, taking into account the fact that it might be
# a commercial gear image.
@register.simple_tag
def get_image_url(image, revision = 'final', size = 'regular'):
    def commercial_gear_url(commercial_gear):
        gear = commercial_gear.base_gear.all()
        if gear:
            return gear[0].get_absolute_url()
        return None

    try:
        commercial_gear = image.featured_gear.all()[0]
        url = commercial_gear_url(commercial_gear)
        if url:
            return url

    except IndexError:
        pass

    return image.get_absolute_url(revision, size)

@register.filter
def gallery_thumbnail(image, revision_label):
    return image.thumbnail('gallery', {'revision_label': revision_label})

@register.filter
def gallery_thumbnail_inverted(image, revision_label):
    return image.thumbnail('gallery_inverted', {'revision_label': revision_label})

# Renders an linked image tag with a placeholder and async loading of the
# actual thumbnail.
def astrobin_image(
    context, image, alias,
    revision = 'final', url_size = 'regular'):

    response_dict = {
        'provide_size': True,
    }

    if alias == '':
        alias = 'thumb'

    if alias in ('gallery_inverted', 'regular_inverted', 'hd_inverted', 'real_inverted'):
        mod = 'inverted'
    else:
        mod = None

    size  = settings.THUMBNAIL_ALIASES[''][alias]['size']

    if image is None or not isinstance(image, Image):
        return {
            'status': 'failure',
            'image': '',
            'alias': alias,
            'revision': revision,
            'size_x': size[0],
            'size_y': size[1],
            'capty_cache_key': 'astrobin_image_no_image',
        }

    w = image.w
    h = image.h

    if w == 0 or h == 0:
        # Old images might not have a size in the database, let's fix it.
        try:
            from django.core.files.images import get_image_dimensions
            (w, h) = get_image_dimensions(image.image_file.file)
            image.w = w
            image.h = h
            image.save()
        except IOError:
            w = size[0]
            h = size[1] if size[1] > 0 else w
            response_dict['status'] = 'error'
            response_dict['error_message'] = _("Data corruption. Please upload this image again. Sorry!")
        except zlib.error:
            w = size[0]
            h = size[1] if size[1] > 0 else w

    if alias in ('regular', 'regular_inverted',
                 'hd'     , 'hd_inverted',
                 'real'   , 'real_inverted'):
        size = (size[0], int(size[0] / (w / float(h))))
        response_dict['provide_size'] = False

    placehold_size = [size[0], size[1]]
    for i in range(0,2):
        if placehold_size[i] > 1920:
            placehold_size[i] = 1920

    if w < placehold_size[0]:
        placehold_size[0] = w
        placehold_size[1] = h

    # Determine whether this is an animated gif, and we should show it as such
    animated = False
    if image.image_file.name.lower().endswith('.gif') and alias in ('regular', 'hd', 'real'):
        gif = PILImage.open(image.image_file.file)
        try:
            gif.seek(1)
        except EOFError:
            animated = False
        else:
            animated = True

    url = get_image_url(image, revision, url_size)

    show_tooltip = alias in (
        'gallery', 'gallery_inverted',
        'thumb',
    )

    ##########
    # BADGES #
    ##########

    badges = []

    if alias in ('thumb', 'gallery', 'gallery_inverted', 'regular', 'regular_inverted'):
        if image.iotd_date():
            badges.append('iotd')

        top100_ids = SearchQuerySet().models(Image).all().order_by('-likes').values_list('django_id', flat = True)[:100]
        if image.pk in top100_ids:
            badges.append('top100')

    field = image.get_thumbnail_field(revision)
    cache_key = image.thumbnail_cache_key(field, alias)
    if animated and alias in ('regular', 'hd', 'real'):
        cache_key += '_animated'
    thumb_url = cache.get(cache_key)

    get_thumb_url = None
    if thumb_url is None:
        get_thumb_kwargs = {
            'id': image.id,
            'alias': alias,
        }

        if revision is None or revision != 'final':
            get_thumb_kwargs['r'] = revision

        get_thumb_url = reverse('image_thumb', kwargs = get_thumb_kwargs)
        if animated:
            get_thumb_url += '?animated'

    return dict(response_dict.items() + {
        'status'        : 'success',
        'image'         : image,
        'alias'         : alias,
        'mod'           : mod,
        'revision'      : revision,
        'size_x'        : size[0],
        'size_y'        : size[1],
        'placehold_size': "%sx%s" % (placehold_size[0], placehold_size[1]),
        'real'          : alias in ('real', 'real_inverted'),
        'url'           : url,
        'show_tooltip'  : show_tooltip,
        'request'       : context['request'],
        'capty_cache_key': "%d_%s_%s" % (image.id, revision, alias),
        'badges'        : badges,
        'animated'      : animated,
        'get_thumb_url' : get_thumb_url,
        'thumb_url'     : thumb_url,
    }.items())

@register.simple_tag(takes_context = True)
def random_id(context, size = 8, chars = string.ascii_uppercase + string.digits):
    id = ''.join(random.choice(chars) for x in range(size))
    context['randomid'] = id
    return ''

register.inclusion_tag(
    'astrobin_apps_images/snippets/image.html',
    takes_context = True)(astrobin_image)

<commit_msg>Use current revision's field to see if this image is animated.<commit_after># Python
import random
import string
from PIL import Image as PILImage
import zlib

# Django
from django.conf import settings
from django.core.cache import cache
from django.core.urlresolvers import reverse
from django.template import Library, Node
from django.template.loader import render_to_string
from django.utils.translation import ugettext as _

# AstroBin
from astrobin.models import CommercialGear, Gear
from astrobin.models import Image

# Third party
from haystack.query import SearchQuerySet

register = Library()

# Returns the URL of an image, taking into account the fact that it might be
# a commercial gear image.
@register.simple_tag
def get_image_url(image, revision = 'final', size = 'regular'):
    def commercial_gear_url(commercial_gear):
        gear = commercial_gear.base_gear.all()
        if gear:
            return gear[0].get_absolute_url()
        return None

    try:
        commercial_gear = image.featured_gear.all()[0]
        url = commercial_gear_url(commercial_gear)
        if url:
            return url

    except IndexError:
        pass

    return image.get_absolute_url(revision, size)

@register.filter
def gallery_thumbnail(image, revision_label):
    return image.thumbnail('gallery', {'revision_label': revision_label})

@register.filter
def gallery_thumbnail_inverted(image, revision_label):
    return image.thumbnail('gallery_inverted', {'revision_label': revision_label})

# Renders an linked image tag with a placeholder and async loading of the
# actual thumbnail.
def astrobin_image(
    context, image, alias,
    revision = 'final', url_size = 'regular'):

    response_dict = {
        'provide_size': True,
    }

    if alias == '':
        alias = 'thumb'

    if alias in ('gallery_inverted', 'regular_inverted', 'hd_inverted', 'real_inverted'):
        mod = 'inverted'
    else:
        mod = None

    size  = settings.THUMBNAIL_ALIASES[''][alias]['size']

    if image is None or not isinstance(image, Image):
        return {
            'status': 'failure',
            'image': '',
            'alias': alias,
            'revision': revision,
            'size_x': size[0],
            'size_y': size[1],
            'capty_cache_key': 'astrobin_image_no_image',
        }

    w = image.w
    h = image.h

    if w == 0 or h == 0:
        # Old images might not have a size in the database, let's fix it.
        try:
            from django.core.files.images import get_image_dimensions
            (w, h) = get_image_dimensions(image.image_file.file)
            image.w = w
            image.h = h
            image.save()
        except IOError:
            w = size[0]
            h = size[1] if size[1] > 0 else w
            response_dict['status'] = 'error'
            response_dict['error_message'] = _("Data corruption. Please upload this image again. Sorry!")
        except zlib.error:
            w = size[0]
            h = size[1] if size[1] > 0 else w

    if alias in ('regular', 'regular_inverted',
                 'hd'     , 'hd_inverted',
                 'real'   , 'real_inverted'):
        size = (size[0], int(size[0] / (w / float(h))))
        response_dict['provide_size'] = False

    placehold_size = [size[0], size[1]]
    for i in range(0,2):
        if placehold_size[i] > 1920:
            placehold_size[i] = 1920

    if w < placehold_size[0]:
        placehold_size[0] = w
        placehold_size[1] = h

    # Determine whether this is an animated gif, and we should show it as such
    field = image.get_thumbnail_field(revision)
    animated = False
    if field.name.lower().endswith('.gif') and alias in ('regular', 'hd', 'real'):
        gif = PILImage.open(field.file)
        try:
            gif.seek(1)
        except EOFError:
            animated = False
        else:
            animated = True

    url = get_image_url(image, revision, url_size)

    show_tooltip = alias in (
        'gallery', 'gallery_inverted',
        'thumb',
    )

    ##########
    # BADGES #
    ##########

    badges = []

    if alias in ('thumb', 'gallery', 'gallery_inverted', 'regular', 'regular_inverted'):
        if image.iotd_date():
            badges.append('iotd')

        top100_ids = SearchQuerySet().models(Image).all().order_by('-likes').values_list('django_id', flat = True)[:100]
        if image.pk in top100_ids:
            badges.append('top100')

    cache_key = image.thumbnail_cache_key(field, alias)
    if animated:
        cache_key += '_animated'
    thumb_url = cache.get(cache_key)

    get_thumb_url = None
    if thumb_url is None:
        get_thumb_kwargs = {
            'id': image.id,
            'alias': alias,
        }

        if revision is None or revision != 'final':
            get_thumb_kwargs['r'] = revision

        get_thumb_url = reverse('image_thumb', kwargs = get_thumb_kwargs)
        if animated:
            get_thumb_url += '?animated'

    return dict(response_dict.items() + {
        'status'        : 'success',
        'image'         : image,
        'alias'         : alias,
        'mod'           : mod,
        'revision'      : revision,
        'size_x'        : size[0],
        'size_y'        : size[1],
        'placehold_size': "%sx%s" % (placehold_size[0], placehold_size[1]),
        'real'          : alias in ('real', 'real_inverted'),
        'url'           : url,
        'show_tooltip'  : show_tooltip,
        'request'       : context['request'],
        'capty_cache_key': "%d_%s_%s" % (image.id, revision, alias),
        'badges'        : badges,
        'animated'      : animated,
        'get_thumb_url' : get_thumb_url,
        'thumb_url'     : thumb_url,
    }.items())

@register.simple_tag(takes_context = True)
def random_id(context, size = 8, chars = string.ascii_uppercase + string.digits):
    id = ''.join(random.choice(chars) for x in range(size))
    context['randomid'] = id
    return ''

register.inclusion_tag(
    'astrobin_apps_images/snippets/image.html',
    takes_context = True)(astrobin_image)

<|endoftext|>


<commit_before>from os.path import basename

from django.contrib.auth.decorators import login_required
from django.shortcuts import render_to_response, get_object_or_404
from django.http import HttpResponseRedirect, HttpResponseForbidden
from django.core.urlresolvers import reverse
from django.template import RequestContext
from django import forms
from django.forms.formsets import formset_factory
from django.db import transaction
from django.utils.translation import ugettext as _

from devilry.ui.messages import UiMessages
from devilry.core.utils.GroupNodes import group_assignmentgroups, print_tree
from devilry.core.models import Delivery, AssignmentGroup

class UploadFileForm(forms.Form):
    file = forms.FileField()
UploadFileFormSet = formset_factory(UploadFileForm, extra=10)

@login_required
def add_delivery_choose_assignment(request):
    active_assignment_groups = AssignmentGroup.active_where_is_candidate(request.user)
    subjects = group_assignmentgroups(active_assignment_groups)

    return render_to_response('devilry/student/add_delivery_choose_assignment.django.html', {
            'subjects': subjects,
            'urlname': 'devilry-student-add_delivery',
            }, context_instance=RequestContext(request))

@login_required
@transaction.autocommit
def add_delivery(request, assignment_group_id, messages=None):
    assignment_group = get_object_or_404(AssignmentGroup, pk=assignment_group_id)
    if not assignment_group.is_candidate(request.user):
        return HttpResponseForbidden("Forbidden")
    if request.method == 'POST':
        formset = UploadFileFormSet(request.POST, request.FILES)
        if formset.is_valid():
            delivery = Delivery.begin(assignment_group, request.user)
            for f in request.FILES.values():
                filename = basename(f.name) # do not think basename is needed, but at least we *know* we only get the filename.
                delivery.add_file(filename, f.chunks())
            delivery.finish()
            return HttpResponseRedirect(
                    reverse('devilry-student-successful_delivery',
                        args=[assignment_group_id]))
    else:
        formset = UploadFileFormSet()

    return render_to_response('devilry/student/add_delivery.django.html', {
        'assignment_group': assignment_group,
        'formset': formset,
        'messages': messages,
        }, context_instance=RequestContext(request))

def successful_delivery(request, assignment_group_id):
    messages = UiMessages()
    messages.add_info(_('Successful delivery'))
    return add_delivery(request, assignment_group_id, messages)

@login_required
def show_assignments(request):
    assignment_groups = AssignmentGroup.active_where_is_candidate(request.user)
    subjects = group_assignmentgroups(assignment_groups)
    old_assignment_groups = AssignmentGroup.old_where_is_candidate(request.user)
    old_subjects = group_assignmentgroups(old_assignment_groups)
    return render_to_response('devilry/student/dashboard/show_assignments.django.html', {
            'subjects': subjects,
            'old_subjects': old_subjects,
            }, context_instance=RequestContext(request))

@login_required
def show_history(request):
    old_assignment_groups = AssignmentGroup.published_where_is_candidate(request.user)
    subjects = group_assignmentgroups(old_assignment_groups)

    return render_to_response('devilry/student/show-history.django.html', {
            'subjects': subjects,
            }, context_instance=RequestContext(request))

@login_required
def show_assignmentgroup(request, assignmentgroup_id):
    assignment_group = get_object_or_404(AssignmentGroup, pk=assignmentgroup_id)
    if not assignment_group.is_candidate(request.user):
        return HttpResponseForbidden("Forbidden")
    return render_to_response('devilry/student/show_assignmentgroup.django.html', {
        'assignment_group': assignment_group,
        }, context_instance=RequestContext(request))

@login_required
def show_delivery(request, delivery_id):
    delivery = get_object_or_404(Delivery, pk=delivery_id)
    if not delivery.assignment_group.is_candidate(request.user):
        return HttpResponseForbidden("Forbidden")
    return render_to_response('devilry/student/show_delivery.django.html', {
        'delivery': delivery,
        }, context_instance=RequestContext(request))
<commit_msg>direct to assignmentgroup after successful delivery<commit_after>from os.path import basename

from django.contrib.auth.decorators import login_required
from django.shortcuts import render_to_response, get_object_or_404
from django.http import HttpResponseRedirect, HttpResponseForbidden
from django.core.urlresolvers import reverse
from django.template import RequestContext
from django import forms
from django.forms.formsets import formset_factory
from django.db import transaction
from django.utils.translation import ugettext as _

from devilry.ui.messages import UiMessages
from devilry.core.utils.GroupNodes import group_assignmentgroups, print_tree
from devilry.core.models import Delivery, AssignmentGroup

class UploadFileForm(forms.Form):
    file = forms.FileField()
UploadFileFormSet = formset_factory(UploadFileForm, extra=10)

@login_required
def add_delivery_choose_assignment(request):
    active_assignment_groups = AssignmentGroup.active_where_is_candidate(request.user)
    subjects = group_assignmentgroups(active_assignment_groups)

    return render_to_response('devilry/student/add_delivery_choose_assignment.django.html', {
            'subjects': subjects,
            'urlname': 'devilry-student-add_delivery',
            }, context_instance=RequestContext(request))

@login_required
@transaction.autocommit
def add_delivery(request, assignment_group_id, messages=None):
    assignment_group = get_object_or_404(AssignmentGroup, pk=assignment_group_id)
    if not assignment_group.is_candidate(request.user):
        return HttpResponseForbidden("Forbidden")
    if request.method == 'POST':
        formset = UploadFileFormSet(request.POST, request.FILES)
        if formset.is_valid():
            delivery = Delivery.begin(assignment_group, request.user)
            for f in request.FILES.values():
                filename = basename(f.name) # do not think basename is needed, but at least we *know* we only get the filename.
                delivery.add_file(filename, f.chunks())
            delivery.finish()
            return HttpResponseRedirect(
                    reverse('devilry-student-successful_delivery',
                        args=[assignment_group_id]))
    else:
        formset = UploadFileFormSet()

    return render_to_response('devilry/student/add_delivery.django.html', {
        'assignment_group': assignment_group,
        'formset': formset,
        'messages': messages,
        }, context_instance=RequestContext(request))

def successful_delivery(request, assignment_group_id):
    messages = UiMessages()
    messages.add_info(_('Successful delivery'))
    #return add_delivery(request, assignment_group_id, messages)
    return show_assignmentgroup(request, assignment_group_id, messages)

@login_required
def show_assignments(request):
    assignment_groups = AssignmentGroup.active_where_is_candidate(request.user)
    subjects = group_assignmentgroups(assignment_groups)
    old_assignment_groups = AssignmentGroup.old_where_is_candidate(request.user)
    old_subjects = group_assignmentgroups(old_assignment_groups)
    return render_to_response('devilry/student/dashboard/show_assignments.django.html', {
            'subjects': subjects,
            'old_subjects': old_subjects,
            }, context_instance=RequestContext(request))

@login_required
def show_history(request):
    old_assignment_groups = AssignmentGroup.published_where_is_candidate(request.user)
    subjects = group_assignmentgroups(old_assignment_groups)

    return render_to_response('devilry/student/show-history.django.html', {
            'subjects': subjects,
            }, context_instance=RequestContext(request))

@login_required
def show_assignmentgroup(request, assignmentgroup_id, messages=None):
    assignment_group = get_object_or_404(AssignmentGroup, pk=assignmentgroup_id)
    if not assignment_group.is_candidate(request.user):
        return HttpResponseForbidden("Forbidden")
    return render_to_response('devilry/student/show_assignmentgroup.django.html', {
        'assignment_group': assignment_group,
        'messages': messages,
        }, context_instance=RequestContext(request))

@login_required
def show_delivery(request, delivery_id):
    delivery = get_object_or_404(Delivery, pk=delivery_id)
    if not delivery.assignment_group.is_candidate(request.user):
        return HttpResponseForbidden("Forbidden")
    return render_to_response('devilry/student/show_delivery.django.html', {
        'delivery': delivery,
        }, context_instance=RequestContext(request))
<|endoftext|>