<commit_before>import logging

from misc import synchronous
from server import Server

logger = logging.getLogger(__name__)

@synchronous
class Thonmux:
    """ **The** "tmux" interface.

    This class prevents that interactions with "tmux" result in an out of sync
    entity tree, where the python objects representation differ from what
    really exists in "tmux".

    It works by keeping track of the *session* provided to its constructor, as
    well as to its active *window* and active *pane*. Whenever an action that
    would alter the tree's state happens, it raises an `exception.EntityOutOf
    Sync`_ that is handled by reconstructing the tree and updating the
    references of the tracked *session*, *window* and *pane*.

    All "tmux" commands are run against the tracked *session*, *window* and
    *pane* as needed.

    Currently, there's support for the following "tmux" command:
    - rename-session
    - new-window
    - select-window
    - next-window
    - previous-window
    - last-window
    - rename-window
    - kill-window
    - window-split
    - select-pane
    - kill-pane
    - resize-pane
    - send-keys

    There's also a convenience command:
    - toggle-zoom (zooms in/out of the tracked *pane*)

    :param str session_name: The name of target session. If a session with the
    provided name already exists, it will attach to it. Otherwise, it will
    create a new session with the provided name.
    :param str socket_name: The name of the socket to be used to localize the
    "tmux" server.
    :param socket_path: The path of the socket to be used to localize the
    "tmux" server.
    :type socket_path: str or None

    Refer to the `"tmux" manual<http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-
    current/man1/tmux.1?query=tmux&sec=1>`_ for more information.
    """

    def __init__(self, session_name, socket_name='default', socket_path=None):
        server = Server(socket_name, socket_path)
        self.session = server.attach_session(session_name)
        self._sync(False)
        logger.debug('Thonmux instance created -> ' + str(self))

    def __repr__(self):
        return 'Thonmux[%s, %s, %s]' % (self.session, self.window, self.pane)

    def _sync(self, session=True):
        if session:
            self.session = self.session._sync()
        self.window = self.session.active_window
        self.pane = self.window.active_pane
        logger.debug('Synchronizing Thonmux: ' + str(self))

    def rename_session(self, name):
        """Renames the tracked *session*.

        :param str name: The name to be applied to the session
        """
        self.session.rename(name)

    def new_window(self, name, start_dir=None):
        """Creates a new window under the tracked *session*. Updates the
        tracked *session*, *window* and *pane* references.

        :param str name: The name to be applied to the window
        :param start_dir: The starting directory for the new window
        :type start_dir: str or None
        """
        self.session.new_window(name, start_dir=start_dir)

    def select_window(self, index):
        """Selects the window with the given index under the tracked *session*.
        Updates the tracked *window* and *pane* references.

        :param str index: The index of the target window
        """
        self.session.select_window(index)

    def next_window(self):
        """Selects the next window under the tracked *session*. Updates the
        tracked *window* and *pane* references.
        """
        self.session.next_window()

    def previous_window(self):
        """Selects the previous window under the tracked *session*. Updates the
        tracked *window* and *pane* references.
        """
        self.session.previous_window()

    def last_window(self):
        """Selects the last window under the tracked *session*. Updates the
        tracked *window* and *pane* references.
        """
        self.session.last_window()

    def rename_window(self, name):
        """Renames the tracked *window*.

        :param str name: The name to be applied to the window
        """
        self.window.rename(name)

    def kill_window(self):
        """Kills (removes) the tracked *window* from under the tracked
        *session*. Updates the tracked *session*, *window* and *pane*
        references.
        """
        self.window.kill()

    def window_split(self, horizontal=False, start_dir=None):
        """Splits the tracked *pane*. Updates the tracked *window* and *pane*
        references.

        :param bool horizontal: Defines whether the split is going to be
        vertical (False) or horizontal (True)
        :param start_dir: The starting directory for the new pane
        :type start_dir: str or None
        """
        self.window.split(horizontal, start_dir=start_dir)

    def select_pane(self, index):
        """Selects the pane with the given index under the tracked *window*.
        Updates the tracked *pane* reference.

        :param str index: The index of the target pane
        """
        self.window.select_pane(index)

    def kill_pane(self):
        """Kills (removes) the tracked *pane* from under the tracked *window*
        Updates the tracked *window* and *pane* references.
        """
        self.pane.kill()

    def resize_pane(self, width, height):
        """Resizes the tracked *pane* using the given width and height.

        :param str width: The width to be applied to the target pane
        :param str height: The height to be applied to the target pane
        """
        self.pane.resize(width, height)

    def send_keys(self, keys, enter=True):
        """Sends the given keys to the tracked *pane*.

        :param str keys: The string to be sent to the target pane
        :param bool enter: Defines whether an 'Enter' should be sent after the
        command (True) or not (False)
        """
        self.pane.send_keys(keys, enter)

    def toggle_zoom(self):
        """Zooms in/out of the tracked *pane*.
        """
        self.pane.zoom()
<commit_msg>Fixing docs<commit_after>import logging

from misc import synchronous
from server import Server

logger = logging.getLogger(__name__)

@synchronous
class Thonmux:
    """**The** "tmux" interface.

    This class prevents that interactions with "tmux" result in an out of sync
    entity tree, where the python objects representation differ from what
    really exists in "tmux".

    It works by keeping track of the *session* provided to its constructor, as
    well as to its active *window* and active *pane*. Whenever an action that
    would alter the tree's state happens, it raises an `exception.EntityOutOf
    Sync`_ that is handled by reconstructing the tree and updating the
    references of the tracked *session*, *window* and *pane*.

    All "tmux" commands are run against the tracked *session*, *window* and
    *pane* as needed.

    Currently, there's support for the following "tmux" command:
    - rename-session
    - new-window
    - select-window
    - next-window
    - previous-window
    - last-window
    - rename-window
    - kill-window
    - window-split
    - select-pane
    - kill-pane
    - resize-pane
    - send-keys

    There's also a convenience command:
    - toggle-zoom (zooms in/out of the tracked *pane*)

    :param str session_name: The name of target session. If a session with the
    provided name already exists, it will attach to it. Otherwise, it will
    create a new session with the provided name.
    :param str socket_name: The name of the socket to be used to localize the
    "tmux" server.
    :param socket_path: The path of the socket to be used to localize the
    "tmux" server.
    :type socket_path: str or None

    Refer to the `"tmux" manual<http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-
    current/man1/tmux.1?query=tmux&sec=1>`_ for more information.
    """

    def __init__(self, session_name, socket_name='default', socket_path=None):
        server = Server(socket_name, socket_path)
        self.session = server.attach_session(session_name)
        self._sync(False)
        logger.debug('Thonmux instance created -> ' + str(self))

    def __repr__(self):
        return 'Thonmux[%s, %s, %s]' % (self.session, self.window, self.pane)

    def _sync(self, session=True):
        if session:
            self.session = self.session._sync()
        self.window = self.session.active_window
        self.pane = self.window.active_pane
        logger.debug('Synchronizing Thonmux: ' + str(self))

    def rename_session(self, name):
        """Renames the tracked *session*.

        :param str name: The name to be applied to the session
        """
        self.session.rename(name)

    def new_window(self, name, start_dir=None):
        """Creates a new window under the tracked *session*. Updates the
        tracked *session*, *window* and *pane* references.

        :param str name: The name to be applied to the window
        :param start_dir: The starting directory for the new window
        :type start_dir: str or None
        """
        self.session.new_window(name, start_dir=start_dir)

    def select_window(self, index):
        """Selects the window with the given index under the tracked *session*.
        Updates the tracked *window* and *pane* references.

        :param str index: The index of the target window
        """
        self.session.select_window(index)

    def next_window(self):
        """Selects the next window under the tracked *session*. Updates the
        tracked *window* and *pane* references.
        """
        self.session.next_window()

    def previous_window(self):
        """Selects the previous window under the tracked *session*. Updates the
        tracked *window* and *pane* references.
        """
        self.session.previous_window()

    def last_window(self):
        """Selects the last window under the tracked *session*. Updates the
        tracked *window* and *pane* references.
        """
        self.session.last_window()

    def rename_window(self, name):
        """Renames the tracked *window*.

        :param str name: The name to be applied to the window
        """
        self.window.rename(name)

    def kill_window(self):
        """Kills (removes) the tracked *window* from under the tracked
        *session*. Updates the tracked *session*, *window* and *pane*
        references.
        """
        self.window.kill()

    def window_split(self, horizontal=False, start_dir=None):
        """Splits the tracked *pane*. Updates the tracked *window* and *pane*
        references.

        :param bool horizontal: Defines whether the split is going to be
        vertical (False) or horizontal (True)
        :param start_dir: The starting directory for the new pane
        :type start_dir: str or None
        """
        self.window.split(horizontal, start_dir=start_dir)

    def select_pane(self, index):
        """Selects the pane with the given index under the tracked *window*.
        Updates the tracked *pane* reference.

        :param str index: The index of the target pane
        """
        self.window.select_pane(index)

    def kill_pane(self):
        """Kills (removes) the tracked *pane* from under the tracked *window*
        Updates the tracked *window* and *pane* references.
        """
        self.pane.kill()

    def resize_pane(self, width, height):
        """Resizes the tracked *pane* using the given width and height.

        :param str width: The width to be applied to the target pane
        :param str height: The height to be applied to the target pane
        """
        self.pane.resize(width, height)

    def send_keys(self, keys, enter=True):
        """Sends the given keys to the tracked *pane*.

        :param str keys: The string to be sent to the target pane
        :param bool enter: Defines whether an 'Enter' should be sent after the
        command (True) or not (False)
        """
        self.pane.send_keys(keys, enter)

    def toggle_zoom(self):
        """Zooms in/out of the tracked *pane*.
        """
        self.pane.zoom()
<|endoftext|>


<commit_before>#! /usr/bin/env python3
#
# 4chan thread live shitposter IRC bot

from __future__ import unicode_literals, absolute_import, print_function, division

import sys
import time

import re
import threading
import configparser
from io import StringIO
import textwrap
from urllib.request import urlopen
from bs4 import BeautifulSoup

import basc_py4chan
from basc_py4chan.util import clean_comment_body
import irc.client

cfg = configparser.ConfigParser()
cfg.read('config.cfg')

# configuration here
irc_server = cfg['IRC'].get('server', fallback='irc.rizon.net')
irc_port = cfg['IRC'].getint('port', fallback=6697)
irc_nick = cfg['IRC'].get('nick', fallback='pyemugenbot')
irc_channel = cfg['IRC'].get('channel', fallback='#emugentest')
admins = cfg['IRC'].get('admins', fallback='').split(',') # comma separated list of users who can restart and shutdown the bot

