<commit_before># coding: utf-8
"""payu.models.fms
   ===============

   Driver interface to the FMS model framework.

   :copyright: Copyright 2011 Marshall Ward, see AUTHORS for details
   :license: Apache License, Version 2.0, see LICENSE for details
"""

# Standard Library

from collections import defaultdict
import os
import resource as res
import shlex
import subprocess as sp
# Use multiprocessing dummy (threads) as collate jobs run in own process
import multiprocessing.dummy as multiprocessing

# Local
from payu.models.model import Model

def cmdthread(cmd, cwd):
    # This is run in a thread, so the GIL of python makes it sensible to
    # capture the output from each process and print it out at the end so
    # it doesn't get scrambled when collates are run in parallel
    result = True
    try:
        output = sp.check_output(shlex.split(cmd), cwd=cwd, stderr=sp.STDOUT)
    except CalledProcessError as e:
        print('{} failed, returned errorcode {}'.format(e.cmd, e.returncode))
        result = False
    print(output)
    return result

class Fms(Model):

    def __init__(self, expt, name, config):

        # payu initalisation
        super(Fms, self).__init__(expt, name, config)

    def set_model_pathnames(self):

        super(Fms, self).set_model_pathnames()

        # Define local FMS directories
        self.work_restart_path = os.path.join(self.work_path, 'RESTART')
        self.work_input_path = os.path.join(self.work_path, 'INPUT')
        self.work_init_path = self.work_input_path

    def archive(self, **kwargs):

        # Remove the 'INPUT' path
        cmd = 'rm -rf {}'.format(self.work_input_path)
        sp.check_call(shlex.split(cmd))

        # Archive restart files before processing model output
        if os.path.isdir(self.restart_path):
            os.rmdir(self.restart_path)

        cmd = 'mv {} {}'.format(self.work_restart_path, self.restart_path)
        sp.check_call(shlex.split(cmd))

    def collate(self):

        # Set the stacksize to be unlimited
        res.setrlimit(res.RLIMIT_STACK, (res.RLIM_INFINITY, res.RLIM_INFINITY))

        # Locate the FMS collation tool
        # Check config for collate executable
        mppnc_path = self.expt.config.get('collate_exe')
        if mppnc_path is None:
            for f in os.listdir(self.expt.lab.bin_path):
                if f.startswith('mppnccombine'):
                    mppnc_path = os.path.join(self.expt.lab.bin_path, f)
                    break
        else:
            if not os.path.isabs(mppnc_path):
                mppnc_path = os.path.join(self.expt.lab.bin_path, mppnc_path)

        assert mppnc_path

        # Check config for collate command line options
        collate_flags = self.expt.config.get('collate_flags')
        if collate_flags is None:
            collate_flags = '-n4 -z -m -r'

        # Import list of collated files to ignore
        collate_ignore = self.expt.config.get('collate_ignore')
        if collate_ignore is None:
            collate_ignore = []
        elif type(collate_ignore) != list:
            collate_ignore = [collate_ignore]

        # Generate collated file list and identify the first tile
        tile_fnames = [f for f in os.listdir(self.output_path)
                       if f[-4:].isdigit() and f[-8:-4] == '.nc.']

        mnc_tiles = defaultdict(list)
        for t_fname in tile_fnames:
            t_base, t_ext = os.path.splitext(t_fname)
            t_ext = t_ext.lstrip('.')

            # Skip any files listed in the ignore list
            if t_base in collate_ignore:
                continue

            mnc_tiles[t_base].append(t_fname)

        # If this is run interactively NCPUS is set in collate_cmd, otherwise
        # the cpu_count will return the number of CPUs assigned to the PBS job
        count = int(os.environ.get('NCPUS', multiprocessing.cpu_count()))
        pool = multiprocessing.Pool(processes=count)

        # Collate each tileset into a single file
        results = []
        for nc_fname in mnc_tiles:
            nc_path = os.path.join(self.output_path, nc_fname)

            # Remove the collated file if it already exists, since it is
            # probably from a failed collation attempt
            # TODO: Validate this somehow
            if os.path.isfile(nc_path):
                os.remove(nc_path)

            cmd = '{} {} {} {}'.format(mppnc_path, collate_flags, nc_fname,
                                       ' '.join(mnc_tiles[nc_fname]))
            print(cmd)
            result = pool.apply_async(cmdthread, args=(cmd, self.output_path))
            results.append(result.get())

        pool.close()
        pool.join()

        # TODO: Categorise the return codes
        if any(rc for rc in results):
            for p, rc in enumerate(results):
                if rc:
                    print('payu: error: Thread {} crased with error code {}.'
                          ''.format(i, rc))
            sys.exit(-1)
<commit_msg>Collate processes now return returncode, None if no error.<commit_after># coding: utf-8
"""payu.models.fms
   ===============

   Driver interface to the FMS model framework.

   :copyright: Copyright 2011 Marshall Ward, see AUTHORS for details
   :license: Apache License, Version 2.0, see LICENSE for details
"""

from __future__ import print_function

# Standard Library

from collections import defaultdict
import os
import resource as res
import shlex
import subprocess as sp
# Use multiprocessing dummy (threads) as collate jobs run in own process
import multiprocessing.dummy as multiprocessing
import sys

# Local
from payu.models.model import Model

def cmdthread(cmd, cwd):
    # This is run in a thread, so the GIL of python makes it sensible to
    # capture the output from each process and print it out at the end so
    # it doesn't get scrambled when collates are run in parallel
    output = ''
    returncode = None
    try:
        output = sp.check_output(shlex.split(cmd), cwd=cwd, stderr=sp.STDOUT)
    except sp.CalledProcessError as e:
        output = '{} failed, returned errorcode {}'.format(e.cmd, e.returncode)
        returncode = e.returncode
    print(output)
    return returncode

class Fms(Model):

    def __init__(self, expt, name, config):

        # payu initalisation
        super(Fms, self).__init__(expt, name, config)

    def set_model_pathnames(self):

        super(Fms, self).set_model_pathnames()

        # Define local FMS directories
        self.work_restart_path = os.path.join(self.work_path, 'RESTART')
        self.work_input_path = os.path.join(self.work_path, 'INPUT')
        self.work_init_path = self.work_input_path

    def archive(self, **kwargs):

        # Remove the 'INPUT' path
        cmd = 'rm -rf {}'.format(self.work_input_path)
        sp.check_call(shlex.split(cmd))

        # Archive restart files before processing model output
        if os.path.isdir(self.restart_path):
            os.rmdir(self.restart_path)

        cmd = 'mv {} {}'.format(self.work_restart_path, self.restart_path)
        sp.check_call(shlex.split(cmd))

    def collate(self):

        # Set the stacksize to be unlimited
        res.setrlimit(res.RLIMIT_STACK, (res.RLIM_INFINITY, res.RLIM_INFINITY))

        # Locate the FMS collation tool
        # Check config for collate executable
        mppnc_path = self.expt.config.get('collate_exe')
        if mppnc_path is None:
            for f in os.listdir(self.expt.lab.bin_path):
                if f.startswith('mppnccombine'):
                    mppnc_path = os.path.join(self.expt.lab.bin_path, f)
                    break
        else:
            if not os.path.isabs(mppnc_path):
                mppnc_path = os.path.join(self.expt.lab.bin_path, mppnc_path)

        assert mppnc_path

        # Check config for collate command line options
        collate_flags = self.expt.config.get('collate_flags')
        if collate_flags is None:
            collate_flags = '-n4 -z -m -r'

        # Import list of collated files to ignore
        collate_ignore = self.expt.config.get('collate_ignore')
        if collate_ignore is None:
            collate_ignore = []
        elif type(collate_ignore) != list:
            collate_ignore = [collate_ignore]

        # Generate collated file list and identify the first tile
        tile_fnames = [f for f in os.listdir(self.output_path)
                       if f[-4:].isdigit() and f[-8:-4] == '.nc.']

        mnc_tiles = defaultdict(list)
        for t_fname in tile_fnames:
            t_base, t_ext = os.path.splitext(t_fname)
            t_ext = t_ext.lstrip('.')

            # Skip any files listed in the ignore list
            if t_base in collate_ignore:
                continue

            mnc_tiles[t_base].append(t_fname)

        # If this is run interactively NCPUS is set in collate_cmd, otherwise
        # the cpu_count will return the number of CPUs assigned to the PBS job
        count = int(os.environ.get('NCPUS', multiprocessing.cpu_count()))
        pool = multiprocessing.Pool(processes=count)

        # Collate each tileset into a single file
        results = []
        for nc_fname in mnc_tiles:
            nc_path = os.path.join(self.output_path, nc_fname)

            # Remove the collated file if it already exists, since it is
            # probably from a failed collation attempt
            # TODO: Validate this somehow
            if os.path.isfile(nc_path):
                os.remove(nc_path)

            cmd = '{} {} {} {}'.format(mppnc_path, collate_flags, nc_fname,
                                       ' '.join(mnc_tiles[nc_fname]))
            print(cmd)
            result = pool.apply_async(cmdthread, args=(cmd, self.output_path))
            results.append(result.get())

        pool.close()
        pool.join()

        # TODO: Categorise the return codes
        if any(rc is not None for rc in results):
            for p, rc in enumerate(results):
                if rc is not None:
                    print('payu: error: Thread {} crased with error code {}.'
                          ''.format(p, rc),file=sys.stderr)
            sys.exit(-1)
<|endoftext|>


<commit_before>__author__ = 'kevin'

import sys
from subprocess import check_output
import os

class Call():

    input_functions = ['canonicalize_file_name', 'catgets', 'confstr', 'ctermid', 'ctermid', 'cuserid', 'dgettext',
                       'dngettext', 'fgetc', 'fgetc_unlocked', 'fgets', 'fgets_unlocked', 'fpathconf', 'fread',
                       'fread_unlocked', 'fscanf', 'getc', 'getchar', 'getchar_unlocked', 'getc_unlocked',
                       'get_current_dir_name', 'getcwd', 'getdelim', '__getdelim', 'getdelim', 'getdents', 'getenv',
                       'gethostbyaddr', 'gethostbyname', 'gethostbyname2', 'gethostent', 'gethostid', 'getline',
                       'getline', 'getlogin', 'getlogin_r', 'getmsg', 'getopt', '_getopt_internal', 'getopt_long',
                       'getopt_long_only', 'getpass', 'getpmsg', 'gets', 'gettext', 'getw', 'getwd', 'ngettext',
                       'pathconf', 'pread', 'pread64', 'ptsname', 'ptsname_r', 'read', 'readdir', 'readlink', 'readv',
                       'realpath', 'recv', 'recv_from', 'recvmesg', 'scanf', '__secure_getenv', 'signal', 'sysconf',
                       'ttyname', 'ttyname_r', 'vfscanf', 'vscanf']

    output_functions = ['dprintf', 'fprintf', 'fputc', 'fputchar_unlocked', 'fputc_unlocked', 'fputs', 'fputs_unlocked',
                        'fwrite', 'fwrite_unlocked', 'perror', 'printf', 'psignal', 'putc', 'putchar', 'putc_unlocked',
                        'putenv', 'putmsg', 'putpmsg', 'puts', 'putw', 'pwrite', 'pwrite64', 'send', 'sendmsg',
                        'sendto', 'setenv', 'sethostid', 'setlogin', 'ungetc', 'vdprintf', 'vfprintf', 'vsyslog',
                        'write', 'writev']

    def __init__(self, clfow_line):
        split_line = clfow_line.split(Cflow.indent)

        self.function_info = split_line[-1]
        self.level = len(split_line) - 1

    def __str__(self):
        return "Level: " + str(self.level) + " - " + self.function_info

    def is_input_function(self):
        is_input = self._leaf_belongs_to(Call.input_functions)
        return is_input

    def is_output_function(self):
        is_output = self._leaf_belongs_to(Call.output_functions)
        return is_output

    def _leaf_belongs_to(self, function_set):
        belongs = False

        if self.is_leaf():
            belongs = self.leaf_function_name in function_set

        return belongs

    def is_leaf(self):
        """Checks if the function call represented by this object is a leaf in the call graph generated by cflow.
        Being a leaf means that the function is not defined in the files given to cflow as arguments to analyze.
        """
        return self.function_info.endswith("()")

    @property
    def leaf_function_name(self):
        return self.function_info[:-2]

class Cflow():
    """Wraps around some of cflow's command line interface"""

    indent = "    "

    _file_patterns = ["*.c", "*.h"]
    _cflow_exec = "cflow"

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

    def _get_cflow_args(self):
        dirs_found = []

        for path, dirs, files in os.walk(os.path.abspath(self.source_dir)):
            for dir in dirs:
                for pattern in Cflow._file_patterns:
                    dirs_found.append(os.path.join(path, dir, pattern))

        return dirs_found

    def _build_cflow_command(self):
        cflow_args = self._get_cflow_args()
        command = "cd {0}; ".format(self.source_dir) + Cflow._cflow_exec + ' ' + ' '.join(cflow_args) + ";"

        return command

    def get_text_call_graph(self):
        cmd_cflow = self._build_cflow_command()
        cflow_output = check_output(cmd_cflow, shell=True).decode("utf-8")

        return cflow_output

class Stack():

    _collection = list()

    def __init__(self):
        pass

    def push(self, data):
        self._collection.append(data)

    def pop(self):
        return self._collection.pop()

    @property
    def top(self):
        return self._collection[-1]

def main(args):
    source_dir = args[1]

    cflow = Cflow(source_dir)
    text_call_graph = cflow.get_text_call_graph()

    main_call = Call(text_call_graph.splitlines()[0])

    parent = Stack()
    parent.push(main_call)
    previous = main_call

    entry_points = list()
    exit_points = list()

    for i, line in enumerate(text_call_graph.splitlines()):
        if i != 0:
            current = Call(line)

            if current.level > previous.level:
                parent.push(previous)
            elif current.level < previous.level:
                for i in range(current.level - previous.level):
                    parent.pop()

            if current.is_input_function():
                entry_points.append(parent.top)

            if current.is_output_function():
                exit_points.append(parent.top)

            previous = current

    print(entry_points)
    print(exit_points)

if __name__ == '__main__':
    main(sys.argv)<commit_msg>Printing to console the result of the calculation.<commit_after>__author__ = 'kevin'

import sys
from subprocess import check_output
import os

class Call():

    input_functions = ['canonicalize_file_name', 'catgets', 'confstr', 'ctermid', 'ctermid', 'cuserid', 'dgettext',
                       'dngettext', 'fgetc', 'fgetc_unlocked', 'fgets', 'fgets_unlocked', 'fpathconf', 'fread',
                       'fread_unlocked', 'fscanf', 'getc', 'getchar', 'getchar_unlocked', 'getc_unlocked',
                       'get_current_dir_name', 'getcwd', 'getdelim', '__getdelim', 'getdelim', 'getdents', 'getenv',
                       'gethostbyaddr', 'gethostbyname', 'gethostbyname2', 'gethostent', 'gethostid', 'getline',
                       'getline', 'getlogin', 'getlogin_r', 'getmsg', 'getopt', '_getopt_internal', 'getopt_long',
                       'getopt_long_only', 'getpass', 'getpmsg', 'gets', 'gettext', 'getw', 'getwd', 'ngettext',
                       'pathconf', 'pread', 'pread64', 'ptsname', 'ptsname_r', 'read', 'readdir', 'readlink', 'readv',
                       'realpath', 'recv', 'recv_from', 'recvmesg', 'scanf', '__secure_getenv', 'signal', 'sysconf',
                       'ttyname', 'ttyname_r', 'vfscanf', 'vscanf']

    output_functions = ['dprintf', 'fprintf', 'fputc', 'fputchar_unlocked', 'fputc_unlocked', 'fputs', 'fputs_unlocked',
                        'fwrite', 'fwrite_unlocked', 'perror', 'printf', 'psignal', 'putc', 'putchar', 'putc_unlocked',
                        'putenv', 'putmsg', 'putpmsg', 'puts', 'putw', 'pwrite', 'pwrite64', 'send', 'sendmsg',
                        'sendto', 'setenv', 'sethostid', 'setlogin', 'ungetc', 'vdprintf', 'vfprintf', 'vsyslog',
                        'write', 'writev']

    def __init__(self, clfow_line):
        split_line = clfow_line.split(Cflow.indent)

        self.function_info = split_line[-1]
        self.level = len(split_line) - 1

    def __str__(self):
        return "Level: " + str(self.level) + " - " + self.function_info

    def is_input_function(self):
        is_input = self._leaf_belongs_to(Call.input_functions)
        return is_input

    def is_output_function(self):
        is_output = self._leaf_belongs_to(Call.output_functions)
        return is_output

    def _leaf_belongs_to(self, function_set):
        belongs = False

        if self.is_leaf():
            belongs = self.leaf_function_name in function_set

        return belongs

    def is_leaf(self):
        """Checks if the function call represented by this object is a leaf in the call graph generated by cflow.
        Being a leaf means that the function is not defined in the files given to cflow as arguments to analyze.
        """
        return self.function_info.endswith("()")

    @property
    def leaf_function_name(self):
        return self.function_info[:-2]

class Cflow():
    """Wraps around some of cflow's command line interface"""

    indent = "    "

    _file_patterns = ["*.c", "*.h"]
    _cflow_exec = "cflow"

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

    def _get_cflow_args(self):
        dirs_found = []

        for path, dirs, files in os.walk(os.path.abspath(self.source_dir)):
            for dir in dirs:
                for pattern in Cflow._file_patterns:
                    dirs_found.append(os.path.join(path, dir, pattern))

        return dirs_found

    def _build_cflow_command(self):
        cflow_args = self._get_cflow_args()
        command = "cd {0}; ".format(self.source_dir) + Cflow._cflow_exec + ' ' + ' '.join(cflow_args) + ";"

        return command

    def get_text_call_graph(self):
        cmd_cflow = self._build_cflow_command()
        cflow_output = check_output(cmd_cflow, shell=True).decode("utf-8")

        return cflow_output

class Stack():

    _collection = list()

    def __init__(self):
        pass

    def push(self, data):
        self._collection.append(data)

    def pop(self):
        return self._collection.pop()

    @property
    def top(self):
        return self._collection[-1]

def main(args):
    source_dir = args[1]

    cflow = Cflow(source_dir)
    text_call_graph = cflow.get_text_call_graph()

    main_call = Call(text_call_graph.splitlines()[0])

    parent = Stack()
    parent.push(main_call)
    previous = main_call

    entry_points = list()
    exit_points = list()

    for i, line in enumerate(text_call_graph.splitlines()):
        if i != 0:
            current = Call(line)

            if current.level > previous.level:
                parent.push(previous)
            elif current.level < previous.level:
                for i in range(current.level - previous.level):
                    parent.pop()

            if current.is_input_function():
                entry_points.append(parent.top)

            if current.is_output_function():
                exit_points.append(parent.top)

            previous = current

    print("entry points: " + str(len(entry_points)))
    print("exit points: " + str(len(exit_points)))

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


<commit_before>import requests
import re
import os
import win32com.client
import time
from html.parser import HTMLParser

#Class to parse the torrent sites and retrieve magnet links
class MyHTMLParser(HTMLParser):
    magnet = ""
    urls = []
    #function to retrieve magnet link by checking the a href tags
    def handle_starttag(self, tag, attrs):
        if tag=='a':
            for name,value in attrs:
                if name=='href':
                    if value[0:7]=='magnet:':
                        self.magnet = value
                    elif value.find('1337x')!=-1:
                        self.urls.append(value)
                    elif value.find('kickass.to')!=-1:
                        self.urls.append(value)
#end of class

#function to get content from the websites as a text using 'requests'
def get_content(url):
    r = requests.get(url)
    return r.text

#general function for matching a pattern and returning the first match
def match_pattern(pattern,content):
    matches = re.search(pattern,content)
    return matches.group()

#function to prompt the user for show name. show name should be as precise as possible with episode or season number. for example 'chuck season 1'
def get_user_input():
    user_input = input("Please enter the show name you want to schedule a download for:")
    print(user_input)
    file = open("showname.txt","w")
    file.write("Show Name : "+user_input)
    file.close()
    return user_input

show_name = ""
parser = MyHTMLParser()

try:
    file = open("showname.txt","r")
    file_content = file.readline()
    if file_content != 'Show Name : 0':
        index = file_content.find(':')
        show_name = file_content[index+2:]
    else:
        file.close()
        show_name = get_user_input()

except FileNotFoundError:
    file = open("showname.txt","w")
    file.write("Show Name : 0")
    file.close()

print(show_name+" asdas")
search_url = "http://torrentz.in/search?f="+show_name

#get content of the torrent search results
main_content = get_content(search_url)
index = main_content.find('peers')

#all of the torrent links on the search results page for torrentz.in are in the for of '/40alphanumerics hence the regex to match
#and retrieve the first match as it is the one with highest peers
search_url = "http://torrentz.in/" + match_pattern("[a-zA-Z0-9]{40}",main_content[index:-1])
#the main_content will now contain the page for torrent specific links i.e. links for a particular torrent such as 1337x h33t kickass etc
main_content = get_content(search_url)

#used the parser to find out if torrent is available at popular and trusted sites
parser.feed(main_content)

#the main content will now contain the actual webpage where the magnet is found
main_content = get_content(parser.urls[0])

#feed the parser the webpage to find the magnet
parser.feed(main_content)

#start application associated with magnet eg bitcomet,utorrent
#os.startfile(parser.magnet)
shell = win32com.client.Dispatch('WScript.Shell')
time.sleep(7)

#send an Enter key to the bitcomet to start the download
#shell.SendKeys("{Enter}",0)
<commit_msg>Clean up<commit_after>import requests
import re
import os
import win32com.client
import time
from html.parser import HTMLParser

#Class to parse the torrent sites and retrieve magnet links
class MyHTMLParser(HTMLParser):
    magnet = ""
    urls = []
    #function to retrieve magnet link by checking the a href tags
    def handle_starttag(self, tag, attrs):
        if tag=='a':
            for name,value in attrs:
                if name=='href':
                    if value[0:7]=='magnet:':
                        self.magnet = value
                    elif value.find('1337x')!=-1:
                        self.urls.append(value)
                    elif value.find('kickass.to')!=-1:
                        self.urls.append(value)