board_name = cfg['4chan'].get('board', fallback='vg')
general = cfg['4chan'].get('general', fallback='emugen|emulation') # matching pattern to find thread
archive = cfg['4chan'].get('archive', fallback='boards.fireden.net')
https = cfg['4chan'].getboolean('https', fallback=True)

board = basc_py4chan.Board(board_name, https)
thread = board.get_thread(0)
bumplimit_warning = True

def archive_url():
    return 'https://' + archive + '/' + board_name + '/thread/' + str(thread.topic.post_id)

def set_thread(board, thread_id):
    global thread
    thread = board.get_thread(thread_id)

def thread_alive(board, thread):
    #return (board.thread_exists(thread_id))
    return board.thread_exists(thread.id) and thread.archived == False

def find_threads(board, general, search_comment=False):
    threads = set()
    for thread in board.get_all_threads():
        if thread.topic.subject is not None:
            if re.search(general, thread.topic.subject, re.I):
                threads.add(thread)
        if search_comment:
            if re.search(general, thread.topic.comment, re.I):
                threads.add(thread)
    return threads

def find_current_thread(board, general):
    for thread in board.get_all_threads():
        if thread.topic.subject is not None:
            if re.search(general, thread.topic.subject, re.I):
                print('Found current thread:', thread.url)
                return thread.topic.post_id
    print("No thread up at the moment")
    return -1

def youtube_match(string):
    youtube = r'(youtu(?<=(v|V)/)|(?<=be/)|(?<=(\?|\&)v=)|(?<=embed/))([\w-]+)'
    return re.search(youtube, string)

def youtube_video_title_lookup(string, include_url=False):
    yt_match = youtube_match(string)
    if yt_match: #youtube handling
        splitline = string.split(' ')
        for i, word in enumerate(splitline):
            if youtube_match(word):
                video_id = yt_match.group(0)
                bs = BeautifulSoup(urlopen('https://www.youtube.com/watch?v=' + video_id), 'html.parser') # html.parser is 7% slower than lxml
                video_title = bs.title.string[0:-10]
                word= '[You\x0301,05Tube\x0f] \x0304' + video_title + '\x0f'
                if include_url:
                    word = word + ' [https://youtu.be/' + video_id + ']'
                splitline[i] = ('').join(word)
        string = (' ').join(splitline)
    return string

def update_thread():
    update = -1
    tries = 0
    while tries < 10:
        try:
            update = thread.update()
            break
        except HTTPError as e:
            print('Update attempt returned HTTP error ' + str(e.response.status_code))
            time.sleep(5+tries)
            continue
        tries += 1
    return update

def chat_new_posts(c, target):
    update = update_thread()
    if update == -1:
        return False
    if (thread_alive(board, thread)):
        if (update > 0):
            new_posts = thread.posts[-update:]
            for post in new_posts:
                output = StringIO(newline='')
                print('[\x02\x0310{}\x0f] '.format(post.post_id),end="",file=output)
                if post.name != 'Anonymous':
                    print('[\x0314name:\x0f ',end="",file=output)
                    if not post.name is None:
                        print(post.name,end="",file=output)
                    if not post.tripcode is None:
                        print('\x0313{}\x0f'.format(post.tripcode),end="",file=output)
                    print('] ',end="",file=output)
                if post.has_file:
                    # File.filename_original attribute has been merged upstream but is not yet in release
                    # https://github.com/bibanon/BASC-py4chan/commit/205d001
                    print('[\x0314file:\x0f {} (\x0319{}\x0f)]'.format(post.file_url, post.file.filename_original),file=output)
                comment = post.comment
                if re.search('<s>', comment):
                    comment = comment.replace('<s>', '\x0301,01')
                    comment = comment.replace('</s>', '\x0f')
                    comment = clean_comment_body(comment)
                else:
                    comment = post.text_comment
                lines = comment.split('\n')
                for line in lines:
                    if not re.match(r'^\s*$', line): # no checking of blank lines
                        quote = r'>>((\d+)|>((((/\w+)*)*)/?))'
                        if re.search(quote, line):
                            splitline = line.split(' ')
                            for i, word in enumerate(splitline):
                                if re.match(quote, word): # quote handling
                                    word = '\x0304', word, '\x0f'
                                    splitline[i] = ('').join(word)
                            line = (' ').join(splitline)

                        if youtube_match(line):
                            line = youtube_video_title_lookup(line, True)
                        greentext = '^>[^>\n]+$'
                        if re.match(greentext, line):
                            print('\x0303{}\x0f'.format(line),file=output)
                        else:
                            print(line,file=output)

                print(output.getvalue(),end="")
                for line in output.getvalue().split('\n'):
                    for wrapped in textwrap.wrap(line, 425): # IRC messages must be under 512 total bytes
                        try:
                            if not c.is_connected():
                                c.reconnect()
                            c.privmsg(target, wrapped)
                        except:
                            print(sys.exc_info()[0])

                output.close()
            return True
        else:
            print('No new posts')
            global bumplimit_warning
            if thread.bumplimit:
                print('Bump limit reached ({} posts), looking for new thread'.format(len(thread.posts)))
                old_thread = thread.id
                set_thread(board, wait_for_new_thread())
                if thread.id != old_thread:
                    discovered = '[\x0308ATTENTION!\x0f] Discovered next thread: ' + thread.url
                    print(discovered)
                    c.privmsg(target, discovered)
                    bumplimit_warning = True
                    return True
                else:
                    if bumplimit_warning:
                        warning = '[\x0305WARNING!\x0f] Current thread has now reached the \x0307bump limit\x0f!'
                        c.privmsg(target, warning)
                        bumplimit_warning = False
            return False
    else:
        print('Thread is dead ' + str(thread.topic.post_id))
        c.privmsg(target, '[\x0305WARNING!\x0f] THREAD IS \x0305DEAD+\x0f! Archive URL: ' + archive_url())
        set_thread(board, wait_for_new_thread())
        discovered = '[\x0308ATTENTION!\x0f] Discovered new thread: ' + thread.url
        print(discovered)
        c.privmsg(target, discovered)
        return True

def wait_for_new_thread():
    new_id = find_current_thread(board, general)

    check_interval = 10
    while (new_id < 1):
        print('Waiting for thread - {}s refresh'.format(check_interval))
        time.sleep(check_interval)
        new_id = find_current_thread(board, general)
        if check_interval < 120:
            check_interval += 5

    return new_id

def feed_loop(c, target):
    print('Bot started up, looking for thread')
    set_thread(board, wait_for_new_thread())
    check_interval = 5
    while (1):
        time.sleep(check_interval)
        if (chat_new_posts(c, target)):
            check_interval = 5
        else:
            if (check_interval < 30):
                check_interval += 5
            print("Waiting {} seconds".format(check_interval))

def on_pubmsg(connection, event):
    args = event.arguments[0]
    yt_match = youtube_match(args)
    if re.search('^' + connection.get_nickname() + ':', args):
        print('Detected my own nick mentioned')
        split_args = args.split(' ')
        cmd = split_args[1]
        if (cmd == 'thread'):
            connection.privmsg(irc_channel, thread.url)
        elif (cmd == 'posts'):
            connection.privmsg(irc_channel, 'Thread is currently at ' + str(len(thread.posts)) + ' posts')
        elif (cmd == 'ppm' or cmd == 'speed'):
            time_since = int(time.time()) - thread.topic.timestamp
            ppm = len(thread.posts) / (time_since / 60)
            connection.privmsg(irc_channel, "{0:.2f} posts per minute".format(ppm))
        elif (cmd == 'search'):
            if len(args.split(' ')) > 3:
                invalid_board = True
                for board in basc_py4chan.get_all_boards():
                    if split_args[2] == board.name:
                        invalid_board = False
                        print('Board found')
                        search_board = basc_py4chan.Board(split_args[2], https)
                        threads = find_threads(search_board, (' ').join(split_args[3:]), True)
                        if len(threads) > 0:
                            print('Thread(s) found')
                            for found_thread in threads:
                                subject = found_thread.topic.subject
                                comment = found_thread.topic.text_comment
                                if subject is not None:
                                    message = '\x0304' + found_thread.topic.subject + '\x0f'
                                else:
                                    line = comment.split('\n')[0]
                                    maxlength = 50
                                    if len(line) > maxlength:
                                        message = '\x0304' + line[:maxlength] + '...' + '\x0f'
                                    else:
                                        message = '\x0304' + line + '\x0f'
                                message = message + ': ' + found_thread.url
                                connection.privmsg(irc_channel, message)
                        else:
                            connection.privmsg(irc_channel, 'No such thread')
                if invalid_board:
                    connection.privmsg(irc_channel, 'No such board')
            else:
                connection.privmsg(irc_channel, 'Not enough arguments')
        elif (cmd == 'commands'):
            commands = ['thread: returns URL to current thread',
                        'posts: returns post count of current thread',
                        'ppm|speed: returns the average posts per minute for this thread'
                        'search <board> <thread>: returns thread title and URL if found'
                       ]
            for msg in commands:
                connection.privmsg(event.source.nick, msg)
        else:
            if (event.source.nick in admins):
                if (cmd == 'restart'):
                    connection.disconnect('As you wish my lord...')
                    import os
                    os.execv(__file__, sys.argv)
                elif (cmd == 'quit' or cmd == 'die'):
                    connection.disconnect('Yes master...')
                    sys.exit()
                elif (cmd == 'msg'):
                    if len(args.split(' ')) > 3:
                        msg = (' ').join(split_args[3:])
                        connection.privmsg(split_args[2], msg)
    elif yt_match:
        output = '↑↑ ' + youtube_video_title_lookup(args[0]) + ' ↑↑'
        connection.privmsg(irc_channel, output)

def on_disconnect(connection, event):
    time.sleep(3)
    connection.reconnect()

def main():
    reactor = irc.client.Reactor()
    try:
        c = reactor.server()
        c.buffer_class = irc.buffer.LenientDecodingLineBuffer
        c.connect(irc_server, irc_port, irc_nick)

        time.sleep(2)
        c.join(irc_channel)
        c.set_keepalive(60)

        c.add_global_handler('pubmsg', on_pubmsg)
        c.add_global_handler('disconnect', on_disconnect)

        t = threading.Thread(target=feed_loop, args=(c,irc_channel,))
        t.start()

        print('Bot runloop started')

    except irc.client.ServerConnectionError:
        print(sys.exc_info()[0])
        raise SystemExit(1)

    print('Main process moving into connection maintainance')
    reactor.process_forever()

if __name__ == '__main__':
    main()
<commit_msg>Added separate function for printing bug messages<commit_after>#! /usr/bin/env python3
#
# 4chan thread live shitposter IRC bot

from __future__ import unicode_literals, absolute_import, print_function, division

import sys
import time
from time import strftime

import re
import threading
import configparser
from io import StringIO
import textwrap
from urllib.request import urlopen
from bs4 import BeautifulSoup