#end of class

#function to get content from the websites as a text using 'requests'
def get_content(url):
    r = requests.get(url)
    return r.text

#general function for matching a pattern and returning the first match
def match_pattern(pattern,content):
    matches = re.search(pattern,content)
    return matches.group()

#function to prompt the user for show name. show name should be as precise as possible with episode or season number. for example 'chuck season 1'
def get_user_input():
    user_input = input("Please enter the show name you want to schedule a download for:")
    print(user_input)
    file = open("showname.txt","w")
    file.write("Show Name : "+user_input)
    file.close()
    return user_input

show_name = ""
parser = MyHTMLParser()

try:
    file = open("showname.txt","r")
    file_content = file.readline()
    if file_content != 'Show Name : 0':
        index = file_content.find(':')
        show_name = file_content[index+2:]
    else:
        file.close()
        show_name = get_user_input()

except FileNotFoundError:
    file = open("showname.txt","w")
    file.write("Show Name : 0")
    file.close()

search_url = "http://torrentz.in/search?f="+show_name

#get content of the torrent search results
main_content = get_content(search_url)
index = main_content.find('peers')

#all of the torrent links on the search results page for torrentz.in are in the for of '/40alphanumerics hence the regex to match
#and retrieve the first match as it is the one with highest peers
search_url = "http://torrentz.in/" + match_pattern("[a-zA-Z0-9]{40}",main_content[index:-1])
#the main_content will now contain the page for torrent specific links i.e. links for a particular torrent such as 1337x h33t kickass etc
main_content = get_content(search_url)

#used the parser to find out if torrent is available at popular and trusted sites
parser.feed(main_content)

#the main content will now contain the actual webpage where the magnet is found
main_content = get_content(parser.urls[0])

#feed the parser the webpage to find the magnet
parser.feed(main_content)

#start application associated with magnet eg bitcomet,utorrent
os.startfile(parser.magnet)
shell = win32com.client.Dispatch('WScript.Shell')
time.sleep(7)

#send an Enter key to the bitcomet to start the download
shell.SendKeys("{Enter}",0)
<|endoftext|>


<commit_before>import logging
import os
import sys

from alias import aliases

builtin_cmds = {'cd', 'pwd', 'exit', 'alias', 'echo',}

class Command:

    def __init__(self, command_text):
        self.text = command_text
        self.command = self.parse_command(command_text)
        self.alias = self.substitute_alias()

    def __str__(self):
        return self.text

    def parse_command(self, command_text):
        return command_text.strip().split()

    def substitute_alias(self):
        if self.command[0] in aliases.keys():
            return aliases[self.command[0]] + ' ' + ' '.join(self.command[1:])
        else:
            return self.text

    def builtin(self):
        if self.command[0] in builtin_cmds:
            return True
        else:
            return False

    def run(self):
        os.system(self.alias)

class NullCommand(Command):
    def __init__(self, command_text):
        self.text = command_text
        self.command = ['']
        self.alias = ''

    def run(self):
        pass

class Builtin(Command): pass

class EchoBuiltin(Builtin):
    def run(self):
        print(' '.join(self.command[1:]))
        logging.debug('Built in echo')

class ChangeDirectoryBuiltin(Builtin):
    def run(self):
        prev_cwd = os.getcwd()

        # no point in doing work if you don't give us a place to go
        if len(self.command) <2:
            return

        if self.command[1] == '-':
            if 'OLDPWD' in os.environ:
                os.chdir(os.environ['OLDPWD'])
            else:
                print('No previous directory set')
        elif self.command[1] == '~':
            os.chdir(os.path.expanduser('~'))
        else:
            os.chdir(self.command[1])

        os.environ['OLDPWD'] = prev_cwd
        logging.debug('Built in chdir to: %s' % self.command[1])

class PrintWorkingDirectoryBuiltin(Builtin):
    def run(self):
        print(os.getcwd())
        logging.debug('Built in pwd')

class ExitBuiltin(Builtin):
    def run(self):
        sys.exit()
        logging.debug('Built in exit')

class CommandFactory:

    def create_command(command_text):
        command_split = command_text.split()

        if len(command_split) == 0:
            return NullCommand(command_text)
        elif command_split[0] == 'cd':
            return ChangeDirectoryBuiltin(command_text)
        elif command_split[0] == 'pwd':
            return PrintWorkingDirectoryBuiltin(command_text)
        elif command_split[0] == 'exit':
            return ExitBuiltin(command_text)
        elif command_split[0] == 'echo':
            return EchoBuiltin(command_text)
        else:
            return Command(command_text)

<commit_msg>If found, use the system echo instead of the built-in<commit_after>import logging
import os
import shutil
import sys

from alias import aliases

builtin_cmds = {'cd', 'pwd', 'exit', 'alias', 'echo',}

class Command:

    def __init__(self, command_text):
        self.text = command_text
        self.command = self.parse_command(command_text)
        self.alias = self.substitute_alias()

    def __str__(self):
        return self.text

    def parse_command(self, command_text):
        return command_text.strip().split()

    def substitute_alias(self):
        if self.command[0] in aliases.keys():
            return aliases[self.command[0]] + ' ' + ' '.join(self.command[1:])
        else:
            return self.text

    def builtin(self):
        if self.command[0] in builtin_cmds:
            return True
        else:
            return False

    def run(self):
        os.system(self.alias)

class NullCommand(Command):
    def __init__(self, command_text):
        self.text = command_text
        self.command = ['']
        self.alias = ''

    def run(self):
        pass

class Builtin(Command): pass

class EchoBuiltin(Builtin):
    def run(self):
        if shutil.which('echo'):
            os.system(self.text)
            logging.debug('Using system echo')
        else:
            print(' '.join(self.command[1:]))
            logging.debug('Built in echo')

class ChangeDirectoryBuiltin(Builtin):
    def run(self):
        prev_cwd = os.getcwd()

        # no point in doing work if you don't give us a place to go
        if len(self.command) <2:
            return

        if self.command[1] == '-':
            if 'OLDPWD' in os.environ:
                os.chdir(os.environ['OLDPWD'])
            else:
                print('No previous directory set')
        elif self.command[1] == '~':
            os.chdir(os.path.expanduser('~'))
        else:
            os.chdir(self.command[1])

        os.environ['OLDPWD'] = prev_cwd
        logging.debug('Built in chdir to: %s' % self.command[1])

class PrintWorkingDirectoryBuiltin(Builtin):
    def run(self):
        print(os.getcwd())
        logging.debug('Built in pwd')

class ExitBuiltin(Builtin):
    def run(self):
        sys.exit()
        logging.debug('Built in exit')

class CommandFactory:

    def create_command(command_text):
        command_split = command_text.split()

        if len(command_split) == 0:
            return NullCommand(command_text)
        elif command_split[0] == 'cd':
            return ChangeDirectoryBuiltin(command_text)
        elif command_split[0] == 'pwd':
            return PrintWorkingDirectoryBuiltin(command_text)
        elif command_split[0] == 'exit':
            return ExitBuiltin(command_text)
        elif command_split[0] == 'echo':
            return EchoBuiltin(command_text)
        else:
            return Command(command_text)

<|endoftext|>


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

# test suite for Carousel

import unittest

#from Kamaelia.Chassis.Carousel import Carousel
from CarouselRewrite import Carousel

from Axon.Component import component
from Axon.Scheduler import scheduler
from Axon.Ipc import producerFinished, shutdownMicroprocess

class MockChild(component):

    def __init__(self, childList, arg=None):
        super(MockChild,self).__init__()
        self.arg=arg
        self.stopNow = False
        childList.append(self)
        self.wasActivated=False

    def main(self):
        self.wasActivated=True
        while not self.stopNow:
            yield 1

class Dummy(component):
    def main(self):
        while 1:
            yield 1