import basc_py4chan
from basc_py4chan.util import clean_comment_body
import irc.client

cfg = configparser.ConfigParser()
cfg.read('config.cfg')

# configuration here
irc_server = cfg['IRC'].get('server', fallback='irc.rizon.net')
irc_port = cfg['IRC'].getint('port', fallback=6697)
irc_nick = cfg['IRC'].get('nick', fallback='pyemugenbot')
irc_channel = cfg['IRC'].get('channel', fallback='#emugentest')
admins = cfg['IRC'].get('admins', fallback='').split(',') # comma separated list of users who can restart and shutdown the bot

board_name = cfg['4chan'].get('board', fallback='vg')
general = cfg['4chan'].get('general', fallback='emugen|emulation') # matching pattern to find thread
archive = cfg['4chan'].get('archive', fallback='boards.fireden.net')
https = cfg['4chan'].getboolean('https', fallback=True)

DEBUG_PRINT = cfg['bot'].getboolean('debug', fallback=True)

board = basc_py4chan.Board(board_name, https)
thread = board.get_thread(0)
bumplimit_warning = True

def archive_url():
    return 'https://' + archive + '/' + board_name + '/thread/' + str(thread.topic.post_id)

def set_thread(board, thread_id):
    global thread
    thread = board.get_thread(thread_id)

def thread_alive(board, thread):
    #return (board.thread_exists(thread_id))
    return board.thread_exists(thread.id) and thread.archived == False

def find_threads(board, general, search_comment=False):
    threads = set()
    for thread in board.get_all_threads():
        if thread.topic.subject is not None:
            if re.search(general, thread.topic.subject, re.I):
                threads.add(thread)
        if search_comment:
            if re.search(general, thread.topic.comment, re.I):
                threads.add(thread)
    return threads

def find_current_thread(board, general):
    for thread in board.get_all_threads():
        if thread.topic.subject is not None:
            if re.search(general, thread.topic.subject, re.I):
                print_debug('Found current thread:', thread.url)
                return thread.topic.post_id
    print_debug("No thread up at the moment")
    return -1

def youtube_match(string):
    youtube = r'(youtu(?<=(v|V)/)|(?<=be/)|(?<=(\?|\&)v=)|(?<=embed/))([\w-]+)'
    return re.search(youtube, string)

def youtube_video_title_lookup(string, include_url=False):
    yt_match = youtube_match(string)
    if yt_match: #youtube handling
        splitline = string.split(' ')
        for i, word in enumerate(splitline):
            if youtube_match(word):
                video_id = yt_match.group(0)
                bs = BeautifulSoup(urlopen('https://www.youtube.com/watch?v=' + video_id), 'html.parser') # html.parser is 7% slower than lxml
                video_title = bs.title.string[0:-10]
                word= '[You\x0301,05Tube\x0f] \x0304' + video_title + '\x0f'
                if include_url:
                    word = word + ' [https://youtu.be/' + video_id + ']'
                splitline[i] = ('').join(word)
        string = (' ').join(splitline)
    return string

def update_thread():
    update = -1
    tries = 0
    while tries < 10:
        try:
            update = thread.update()
            break
        except HTTPError as e:
            print_debug('Update attempt returned HTTP error ' + str(e.response.status_code), 'ERROR')
            time.sleep(5+tries)
            continue
        tries += 1
    return update

def chat_new_posts(c, target):
    update = update_thread()
    if update == -1:
        return False
    if (thread_alive(board, thread)):
        if (update > 0):
            new_posts = thread.posts[-update:]
            for post in new_posts:
                output = StringIO(newline='')
                print('[\x02\x0310{}\x0f] '.format(post.post_id),end="",file=output)
                if post.name != 'Anonymous':
                    print('[\x0314name:\x0f ',end="",file=output)
                    if not post.name is None:
                        print(post.name,end="",file=output)
                    if not post.tripcode is None:
                        print('\x0313{}\x0f'.format(post.tripcode),end="",file=output)
                    print('] ',end="",file=output)
                if post.has_file:
                    # File.filename_original attribute has been merged upstream but is not yet in release
                    # https://github.com/bibanon/BASC-py4chan/commit/205d001
                    print('[\x0314file:\x0f {} (\x0319{}\x0f)]'.format(post.file_url, post.file.filename_original),file=output)
                comment = post.comment
                if re.search('<s>', comment):
                    comment = comment.replace('<s>', '\x0301,01')
                    comment = comment.replace('</s>', '\x0f')
                    comment = clean_comment_body(comment)
                else:
                    comment = post.text_comment
                lines = comment.split('\n')
                for line in lines:
                    if not re.match(r'^\s*$', line): # no checking of blank lines
                        quote = r'>>((\d+)|>((((/\w+)*)*)/?))'
                        if re.search(quote, line):
                            splitline = line.split(' ')
                            for i, word in enumerate(splitline):
                                if re.match(quote, word): # quote handling
                                    word = '\x0304', word, '\x0f'
                                    splitline[i] = ('').join(word)
                            line = (' ').join(splitline)

                        if youtube_match(line):
                            line = youtube_video_title_lookup(line, True)
                        greentext = '^>[^>\n]+$'
                        if re.match(greentext, line):
                            print('\x0303{}\x0f'.format(line),file=output)
                        else:
                            print(line,file=output)

                print_debug(output.getvalue(), 'POST', False)
                for line in output.getvalue().split('\n'):
                    for wrapped in textwrap.wrap(line, 425): # IRC messages must be under 512 total bytes
                        try:
                            if not c.is_connected():
                                c.reconnect()
                            c.privmsg(target, wrapped)
                        except:
                            print_debug(sys.exc_info()[0], 'ERROR')

                output.close()
            return True
        else:
            print_debug('No new posts')
            global bumplimit_warning
            if thread.bumplimit:
                print_debug('Bump limit reached ({} posts), looking for new thread'.format(len(thread.posts)), 'WARNING')
                old_thread = thread.id
                set_thread(board, wait_for_new_thread())
                if thread.id != old_thread:
                    discovered = '[\x0308ATTENTION!\x0f] Discovered next thread: ' + thread.url
                    print_debug(discovered)
                    c.privmsg(target, discovered)
                    bumplimit_warning = True
                    return True
                else:
                    if bumplimit_warning:
                        warning = '[\x0305WARNING!\x0f] Current thread has now reached the \x0307bump limit\x0f!'
                        c.privmsg(target, warning)
                        bumplimit_warning = False
            return False
    else:
        print_debug('Thread is dead ' + str(thread.topic.post_id), 'WARNING')
        c.privmsg(target, '[\x0305WARNING!\x0f] THREAD IS \x0305DEAD\x0f! Archive URL: ' + archive_url())
        set_thread(board, wait_for_new_thread())
        discovered = '[\x0308ATTENTION!\x0f] Discovered new thread: ' + thread.url
        print_debug(discovered)
        c.privmsg(target, discovered)
        return True

def wait_for_new_thread():
    new_id = find_current_thread(board, general)

    check_interval = 10
    while (new_id < 1):
        print_debug('Waiting for thread - {}s refresh'.format(check_interval))
        time.sleep(check_interval)
        new_id = find_current_thread(board, general)
        if check_interval < 120:
            check_interval += 5

    return new_id

def feed_loop(c, target):
    print_debug('Bot started up, looking for thread')
    set_thread(board, wait_for_new_thread())
    check_interval = 5
    while (1):
        time.sleep(check_interval)
        if (chat_new_posts(c, target)):
            check_interval = 5
        else:
            if (check_interval < 30):
                check_interval += 5
            print_debug("Waiting {} seconds".format(check_interval))

def on_pubmsg(connection, event):
    args = event.arguments[0]
    yt_match = youtube_match(args)
    if re.search('^' + connection.get_nickname() + ':', args):
        print_debug('Detected my own nick mentioned')
        split_args = args.split(' ')
        cmd = split_args[1]
        if (cmd == 'thread'):
            connection.privmsg(irc_channel, thread.url)
        elif (cmd == 'posts'):
            connection.privmsg(irc_channel, 'Thread is currently at ' + str(len(thread.posts)) + ' posts')
        elif (cmd == 'ppm' or cmd == 'speed'):
            time_since = int(time.time()) - thread.topic.timestamp
            ppm = len(thread.posts) / (time_since / 60)
            connection.privmsg(irc_channel, "{0:.2f} posts per minute".format(ppm))
        elif (cmd == 'search'):
            if len(args.split(' ')) > 3:
                invalid_board = True
                for board in basc_py4chan.get_all_boards():
                    if split_args[2] == board.name:
                        invalid_board = False
                        print_debug('Board found')
                        search_board = basc_py4chan.Board(split_args[2], https)
                        threads = find_threads(search_board, (' ').join(split_args[3:]), True)
                        if len(threads) > 0:
                            print_debug('Thread(s) found')
                            for found_thread in threads:
                                subject = found_thread.topic.subject
                                comment = found_thread.topic.text_comment
                                if subject is not None:
                                    message = '\x0304' + found_thread.topic.subject + '\x0f'
                                else:
                                    line = comment.split('\n')[0]
                                    maxlength = 50
                                    if len(line) > maxlength:
                                        message = '\x0304' + line[:maxlength] + '...' + '\x0f'
                                    else:
                                        message = '\x0304' + line + '\x0f'
                                message = message + ': ' + found_thread.url
                                connection.privmsg(irc_channel, message)
                        else:
                            connection.privmsg(irc_channel, 'No such thread')
                if invalid_board:
                    connection.privmsg(irc_channel, 'No such board')
            else:
                connection.privmsg(irc_channel, 'Not enough arguments')
        elif (cmd == 'commands'):
            commands = ['thread: returns URL to current thread',
                        'posts: returns post count of current thread',
                        'ppm|speed: returns the average posts per minute for this thread'
                        'search <board> <thread>: returns thread title and URL if found'
                       ]
            for msg in commands:
                connection.privmsg(event.source.nick, msg)
        else:
            if (event.source.nick in admins):
                if (cmd == 'restart'):
                    connection.disconnect('As you wish my lord...')
                    import os
                    os.execv(__file__, sys.argv)
                elif (cmd == 'quit' or cmd == 'die'):
                    connection.disconnect('Yes master...')
                    sys.exit()
                elif (cmd == 'msg'):
                    if len(args.split(' ')) > 3:
                        msg = (' ').join(split_args[3:])
                        connection.privmsg(split_args[2], msg)
    elif yt_match:
        output = '↑↑ ' + youtube_video_title_lookup(args[0]) + ' ↑↑'
        connection.privmsg(irc_channel, output)

def on_disconnect(connection, event):
    time.sleep(3)
    connection.reconnect()

def print_debug(msg, type='INFO', newline=True, time=True):
    if DEBUG_PRINT:
        message = '[{}] {}'.format(type, msg)
        if time:
            message = strftime('%Y-%m-%d %H:%M:%S') + ' ' + message
        if newline:
            print(message)
        else:
            print(message, end='')

def main():
    reactor = irc.client.Reactor()
    try:
        c = reactor.server()
        c.buffer_class = irc.buffer.LenientDecodingLineBuffer
        c.connect(irc_server, irc_port, irc_nick)

        time.sleep(2)
        c.join(irc_channel)
        c.set_keepalive(60)

        c.add_global_handler('pubmsg', on_pubmsg)
        c.add_global_handler('disconnect', on_disconnect)

        t = threading.Thread(target=feed_loop, args=(c,irc_channel,))
        t.start()

        print_debug('Bot runloop started')

    except irc.client.ServerConnectionError:
        print(sys.exc_info()[0])
        raise SystemExit(1)

    print_debug('Main process moving into connection maintainance')
    reactor.process_forever()

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


<commit_before>#! /usr/bin/env python3
#
# 4chan thread live shitposter IRC bot

from __future__ import unicode_literals, absolute_import, print_function, division

import sys
import time

import re
import threading
import configparser
from io import StringIO
import textwrap

import basc_py4chan
from basc_py4chan.util import clean_comment_body
import irc.client

cfg = configparser.ConfigParser()
cfg.read('config.cfg')

# configuration here
irc_server = cfg['IRC'].get('server', fallback='irc.rizon.net')
irc_port = cfg['IRC'].getint('port', fallback=6697)
irc_nick = cfg['IRC'].get('nick', fallback='pyemugenbot')
irc_channel = cfg['IRC'].get('channel', fallback='#emugentest')

board_name = cfg['4chan'].get('board', fallback='vg')
general = cfg['4chan'].get('general', fallback='emugen|emulation') # matching pattern to find thread
archive = cfg['4chan'].get('archive', fallback='boards.fireden.net')

board = basc_py4chan.Board(board_name)
thread = board.get_thread(0)
bumplimit_warning = true

def archive_url():
    return 'https://' + archive + '/' + board_name + '/thread/' + str(thread.topic.post_id)

def print_new_posts():
    update = thread.update()
    if (update > 0):
        new_posts = thread.posts[-update:]
        for post in new_posts:
            output = StringIO(newline='')
            #print("New post", post.post_id, "::")
            print('[{}] '.format(post.post_id),end="",file=output)
            if post.name != 'Anonymous':
                print('[name: ',end="",file=output)
                if post.name != 'None':
                    print('{}'.format(post.name),end="",file=output)
                if not post.tripcode is None:
                    print(post.tripcode,end="",file=output)
                print('] ',end="",file=output)
            if post.has_file:
                print('[img: {}]'.format(post.file_url),file=output)
            comment = post.text_comment
            lines = comment.split('\n')
            for line in lines:
                if not re.match(r'^\s*$', line):
                    print(line,file=output)
            print(output.getvalue(),end="")
            output.close()

def set_thread(board, thread_id):
    global thread
    thread = board.get_thread(thread_id)

def thread_alive(board, thread):
    #return (board.thread_exists(thread_id))
    return board.thread_exists(thread.id) and thread.archived == False

def find_current_thread(board, general):
    for thread in board.get_all_threads():
        if thread.topic.subject is not None:
            if re.search(general, thread.topic.subject, re.I):
                print('Found current thread:', thread.url)
                return thread.topic.post_id
    print("No thread up at the moment")
    return -1

def chat_all_new_posts(c, target):
    update = thread.update()
    if (thread_alive(board, thread)):
        if (update > 0):
            new_posts = thread.posts[-update:]
            for post in new_posts:
                output = StringIO(newline='')
                print('[\x02\x0310{}\x0f] '.format(post.post_id),end="",file=output)
                if post.name != 'Anonymous':
                    print('[\x0314name:\x0f ',end="",file=output)
                    if not post.name is None:
                        print(post.name,end="",file=output)
                    if not post.tripcode is None:
                        print('\x0313{}\x0f'.format(post.tripcode),end="",file=output)
                    print('] ',end="",file=output)
                if post.has_file:
                    #print('[\x0310file:\x0f {}]'.format(https_url(post.file_url)),file=output)

                    # File.filename_original attribute has been merged upstream but is not yet in release
                    # https://github.com/bibanon/BASC-py4chan/commit/205d001
                    print('[\x0314file:\x0f {} (\x0319{}\x0f)]'.format(https_url(post.file_url), post.file.filename_original),file=output)
                comment = post.comment
                if re.search('<s>', comment):
                    comment = comment.replace('<s>', '\x0301,01')
                    comment = comment.replace('</s>', '\x0f')
                    comment = clean_comment_body(comment)
                else:
                    comment = post.text_comment
                lines = comment.split('\n')
                for line in lines:
                    if not re.match(r'^\s*$', line):
                        quote = r'>>((\d+)|>((((/\w+)*)*)/?))'
                        if re.search(quote, line):
                            splitline = line.split(' ')
                            for i, word in enumerate(splitline):
                                if re.match(quote, word):
                                    word = '\x0304', word, '\x0f'
                                    splitline[i] = ('').join(word)
                            line = (' ').join(splitline)
                        greentext = '^>[^>\n]+$'
                        if re.match(greentext, line):
                            print('\x0303{}\x0f'.format(line),file=output)
                        else:
                            print(line,file=output)

                print(output.getvalue(),end="")
                for line in output.getvalue().split('\n'):
                    for wrapped in textwrap.wrap(line, 425): # IRC messages must be under 512 total bytes
                        try:
                            c.privmsg(target, wrapped)
                        except:
                            print('Exception: ' + sys.exc_info()[0])

                output.close()
            return True
        else:
            print('No new posts')
            if thread.bumplimit:
                print('Bump limit reached ({} posts), looking for new thread'.format(len(thread.posts)))
                old_thread = thread.id
                set_thread(board, wait_for_new_thread())
                if thread.id != old_thread:
                    discovered = 'Discovered next thread: ' + https_url(thread.url)
                    print(discovered)
                    c.privmsg(target, discovered)
                    global bumplimit_warning
                    bumplimit_warning = true
                    return True
                else:
                    if bumplimit_warning:
                        warning = 'Current thread has now reached the \x0307bump limit\x0f!'
                        c.privmsg(target, warning)
                        global bumplimit_warning
                        bumplimit_warning = false
            return False
    else:
        print('Thread is dead ' + str(thread.topic.post_id))
        c.privmsg(target, 'THREAD IS \x0305DEAD+\x0f! Archive URL: ' + archive_url())
        set_thread(board, wait_for_new_thread())
        discovered = 'Discovered new thread: ' + https_url(thread.url)
        print(discovered)
        c.privmsg(target, discovered)
        return True

def wait_for_new_thread():
    new_id = find_current_thread(board, general)

    check_interval = 10
    while (new_id < 1):
        print('Waiting for thread - {}s refresh'.format(check_interval))
        time.sleep(check_interval)
        new_id = find_current_thread(board, general)
        if check_interval < 120:
            check_interval += 5

    return new_id

def feed_loop(c, target):
    print('Bot started up, looking for thread')
    set_thread(board, wait_for_new_thread())
    check_interval = 5
    while (1):
        time.sleep(check_interval)
        if (chat_all_new_posts(c, target)):
            check_interval = 5
        else:
            if (check_interval < 30):
                check_interval += 5
            print("Waiting {} seconds".format(check_interval))

def https_url(url):
    return url.replace('http', 'https')

def main():
    reactor = irc.client.Reactor()
    try:
        c = reactor.server()
        c.connect(irc_server, irc_port, irc_nick)

        c.join(irc_channel)
        c.set_keepalive(60)

        t = threading.Thread(target=feed_loop, args=(c,irc_channel,))
        t.start()

        print('Bot runloop started')

    except irc.client.ServerConnectionError:
        print(sys.exc_info()[1])
        raise SystemExit(1)

    print('Main process moving into connection maintainance')
    reactor.process_forever()

if __name__ == '__main__':
    main()
<commit_msg>Syntax fix<commit_after>#! /usr/bin/env python3
#
# 4chan thread live shitposter IRC bot

from __future__ import unicode_literals, absolute_import, print_function, division

import sys
import time

import re
import threading
import configparser
from io import StringIO
import textwrap

import basc_py4chan
from basc_py4chan.util import clean_comment_body
import irc.client

cfg = configparser.ConfigParser()
cfg.read('config.cfg')

# configuration here
irc_server = cfg['IRC'].get('server', fallback='irc.rizon.net')
irc_port = cfg['IRC'].getint('port', fallback=6697)
irc_nick = cfg['IRC'].get('nick', fallback='pyemugenbot')
irc_channel = cfg['IRC'].get('channel', fallback='#emugentest')

board_name = cfg['4chan'].get('board', fallback='vg')
general = cfg['4chan'].get('general', fallback='emugen|emulation') # matching pattern to find thread
archive = cfg['4chan'].get('archive', fallback='boards.fireden.net')

board = basc_py4chan.Board(board_name)
thread = board.get_thread(0)
bumplimit_warning = True

def archive_url():
    return 'https://' + archive + '/' + board_name + '/thread/' + str(thread.topic.post_id)

def print_new_posts():
    update = thread.update()
    if (update > 0):
        new_posts = thread.posts[-update:]
        for post in new_posts:
            output = StringIO(newline='')
            #print("New post", post.post_id, "::")
            print('[{}] '.format(post.post_id),end="",file=output)
            if post.name != 'Anonymous':
                print('[name: ',end="",file=output)
                if post.name != 'None':
                    print('{}'.format(post.name),end="",file=output)
                if not post.tripcode is None:
                    print(post.tripcode,end="",file=output)
                print('] ',end="",file=output)
            if post.has_file:
                print('[img: {}]'.format(post.file_url),file=output)
            comment = post.text_comment
            lines = comment.split('\n')
            for line in lines:
                if not re.match(r'^\s*$', line):
                    print(line,file=output)
            print(output.getvalue(),end="")
            output.close()

def set_thread(board, thread_id):
    global thread
    thread = board.get_thread(thread_id)

def thread_alive(board, thread):
    #return (board.thread_exists(thread_id))
    return board.thread_exists(thread.id) and thread.archived == False

def find_current_thread(board, general):
    for thread in board.get_all_threads():
        if thread.topic.subject is not None:
            if re.search(general, thread.topic.subject, re.I):
                print('Found current thread:', thread.url)
                return thread.topic.post_id
    print("No thread up at the moment")
    return -1