class Test_Carousel(unittest.TestCase):

    def setup_test(self, **args):
        self.children=[]

        self.scheduler = scheduler()
        scheduler.run = self.scheduler

        if "componentFactory" not in args:
            def defaultFactory(arg,parent=self):
                child = MockChild(self.children, arg)
                return child

            args["componentFactory"]=defaultFactory

        self.carousel = Carousel(**args)

        self.inSrc = Dummy()
        self.inSrc.link((self.inSrc,"outbox"), (self.carousel,"inbox"))
        self.inSrc.link((self.inSrc,"signal"), (self.carousel,"control"))

        self.outDest = Dummy()
        self.outDest.link((self.carousel,"outbox"), (self.outDest,"inbox"))
        self.outDest.link((self.carousel,"signal"), (self.outDest,"control"))

        self.nextFbk = Dummy()
        self.nextFbk.link((self.carousel,"requestNext"), (self.nextFbk,"inbox"))
        self.nextFbk.link((self.nextFbk,"outbox"), (self.carousel,"next"))

        self.carousel.activate(Scheduler=self.scheduler)
        self.inSrc.activate(Scheduler=self.scheduler)
        self.outDest.activate(Scheduler=self.scheduler)
        self.nextFbk.activate(Scheduler=self.scheduler)

        self.run = self.scheduler.main()

    def sendToInbox(self,data):
        self.inSrc.send(data,"outbox")

    def sendToControl(self,data):
        self.inSrc.send(data,"signal")

    def sendToNext(self,data):
        self.nextFbk.send(data,"outbox")

    def dataReadyOutbox(self):
        return self.outDest.dataReady("inbox")

    def dataReadySignal(self):
        return self.outDest.dataReady("control")

    def dataReadyRequestNext(self):
        return self.nextFbk.dataReady("inbox")

    def recvOutbox(self):
        return self.outDest.recv("inbox")

    def recvSignal(self):
        return self.outDest.recv("control")

    def recvRequestNext(self):
        return self.nextFbk.recv("inbox")

    def collectOutbox(self):
        out=[]
        while self.dataReadyOutbox():
            out.append(self.recvOutbox())
        return out

    def collectSignal(self):
        out=[]
        while self.dataReadySignal():
            out.append(self.recvSignal())
        return out

    def collectRequestNext(self):
        out=[]
        while self.dataReadyRequestNext():
            out.append(self.recvRequestNext())
        return out

    def runFor(self, cycles):
        numcycles=cycles*5    # approx this many components in the system
        for i in range(0,numcycles): self.run.next()

    def test_byDefaultDoesNothing(self):
        self.setup_test()

        self.runFor(cycles=1000)

        self.assert_(self.children==[], "Carousel should create no children")
        self.assert_(not self.dataReadyOutbox(), "Carousel should have sent nothing to its 'outbox' outbox")
        self.assert_(not self.dataReadySignal(), "Carousel should have sent nothing to its 'signal' outbox")
        self.assert_(not self.dataReadyRequestNext(), "Carousel should have sent nothing to its 'requestNext' outbox")
        self.assert_(not self.carousel._isStopped(), "Carousel should still be running")

    def test_canAskToMake1stRequest(self):
        self.setup_test(make1stRequest=True)

        self.runFor(cycles=1000)

        self.assert_(self.children==[], "Carousel should create no children")
        self.assert_(not self.dataReadyOutbox(), "Carousel should have sent nothing to its 'outbox' outbox")
        self.assert_(not self.dataReadySignal(), "Carousel should have sent nothing to its 'signal' outbox")
        self.assert_(self.collectRequestNext()==["NEXT"], "Carousel should have sent a single 'NEXT' to its 'requestNext' outbox")
        self.assert_(not self.carousel._isStopped(), "Carousel should still be running")

    def test_shutsDownWhenToldToAndIdle(self):
        for IPC in (producerFinished, shutdownMicroprocess):
            self.setup_test()

            self.runFor(cycles=1000)
            self.sendToControl(IPC())
            self.assert_(not self.carousel._isStopped(), "Carousel should still be running")
            self.runFor(cycles=1000)

            got=self.collectSignal()
            self.assert_(len(got)==1 and isinstance(got[0],IPC), "Carousel should send a "+IPC.__class__.__name__+" message out its 'signal' outbox")
            self.assert_(self.carousel._isStopped(), "Carousel should have terminated")

    def test_messageToNextRunsFactoryFunction(self):
        """When a message is sent to the "next" inbox, the supplied factory function is run with that argument."""
        self.factoryRun=None
        def factory(arg):
            self.factoryRun=arg
            return Dummy()

        self.setup_test(componentFactory=factory)

        self.runFor(cycles=5)
        self.assert_(self.factoryRun==None)
        self.sendToNext("BLAH")
        self.runFor(cycles=5)
        self.assert_(self.factoryRun=="BLAH")

    def test_messageToNextSpawnsChild(self):
        self.setup_test()
        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=5)

        self.assert_(len(self.children)==1, "Carousel should have spawned a child in response to the 'next' request")
        self.assert_(self.children[-1].arg=="BLAH", "Carousel should have spawned child with the 'next' message as the argument")
        self.assert_(self.children[-1].wasActivated, "The child should have been activated")

    def test_childTerminationTriggersRequestNext(self):
        self.setup_test()
        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=5)

        self.children[-1].stopNow=True
        self.runFor(cycles=5)

        self.assert_(self.collectRequestNext()==["NEXT"], "Carousel should have sent a single 'NEXT' to its 'requestNext' outbox")

    def test_childShutdownSignalDoesntTriggerRequest(self):
        for IPC in (producerFinished,shutdownMicroprocess):
            self.setup_test()
            self.runFor(cycles=5)
            self.sendToNext("BLAH")
            self.runFor(cycles=5)

            self.children[-1].send(IPC(),"signal")
            self.runFor(cycles=50)

            self.assert_(self.collectRequestNext()==[], "Carousel should have not sent anything 'requestNext' outbox")

    def test_ChildReceivesShutdownSignal(self):
        for IPC in (producerFinished,shutdownMicroprocess):
            self.setup_test()
            self.runFor(cycles=5)
            self.sendToNext("BLAH")
            self.runFor(cycles=5)

            self.sendToControl(IPC())
            self.runFor(cycles=50)

            self.assert_(self.children[-1].dataReady("control"), "Child should have received something on its 'control' inbox")
            msg=self.children[-1].recv("control")
            self.assert_(isinstance(msg,IPC), "Child should have received a "+IPC.__class__.__name__+" message out its 'control' inbox")

    def test_nextRequestStartsNewchildOnceCurrentHasTerminated(self):
        self.setup_test()
        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=5)

        for i in range(0,5):
            self.sendToNext("BLAH")
            self.runFor(cycles=50)

            self.assert_(len(self.children)==i+1, "The new child should not be created until the previous has terminated")
            self.children[-1].stopNow=True
            self.runFor(cycles=5)

            self.assert_(len(self.children)==i+2, "The 'next' message should have resulted in a new child")
            self.assert_(self.children[-2]._isStopped(), "The older child should by now be terminated")
            self.assert_(self.children[-1].wasActivated and not self.children[-1]._isStopped(), "The new child should be active and running")

    def test_dataReachesChildInbox(self):
        self.setup_test()
        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=1)

        for i in range(0,5):
            MSG = "HELLO"+str(i)
            self.sendToInbox(MSG)
            self.runFor(cycles=1)

            self.assert_(self.children[-1].dataReady("inbox"), "Something should have arrived at the inbox")
            self.assert_(self.children[-1].recv("inbox")==MSG, "The message sent to the Carousel's 'inbox' inbox should have reached the child's 'inbox' inbox")

            self.runFor(cycles=10)

    def test_dataReachesCarouselOutbox(self):
        self.setup_test()

        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=2)

        for i in range(0,5):
            MSG = "HELLO"+str(i)
            self.children[-1].send(MSG,"outbox")
            self.runFor(cycles=1)

            self.assert_(self.collectOutbox()==[MSG], "The message sent to the child's 'outbox' outbox should have reached the Carousel's 'outbox' outbox")

            self.runFor(cycles=10)

    def test_childSignalIgnored(self):
        self.setup_test()

        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=2)

        for MSG in (producerFinished,shutdownMicroprocess,"HELLO!"):
            self.children[-1].send(MSG,"signal")
            self.runFor(cycles=1)

            self.assert_(self.collectSignal()==[], "Any message sent to the child's 'signal' outbox should not have reached the Carousel's 'signal' outbox")

            self.runFor(cycles=10)

if __name__ == "__main__":
    unittest.main()
    <commit_msg>Added to tests<commit_after>#!/usr/bin/env python

# test suite for Carousel

import unittest

#from Kamaelia.Chassis.Carousel import Carousel
from CarouselRewrite import Carousel

from Axon.Component import component
from Axon.Scheduler import scheduler
from Axon.Ipc import producerFinished, shutdownMicroprocess

class MockChild(component):

    def __init__(self, childList, arg=None):
        super(MockChild,self).__init__()
        self.arg=arg
        self.stopNow = False
        childList.append(self)
        self.wasActivated=False

    def main(self):
        self.wasActivated=True
        while not self.stopNow:
            yield 1

class Dummy(component):
    def main(self):
        while 1:
            yield 1

class Test_Carousel(unittest.TestCase):

    def setup_test(self, **args):
        self.children=[]

        self.scheduler = scheduler()
        scheduler.run = self.scheduler

        if "componentFactory" not in args:
            def defaultFactory(arg,parent=self):
                child = MockChild(self.children, arg)
                return child

            args["componentFactory"]=defaultFactory

        self.carousel = Carousel(**args)

        self.inSrc = Dummy()
        self.inSrc.link((self.inSrc,"outbox"), (self.carousel,"inbox"))
        self.inSrc.link((self.inSrc,"signal"), (self.carousel,"control"))

        self.outDest = Dummy()
        self.outDest.link((self.carousel,"outbox"), (self.outDest,"inbox"))
        self.outDest.link((self.carousel,"signal"), (self.outDest,"control"))

        self.nextFbk = Dummy()
        self.nextFbk.link((self.carousel,"requestNext"), (self.nextFbk,"inbox"))
        self.nextFbk.link((self.nextFbk,"outbox"), (self.carousel,"next"))

        self.carousel.activate(Scheduler=self.scheduler)
        self.inSrc.activate(Scheduler=self.scheduler)
        self.outDest.activate(Scheduler=self.scheduler)
        self.nextFbk.activate(Scheduler=self.scheduler)

        self.run = self.scheduler.main()

    def sendToInbox(self,data):
        self.inSrc.send(data,"outbox")

    def sendToControl(self,data):
        self.inSrc.send(data,"signal")

    def sendToNext(self,data):
        self.nextFbk.send(data,"outbox")

    def dataReadyOutbox(self):
        return self.outDest.dataReady("inbox")

    def dataReadySignal(self):
        return self.outDest.dataReady("control")

    def dataReadyRequestNext(self):
        return self.nextFbk.dataReady("inbox")

    def recvOutbox(self):
        return self.outDest.recv("inbox")

    def recvSignal(self):
        return self.outDest.recv("control")

    def recvRequestNext(self):
        return self.nextFbk.recv("inbox")

    def collectOutbox(self):
        out=[]
        while self.dataReadyOutbox():
            out.append(self.recvOutbox())
        return out

    def collectSignal(self):
        out=[]
        while self.dataReadySignal():
            out.append(self.recvSignal())
        return out

    def collectRequestNext(self):
        out=[]
        while self.dataReadyRequestNext():
            out.append(self.recvRequestNext())
        return out

    def runFor(self, cycles):
        numcycles=cycles*5    # approx this many components in the system
        for i in range(0,numcycles): self.run.next()

    def test_byDefaultDoesNothing(self):
        self.setup_test()

        self.runFor(cycles=1000)

        self.assert_(self.children==[], "Carousel should create no children")
        self.assert_(not self.dataReadyOutbox(), "Carousel should have sent nothing to its 'outbox' outbox")
        self.assert_(not self.dataReadySignal(), "Carousel should have sent nothing to its 'signal' outbox")
        self.assert_(not self.dataReadyRequestNext(), "Carousel should have sent nothing to its 'requestNext' outbox")
        self.assert_(not self.carousel._isStopped(), "Carousel should still be running")

    def test_canAskToMake1stRequest(self):
        self.setup_test(make1stRequest=True)

        self.runFor(cycles=1000)

        self.assert_(self.children==[], "Carousel should create no children")
        self.assert_(not self.dataReadyOutbox(), "Carousel should have sent nothing to its 'outbox' outbox")
        self.assert_(not self.dataReadySignal(), "Carousel should have sent nothing to its 'signal' outbox")
        self.assert_(self.collectRequestNext()==["NEXT"], "Carousel should have sent a single 'NEXT' to its 'requestNext' outbox")
        self.assert_(not self.carousel._isStopped(), "Carousel should still be running")

    def test_shutsDownWhenToldToAndIdle(self):
        for IPC in (producerFinished, shutdownMicroprocess):
            self.setup_test()

            self.runFor(cycles=1000)
            self.sendToControl(IPC())
            self.assert_(not self.carousel._isStopped(), "Carousel should still be running")
            self.runFor(cycles=1000)

            got=self.collectSignal()
            self.assert_(len(got)==1 and isinstance(got[0],IPC), "Carousel should send a "+IPC.__class__.__name__+" message out its 'signal' outbox")
            self.assert_(self.carousel._isStopped(), "Carousel should have terminated")

    def test_messageToNextRunsFactoryFunction(self):
        """When a message is sent to the "next" inbox, the supplied factory function is run with that argument."""
        self.factoryRun=None
        def factory(arg):
            self.factoryRun=arg
            return Dummy()

        self.setup_test(componentFactory=factory)

        self.runFor(cycles=5)
        self.assert_(self.factoryRun==None)
        self.sendToNext("BLAH")
        self.runFor(cycles=5)
        self.assert_(self.factoryRun=="BLAH")

    def test_messageToNextSpawnsChild(self):
        self.setup_test()
        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=5)

        self.assert_(len(self.children)==1, "Carousel should have spawned a child in response to the 'next' request")
        self.assert_(self.children[-1].arg=="BLAH", "Carousel should have spawned child with the 'next' message as the argument")
        self.assert_(self.children[-1].wasActivated, "The child should have been activated")

    def test_childTerminationTriggersRequestNext(self):
        self.setup_test()
        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=5)

        self.children[-1].stopNow=True
        self.runFor(cycles=5)

        self.assert_(self.collectRequestNext()==["NEXT"], "Carousel should have sent a single 'NEXT' to its 'requestNext' outbox")

    def test_childShutdownSignalDoesntTriggerRequest(self):
        for IPC in (producerFinished,shutdownMicroprocess):
            self.setup_test()
            self.runFor(cycles=5)
            self.sendToNext("BLAH")
            self.runFor(cycles=5)

            self.children[-1].send(IPC(),"signal")
            self.runFor(cycles=50)

            self.assert_(self.collectRequestNext()==[], "Carousel should have not sent anything 'requestNext' outbox")

    def test_ChildReceivesShutdownSignal(self):
        for IPC in (producerFinished,shutdownMicroprocess):
            self.setup_test()
            self.runFor(cycles=5)
            self.sendToNext("BLAH")
            self.runFor(cycles=5)

            self.sendToControl(IPC())
            self.runFor(cycles=50)

            self.assert_(self.children[-1].dataReady("control"), "Child should have received something on its 'control' inbox")
            msg=self.children[-1].recv("control")
            self.assert_(isinstance(msg,IPC), "Child should have received a "+IPC.__class__.__name__+" message out its 'control' inbox")

    def test_nextRequestStartsNewchildOnceCurrentHasTerminated(self):
        self.setup_test()
        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=5)

        for i in range(0,5):
            self.sendToNext("BLAH")
            self.runFor(cycles=50)

            self.assert_(len(self.children)==i+1, "The new child should not be created until the previous has terminated")
            self.children[-1].stopNow=True
            self.runFor(cycles=5)

            self.assert_(len(self.children)==i+2, "The 'next' message should have resulted in a new child")
            self.assert_(self.children[-2]._isStopped(), "The older child should by now be terminated")
            self.assert_(self.children[-1].wasActivated and not self.children[-1]._isStopped(), "The new child should be active and running")

    def test_dataReachesChildInbox(self):
        self.setup_test()
        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=1)

        for i in range(0,5):
            MSG = "HELLO"+str(i)
            self.sendToInbox(MSG)
            self.runFor(cycles=1)

            self.assert_(self.children[-1].dataReady("inbox"), "Something should have arrived at the inbox")
            self.assert_(self.children[-1].recv("inbox")==MSG, "The message sent to the Carousel's 'inbox' inbox should have reached the child's 'inbox' inbox")

            self.runFor(cycles=10)

    def test_dataReachesCarouselOutbox(self):
        self.setup_test()

        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=2)

        for i in range(0,5):
            MSG = "HELLO"+str(i)
            self.children[-1].send(MSG,"outbox")
            self.runFor(cycles=1)

            self.assert_(self.collectOutbox()==[MSG], "The message sent to the child's 'outbox' outbox should have reached the Carousel's 'outbox' outbox")

            self.runFor(cycles=10)

    def test_childSignalIgnored(self):
        self.setup_test()

        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=2)

        for MSG in (producerFinished,shutdownMicroprocess,"HELLO!"):
            self.children[-1].send(MSG,"signal")
            self.runFor(cycles=1)

            self.assert_(self.collectSignal()==[], "Any message sent to the child's 'signal' outbox should not have reached the Carousel's 'signal' outbox")

            self.runFor(cycles=10)

    def test_terminatingCarouselWithChildPassesSignalToChildToo(self):

        for IPC in (producerFinished,):
            self.setup_test()

            # create new child
            self.runFor(cycles=5)
            self.sendToNext("BLAH")
            self.runFor(cycles=50)

            # send shutdown to Carousel
            self.sendToControl(IPC())
            self.runFor(cycles=5)

            # did the child get it
            msg = self.children[-1].recv("control")
            self.assert_(isinstance(msg,IPC), "Child should also receive a "+IPC.__class__.__name__+" request")
            self.children[-1].stopNow=True
            self.runFor(cycles=5)

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


<commit_before># -*- coding: utf8 -*-

"""
Module containing the available commands of the game, the factory class to
create the commands...
Today, the available commands are:
- help
- look
- move
- quit|q|exit
- talk
"""

import character
import area
import random
import string
import player
import item
import json
from sentence import sentence

"""
Code corresponding to the quit command
"""
quit = -1

class command():
	"""
	Base class for the commands
	"""

	def setArgs(self, args):
		"""
		c.setArgs(args)

		Define the arguments of the command.

		@params list arguments of the command to run
		"""
		self._args = args

	def setPlayer(self, p):
		"""
		c.setPlayer(p)

		Define the current player in the command's context.

		@params player.player
		"""
		self._player = p

class factory:
	"""
	Class to instanciate a command from a string.
	"""

	@staticmethod
	def create(p, commandFull):
		"""
		command.factory.create(p, commandFull) -> command.command

		Create the desired command.

		@param p player.player Current player.
		@param commandFull list command to run, the first element of the list
			is the command, the other elements are the command's arguments.

		@return the created command
		"""

		cmd = commandFull[0]
		del commandFull[0]

		if cmd not in ("createPlayer", "help")\
			and (not p.isConnected() or not p.connect()):
			raise player.exception(
				"A player must be connected to launch the command %s" % cmd
			)

		if cmd == 'look':
			command = look()
		elif cmd == 'talk':
			command = talk()
		elif cmd == 'move':
			command = move()
		elif cmd == 'take':
			command = take()
		elif cmd == 'drop':
			command = drop()
		elif cmd == 'createPlayer':
			if p.isConnected():
				raise player.exception(
					"You cannot create a new player when you're connected"
				)
		elif cmd in ('inventory', 'inv'):
			command = inventory()
		elif cmd in ('quit', 'exit', 'q'):
			return quit
		elif cmd == 'help':
			command = help()
		else:
			raise exception('Unknown command')

		command.setArgs(commandFull)
		command.setPlayer(p)
		return command

class help(command):
	"""
	Help command
	"""

	def run(self):
		"""
		c.run()

		Display a help message.
		"""
		print('Available commands:')
		print('talk <Character name> "<Sentence>": Talk to a character')
		print('move <%s>: Go to the indicated direction' % '|'.join(area.directions))
		print('look: See what is in the current area' +
			' (characters, items, neighbour areas...)')
		print('createPlayer: Not Yet Implemented')
		print('help: Display this help')
		print('quit|exit|q: Quit the game')

class look(command):
	"""
	Look command
	"""
	def run(self):
		"""
		c.run()

		Display some informations about the player's current position
		(characters arround, availables directions...).
		"""
		# Display surrounding characters
		characters = character.character.searchByIdArea(self._player._model['id_area'])
		# the player is in the result list
		if len(characters) == 1:
			print("You're alone here.")
		else:
			print("Characters arround:")
			for c in characters:
				if c._model['id_character'] != self._player._model['id_character']:
					print(c._model['name'])

		# Display accessible areas
		areas = area.model.getSurroundingAreas(self._player._model['id_area'])
		print("You can go " +
			', '.join(filter(lambda k: areas[k] == 1, areas)) + '.')

		# Display surrounding objects
		items = json.loads(
			area.model.loadById(self._player._model['id_area'], ['items'])['items']
		)
		if len(items) > 0:
			print("You see the following items:")
			for i in items:
				it = item.model.loadById(i)
				print(str(items[i]['quantity']).rjust(3) + ' ' + it['name'])

class move(command):
	"""
	Move command
	"""

	def run(self):
		"""
		c.run()

		Move the player in the desired direction.
		"""
		if len(self._args) == 0:
			raise exception("Where shall I go ?")

		direction = self._args[0]
		if direction not in area.directions:
			raise exception("%s is not a valid direction" % direction)

		a = area.area.getNeighbourgFromDirection(
			self._player._model['id_area'], direction
		)

		if a is None:
			raise exception('I cannot go there')
		else:
			self._player.goTo(a._model['id_area'])
			print('lets go %s' % direction)

class talk(command):
	"""
	Talk command
	"""

	def run(self):
		"""
		Say something to a character in the player's area.
		"""
		if len(self._args) == 0:
			raise exception("Who must I talk to ?")
		elif len(self._args) == 1:
			raise exception("What must I say ?")

		characterName = self._args[0]
		triggerWord = self._args[1]
		c = character.character.searchByNameAndIdArea(
			characterName, self._player._model['id_area']
		)

		if c is None:
			raise character.exception("Unknown Character")

		s = sentence.loadByCharacterIdAndTriggerWord(
			c.getId(), triggerWord
		)

		if len(s) is 0:
			print("What ?")
			return

		s = s[random.randint(0, len(s) - 1)]
		print(self.processSentence(
			s.getSentence(), self._player._model['name']
		))

	def processSentence(self, s, characterName):
		return s % {'player_name': characterName}

class take(command):
	def run(self):
		if len(self._args) == 0:
			raise exception("What shall I take ?")

		if len(self._args) == 1:
			quantity = 1
			name = self._args[0]
		else:
			quantity = int(self._args[0])
			name = self._args[1]

		#~ Item the player want to take
		i = item.model.loadBy({'name': name}, ['id_item'])

		if len(i) == 0:
			raise item.exception("I don't see this here.")

		i = str(i[0]['id_item'])
		#~ Available items in the area
		items = area.area.getItems(self._player._model['id_area'])

		if i not in items.keys():
			raise item.exception("I don't see this here.")

		if quantity > items[i]['quantity']:
			raise item.exception("There is not enough items of this kind.")

		i = [int(i)] * quantity
		self._player.addItemsToInventory(i)
		area.area.removeItems(self._player._model['id_area'], i)

		print("You took {0} {1}".format(quantity, name))

class drop(command):
	def run(self):
		"""
		c.run()

		Drop an item being in the inventory. The item will be let on the floor
		of the player's current area.
		"""
		# Check an item to drop is provided
		if len(self._args) == 0:
			raise exception("What shall I drop ?")

		# check if a quantity is provided
		if len(self._args) == 1:
			quantity = 1
			name = self._args[0]
		else:
			quantity = int(self._args[0])
			name = self._args[1]

		# Item the player want to drop
		i = item.model.loadBy({'name': name}, ['id_item'])

		if len(i) == 0:
			raise item.exception("You have none of those.")

		i = str(i[0]['id_item'])
		inv = self._player.getInventory()
		if i not in inv.keys():
			raise item.exception("You have none of those.")
		elif quantity > inv[i]['quantity']:
			raise item.exception("You don't have enough {0} to drop.".format(name))

		# Drop it
		self._player.removeItemsFromInventory(i)
		area.area.addItems(self._player._model['id_area'], i)

		print("You dropped {0} {1}".format(quantity, name))

class inventory(command):
	def run(self):
		"""
		c.run()

		Display the player's inventory.
		"""

		i = self._player.getInventory()
		for itemId in i:
			it = item.model.loadById(itemId)
			print(str(i[itemId]['quantity']).rjust(3) + ' ' + it['name'])

class exception(BaseException):
	"""
	Class for the exceptions concerning commands.
	"""
	pass