def chat_all_new_posts(c, target):
    update = thread.update()
    if (thread_alive(board, thread)):
        if (update > 0):
            new_posts = thread.posts[-update:]
            for post in new_posts:
                output = StringIO(newline='')
                print('[\x02\x0310{}\x0f] '.format(post.post_id),end="",file=output)
                if post.name != 'Anonymous':
                    print('[\x0314name:\x0f ',end="",file=output)
                    if not post.name is None:
                        print(post.name,end="",file=output)
                    if not post.tripcode is None:
                        print('\x0313{}\x0f'.format(post.tripcode),end="",file=output)
                    print('] ',end="",file=output)
                if post.has_file:
                    #print('[\x0310file:\x0f {}]'.format(https_url(post.file_url)),file=output)

                    # File.filename_original attribute has been merged upstream but is not yet in release
                    # https://github.com/bibanon/BASC-py4chan/commit/205d001
                    print('[\x0314file:\x0f {} (\x0319{}\x0f)]'.format(https_url(post.file_url), post.file.filename_original),file=output)
                comment = post.comment
                if re.search('<s>', comment):
                    comment = comment.replace('<s>', '\x0301,01')
                    comment = comment.replace('</s>', '\x0f')
                    comment = clean_comment_body(comment)
                else:
                    comment = post.text_comment
                lines = comment.split('\n')
                for line in lines:
                    if not re.match(r'^\s*$', line):
                        quote = r'>>((\d+)|>((((/\w+)*)*)/?))'
                        if re.search(quote, line):
                            splitline = line.split(' ')
                            for i, word in enumerate(splitline):
                                if re.match(quote, word):
                                    word = '\x0304', word, '\x0f'
                                    splitline[i] = ('').join(word)
                            line = (' ').join(splitline)
                        greentext = '^>[^>\n]+$'
                        if re.match(greentext, line):
                            print('\x0303{}\x0f'.format(line),file=output)
                        else:
                            print(line,file=output)

                print(output.getvalue(),end="")
                for line in output.getvalue().split('\n'):
                    for wrapped in textwrap.wrap(line, 425): # IRC messages must be under 512 total bytes
                        try:
                            c.privmsg(target, wrapped)
                        except:
                            print('Exception: ' + sys.exc_info()[0])

                output.close()
            return True
        else:
            print('No new posts')
            if thread.bumplimit:
                print('Bump limit reached ({} posts), looking for new thread'.format(len(thread.posts)))
                old_thread = thread.id
                set_thread(board, wait_for_new_thread())
                if thread.id != old_thread:
                    discovered = 'Discovered next thread: ' + https_url(thread.url)
                    print(discovered)
                    c.privmsg(target, discovered)
                    global bumplimit_warning
                    bumplimit_warning = True
                    return True
                else:
                    if bumplimit_warning:
                        warning = 'Current thread has now reached the \x0307bump limit\x0f!'
                        c.privmsg(target, warning)
                        global bumplimit_warning
                        bumplimit_warning = False
            return False
    else:
        print('Thread is dead ' + str(thread.topic.post_id))
        c.privmsg(target, 'THREAD IS \x0305DEAD+\x0f! Archive URL: ' + archive_url())
        set_thread(board, wait_for_new_thread())
        discovered = 'Discovered new thread: ' + https_url(thread.url)
        print(discovered)
        c.privmsg(target, discovered)
        return True

def wait_for_new_thread():
    new_id = find_current_thread(board, general)

    check_interval = 10
    while (new_id < 1):
        print('Waiting for thread - {}s refresh'.format(check_interval))
        time.sleep(check_interval)
        new_id = find_current_thread(board, general)
        if check_interval < 120:
            check_interval += 5

    return new_id

def feed_loop(c, target):
    print('Bot started up, looking for thread')
    set_thread(board, wait_for_new_thread())
    check_interval = 5
    while (1):
        time.sleep(check_interval)
        if (chat_all_new_posts(c, target)):
            check_interval = 5
        else:
            if (check_interval < 30):
                check_interval += 5
            print("Waiting {} seconds".format(check_interval))

def https_url(url):
    return url.replace('http', 'https')

def main():
    reactor = irc.client.Reactor()
    try:
        c = reactor.server()
        c.connect(irc_server, irc_port, irc_nick)

        c.join(irc_channel)
        c.set_keepalive(60)

        t = threading.Thread(target=feed_loop, args=(c,irc_channel,))
        t.start()

        print('Bot runloop started')

    except irc.client.ServerConnectionError:
        print(sys.exc_info()[1])
        raise SystemExit(1)

    print('Main process moving into connection maintainance')
    reactor.process_forever()

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


<commit_before>#!/usr/bin/env python
"""
tox-bootstrap
=============

http://code.google.com/p/pytox/issues/detail?id=1

Getting started
---------------

::

    $ cd my_project/
    $ ls
    . .. src/ doc/ setup.py tox.ini
    $ curl http://github.com/srid/tox-bootstrap/raw/master/toxbootstrap.py -O

Instead of running "tox", now you can just run "python toxbootstrap.py" which
will take care of installing tox (if not already installed into
``.tox/toxinstall``)::

    $ python toxbootstrap.py

If you're using Hudson_, you may also do::

    import sys
    sys.path.insert(0, '.') # sometimes necessary :/
    import toxbootstrap
    toxbootstrap.cmdline() # also accepts argv list

.. _Hudson: http://hudson-ci.org/

ToDo
----

1. Detect tox in ``$PATH`` (eg: ``C:\Python26\Scripts`` or
   ``%APPDATA%\Python\Scripts``)

2. Gracefully ignore PyPI xmlrpc downtime errors when checking for new release.

"""

import sys
import os
from os import path
import logging

from subprocess import Popen, PIPE, check_call, CalledProcessError

PY3 = sys.version_info[0] == 3

if PY3:
    from urllib.request import urlretrieve
    import xmlrpc.client as xmlrpclib
else:
    from urllib import urlretrieve
    import xmlrpclib

logging.basicConfig(level=logging.INFO)

# Last stable: 1.4.9
VIRTUALENVPY_URL = 'http://bitbucket.org/ianb/virtualenv/raw/6d187b9cf916/virtualenv.py'

def run(cmd, shell=True):
    """Run the given command in shell"""
    logging.info('Running command: %s', cmd)
    check_call(cmd, shell=shell)

def crun(cmd, shell=True):
    """Run the given command and return its output"""
    logging.info('Running command (for output): %s', cmd)
    p = Popen(cmd, stdout=PIPE, shell=shell)
    stdout, stderr = p.communicate()
    return stdout

def wget(url):
    """Download the given file to current directory"""
    logging.info('Downloading %s', url)
    localpath = path.join(path.abspath(os.getcwd()), path.basename(url))
    urlretrieve(url, localpath)

def has_script(venv, name):
    """Check if the virtualenv has the given script

    Looks for bin/$name (unix) or Scripts/$name.exe (windows) in the virtualenv
    """
    if sys.platform == 'win32':
        return any([path.exists(path.join(venv, 'Scripts', name)),
                    path.exists(path.join(venv, 'Scripts', name + '.exe'))])
    else:
        return path.exists(path.join(venv, 'bin', name))

def get_script_path(venv, name):
    """Return the full path to the script in virtualenv directory"""
    if sys.platform == 'win32':
        p = path.join(venv, 'Scripts', name)
        if not path.exists(p):
            p = path.join(venv, 'Scripts', name + '.exe')
    else:
        p = path.join(venv, 'bin', name)

    if not path.exists(p):
        raise NameError('cannot find a script named "%s"' % (name,))

    return p

def get_tox_version(venv):
    """Return the installed version of tox"""
    py = get_script_path(venv, 'python')
    s = 'import tox,sys; sys.stdout.write(str(tox.__version__))'
    if sys.version_info[:2] >= (2, 6):
        return crun('%s -s -c "%s"' % (py, s))
    else:
        return crun('%s -c "%s"' % (py, s))

def parse_simple_version(v):
    """A simplified version of pkg_resources.parse_version

    This method can only parse simple versions like the ones with a set of
    numbers separated by dots (eg: 1.2.3)
    """
    return [int(c) for c in v.split('.')]

def pypi_get_latest_version(pkgname):
    """Return the latest version of package from PyPI"""
    pypi = xmlrpclib.ServerProxy('http://pypi.python.org/pypi')
    versions = pypi.package_releases('tox')
    assert versions
    versions.sort(key=parse_simple_version, reverse=True)
    return versions[0]

def cmdline(argv=None):
    os.chdir(path.abspath(path.dirname(__file__)))
    if not path.isdir('.tox'):
        os.mkdir('.tox')
    os.chdir('.tox')

    # create virtual environment
    if not path.isdir('toxinstall') or not has_script('toxinstall', 'python'):
        # get virtualenv.py
        if not path.isfile('virtualenv.py'):
            wget(VIRTUALENVPY_URL)
        assert path.isfile('virtualenv.py')

        # XXX: we use --no-site-packages because: if tox is installed in global
        # site-packages, then pip will not install it locally. ideal fix for
        # this should be to first look for tox in the global scripts/ directory
        run('%s virtualenv.py --no-site-packages --distribute toxinstall' % sys.executable)

    assert has_script('toxinstall', 'python'), 'no python script'
    assert has_script('toxinstall', 'pip'), 'no pip script'

    pip = get_script_path('toxinstall', 'pip')

    # install/upgrade tox itself
    if any([
        not has_script('toxinstall', 'tox'),
        get_tox_version('toxinstall') != pypi_get_latest_version('tox')]):
        run('%s install --upgrade --download-cache=pip-cache tox' % (pip,))

    assert has_script('toxinstall', 'tox')
    tox_script = path.abspath(get_script_path('toxinstall', 'tox'))
    logging.info('tox is already installed at %s', tox_script)

    virtualenv = get_script_path('toxinstall', 'virtualenv')

    # XXX: virtualenv 1.5 is broken; replace it
    if crun('%s --version' % (virtualenv,)).strip() == '1.5':
        logging.info(
            'Replacing the unstable virtualenv-1.5 with the latest stable')
        run('%s uninstall -y virtualenv' % (pip,))
        run('%s install virtualenv!=1.5' % (pip,))

    # Now run the locally-installed tox
    os.chdir('..')
    try:
        run([tox_script] + (argv or []), shell=False)
    except CalledProcessError:
        _, e, _ = sys.exc_info()
        logging.error('tox exited with error code %d', e.returncode)
        sys.exit(e.returncode)

if __name__ == '__main__':
    cmdline(sys.argv[1:])
<commit_msg>bootstrap: update urls/refs in docstring<commit_after>#!/usr/bin/env python
"""
tox-bootstrap
=============

A bootstrap to automatically install tox and dependencies on machines that may
not already have tox installed. This is useful when configuring a number of
Hudson quickly; only Python needs to be installed.

Getting started
---------------

::

    $ cd my_project/
    $ ls
    . .. src/ doc/ setup.py tox.ini
    $ curl http://pytox.googlecode.com/hg/toxbootstrap.py -O

Instead of running "tox", now you can just run "python toxbootstrap.py" which
will take care of installing tox (if not already installed into
``.tox/toxinstall``)::

    $ python toxbootstrap.py

If you're using Hudson_, you may also do::

    import sys
    sys.path.insert(0, '.') # sometimes necessary :/
    import toxbootstrap
    toxbootstrap.cmdline() # also accepts argv list

.. _Hudson: http://hudson-ci.org/

ToDo
----

1. Detect tox in ``$PATH`` (eg: ``C:\Python26\Scripts`` or
   ``%APPDATA%\Python\Scripts``)

2. Gracefully ignore PyPI xmlrpc downtime errors when checking for new release.

"""

import sys
import os
from os import path
import logging

from subprocess import Popen, PIPE, check_call, CalledProcessError

PY3 = sys.version_info[0] == 3

if PY3:
    from urllib.request import urlretrieve
    import xmlrpc.client as xmlrpclib
else:
    from urllib import urlretrieve
    import xmlrpclib

logging.basicConfig(level=logging.INFO)

# Last stable: 1.4.9
VIRTUALENVPY_URL = 'http://bitbucket.org/ianb/virtualenv/raw/6d187b9cf916/virtualenv.py'

def run(cmd, shell=True):
    """Run the given command in shell"""
    logging.info('Running command: %s', cmd)
    check_call(cmd, shell=shell)

def crun(cmd, shell=True):
    """Run the given command and return its output"""
    logging.info('Running command (for output): %s', cmd)
    p = Popen(cmd, stdout=PIPE, shell=shell)
    stdout, stderr = p.communicate()
    return stdout

def wget(url):
    """Download the given file to current directory"""
    logging.info('Downloading %s', url)
    localpath = path.join(path.abspath(os.getcwd()), path.basename(url))
    urlretrieve(url, localpath)

def has_script(venv, name):
    """Check if the virtualenv has the given script

    Looks for bin/$name (unix) or Scripts/$name.exe (windows) in the virtualenv
    """
    if sys.platform == 'win32':
        return any([path.exists(path.join(venv, 'Scripts', name)),
                    path.exists(path.join(venv, 'Scripts', name + '.exe'))])
    else:
        return path.exists(path.join(venv, 'bin', name))

def get_script_path(venv, name):
    """Return the full path to the script in virtualenv directory"""
    if sys.platform == 'win32':
        p = path.join(venv, 'Scripts', name)
        if not path.exists(p):
            p = path.join(venv, 'Scripts', name + '.exe')
    else:
        p = path.join(venv, 'bin', name)

    if not path.exists(p):
        raise NameError('cannot find a script named "%s"' % (name,))

    return p

def get_tox_version(venv):
    """Return the installed version of tox"""
    py = get_script_path(venv, 'python')
    s = 'import tox,sys; sys.stdout.write(str(tox.__version__))'
    if sys.version_info[:2] >= (2, 6):
        return crun('%s -s -c "%s"' % (py, s))
    else:
        return crun('%s -c "%s"' % (py, s))

def parse_simple_version(v):
    """A simplified version of pkg_resources.parse_version

    This method can only parse simple versions like the ones with a set of
    numbers separated by dots (eg: 1.2.3)
    """
    return [int(c) for c in v.split('.')]

def pypi_get_latest_version(pkgname):
    """Return the latest version of package from PyPI"""
    pypi = xmlrpclib.ServerProxy('http://pypi.python.org/pypi')
    versions = pypi.package_releases('tox')
    assert versions
    versions.sort(key=parse_simple_version, reverse=True)
    return versions[0]

def cmdline(argv=None):
    os.chdir(path.abspath(path.dirname(__file__)))
    if not path.isdir('.tox'):
        os.mkdir('.tox')
    os.chdir('.tox')

    # create virtual environment
    if not path.isdir('toxinstall') or not has_script('toxinstall', 'python'):
        # get virtualenv.py
        if not path.isfile('virtualenv.py'):
            wget(VIRTUALENVPY_URL)
        assert path.isfile('virtualenv.py')

        # XXX: we use --no-site-packages because: if tox is installed in global
        # site-packages, then pip will not install it locally. ideal fix for
        # this should be to first look for tox in the global scripts/ directory
        run('%s virtualenv.py --no-site-packages --distribute toxinstall' % sys.executable)

    assert has_script('toxinstall', 'python'), 'no python script'
    assert has_script('toxinstall', 'pip'), 'no pip script'

    pip = get_script_path('toxinstall', 'pip')

    # install/upgrade tox itself
    if any([
        not has_script('toxinstall', 'tox'),
        get_tox_version('toxinstall') != pypi_get_latest_version('tox')]):
        run('%s install --upgrade --download-cache=pip-cache tox' % (pip,))

    assert has_script('toxinstall', 'tox')
    tox_script = path.abspath(get_script_path('toxinstall', 'tox'))
    logging.info('tox is already installed at %s', tox_script)

    virtualenv = get_script_path('toxinstall', 'virtualenv')

    # XXX: virtualenv 1.5 is broken; replace it
    if crun('%s --version' % (virtualenv,)).strip() == '1.5':
        logging.info(
            'Replacing the unstable virtualenv-1.5 with the latest stable')
        run('%s uninstall -y virtualenv' % (pip,))
        run('%s install virtualenv!=1.5' % (pip,))

    # Now run the locally-installed tox
    os.chdir('..')
    try:
        run([tox_script] + (argv or []), shell=False)
    except CalledProcessError:
        _, e, _ = sys.exc_info()
        logging.error('tox exited with error code %d', e.returncode)
        sys.exit(e.returncode)

if __name__ == '__main__':
    cmdline(sys.argv[1:])
<|endoftext|>


<commit_before>
"""

"""

import numpy as np
from ..TS_statistics.utils import build_ngram_arrays, create_ngram,\
    uniform_input_samevals, uniform_input_lags
from ..TS_statistics.probabilitytools import compute_conditional_probs,\
    compute_marginal_probs
from ..TS_statistics.ts_statistics import prob_ngram_x, prob_ngram_xy,\
    prob_ngram_ind, prob_xy, prob_xy_ind, prob_x, compute_joint_probs
from ..TS_statistics.regime_statistics import prob_regimes_x, temporal_counts,\
    temporal_average_counts, count_repeated, temporal_densities, parse_spks,\
    isis_computation, isi_distribution, general_count, counts_normalization,\
    temporal_si, prob_spk_xy, count_into_bursts

def test():
    #####
    X = np.random.randn(1000).cumsum()
    X_disc = np.random.randint(0, 20, 1000)
    X_mdisc = np.random.randint(0, 20, (1000, 5))

    ################
    #Test functions
    ##################

    ## Utils
    #########
    uniform_input_lags([5], X)
    lags = uniform_input_lags(np.array([5]), X)
    uniform_input_samevals(True, X_disc)
    uniform_input_samevals(False, np.atleast_2d(X_disc).T)
    uniform_input_samevals(range(20), X_disc)
    uniform_input_samevals(np.arange(20), X_disc)

    ngram = create_ngram(X_disc, lags, samevals=True)
    lags = lags = uniform_input_lags(np.array([5]), X_disc)
    ngram = create_ngram(X_disc, range(5), samevals=True)

    pres, post = [0], [0]
    L = 1
    build_ngram_arrays(np.atleast_2d(X_disc).T, post, pres, L)
    L = 2
    build_ngram_arrays(np.atleast_2d(X_disc).T, post, pres, L)

    ## TO IMPLEMENT
#    X_mdisc = np.random.randint(0, 20, (1000, 5))
#    pres, post = [0, 1, 2], [[1, 2, 3], [2, 3, 4], [0, 1, 4]]
#    build_ngram_arrays(X_mdisc, post, pres, L)
#
    ## probabilitytools
    ###################
    probs = np.random.random((10, 7, 5))
    p_x = compute_marginal_probs(probs, [0])
    assert(p_x.shape == (7, 5))
    p_x = compute_marginal_probs(probs, [1])
    assert(p_x.shape == (10, 5))
    p_x = compute_marginal_probs(probs, [1, 2])
    assert(p_x.shape == (10,))

    p_x_y = compute_conditional_probs(probs, [0])
    assert(p_x_y.shape == probs.shape)
    p_x_y = compute_conditional_probs(probs, [1])
    assert(p_x_y.shape == probs.shape)
    p_x_y = compute_conditional_probs(probs, [1, 2])
    assert(p_x_y.shape == probs.shape)

    ## probabilitytools
    ###################
    L = 3
    X_m = np.random.randint(0, 5, (1000, 4))
    x, y = np.random.randint(0, 5, 1000), np.random.randint(0, 5, 1000)

    prob_ngram_ind(x, y, 1, auto=False, samevals=False, normalize=True)
    prob_ngram_ind(x, y, 1, auto=True, samevals=[range(5)]*2, normalize=True)
    prob_ngram_ind(x, y, 2, auto=False, samevals=False, normalize=True)
    prob_ngram_ind(x, y, 2, auto=True, samevals=[np.arange(5)]*2,
                   normalize=True)
    prob_ngram_ind(x, y, L, auto=False, samevals=np.arange(5), normalize=True)
    prob_ngram_ind(x, y, L, auto=True, samevals=True, normalize=True)

    prob_ngram_xy(X_m, 1, bins=None, auto=True, samevals=True, normalize=True)
    prob_ngram_xy(X_m, 1, bins=None, auto=True, samevals=False, normalize=True)
    prob_ngram_xy(X_m, 1, bins=None, auto=True, samevals=np.arange(5),
                  normalize=True)
    prob_ngram_xy(X_m, 1, bins=None, auto=True, samevals=[range(5)]*4,
                  normalize=True)

    prob_ngram_x(X_m, 1, bins=None, samevals=True, normalize=True)
    prob_ngram_x(X_m, 1, bins=None, samevals=False, normalize=True)
    prob_ngram_x(X_m, 1, bins=None, samevals=np.arange(5), normalize=True)
    prob_ngram_x(X_m, 1, bins=None, samevals=[np.arange(5)]*4, normalize=True)

    compute_joint_probs(X_m, values=[], normalize=True)
    compute_joint_probs(X_m, values=np.arange(5), normalize=True)
    compute_joint_probs(X_m, values=np.arange(5), normalize=True)

    prob_xy_ind(x, y, samevals=True, bins=0, timelag=0, normalize=True)
    prob_xy_ind(x, y, samevals=False, bins=0, timelag=1, normalize=True)
    prob_xy_ind(x, y, samevals=True, bins=0, timelag=0, normalize=True)
    prob_xy_ind(x, y, samevals=False, bins=0, timelag=2, normalize=True)
    prob_xy_ind(x, y, samevals=False, bins=0, timelag=-2, normalize=True)
    prob_xy_ind(x, y, samevals=False, bins=0, timelag=-1, normalize=True)
    prob_xy_ind(x, y, samevals=False, bins=[None, None], timelag=-1,
                normalize=True)
    prob_xy_ind(x, y, samevals=False, bins=[0, 0], timelag=-1, normalize=True)
    prob_xy_ind(x, y, samevals=np.arange(4), bins=2, timelag=-1,
                normalize=True)

    prob_xy(X_m, bins=0, maxl=1, samevals=True)
    prob_xy(X_m, bins=0, maxl=1, samevals=False)
    prob_xy(X_m, bins=0, maxl=1, samevals=np.arange(5))
    prob_xy(X_m, bins=0, maxl=1, samevals=[np.arange(5)]*4)

    prob_x(X_m, n_bins=0, individually=True, normalize=True)
    prob_x(X_m, n_bins=2, individually=False, normalize=True)

    #### Regime statistics
    #######################
    raster = np.random.randint(0, 10, (1000, 4))
    times_event = np.random.random(1000).cumsum()
    element_event = np.random.randint(0, 5, 1000)
    regimes_event = np.random.randint(0, 2, 1000)
    spks = times_event, element_event, regimes_event

    parse_spks(raster)
    parse_spks(spks)

    prob_regimes_x(spks)
    prob_regimes_x(spks, 10)
    prob_regimes_x(spks, normalized=True)
    prob_regimes_x(spks, 10, normalized=True)

    temporal_counts(spks, normalized=False, collapse_reg=True)
    temporal_counts(spks, normalized=False, collapse_reg=False)
    temporal_counts(spks, normalized=True, collapse_reg=True)
    temporal_counts(spks, normalized=True, collapse_reg=False)

    temporal_average_counts(spks, window=0, collapse_reg=True)
    temporal_average_counts(spks, window=20, collapse_reg=True)
    temporal_average_counts(spks, window=0, collapse_reg=False)
    temporal_average_counts(spks, window=20, collapse_reg=False)

    count_repeated(raster[:, 0])

    temporal_densities(spks, w_limit=0, collapse_reg=True)
    temporal_densities(spks, w_limit=20, collapse_reg=True)
    temporal_densities(spks, w_limit=0, collapse_reg=False)
    temporal_densities(spks, w_limit=20, collapse_reg=False)