<commit_msg>help command updated<commit_after># -*- coding: utf8 -*-

"""
Module containing the available commands of the game, the factory class to
create the commands...
Today, the available commands are:
- help
- look
- move
- quit|q|exit
- talk
"""

import character
import area
import random
import string
import player
import item
import json
from sentence import sentence

"""
Code corresponding to the quit command
"""
quit = -1

class command():
	"""
	Base class for the commands
	"""

	def setArgs(self, args):
		"""
		c.setArgs(args)

		Define the arguments of the command.

		@params list arguments of the command to run
		"""
		self._args = args

	def setPlayer(self, p):
		"""
		c.setPlayer(p)

		Define the current player in the command's context.

		@params player.player
		"""
		self._player = p

class factory:
	"""
	Class to instanciate a command from a string.
	"""

	@staticmethod
	def create(p, commandFull):
		"""
		command.factory.create(p, commandFull) -> command.command

		Create the desired command.

		@param p player.player Current player.
		@param commandFull list command to run, the first element of the list
			is the command, the other elements are the command's arguments.

		@return the created command
		"""

		cmd = commandFull[0]
		del commandFull[0]

		if cmd not in ("createPlayer", "help")\
			and (not p.isConnected() or not p.connect()):
			raise player.exception(
				"A player must be connected to launch the command %s" % cmd
			)

		if cmd == 'look':
			command = look()
		elif cmd == 'talk':
			command = talk()
		elif cmd == 'move':
			command = move()
		elif cmd == 'take':
			command = take()
		elif cmd == 'drop':
			command = drop()
		elif cmd == 'createPlayer':
			if p.isConnected():
				raise player.exception(
					"You cannot create a new player when you're connected"
				)
		elif cmd in ('inventory', 'inv'):
			command = inventory()
		elif cmd in ('quit', 'exit', 'q'):
			return quit
		elif cmd == 'help':
			command = help()
		else:
			raise exception('Unknown command')

		command.setArgs(commandFull)
		command.setPlayer(p)
		return command

class help(command):
	"""
	Help command
	"""

	def run(self):
		"""
		c.run()

		Display a help message.
		"""
		print('Available commands:')
		print('talk <Character name> "<Sentence>": Talk to a character')
		print('move <%s>: Go to the indicated direction' % '|'.join(area.directions))
		print('look: See what is in the current area' +
			' (characters, items, neighbour areas...)')
		print('inv|inventory: List the items the player has in his inventory')
		print('createPlayer: Not Yet Implemented')
		print('help: Display this help')
		print('quit|exit|q: Quit the game')

class look(command):
	"""
	Look command
	"""
	def run(self):
		"""
		c.run()

		Display some informations about the player's current position
		(characters arround, availables directions...).
		"""
		# Display surrounding characters
		characters = character.character.searchByIdArea(self._player._model['id_area'])
		# the player is in the result list
		if len(characters) == 1:
			print("You're alone here.")
		else:
			print("Characters arround:")
			for c in characters:
				if c._model['id_character'] != self._player._model['id_character']:
					print(c._model['name'])

		# Display accessible areas
		areas = area.model.getSurroundingAreas(self._player._model['id_area'])
		print("You can go " +
			', '.join(filter(lambda k: areas[k] == 1, areas)) + '.')

		# Display surrounding objects
		items = json.loads(
			area.model.loadById(self._player._model['id_area'], ['items'])['items']
		)
		if len(items) > 0:
			print("You see the following items:")
			for i in items:
				it = item.model.loadById(i)
				print(str(items[i]['quantity']).rjust(3) + ' ' + it['name'])

class move(command):
	"""
	Move command
	"""

	def run(self):
		"""
		c.run()

		Move the player in the desired direction.
		"""
		if len(self._args) == 0:
			raise exception("Where shall I go ?")

		direction = self._args[0]
		if direction not in area.directions:
			raise exception("%s is not a valid direction" % direction)

		a = area.area.getNeighbourgFromDirection(
			self._player._model['id_area'], direction
		)

		if a is None:
			raise exception('I cannot go there')
		else:
			self._player.goTo(a._model['id_area'])
			print('lets go %s' % direction)

class talk(command):
	"""
	Talk command
	"""

	def run(self):
		"""
		Say something to a character in the player's area.
		"""
		if len(self._args) == 0:
			raise exception("Who must I talk to ?")
		elif len(self._args) == 1:
			raise exception("What must I say ?")

		characterName = self._args[0]
		triggerWord = self._args[1]
		c = character.character.searchByNameAndIdArea(
			characterName, self._player._model['id_area']
		)

		if c is None:
			raise character.exception("Unknown Character")

		s = sentence.loadByCharacterIdAndTriggerWord(
			c.getId(), triggerWord
		)

		if len(s) is 0:
			print("What ?")
			return

		s = s[random.randint(0, len(s) - 1)]
		print(self.processSentence(
			s.getSentence(), self._player._model['name']
		))

	def processSentence(self, s, characterName):
		return s % {'player_name': characterName}

class take(command):
	def run(self):
		if len(self._args) == 0:
			raise exception("What shall I take ?")

		if len(self._args) == 1:
			quantity = 1
			name = self._args[0]
		else:
			quantity = int(self._args[0])
			name = self._args[1]

		#~ Item the player want to take
		i = item.model.loadBy({'name': name}, ['id_item'])

		if len(i) == 0:
			raise item.exception("I don't see this here.")

		i = str(i[0]['id_item'])
		#~ Available items in the area
		items = area.area.getItems(self._player._model['id_area'])

		if i not in items.keys():
			raise item.exception("I don't see this here.")

		if quantity > items[i]['quantity']:
			raise item.exception("There is not enough items of this kind.")

		i = [int(i)] * quantity
		self._player.addItemsToInventory(i)
		area.area.removeItems(self._player._model['id_area'], i)

		print("You took {0} {1}".format(quantity, name))

class drop(command):
	def run(self):
		"""
		c.run()

		Drop an item being in the inventory. The item will be let on the floor
		of the player's current area.
		"""
		# Check an item to drop is provided
		if len(self._args) == 0:
			raise exception("What shall I drop ?")

		# check if a quantity is provided
		if len(self._args) == 1:
			quantity = 1
			name = self._args[0]
		else:
			quantity = int(self._args[0])
			name = self._args[1]

		# Item the player want to drop
		i = item.model.loadBy({'name': name}, ['id_item'])

		if len(i) == 0:
			raise item.exception("You have none of those.")

		i = str(i[0]['id_item'])
		inv = self._player.getInventory()
		if i not in inv.keys():
			raise item.exception("You have none of those.")
		elif quantity > inv[i]['quantity']:
			raise item.exception("You don't have enough {0} to drop.".format(name))

		# Drop it
		self._player.removeItemsFromInventory(i)
		area.area.addItems(self._player._model['id_area'], i)

		print("You dropped {0} {1}".format(quantity, name))

class inventory(command):
	def run(self):
		"""
		c.run()

		Display the player's inventory.
		"""

		i = self._player.getInventory()
		for itemId in i:
			it = item.model.loadById(itemId)
			print(str(i[itemId]['quantity']).rjust(3) + ' ' + it['name'])

class exception(BaseException):
	"""
	Class for the exceptions concerning commands.
	"""
	pass
<|endoftext|>


<commit_before>"""
Django settings for presentations project.

For more information on this file, see
https://docs.djangoproject.com/en/1.6/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.6/ref/settings/
"""

import os
import dj_database_url

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(__file__))

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ['SECRET_KEY']

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

TEMPLATE_DEBUG = True

ALLOWED_HOSTS = []

# Application definition

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'south',
    'presentationsapp',
)

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

ROOT_URLCONF = 'presentations.urls'

WSGI_APPLICATION = 'presentations.wsgi.application'

# Database
# https://docs.djangoproject.com/en/1.6/ref/settings/#databases

DATABASES = {}

# Internationalization
# https://docs.djangoproject.com/en/1.6/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Parse database configuration from $DATABASE_URL

DATABASES['default'] =  dj_database_url.config()

# Honor the 'X-Forwarded-Proto' header for request.is_secure()

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

# Allow all host headers

ALLOWED_HOSTS = ['*']

# Static asset configuration

STATIC_ROOT = 'staticfiles'
STATIC_URL = '/static/'

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)
<commit_msg>Add template handling<commit_after>"""
Django settings for presentations project.

For more information on this file, see
https://docs.djangoproject.com/en/1.6/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.6/ref/settings/
"""

import os
import dj_database_url

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(__file__))

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ['SECRET_KEY']

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

TEMPLATE_DEBUG = True

ALLOWED_HOSTS = []

# Application definition

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'south',
    'presentationsapp',
)

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

ROOT_URLCONF = 'presentations.urls'

WSGI_APPLICATION = 'presentations.wsgi.application'

# Database
# https://docs.djangoproject.com/en/1.6/ref/settings/#databases

DATABASES = {}

# Internationalization
# https://docs.djangoproject.com/en/1.6/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Parse database configuration from $DATABASE_URL

DATABASES['default'] =  dj_database_url.config()

# Honor the 'X-Forwarded-Proto' header for request.is_secure()

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

# Allow all host headers

ALLOWED_HOSTS = ['*']

# Static asset configuration

STATIC_ROOT = 'staticfiles'
STATIC_URL = '/static/'

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)

TEMPLATE_DIRS = (
    os.path.join(BASE_DIR, 'template'),
)
<|endoftext|>


<commit_before>#!/usr/bin/env python3
# vim:fileencoding=utf-8:ts=8:et:sw=4:sts=4:tw=79

"""
command.py

Handle commands received on IRC.

Copyright (c) 2015 Twisted Pear <tp at pump19 dot eu>
See the file LICENSE for copying permission.
"""

import aiomc
import asyncio
import dbutils
import functools
import itertools
import locale
import logging
import random
import re
import songs
import twitch

BINGO_URL = "https://pump19.eu/bingo"
CODEFALL_URL = "https://pump19.eu/codefall"
COMMAND_URL = "https://pump19.eu/commands"
LRRMC_SERVERS = {
    "vanilla": {
        "name": "LRR Vanilla Minecraft Server",
        "host": "minecraft.darkmorford.net",
        "port": 25565,
        "info": "Check http://minecraft.darkmorford.net:8123/ "
                "for the dynamic map."
    },
    "ftb": {
        "name": "LRR FTB Minecraft Server",
        "host": "ftb.lrrcraft.com",
        "port": 25565,
        "info": "One up James on Feed The Beej Beyond."
    }
}

CMD_REGEX = {
    "vod":
        re.compile("^vod$"),
    "clip":
        re.compile("^clip$"),
    "18gac":
        re.compile("^(?:18gac|🎮)(?: (?P<extra>\d))?$"),
    "codefall":
        re.compile("^(?:codefall|🎁)(?: (?P<limit>\d))?$"),
    "lrrmc":
        re.compile("^(?:lrrmc|⛏)(?: (?P<server>\w+))?$"),
    "lastfm":
        re.compile("^(?:last\.fm|🎵) (?P<user>\w+)$", re.ASCII),
    "roll":
        re.compile("^(?:roll|🎲)(?: (?P<count>\d+)?d(?P<sides>\d+))?"),
    "bingo":
        re.compile("^bingo$"),
    "help":
        re.compile("^help|🚑$")
}