#    ## Interevent statistics
#    ##
    assert(np.all(np.isfinite(spks)))
    isis_computation(spks, logscale=False)
    isis_computation(spks, logscale=True)
#
#    isi_distribution(spks, 10, globally=False, normalized=True,
#                     logscale=True)
    isi_distribution(spks, 10, globally=True, normalized=True,
                     logscale=False)
#    isi_distribution(spks, 10, globally=False, normalized=False,
#                     logscale=False)
#    isi_distribution(spks, 10, globally=True, normalized=False,
#                     logscale=True)

    temporal_si(spks)

    ## Probs utils
    ##
    c_xy, max_l = np.random.randint(0, 100, (10, 10, 6)), 5
    general_count(c_xy)
    general_count(c_xy, max_l)

    counts_normalization(np.random.randint(0, 100, 1000), 1000)
    counts_normalization(c_xy, 1000)

    ## Counting probs in the events information information
    ##
    prob_spk_xy(spks, max_l=8, normalized=False)
    prob_spk_xy(spks, max_l=8, normalized=True)

    ## Statistics bursts
    bursts = [np.arange(1, 10), np.arange(50, 60)]
    count_into_bursts(spks, bursts, elements=None)
    count_into_bursts(spks, bursts, elements=range(5))
<commit_msg>Exploring tests: ts statistics.<commit_after>
"""

"""

import numpy as np
from ..TS_statistics.utils import build_ngram_arrays, create_ngram,\
    uniform_input_samevals, uniform_input_lags
from ..TS_statistics.probabilitytools import compute_conditional_probs,\
    compute_marginal_probs
from ..TS_statistics.ts_statistics import prob_ngram_x, prob_ngram_xy,\
    prob_ngram_ind, prob_xy, prob_xy_ind, prob_x, compute_joint_probs
from ..TS_statistics.regime_statistics import prob_regimes_x, temporal_counts,\
    temporal_average_counts, count_repeated, temporal_densities, parse_spks,\
    isis_computation, isi_distribution, general_count, counts_normalization,\
    temporal_si, prob_spk_xy, count_into_bursts

def test():
    #####
    X = np.random.randn(1000).cumsum()
    X_disc = np.random.randint(0, 20, 1000)
    X_mdisc = np.random.randint(0, 20, (1000, 5))

    ################
    #Test functions
    ##################

    ## Utils
    #########
    uniform_input_lags([5], X)
    lags = uniform_input_lags(np.array([5]), X)
    uniform_input_samevals(True, X_disc)
    uniform_input_samevals(False, np.atleast_2d(X_disc).T)
    uniform_input_samevals(range(20), X_disc)
    uniform_input_samevals(np.arange(20), X_disc)

    ngram = create_ngram(X_disc, lags, samevals=True)
    lags = lags = uniform_input_lags(np.array([5]), X_disc)
    ngram = create_ngram(X_disc, range(5), samevals=True)

    pres, post = [0], [0]
    L = 1
    build_ngram_arrays(np.atleast_2d(X_disc).T, post, pres, L)
    L = 2
    build_ngram_arrays(np.atleast_2d(X_disc).T, post, pres, L)

    ## TO IMPLEMENT
#    X_mdisc = np.random.randint(0, 20, (1000, 5))
#    pres, post = [0, 1, 2], [[1, 2, 3], [2, 3, 4], [0, 1, 4]]
#    build_ngram_arrays(X_mdisc, post, pres, L)
#
    ## probabilitytools
    ###################
    probs = np.random.random((10, 7, 5))
    p_x = compute_marginal_probs(probs, [0])
    assert(p_x.shape == (7, 5))
    p_x = compute_marginal_probs(probs, [1])
    assert(p_x.shape == (10, 5))
    p_x = compute_marginal_probs(probs, [1, 2])
    assert(p_x.shape == (10,))

    p_x_y = compute_conditional_probs(probs, [0])
    assert(p_x_y.shape == probs.shape)
    p_x_y = compute_conditional_probs(probs, [1])
    assert(p_x_y.shape == probs.shape)
    p_x_y = compute_conditional_probs(probs, [1, 2])
    assert(p_x_y.shape == probs.shape)

    ## probabilitytools
    ###################
    L = 3
    X_m = np.random.randint(0, 5, (1000, 4))
    x, y = np.random.randint(0, 5, 1000), np.random.randint(0, 5, 1000)

    prob_ngram_ind(x, y, 1, auto=False, samevals=False, normalize=True)
    prob_ngram_ind(x, y, 1, auto=True, samevals=[range(5)]*2, normalize=True)
    prob_ngram_ind(x, y, 2, auto=False, samevals=False, normalize=True)
    prob_ngram_ind(x, y, 2, auto=True, samevals=[np.arange(5)]*2,
                   normalize=True)
    prob_ngram_ind(x, y, L, auto=False, samevals=np.arange(5), normalize=True)
    prob_ngram_ind(x, y, L, auto=True, samevals=True, normalize=True)

    prob_ngram_xy(X_m, 1, bins=None, auto=True, samevals=True, normalize=True)
    prob_ngram_xy(X_m, 1, bins=None, auto=True, samevals=False, normalize=True)
    prob_ngram_xy(X_m, 1, bins=None, auto=True, samevals=np.arange(5),
                  normalize=True)
    prob_ngram_xy(X_m, 1, bins=None, auto=True, samevals=[range(5)]*4,
                  normalize=True)

    prob_ngram_x(X_m, 1, bins=None, samevals=True, normalize=True)
    prob_ngram_x(X_m, 1, bins=None, samevals=False, normalize=True)
    prob_ngram_x(X_m, 1, bins=None, samevals=np.arange(5), normalize=True)
    prob_ngram_x(X_m, 1, bins=None, samevals=[np.arange(5)]*4, normalize=True)

    compute_joint_probs(X_m, values=[], normalize=True)
    compute_joint_probs(X_m, values=np.arange(5), normalize=True)
    compute_joint_probs(X_m, values=np.arange(5), normalize=True)

    prob_xy_ind(x, y, samevals=True, bins=0, timelag=0, normalize=True)
    prob_xy_ind(x, y, samevals=False, bins=0, timelag=1, normalize=True)
    prob_xy_ind(x, y, samevals=True, bins=0, timelag=0, normalize=True)
    prob_xy_ind(x, y, samevals=False, bins=0, timelag=2, normalize=True)
    prob_xy_ind(x, y, samevals=False, bins=0, timelag=-2, normalize=True)
    prob_xy_ind(x, y, samevals=False, bins=0, timelag=-1, normalize=True)
    prob_xy_ind(x, y, samevals=False, bins=[None, None], timelag=-1,
                normalize=True)
    prob_xy_ind(x, y, samevals=False, bins=[0, 0], timelag=-1, normalize=True)
    prob_xy_ind(x, y, samevals=np.arange(4), bins=2, timelag=-1,
                normalize=True)

    prob_xy(X_m, bins=0, maxl=1, samevals=True)
    prob_xy(X_m, bins=0, maxl=1, samevals=False)
    prob_xy(X_m, bins=0, maxl=1, samevals=np.arange(5))
    prob_xy(X_m, bins=0, maxl=1, samevals=[np.arange(5)]*4)

    prob_x(X_m, n_bins=0, individually=True, normalize=True)
    prob_x(X_m, n_bins=2, individually=False, normalize=True)

    #### Regime statistics
    #######################
    raster = np.random.randint(0, 10, (1000, 4))
    times_event = np.random.random(1000).cumsum()
    element_event = np.random.randint(0, 5, 1000)
    regimes_event = np.random.randint(0, 2, 1000)
    spks = times_event, element_event, regimes_event

    parse_spks(raster)
    parse_spks(spks)

    prob_regimes_x(spks)
    prob_regimes_x(spks, 10)
    prob_regimes_x(spks, normalized=True)
    prob_regimes_x(spks, 10, normalized=True)

    temporal_counts(spks, normalized=False, collapse_reg=True)
    temporal_counts(spks, normalized=False, collapse_reg=False)
    temporal_counts(spks, normalized=True, collapse_reg=True)
    temporal_counts(spks, normalized=True, collapse_reg=False)

    temporal_average_counts(spks, window=0, collapse_reg=True)
    temporal_average_counts(spks, window=20, collapse_reg=True)
    temporal_average_counts(spks, window=0, collapse_reg=False)
    temporal_average_counts(spks, window=20, collapse_reg=False)

    count_repeated(raster[:, 0])

    temporal_densities(spks, w_limit=0, collapse_reg=True)
    temporal_densities(spks, w_limit=20, collapse_reg=True)
    temporal_densities(spks, w_limit=0, collapse_reg=False)
    temporal_densities(spks, w_limit=20, collapse_reg=False)

#    ## Interevent statistics
#    ##
    assert(np.all(np.isfinite(spks)))
    isis_computation(spks, logscale=False)
    isis_computation(spks, logscale=True)
#
#    isi_distribution(spks, 10, globally=False, normalized=True,
#                     logscale=True)
    isi_distribution(spks, 10, globally=True, normalized=True,
                     logscale=False)
    isi_distribution(spks, 10, globally=False, normalized=False,
                     logscale=False)
#    isi_distribution(spks, 10, globally=True, normalized=False,
#                     logscale=True)

    temporal_si(spks)

    ## Probs utils
    ##
    c_xy, max_l = np.random.randint(0, 100, (10, 10, 6)), 5
    general_count(c_xy)
    general_count(c_xy, max_l)

    counts_normalization(np.random.randint(0, 100, 1000), 1000)
    counts_normalization(c_xy, 1000)

    ## Counting probs in the events information information
    ##
    prob_spk_xy(spks, max_l=8, normalized=False)
    prob_spk_xy(spks, max_l=8, normalized=True)

    ## Statistics bursts
    bursts = [np.arange(1, 10), np.arange(50, 60)]
    count_into_bursts(spks, bursts, elements=None)
    count_into_bursts(spks, bursts, elements=range(5))
<|endoftext|>


<commit_before>"""
Contains fun commands that don't serve any purpose!
"""

import logging
import tempfile
from collections import namedtuple
from io import BytesIO
from typing import Any, Dict

import aiohttp
import discord
from discord.ext import commands
from PIL import Image, ImageEnhance

from dog import Cog
from dog.core import checks, utils

SHIBE_ENDPOINT = 'http://shibe.online/api/shibes?count=1&urls=true&httpsUrls=true'
DOGFACTS_ENDPOINT = 'https://dog-api.kinduff.com/api/facts'

logger = logging.getLogger(__name__)

async def _get(session: aiohttp.ClientSession, url: str) -> aiohttp.ClientResponse:
    async with session.get(url) as response:
        return response

async def _get_bytesio(session: aiohttp.ClientSession, url: str) -> BytesIO:
    # can't use _get for some reason
    async with session.get(url) as resp:
        return BytesIO(await resp.read())

async def _get_json(session: aiohttp.ClientSession, url: str) -> Dict[Any, Any]:
    resp = await _get(session, url)
    return await resp.json()

UrbanDefinition = namedtuple('UrbanDefinition', [
    'word', 'definition', 'thumbs_up', 'thumbs_down', 'example',
    'permalink', 'author', 'defid', 'current_vote'
])

async def urban(session: aiohttp.ClientSession, word: str) -> UrbanDefinition:
    UD_ENDPOINT = 'http://api.urbandictionary.com/v0/define?term={}'
    async with session.get(UD_ENDPOINT.format(utils.urlescape(word))) as resp:
        json = await resp.json()
        if json['result_type'] == 'no_results':
            return None
        result = json['list'][0]
        return UrbanDefinition(**result)

def make_urban_embed(d: UrbanDefinition) -> discord.Embed:
    embed = discord.Embed(title=d.word, description=d.definition)
    embed.add_field(name='Example', value=d.example, inline=False)
    embed.add_field(name='\N{THUMBS UP SIGN}', value=utils.commas(d.thumbs_up))
    embed.add_field(name='\N{THUMBS DOWN SIGN}', value=utils.commas(d.thumbs_down))
    return embed

class Fun(Cog):
    @commands.command()
    @commands.guild_only()
    @checks.config_is_set('woof_command_enabled')
    async def woof(self, ctx):
        """ Sample command. """
        await ctx.send('Woof!')

    @commands.command()
    @commands.cooldown(1, 2, commands.BucketType.user)
    async def urban(self, ctx, *, word: str):
        """ Finds UrbanDictionary definitions. """
        async with ctx.channel.typing():
            result = await urban(self.bot.session, word)
            if not result:
                return await ctx.send('No results!')
            await ctx.send(embed=make_urban_embed(result))

    @commands.command()
    @commands.cooldown(1, 2, commands.BucketType.user)
    async def shibe(self, ctx):
        """
        Woof!

        Grabs a random Shiba Inu picture from shibe.online.
        """
        async with ctx.channel.typing():
            try:
                resp = await _get_json(self.bot.session, SHIBE_ENDPOINT)
            except aiohttp.ClientError:
                return await ctx.send('\N{DISAPPOINTED FACE} Failed to contact the shibe API.')
            dog_url = resp[0]
            await ctx.send(embed=discord.Embed().set_image(url=dog_url))

    @commands.command()
    @commands.cooldown(1, 5, commands.BucketType.user)
    async def wacky(self, ctx, who: discord.Member=None):
        """ Turns your avatar into... """
        if not who:
            who = ctx.message.author
        logger.info('wacky: get: %s', who.avatar_url)

        async with ctx.channel.typing():
            avatar_data = await _get_bytesio(self.bot.session, who.avatar_url_as(format='png'))

            logger.info('wacky: enhancing...')
            im = Image.open(avatar_data)
            converter = ImageEnhance.Color(im)
            im = converter.enhance(50)

            with BytesIO() as bio:
                logger.info('wacky: saving...')
                im.save(bio, format='jpeg', quality=0)
                logger.info('wacky: sending...')
                bio.seek(0)
                await ctx.send(file=discord.File(bio, 'result.jpg'))

            # close images
            avatar_data.close()

    @commands.command()
    @commands.cooldown(1, 2, commands.BucketType.user)
    async def dogfact(self, ctx):
        """ Returns a random dog fact. """
        async with ctx.channel.typing():
            try:
                facts = await _get_json(self.bot.session, DOGFACTS_ENDPOINT)
            except aiohttp.ClientError:
                return await ctx.send('\N{DISAPPOINTED FACE} Failed to get a dog fact.')
            if not facts['success']:
                await ctx.send('I couldn\'t contact the Dog Facts API.')
                return
            await ctx.send(facts['facts'][0])

def setup(bot):
    bot.add_cog(Fun(bot))
<commit_msg>Greatly refactor d?wacky<commit_after>"""
Contains fun commands that don't serve any purpose!
"""

import logging
from collections import namedtuple
from io import BytesIO
from typing import Any, Dict

import aiohttp
import discord
from discord.ext import commands
from PIL import Image, ImageEnhance

from dog import Cog
from dog.core import checks, utils

SHIBE_ENDPOINT = 'http://shibe.online/api/shibes?count=1&urls=true&httpsUrls=true'
DOGFACTS_ENDPOINT = 'https://dog-api.kinduff.com/api/facts'

logger = logging.getLogger(__name__)

async def _get(session: aiohttp.ClientSession, url: str) -> aiohttp.ClientResponse:
    async with session.get(url) as response:
        return response

async def _get_bytesio(session: aiohttp.ClientSession, url: str) -> BytesIO:
    # can't use _get for some reason
    async with session.get(url) as resp:
        return BytesIO(await resp.read())

async def _get_json(session: aiohttp.ClientSession, url: str) -> Dict[Any, Any]:
    resp = await _get(session, url)
    return await resp.json()

UrbanDefinition = namedtuple('UrbanDefinition', [
    'word', 'definition', 'thumbs_up', 'thumbs_down', 'example',
    'permalink', 'author', 'defid', 'current_vote'
])

async def urban(session: aiohttp.ClientSession, word: str) -> UrbanDefinition:
    """ Queries UrbanDictionary for a definition. """
    UD_ENDPOINT = 'http://api.urbandictionary.com/v0/define?term={}'
    async with session.get(UD_ENDPOINT.format(utils.urlescape(word))) as resp:
        json = await resp.json()
        if json['result_type'] == 'no_results':
            return None
        result = json['list'][0]
        return UrbanDefinition(**result)

def make_urban_embed(d: UrbanDefinition) -> discord.Embed:
    """ Makes a ``discord.Embed`` from an ``UrbanDefinition``. """
    embed = discord.Embed(title=d.word, description=d.definition)
    embed.add_field(name='Example', value=d.example, inline=False)
    embed.add_field(name='\N{THUMBS UP SIGN}', value=utils.commas(d.thumbs_up))
    embed.add_field(name='\N{THUMBS DOWN SIGN}', value=utils.commas(d.thumbs_down))
    return embed

class Fun(Cog):
    @commands.command()
    @commands.guild_only()
    @checks.config_is_set('woof_command_enabled')
    async def woof(self, ctx):
        """ Sample command. """
        await ctx.send('Woof!')

    @commands.command()
    @commands.cooldown(1, 2, commands.BucketType.user)
    async def urban(self, ctx, *, word: str):
        """ Finds UrbanDictionary definitions. """
        async with ctx.channel.typing():
            result = await urban(self.bot.session, word)
            if not result:
                return await ctx.send('No results!')
            await ctx.send(embed=make_urban_embed(result))

    @commands.command()
    @commands.cooldown(1, 2, commands.BucketType.user)
    async def shibe(self, ctx):
        """
        Woof!

        Grabs a random Shiba Inu picture from shibe.online.
        """
        async with ctx.channel.typing():
            try:
                resp = await _get_json(self.bot.session, SHIBE_ENDPOINT)
            except aiohttp.ClientError:
                return await ctx.send('\N{DISAPPOINTED FACE} Failed to contact the shibe API.')
            dog_url = resp[0]
            await ctx.send(embed=discord.Embed().set_image(url=dog_url))

    @commands.command()
    @commands.cooldown(1, 5, commands.BucketType.user)
    async def wacky(self, ctx, who: discord.Member=None):
        """ Turns your avatar into... """
        if not who:
            who = ctx.message.author
        logger.info('wacky: get: %s', who.avatar_url)

        async with ctx.channel.typing():
            avatar_url = who.avatar_url_as(format='png')
            with await _get_bytesio(self.bot.session, avatar_url) as avatar_data:
                im = Image.open(avatar_data)
                converter = ImageEnhance.Color(im)
                im = converter.enhance(50)

                with BytesIO() as bio:
                    im.save(bio, format='jpeg', quality=0)
                    bio.seek(0)
                    await ctx.send(file=discord.File(bio, 'result.jpg'))

                im.close()

    @commands.command()
    @commands.cooldown(1, 2, commands.BucketType.user)
    async def dogfact(self, ctx):
        """ Returns a random dog fact. """
        async with ctx.channel.typing():
            try:
                facts = await _get_json(self.bot.session, DOGFACTS_ENDPOINT)
            except aiohttp.ClientError:
                return await ctx.send('\N{DISAPPOINTED FACE} Failed to get a dog fact.')
            if not facts['success']:
                await ctx.send('I couldn\'t contact the Dog Facts API.')
                return
            await ctx.send(facts['facts'][0])

def setup(bot):
    bot.add_cog(Fun(bot))
<|endoftext|>