# set up locale for currency formatting (patreon command wants that)
locale.setlocale(locale.LC_MONETARY, "en_US.utf8")

class CommandHandler:
    """
    The command handler interacts with an IRC client and dispatches commands.
    It registers itself as a handler for PRIVMSG events.
    """
    logger = logging.getLogger("command")

    class Limiter:
        """
        A decorator that suppresses method calls within a certain time span.
        """

        logger = logging.getLogger("command.limiter")

        def __init__(self, *, span=15, loop=None):
            """Initialize rate limiter with a default delay of 15."""
            self.span = span
            self.loop = loop or asyncio.get_event_loop()

        def __call__(self, func):

            @functools.wraps(func)
            async def wrapper(*args, **kwargs):
                now = self.loop.time()
                if (now - wrapper._spam_last) > wrapper._spam_span:
                    wrapper._spam_last = now
                    await func(*args, **kwargs)
                else:
                    self.logger.warning("Suppressed call to {name}.".format(
                        name=func.__name__))

            # each wrapper remembers its own delay and last call
            wrapper._spam_span = self.span
            wrapper._spam_last = 0.0

            return wrapper

    rate_limited = Limiter()

    class CommandRouter:
        """A simple router matching strings against a set of regular
           expressions match to a callable."""

        routes = list()

        def add_route(self, regex, callback):
            self.routes.append((regex, callback))

        def get_route(self, string):
            for (regex, callback) in self.routes:
                match = regex.fullmatch(string)
                if not match:
                    continue

                # add matching groups to function
                return functools.partial(callback, **match.groupdict())

            return None

    router = CommandRouter()

    def __init__(self, client, *, loop=None, prefix="&", override=None):
        """Initialize the command handler and register for PRIVMSG events."""
        self.logger.info("Creating CommandHandler instance.")

        self.prefix = tuple(prefix)
        self.override = override
        self.client = client
        self.client.event_handler("PRIVMSG")(self.handle_privmsg)
        self.loop = loop or asyncio.get_event_loop()
        self.rate_limited.loop = loop

        self.setup_routing()

    def setup_routing(self):
        """Connect command handlers to regular expressions using the router."""
        for key, regex in CMD_REGEX.items():
            cmd_name = "handle_command_{0}".format(key)
            handle_command = getattr(self, cmd_name, None)
            if handle_command and callable(handle_command):
                self.router.add_route(regex, handle_command)

    async def handle_privmsg(self, nick, target, message, **kwargs):
        """
        Handle a PRIVMSG event and dispatch any command to the relevant method.
        """
        # ignore everything that's not a command with our prefix
        if not message.startswith(self.prefix) or len(message) < 2:
            return

        # remove prefix, regex will retrieve the arguments
        cmd = message[1:]

        self.logger.info("Got command \"{0}\" from {1}.".format(cmd, nick))

        # is this a query? if so, send messages to nick instead
        if target == self.client.nickname:
            target = nick

        # check if we can handle that command
        handle_command = self.router.get_route(cmd)
        if handle_command and callable(handle_command):
            await handle_command(target, nick)

    @rate_limited
    async def handle_command_vod(self, target, nick):
        """
        Handle !vod command.
        Post the most recent Twitch.tv broadcast.
        """
        broadcasts = await twitch.get_broadcasts(27132299, 1)
        vod = next(broadcasts, None)

        broadcast_msg = "Latest Broadcast: {0} [{2}] | {1}".format(*vod)

        await self.client.privmsg(target, broadcast_msg)

    @rate_limited
    async def handle_command_clip(self, target, nick):
        """
        Handle !clip command.
        Post the most viewed Twitch.tv clip.
        """
        clips = await twitch.get_top_clips("loadingreadyrun", 1)
        clip = next(clips, None)

        clip_msg = "Top Clip: {0} [{2}] | https://clips.twitch.tv/{1}".format(
                *clip)
        await self.client.privmsg(target, clip_msg)

    @rate_limited
    async def handle_command_18gac(self, target, nick, *, extra=None):
        """
        Handle !18gac command.
        Post the 18th +n most watched games on Twitch.tv.
        Filters out most recently streamed games.
        """
        extra = max(int(extra), 1) if extra else 3
        history = await dbutils.get_18gac_history()

        limit = extra + len(history)
        games = await twitch.get_top_games(limit, 17, loop=self.loop)
        games = enumerate(games, 18)
        game18 = next(games)
        if game18[1][0] in history:
            game18 = (game18[0], (game18[1][0], game18[1][1] + " 🔁"))
        games = filter(lambda g: g[1][0] not in history, games)
        games = itertools.islice(games, extra)
        games = itertools.chain([game18], games)

        game_msgs = ('#{0}: {2}'.format(idx, *game) for idx, game in games)

        game18_msg = "18th Game …and Counting: {0}.".format(
                " | ".join(game_msgs))

        await self.client.privmsg(target, game18_msg)

    @rate_limited
    async def handle_command_codefall(self, target, nick, *, limit=None):
        """
        Handle !codefall [limit] command.
        If available, post a single unclaimed codefall URL.
        """
        limit = min(int(limit), 3) if limit else 1

        entries = await dbutils.get_codefall_entries(
                nick, limit, loop=self.loop)

        if not entries:
            no_codefall_msg = ("Could not find any unclaimed codes. "
                               "You can add new entries at {url}".format(
                                   url=CODEFALL_URL))
            await self.client.privmsg(target, no_codefall_msg)
            return

        entry_msgs = ("{1} ({2}) {0}".format(*entry) for entry in entries)
        codefall_msg = "Codefall | {0}".format(" | ".join(entry_msgs))

        await self.client.privmsg(target, codefall_msg)

    @rate_limited
    async def handle_command_lrrmc(self, target, nick, *, server="vanilla"):
        """
        Handle !lrrmc command.
        Query and post the status of the LRR Minecraft server.
        """
        server = LRRMC_SERVERS.get(server, LRRMC_SERVERS["vanilla"])
        # don't stall forever when querying status
        status_coro = aiomc.get_status(
            server["host"], server["port"],
            loop=self.loop)

        try:
            status = await asyncio.wait_for(status_coro, 2.0)
        except asyncio.TimeoutError:
            status = None

        base_msg = ("Join the {name} on {host}:{port}! {info} "
                    "Current Status: {status}")

        if not status:
            no_lrrmc_msg = base_msg.format(**server, status="Unknown")
            await self.client.privmsg(target, no_lrrmc_msg)
            return

        try:
            nowp = status["players"]["online"]
            maxp = status["players"]["max"]
        except (KeyError, TypeError):
            nowp = maxp = "?"

        status_msg = "Online - {now}/{max} players".format(now=nowp, max=maxp)

        lrrmc_msg = base_msg.format(**server, status=status_msg)
        await self.client.privmsg(target, lrrmc_msg)

    @rate_limited
    async def handle_command_lastfm(self, target, nick, *, user=None):
        """
        Handle !last.fm command.
        Query information on the provided last.fm user handle and print the
        most recently listened track.
        """
        coro = songs.get_lastfm_info(user, loop=self.loop)

        info = await coro
        if not info:
            no_lastfm_msg = ("Cannot query last.fm user information for "
                             "{user}.".format(user=user))
            await self.client.privmsg(target, no_lastfm_msg)
            return

        name = info.get("name")
        live = info.get("live")
        track = info.get("track")
        artist = info.get("artist")

        if not track and not artist:
            no_lastfm_msg = ("Cannot query most recently played track for "
                             "{name}.".format(name=name))
            await self.client.privmsg(target, no_lastfm_msg)
            return

        tempus = "is listening" if live else "last listened"

        lastfm_msg = "{name} {tempus} to \"{track}\" by {artist}".format(
                name=name, tempus=tempus, track=track, artist=artist)
        await self.client.privmsg(target, lastfm_msg)

    @rate_limited
    async def handle_command_roll(self, target, nick, *,
                                  count=None, sides=None):
        """
        Handle !roll [[<n>]d<m>] command.
        Simulate n rolls of m sided dice and print the result.
        """
        count = int(count) if count else 1
        sides = int(sides) if sides else 20

        # nothing to do
        if count < 1:
            return

        if count > 10:
            out_of_dice_msg = "only has 10 dice"
            await self.client.describe(target, out_of_dice_msg)
            return

        if sides is 0:
            no_sides_msg = "slowly backs away from the singularity."
            await self.client.describe(target, no_sides_msg)
            return

        if sides > 100:
            too_many_sides_msg = "doesn't have one of those."
            await self.client.describe(target, too_many_sides_msg)
            return

        if sides is 1:
            roll_msg = "Rolling {0}... got {1}. Duh.".format(
                "a marble" if count == 1 else "some marbles", count)
        elif sides is 2:
            coins = (random.choice(("Heads", "Tails")) for _ in range(count))
            numerus = "a coin" if count == 1 else "{0} coins".format(count)
            roll_msg = "Tossing {0}... got {1}.".format(
                numerus, ", ".join(coins))
        else:
            rolls = [random.randint(1, sides) for _ in range(count)]
            total = sum(rolls)
            numerus = ("a d{0}".format(sides) if count == 1 else
                       "{0} d{1}s".format(count, sides))
            roll_msg = "Rolling {0}... got {1}{2}.".format(
                numerus, ", ".join(map(str, rolls)),
                " => {0}".format(total) if count > 1 else "")

        await self.client.privmsg(target, roll_msg)

    @rate_limited
    async def handle_command_bingo(self, target, nick):
        """
        Handle !bingo command.
        Posts a link to the Trope Bingo cards.
        """
        bingo_msg = ("Check out {url} "
                     "for our interactive Trope Bingo cards.").format(
                         url=BINGO_URL)
        await self.client.privmsg(target, bingo_msg)

    @rate_limited
    async def handle_command_help(self, target, nick):
        """
        Handle !help command.
        Posts a link to the golem's list of supported commands.
        """
        help_msg = ("Pump19 is run by Twisted Pear. "
                    "Check {url} for a list of supported commands.").format(
                        url=COMMAND_URL)
        await self.client.privmsg(target, help_msg)
<commit_msg>Use the recycling symbol to indicate repeated games<commit_after>#!/usr/bin/env python3
# vim:fileencoding=utf-8:ts=8:et:sw=4:sts=4:tw=79

"""
command.py

Handle commands received on IRC.

Copyright (c) 2015 Twisted Pear <tp at pump19 dot eu>
See the file LICENSE for copying permission.
"""

import aiomc
import asyncio
import dbutils
import functools
import itertools
import locale
import logging
import random
import re
import songs
import twitch

BINGO_URL = "https://pump19.eu/bingo"
CODEFALL_URL = "https://pump19.eu/codefall"
COMMAND_URL = "https://pump19.eu/commands"
LRRMC_SERVERS = {
    "vanilla": {
        "name": "LRR Vanilla Minecraft Server",
        "host": "minecraft.darkmorford.net",
        "port": 25565,
        "info": "Check http://minecraft.darkmorford.net:8123/ "
                "for the dynamic map."
    },
    "ftb": {
        "name": "LRR FTB Minecraft Server",
        "host": "ftb.lrrcraft.com",
        "port": 25565,
        "info": "One up James on Feed The Beej Beyond."
    }
}

CMD_REGEX = {
    "vod":
        re.compile("^vod$"),
    "clip":
        re.compile("^clip$"),
    "18gac":
        re.compile("^(?:18gac|🎮)(?: (?P<extra>\d))?$"),
    "codefall":
        re.compile("^(?:codefall|🎁)(?: (?P<limit>\d))?$"),
    "lrrmc":
        re.compile("^(?:lrrmc|⛏)(?: (?P<server>\w+))?$"),
    "lastfm":
        re.compile("^(?:last\.fm|🎵) (?P<user>\w+)$", re.ASCII),
    "roll":
        re.compile("^(?:roll|🎲)(?: (?P<count>\d+)?d(?P<sides>\d+))?"),
    "bingo":
        re.compile("^bingo$"),
    "help":
        re.compile("^help|🚑$")
}

# set up locale for currency formatting (patreon command wants that)
locale.setlocale(locale.LC_MONETARY, "en_US.utf8")

class CommandHandler:
    """
    The command handler interacts with an IRC client and dispatches commands.
    It registers itself as a handler for PRIVMSG events.
    """
    logger = logging.getLogger("command")

    class Limiter:
        """
        A decorator that suppresses method calls within a certain time span.
        """

        logger = logging.getLogger("command.limiter")

        def __init__(self, *, span=15, loop=None):
            """Initialize rate limiter with a default delay of 15."""
            self.span = span
            self.loop = loop or asyncio.get_event_loop()

        def __call__(self, func):

            @functools.wraps(func)
            async def wrapper(*args, **kwargs):
                now = self.loop.time()
                if (now - wrapper._spam_last) > wrapper._spam_span:
                    wrapper._spam_last = now
                    await func(*args, **kwargs)
                else:
                    self.logger.warning("Suppressed call to {name}.".format(
                        name=func.__name__))

            # each wrapper remembers its own delay and last call
            wrapper._spam_span = self.span
            wrapper._spam_last = 0.0

            return wrapper

    rate_limited = Limiter()

    class CommandRouter:
        """A simple router matching strings against a set of regular
           expressions match to a callable."""

        routes = list()

        def add_route(self, regex, callback):
            self.routes.append((regex, callback))

        def get_route(self, string):
            for (regex, callback) in self.routes:
                match = regex.fullmatch(string)
                if not match:
                    continue

                # add matching groups to function
                return functools.partial(callback, **match.groupdict())

            return None

    router = CommandRouter()

    def __init__(self, client, *, loop=None, prefix="&", override=None):
        """Initialize the command handler and register for PRIVMSG events."""
        self.logger.info("Creating CommandHandler instance.")

        self.prefix = tuple(prefix)
        self.override = override
        self.client = client
        self.client.event_handler("PRIVMSG")(self.handle_privmsg)
        self.loop = loop or asyncio.get_event_loop()
        self.rate_limited.loop = loop

        self.setup_routing()

    def setup_routing(self):
        """Connect command handlers to regular expressions using the router."""
        for key, regex in CMD_REGEX.items():
            cmd_name = "handle_command_{0}".format(key)
            handle_command = getattr(self, cmd_name, None)
            if handle_command and callable(handle_command):
                self.router.add_route(regex, handle_command)

    async def handle_privmsg(self, nick, target, message, **kwargs):
        """
        Handle a PRIVMSG event and dispatch any command to the relevant method.
        """
        # ignore everything that's not a command with our prefix
        if not message.startswith(self.prefix) or len(message) < 2:
            return

        # remove prefix, regex will retrieve the arguments
        cmd = message[1:]

        self.logger.info("Got command \"{0}\" from {1}.".format(cmd, nick))

        # is this a query? if so, send messages to nick instead
        if target == self.client.nickname:
            target = nick

        # check if we can handle that command
        handle_command = self.router.get_route(cmd)
        if handle_command and callable(handle_command):
            await handle_command(target, nick)

    @rate_limited
    async def handle_command_vod(self, target, nick):
        """
        Handle !vod command.
        Post the most recent Twitch.tv broadcast.
        """
        broadcasts = await twitch.get_broadcasts(27132299, 1)
        vod = next(broadcasts, None)

        broadcast_msg = "Latest Broadcast: {0} [{2}] | {1}".format(*vod)

        await self.client.privmsg(target, broadcast_msg)

    @rate_limited
    async def handle_command_clip(self, target, nick):
        """
        Handle !clip command.
        Post the most viewed Twitch.tv clip.
        """
        clips = await twitch.get_top_clips("loadingreadyrun", 1)
        clip = next(clips, None)

        clip_msg = "Top Clip: {0} [{2}] | https://clips.twitch.tv/{1}".format(
                *clip)
        await self.client.privmsg(target, clip_msg)

    @rate_limited
    async def handle_command_18gac(self, target, nick, *, extra=None):
        """
        Handle !18gac command.
        Post the 18th +n most watched games on Twitch.tv.
        Filters out most recently streamed games.
        """
        extra = max(int(extra), 1) if extra else 3
        history = await dbutils.get_18gac_history()

        limit = extra + len(history)
        games = await twitch.get_top_games(limit, 17, loop=self.loop)
        games = enumerate(games, 18)
        game18 = next(games)
        if game18[1][0] in history:
            game18 = (game18[0], (game18[1][0], game18[1][1] + " \u267B"))
        games = filter(lambda g: g[1][0] not in history, games)
        games = itertools.islice(games, extra)
        games = itertools.chain([game18], games)

        game_msgs = ('#{0}: {2}'.format(idx, *game) for idx, game in games)

        game18_msg = "18th Game …and Counting: {0}.".format(
                " | ".join(game_msgs))

        await self.client.privmsg(target, game18_msg)

    @rate_limited
    async def handle_command_codefall(self, target, nick, *, limit=None):
        """
        Handle !codefall [limit] command.
        If available, post a single unclaimed codefall URL.
        """
        limit = min(int(limit), 3) if limit else 1

        entries = await dbutils.get_codefall_entries(
                nick, limit, loop=self.loop)

        if not entries:
            no_codefall_msg = ("Could not find any unclaimed codes. "
                               "You can add new entries at {url}".format(
                                   url=CODEFALL_URL))
            await self.client.privmsg(target, no_codefall_msg)
            return

        entry_msgs = ("{1} ({2}) {0}".format(*entry) for entry in entries)
        codefall_msg = "Codefall | {0}".format(" | ".join(entry_msgs))

        await self.client.privmsg(target, codefall_msg)

    @rate_limited
    async def handle_command_lrrmc(self, target, nick, *, server="vanilla"):
        """
        Handle !lrrmc command.
        Query and post the status of the LRR Minecraft server.
        """
        server = LRRMC_SERVERS.get(server, LRRMC_SERVERS["vanilla"])
        # don't stall forever when querying status
        status_coro = aiomc.get_status(
            server["host"], server["port"],
            loop=self.loop)

        try:
            status = await asyncio.wait_for(status_coro, 2.0)
        except asyncio.TimeoutError:
            status = None

        base_msg = ("Join the {name} on {host}:{port}! {info} "
                    "Current Status: {status}")

        if not status:
            no_lrrmc_msg = base_msg.format(**server, status="Unknown")
            await self.client.privmsg(target, no_lrrmc_msg)
            return

        try:
            nowp = status["players"]["online"]
            maxp = status["players"]["max"]
        except (KeyError, TypeError):
            nowp = maxp = "?"

        status_msg = "Online - {now}/{max} players".format(now=nowp, max=maxp)

        lrrmc_msg = base_msg.format(**server, status=status_msg)
        await self.client.privmsg(target, lrrmc_msg)

    @rate_limited
    async def handle_command_lastfm(self, target, nick, *, user=None):
        """
        Handle !last.fm command.
        Query information on the provided last.fm user handle and print the
        most recently listened track.
        """
        coro = songs.get_lastfm_info(user, loop=self.loop)

        info = await coro
        if not info:
            no_lastfm_msg = ("Cannot query last.fm user information for "
                             "{user}.".format(user=user))
            await self.client.privmsg(target, no_lastfm_msg)
            return

        name = info.get("name")
        live = info.get("live")
        track = info.get("track")
        artist = info.get("artist")

        if not track and not artist:
            no_lastfm_msg = ("Cannot query most recently played track for "
                             "{name}.".format(name=name))
            await self.client.privmsg(target, no_lastfm_msg)
            return

        tempus = "is listening" if live else "last listened"

        lastfm_msg = "{name} {tempus} to \"{track}\" by {artist}".format(
                name=name, tempus=tempus, track=track, artist=artist)
        await self.client.privmsg(target, lastfm_msg)

    @rate_limited
    async def handle_command_roll(self, target, nick, *,
                                  count=None, sides=None):
        """
        Handle !roll [[<n>]d<m>] command.
        Simulate n rolls of m sided dice and print the result.
        """
        count = int(count) if count else 1
        sides = int(sides) if sides else 20

        # nothing to do
        if count < 1:
            return

        if count > 10:
            out_of_dice_msg = "only has 10 dice"
            await self.client.describe(target, out_of_dice_msg)
            return

        if sides is 0:
            no_sides_msg = "slowly backs away from the singularity."
            await self.client.describe(target, no_sides_msg)
            return

        if sides > 100:
            too_many_sides_msg = "doesn't have one of those."
            await self.client.describe(target, too_many_sides_msg)
            return

        if sides is 1:
            roll_msg = "Rolling {0}... got {1}. Duh.".format(
                "a marble" if count == 1 else "some marbles", count)
        elif sides is 2:
            coins = (random.choice(("Heads", "Tails")) for _ in range(count))
            numerus = "a coin" if count == 1 else "{0} coins".format(count)
            roll_msg = "Tossing {0}... got {1}.".format(
                numerus, ", ".join(coins))
        else:
            rolls = [random.randint(1, sides) for _ in range(count)]
            total = sum(rolls)
            numerus = ("a d{0}".format(sides) if count == 1 else
                       "{0} d{1}s".format(count, sides))
            roll_msg = "Rolling {0}... got {1}{2}.".format(
                numerus, ", ".join(map(str, rolls)),
                " => {0}".format(total) if count > 1 else "")

        await self.client.privmsg(target, roll_msg)

    @rate_limited
    async def handle_command_bingo(self, target, nick):
        """
        Handle !bingo command.
        Posts a link to the Trope Bingo cards.
        """
        bingo_msg = ("Check out {url} "
                     "for our interactive Trope Bingo cards.").format(
                         url=BINGO_URL)
        await self.client.privmsg(target, bingo_msg)

    @rate_limited
    async def handle_command_help(self, target, nick):
        """
        Handle !help command.
        Posts a link to the golem's list of supported commands.
        """
        help_msg = ("Pump19 is run by Twisted Pear. "
                    "Check {url} for a list of supported commands.").format(
                        url=COMMAND_URL)
        await self.client.privmsg(target, help_msg)
<|endoftext|>