<commit_before># Filename: logger.py
# pylint: disable=locally-disabled,C0103
"""
The logging facility.

"""
from __future__ import absolute_import, print_function, division

from hashlib import sha256
from inspect import getframeinfo, stack
import socket
import logging

from .tools import colored, supports_color

__author__ = "Tamas Gal"
__copyright__ = "Copyright 2016, Tamas Gal and the KM3NeT collaboration."
__credits__ = []
__license__ = "MIT"
__maintainer__ = "Tamas Gal"
__email__ = "tgal@km3net.de"
__status__ = "Development"

loggers = {}    # this holds all the registered loggers
# logging.basicConfig()

DEPRECATION = 45
logging.addLevelName(DEPRECATION, "DEPRECATION")
ONCE = 45
logging.addLevelName(ONCE, "ONCE")

def deprecation(self, message, *args, **kws):
    """Show a deprecation warning."""
    self._log(DEPRECATION, message, args, **kws)

def once(self, message, *args, identifier=None, **kws):
    """Show a message only once, determined by position in source or identifer.

    This will not work in IPython or Jupyter notebooks if no identifier is
    specified, since then the determined position in source contains the
    execution number of the input (cell), which changes every time.
    Set a unique identifier, otherwise the message will be printed every
    time.
    """
    if identifier is None:
        caller = getframeinfo(stack()[1][0])
        identifier = "%s:%d" % (caller.filename, caller.lineno)
    if not hasattr(self, 'once_dict'):
        self.once_dict = {}
    if identifier in self.once_dict:
        return
    self.once_dict[identifier] = True
    self._log(ONCE, message, args, **kws)

logging.Logger.deprecation = deprecation
logging.Logger.once = once

if supports_color():
    logging.addLevelName(
        logging.INFO,
        "\033[1;32m%s\033[1;0m" % logging.getLevelName(logging.INFO)
    )
    logging.addLevelName(
        logging.DEBUG,
        "\033[1;34m%s\033[1;0m" % logging.getLevelName(logging.DEBUG)
    )
    logging.addLevelName(
        logging.WARNING,
        "\033[1;33m%s\033[1;0m" % logging.getLevelName(logging.WARNING)
    )
    logging.addLevelName(
        logging.ERROR,
        "\033[1;31m%s\033[1;0m" % logging.getLevelName(logging.ERROR)
    )
    logging.addLevelName(
        logging.CRITICAL,
        "\033[1;101m%s\033[1;0m" % logging.getLevelName(logging.CRITICAL)
    )
    logging.addLevelName(DEPRECATION, "\033[1;35m%s\033[1;0m" % 'DEPRECATION')
    logging.addLevelName(ONCE, "\033[1;36m%s\033[1;0m" % 'ONCE')

class LogIO(object):
    """Read/write logging information.
    """

    def __init__(
            self, node, stream, url='pi2089.physik.uni-erlangen.de', port=28777
    ):
        self.node = node
        self.stream = stream
        self.url = url
        self.port = port
        self.sock = None
        self.connect()

    def send(self, message, level='info'):
        message_string = "+log|{0}|{1}|{2}|{3}\r\n" \
                         .format(self.stream, self.node, level, message)
        try:
            self.sock.send(message_string)
        except socket.error:
            print("Lost connection, reconnecting...")
            self.connect()
            self.sock.send(message_string)

    def connect(self):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.connect((self.url, self.port))

def get_logger(name):
    """Helper function to get a logger"""
    if name in loggers:
        return loggers[name]
    logger = logging.getLogger(name)
    logger.propagate = False
    pre1, suf1 = hash_coloured_escapes(name) if supports_color() else ('', '')
    pre2, suf2 = hash_coloured_escapes(name + 'salt')  \
                 if supports_color() else ('', '')
    formatter = logging.Formatter(
        '%(levelname)s {}+{}+{} '
        '%(name)s: %(message)s'.format(pre1, pre2, suf1)
    )
    ch = logging.StreamHandler()
    ch.setFormatter(formatter)
    logger.addHandler(ch)
    loggers[name] = logger

    logger.once_dict = {}

    return logger

def available_loggers():
    """Return a list of avialable logger names"""
    return list(logging.Logger.manager.loggerDict.keys())

def set_level(name, level):
    """Set the log level for given logger"""
    get_logger(name).setLevel(level)

def get_printer(name, color=None, ansi_code=None, force_color=False):
    """Return a function which prints a message with a coloured name prefix"""

    if force_color or supports_color():
        if color is None and ansi_code is None:
            cpre_1, csuf_1 = hash_coloured_escapes(name)
            cpre_2, csuf_2 = hash_coloured_escapes(name + 'salt')
            name = cpre_1 + '+' + cpre_2 + '+' + csuf_1 + ' ' + name
        else:
            name = colored(name, color=color, ansi_code=ansi_code)

    prefix = name + ': '

    def printer(text):
        print(prefix + str(text))

    return printer

def hash_coloured(text):
    """Return a ANSI coloured text based on its hash"""
    ansi_code = int(sha256(text.encode('utf-8')).hexdigest(), 16) % 230
    return colored(text, ansi_code=ansi_code)

def hash_coloured_escapes(text):
    """Return the ANSI hash colour prefix and suffix for a given text"""
    ansi_code = int(sha256(text.encode('utf-8')).hexdigest(), 16) % 230
    prefix, suffix = colored('SPLIT', ansi_code=ansi_code).split('SPLIT')
    return prefix, suffix
<commit_msg>Add python 2 compat<commit_after># Filename: logger.py
# pylint: disable=locally-disabled,C0103
"""
The logging facility.

"""
from __future__ import absolute_import, print_function, division

from hashlib import sha256
from inspect import getframeinfo, stack
import socket
import logging

from .tools import colored, supports_color

__author__ = "Tamas Gal"
__copyright__ = "Copyright 2016, Tamas Gal and the KM3NeT collaboration."
__credits__ = []
__license__ = "MIT"
__maintainer__ = "Tamas Gal"
__email__ = "tgal@km3net.de"
__status__ = "Development"

loggers = {}    # this holds all the registered loggers
# logging.basicConfig()

DEPRECATION = 45
logging.addLevelName(DEPRECATION, "DEPRECATION")
ONCE = 45
logging.addLevelName(ONCE, "ONCE")

def deprecation(self, message, *args, **kws):
    """Show a deprecation warning."""
    self._log(DEPRECATION, message, args, **kws)

def once(self, message, *args, **kws):
    """Show a message only once, determined by position in source or identifer.

    This will not work in IPython or Jupyter notebooks if no identifier is
    specified, since then the determined position in source contains the
    execution number of the input (cell), which changes every time.
    Set a unique identifier, otherwise the message will be printed every
    time.
    """
    # TODO: after py2 support drop, put this into
    # function signature: identifier=None (between *args and **kws)
    identifier = kws.get('identifier')

    if identifier is None:
        caller = getframeinfo(stack()[1][0])
        identifier = "%s:%d" % (caller.filename, caller.lineno)
    if not hasattr(self, 'once_dict'):
        self.once_dict = {}
    if identifier in self.once_dict:
        return
    self.once_dict[identifier] = True
    self._log(ONCE, message, args, **kws)

logging.Logger.deprecation = deprecation
logging.Logger.once = once

if supports_color():
    logging.addLevelName(
        logging.INFO,
        "\033[1;32m%s\033[1;0m" % logging.getLevelName(logging.INFO)
    )
    logging.addLevelName(
        logging.DEBUG,
        "\033[1;34m%s\033[1;0m" % logging.getLevelName(logging.DEBUG)
    )
    logging.addLevelName(
        logging.WARNING,
        "\033[1;33m%s\033[1;0m" % logging.getLevelName(logging.WARNING)
    )
    logging.addLevelName(
        logging.ERROR,
        "\033[1;31m%s\033[1;0m" % logging.getLevelName(logging.ERROR)
    )
    logging.addLevelName(
        logging.CRITICAL,
        "\033[1;101m%s\033[1;0m" % logging.getLevelName(logging.CRITICAL)
    )
    logging.addLevelName(DEPRECATION, "\033[1;35m%s\033[1;0m" % 'DEPRECATION')
    logging.addLevelName(ONCE, "\033[1;36m%s\033[1;0m" % 'ONCE')

class LogIO(object):
    """Read/write logging information.
    """

    def __init__(
            self, node, stream, url='pi2089.physik.uni-erlangen.de', port=28777
    ):
        self.node = node
        self.stream = stream
        self.url = url
        self.port = port
        self.sock = None
        self.connect()

    def send(self, message, level='info'):
        message_string = "+log|{0}|{1}|{2}|{3}\r\n" \
                         .format(self.stream, self.node, level, message)
        try:
            self.sock.send(message_string)
        except socket.error:
            print("Lost connection, reconnecting...")
            self.connect()
            self.sock.send(message_string)

    def connect(self):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.connect((self.url, self.port))

def get_logger(name):
    """Helper function to get a logger"""
    if name in loggers:
        return loggers[name]
    logger = logging.getLogger(name)
    logger.propagate = False
    pre1, suf1 = hash_coloured_escapes(name) if supports_color() else ('', '')
    pre2, suf2 = hash_coloured_escapes(name + 'salt')  \
                 if supports_color() else ('', '')
    formatter = logging.Formatter(
        '%(levelname)s {}+{}+{} '
        '%(name)s: %(message)s'.format(pre1, pre2, suf1)
    )
    ch = logging.StreamHandler()
    ch.setFormatter(formatter)
    logger.addHandler(ch)
    loggers[name] = logger

    logger.once_dict = {}

    return logger

def available_loggers():
    """Return a list of avialable logger names"""
    return list(logging.Logger.manager.loggerDict.keys())

def set_level(name, level):
    """Set the log level for given logger"""
    get_logger(name).setLevel(level)

def get_printer(name, color=None, ansi_code=None, force_color=False):
    """Return a function which prints a message with a coloured name prefix"""

    if force_color or supports_color():
        if color is None and ansi_code is None:
            cpre_1, csuf_1 = hash_coloured_escapes(name)
            cpre_2, csuf_2 = hash_coloured_escapes(name + 'salt')
            name = cpre_1 + '+' + cpre_2 + '+' + csuf_1 + ' ' + name
        else:
            name = colored(name, color=color, ansi_code=ansi_code)

    prefix = name + ': '

    def printer(text):
        print(prefix + str(text))

    return printer

def hash_coloured(text):
    """Return a ANSI coloured text based on its hash"""
    ansi_code = int(sha256(text.encode('utf-8')).hexdigest(), 16) % 230
    return colored(text, ansi_code=ansi_code)

def hash_coloured_escapes(text):
    """Return the ANSI hash colour prefix and suffix for a given text"""
    ansi_code = int(sha256(text.encode('utf-8')).hexdigest(), 16) % 230
    prefix, suffix = colored('SPLIT', ansi_code=ansi_code).split('SPLIT')
    return prefix, suffix
<|endoftext|>


<commit_before>__author__ = 'tamasgal'

import logging

logging.addLevelName(logging.INFO, "\033[1;32m%s\033[1;0m" % logging.getLevelName(logging.INFO))
logging.addLevelName(logging.DEBUG, "\033[1;34m%s\033[1;0m" % logging.getLevelName(logging.DEBUG))
logging.addLevelName(logging.WARNING, "\033[1;33m%s\033[1;0m" % logging.getLevelName(logging.WARNING))
logging.addLevelName(logging.ERROR, "\033[1;31m%s\033[1;0m" % logging.getLevelName(logging.ERROR))

formatter = logging.Formatter('[%(levelname)s] %(name)s: %(message)s')

def get_logger(name, log_level=logging.DEBUG):
    log = logging.getLogger(name)
    log.setLevel(log_level)

    ch = logging.StreamHandler()
    ch.setLevel(log_level)
    ch.setFormatter(formatter)

    log.addHandler(ch)
    return log
<commit_msg>Adds docstring with example<commit_after>__author__ = 'tamasgal'

import logging

logging.addLevelName(logging.INFO, "\033[1;32m%s\033[1;0m" % logging.getLevelName(logging.INFO))
logging.addLevelName(logging.DEBUG, "\033[1;34m%s\033[1;0m" % logging.getLevelName(logging.DEBUG))
logging.addLevelName(logging.WARNING, "\033[1;33m%s\033[1;0m" % logging.getLevelName(logging.WARNING))
logging.addLevelName(logging.ERROR, "\033[1;31m%s\033[1;0m" % logging.getLevelName(logging.ERROR))

formatter = logging.Formatter('[%(levelname)s] %(name)s: %(message)s')

def get_logger(name, log_level=logging.DEBUG):
    """Create a fancy logger with the given name.

    If you use it in your own module, give it __name__ as name.

    Usage example:
    --------
    >>> from km3pipe.logger import get_logger
    >>> log = get_logger('foo_logger')
    >>> log.debug("This is a foo debug.")
    [DEBUG] foo_logger: This is a foo debug.
    >>> log.info("This is a foo info.")
    [INFO] foo_logger: This is a foo info.
    >>> log.warn("This is a foo warning.")
    [WARNING] foo_logger: This is a foo warning.
    >>> log.error("This is a foo error.")
    [ERROR] foo_logger: This is a foo error.

    """
    log = logging.getLogger(name)
    log.setLevel(log_level)

    ch = logging.StreamHandler()
    ch.setLevel(log_level)
    ch.setFormatter(formatter)

    log.addHandler(ch)
    return log
<|endoftext|>


<commit_before>"""
User interface for the Crawler class

Author: Mark Boon
Date: 28/08/2017
Version: 2.0.0
"""

from crawler import *

def crawl(*urls):
    // load crawler threads
    for link in urls:
        current_worker = Worker(link)
        load = threading.Thread(target=current_worker.work)
        load.start()
<commit_msg>Delete controller.py<commit_after><|endoftext|>


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

import feedparser
import urllib
import re
import sys
import os
import subprocess
from xml.etree.cElementTree import parse, tostring
from werkzeug.contrib.atom import AtomFeed
from datetime import datetime
from glob import glob

base_url = 'https://moeffju.net/data/rp13'

schedule = parse('rp13-schedule.xml')

feed_urls = ['https://gdata.youtube.com/feeds/api/users/republica2010/uploads?max-results=50&start-index=%s' %
             i for i in range(0, 100, 50)]
feed_content = ''
for url in feed_urls:
    print >>sys.stderr, url
    feed_content += urllib.urlopen(url).read()
ytfeed = feedparser.parse(feed_content)

feed = AtomFeed("re:publica 2013: Audio", feed_url="%s/audio.atom" % base_url,
                subtitle="Audio feed of re:publica 2013 sessions")

for entry in ytfeed.entries:
    try:
        event_id = re.search('Find out more at: http://13.re-publica.de/node/(\d+)', entry['summary']).group(1)
        ytid = re.search('http://gdata.youtube.com/feeds/api/videos/(.*)', entry['id']).group(1)
    except AttributeError as e:
        print >>sys.stderr, "Skipping entry: %s" % entry['title']
        continue
    print >>sys.stderr, "ID %s / YTID %s: %s" % (event_id, ytid, entry['title'])

    event = schedule.find('.//event[@id="%s"]' % event_id)
    fns = glob('*%s.*' % ytid)
    if len(fns) > 0:
        print >>sys.stderr, "Matched: %s" % ', '.join(fns)
    else:
        print >>sys.stderr, "Downloading: %s" % ytid
        subprocess.call('youtube-dl --extract-audio --audio-format mp3 -c -f 18 -- "https://www.youtube.com/watch?v=%s" >&2' % ytid, shell=True)
        fns = glob('*%s.*' % ytid)
    links = []
    links.append({'href': "https://www.youtube.com/watch?v=%s" % ytid, 'rel': 'alternate', 'type': 'text/html'})
    for fn in fns:
        if fn[-3:] == 'ogg':
            links.append({'href': "%s/%s" % (base_url, fn), 'rel': 'enclosure',
                         'type': 'audio/ogg; codecs=vorbis', 'length': os.path.getsize(fn)})
        elif fn[-3:] == 'mp3':
            links.append({'href': "%s/%s" % (base_url, fn), 'rel': 'enclosure',
                         'type': 'audio/mpeg', 'length': os.path.getsize(fn)})

    try:
        content = event.find('description').text.replace('<', '<').replace('>', '>').replace('&', '&')
        content = re.sub('<img[^>]*>', '(Image removed)', content)
    except:
        content = ''

    try:
        summary = event.find('abstract').text.replace('<', '<').replace('>', '>').replace('&', '&')
    except:
        summary = ''

    feed.add(title=event.find('title').text,
             title_type='html',
             content=content,
             summary=summary,
             id="tag:moeffju.net,%s:rp13,audio,%s,%s" % (datetime.strptime(entry['published'], '%Y-%m-%dT%H:%M:%S.000Z').strftime('%Y-%m-%d'), event_id, ytid),
             author=[e.text for e in event.findall('.//person')],
             rights="Creative Commons Attribution-ShareAlike 3.0 Germany (CC BY-SA 3.0 DE)",
             updated=datetime.strptime(entry['updated'], '%Y-%m-%dT%H:%M:%S.000Z'),
             published=datetime.strptime(entry['published'], '%Y-%m-%dT%H:%M:%S.000Z'),
             links=links,
             )

print feed.to_string().encode('utf-8')
<commit_msg>More videos and smarter resume<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

import feedparser
import urllib
import re
import sys
import os
import subprocess
from xml.etree.cElementTree import parse, tostring
from werkzeug.contrib.atom import AtomFeed
from datetime import datetime
from glob import glob

base_url = 'https://moeffju.net/data/rp13'

schedule = parse('rp13-schedule.xml')

feed_urls = ['https://gdata.youtube.com/feeds/api/users/republica2010/uploads?max-results=50&start-index=%s' %
             i for i in range(0, 300, 50)]
feed_content = ''
for url in feed_urls:
    print >>sys.stderr, url
    feed_content += urllib.urlopen(url).read()
ytfeed = feedparser.parse(feed_content)

feed = AtomFeed("re:publica 2013: Audio", feed_url="%s/audio.atom" % base_url,
                subtitle="Audio feed of re:publica 2013 sessions")

for entry in ytfeed.entries:
    try:
        event_id = re.search('Find out more at: http://13.re-publica.de/node/(\d+)', entry['summary']).group(1)
        ytid = re.search('http://gdata.youtube.com/feeds/api/videos/(.*)', entry['id']).group(1)
    except AttributeError as e:
        print >>sys.stderr, "Skipping entry: %s" % entry['title']
        continue
    print >>sys.stderr, "ID %s / YTID %s: %s" % (event_id, ytid, entry['title'])

    event = schedule.find('.//event[@id="%s"]' % event_id)
    fns = glob('*%s.mp3' % ytid) + glob('*%s.ogg' % ytid)
    if len(fns) > 0:
        print >>sys.stderr, "Matched: %s" % ', '.join(fns)
    else:
        print >>sys.stderr, "Downloading: %s" % ytid
        subprocess.call('youtube-dl --extract-audio --audio-format mp3 -c -f 18 -- "https://www.youtube.com/watch?v=%s" >&2' % ytid, shell=True)
        fns = glob('*%s.mp3' % ytid) + glob('*%s.ogg' % ytid)
    links = []
    links.append({'href': "https://www.youtube.com/watch?v=%s" % ytid, 'rel': 'alternate', 'type': 'text/html'})
    for fn in fns:
        if fn[-3:] == 'ogg':
            links.append({'href': "%s/%s" % (base_url, fn), 'rel': 'enclosure',
                         'type': 'audio/ogg; codecs=vorbis', 'length': os.path.getsize(fn)})
        elif fn[-3:] == 'mp3':
            links.append({'href': "%s/%s" % (base_url, fn), 'rel': 'enclosure',
                         'type': 'audio/mpeg', 'length': os.path.getsize(fn)})

    try:
        content = event.find('description').text.replace('<', '<').replace('>', '>').replace('&', '&')
        content = re.sub('<img[^>]*>', '(Image removed)', content)
    except:
        content = ''

    try:
        summary = event.find('abstract').text.replace('<', '<').replace('>', '>').replace('&', '&')
    except:
        summary = ''

    feed.add(title=event.find('title').text,
             title_type='html',
             content=content,
             summary=summary,
             id="tag:moeffju.net,%s:rp13,audio,%s,%s" % (datetime.strptime(entry['published'], '%Y-%m-%dT%H:%M:%S.000Z').strftime('%Y-%m-%d'), event_id, ytid),
             author=[e.text for e in event.findall('.//person')],
             rights="Creative Commons Attribution-ShareAlike 3.0 Germany (CC BY-SA 3.0 DE)",
             updated=datetime.strptime(entry['updated'], '%Y-%m-%dT%H:%M:%S.000Z'),
             published=datetime.strptime(entry['published'], '%Y-%m-%dT%H:%M:%S.000Z'),
             links=links,
             )

print feed.to_string().encode('utf-8')
<|endoftext|>


<commit_before>#!/usr/bin/env python2
#import all the libraries and elements that we need
import time
import datetime
import sys
import pigpio
import string

import CloudFunctions

#setup a pi object
pi = pigpio.pi()

#define global variables defaults
LOCATION = "CAXX0518"	#location of the weather we want
CITY = "Vancouver"      #location of the city we want to sunrise and sunset data
UNITS = "metric"	#default units for the weather
MODE = "lamp"	#mode we want to be in (default is mirror weather at location)
AUDIO_EN = 1
DEFAULT_COLOUR = [255, 255, 255]	#default colour shown in lamp and pulse mode
DAY_COLOUR = [255, 255, 255]            #colour for the day mode
NIGHT_COLOUR = [50, 100, 200]           #colour for the night mode
DAY_BRIGHTNESS = 1                      #Brightness multiplier for the day
DAY_ACCENT_BRIGHTNESS = 1               #brightness of the accents in day
NIGHT_BRIGHTNESS = 0.1                  #Brightness multiplier for the night
NIGHT_ACCENT_BRIGHTNESS = 0.2           #brightness of the accents at night
WEATHER = ["Clear",26,0700,1900,15,20]	#default weather, clear, 26 degrees, sunrise 7am, 7pm sunset, 15km/h winds, 20km visibility
SUNRISE = WEATHER[2]                    #default sunrise time
SUNSET = WEATHER[3]                     #default sunset time
PULSE_RATE = 1                          #default pulse rate, smaller = faster
COUNT = 0
DIRECTION = 1
current_weather_status = "Clear"
music_count = 0

#setup a location object for weather
location = CloudFunctions.CWeather(CITY, LOCATION, UNITS)

#get the latest weather from location
WEATHER = location.getWeatherData()

#open the settings file and grab all our globals from there
with open("settings.conf", "r") as f:
    for line in f:
    	setting = string.split(line, "=")
        if setting[0] == "location":
        	LOCATION = setting[1].rstrip()
        elif setting[0] == "city":
        	CITY = setting[1].rstrip()
        elif setting[0] == "units":
        	UNITS = setting[1].rstrip()
        elif setting[0] == "mode":
        	MODE = setting[1].rstrip()
        elif setting[0] == "default_colour":
        	DEFAULT_COLOUR = string.split(setting[1].rstrip(), ",")
        elif setting[0] == "audio_enable":
        	AUDIO_EN = int(setting[1].rstrip())
        elif setting[0] == "day_colour":
        	DAY_COLOUR = string.split(setting[1].rstrip(), ",")
        elif setting[0] == "night_colour":
        	NIGHT_COLOUR = string.split(setting[1].rstrip(), ",")
        elif setting[0] == "day_brightness":
        	DAY_BRIGHTNESS = setting[1].rstrip()
        elif setting[0] == "night_brightness":
        	NIGHT_BRIGHTNESS = setting[1].rstrip()
        elif setting[0] == "day_accent_brightness":
        	DAY_ACCENT_BRIGHTNESS = setting[1].rstrip()
        elif setting[0] == "night_accent_brightness":
        	NIGHT_ACCENT_BRIGHTNESS = setting[1].rstrip()
        elif setting[0] == "pulse_rate":
        	PULSE_RATE = float(setting[1].rstrip())
        else:
        	print "\nSetting in config file not recognised %s" % line

#close the file for other programs
f.close()

#define all the functions we need in the program
#function to start all the pins with current duty cycle
def startLeds( leds, duty_cycles ):
	"Function turns on all LEDs in array of LED objects provided"
	print "\nStarting all LEDs!"
	for index in range(len(leds)):
		pi.set_PWM_dutycycle(leds[index], duty_cycles[index])
	return

#function to stop all pins
def stopLeds( leds ):
	"Turns off all LEDs in array of LED objects provided"
	print "\nSwitching off all LEDs!"
	for index in range(len(leds)):
		pi.set_PWM_dutycycle(leds[index], 0)
		pi.stop()
	return

#function to update the pin duty cylces
def updateLeds( leds, duty_cycles ):
	"Updates all leds with latest duty cycle provided"
	print "\nUpdating LED duty cycles!"
	for index in range(len(leds)):
		real_brightness = int(int(duty_cycles[index]) * (float(255) / 255.0))
		pi.set_PWM_dutycycle(leds[index], real_brightness)
	return

#function to define lamp mode
def lampMode(duty_cycles, DEFAULT_COLOUR):
	"Outputs duty cycle values based on lamp mode and default colour"
	for channel in range(0, 9, 3):
		for colour in range (0, 3, 1):
			duty_cycles[channel + colour] = DEFAULT_COLOUR[colour]
	return

#function for pulsing mode
def pulseMode(cycle, duty_cycles, DEFAULT_COLOUR):
	"Pulses a given colour"
	for channel in range(0, 9, 3):
		for colour in range (0, 3, 1):
			duty_cycles[channel + colour] = int((float(cycle[COUNT])/100.0) * float(int(DEFAULT_COLOUR[colour])))

	#check the limits and swap dir if needed
	if cycle[COUNT] >= 100:
		cycle[COUNT] = 100
		if cycle[DIRECTION] == 1:
			cycle[DIRECTION] = 0
		else:
			cycle[DIRECTION] = 1
	elif cycle[COUNT] <= 0:
		cycle[COUNT] = 0
		if cycle[DIRECTION] == 1:
			cycle[DIRECTION] = 0
		else:
			cycle[DIRECTION] = 1

	#increment/decrement the counter based on direction
	if cycle[DIRECTION] == 1:
		cycle[COUNT] = cycle[COUNT] + PULSE_RATE
	else:
		cycle[COUNT] = cycle[COUNT] - PULSE_RATE

        return

#function which runs the duty cycles for weather mode
def weatherMirrorMode(cycle, duty_cycles, WEATHER):
        global current_weather_status
        global music_count

	"Outputs duty cycle values based on weather outside"
	#get the latest weather from the weather object
	WEATHER = location.getWeatherData()
	SUNRISE = WEATHER[2]
	SUNSET = WEATHER[3]

	#get the current time
        time = datetime.datetime.now().time();
        time = string.split(str(time), ':')
        time = int(time[0] + time[1])

        #check where in the day night cycle we are
	if (time < SUNRISE and time < SUNSET) or (time > SUNRISE and time > SUNSET):
            #we are in the night time, put lights into night colour mode
            print "Night time!"

            #set the main lamp colour
            for channel in range(0, 3, 3):
		for colour in range (0, 3, 1):
                    duty_cycles[channel + colour] = int(float(NIGHT_BRIGHTNESS) * float(int(NIGHT_COLOUR[colour])))

            #set the accent channel colours
            for channel in range(3, 9, 3):
		for colour in range (0, 3, 1):
                    duty_cycles[channel + colour] = int((float(cycle[COUNT])/100.0) * float(NIGHT_ACCENT_BRIGHTNESS) * float(int(NIGHT_COLOUR[colour])))
        else:
            #we are in the day time, put lights into day colour mode
            print "Day time!"
            #set the main lamp colour
            for channel in range(0, 3, 3):
		for colour in range (0, 3, 1):
                    duty_cycles[channel + colour] = int(fl636oat(DAY_BRIGHTNESS) * float(int(DAY_COLOUR[colour])))

            #set the accent channel colours
            for channel in range(3, 9, 3):
		for colour in range (0, 3, 1):
                    duty_cycles[channel + colour] = int((float(cycle[COUNT])/100.0) * float(DAY_ACCENT_BRIGHTNESS) * float(int(DAY_COLOUR[colour])))

        #set the sound based on conditions
        if AUDIO_EN == 1:
            audio_shit = CloudFunctions.PlayWeatherStatusTrack(current_weather_status, WEATHER[0], music_count)
            current_weather_status = audio_shit[0]
            music_count = audio_shit[1]
        else:
            CloudFunctions.PlayWeatherStatusTrack(current_weather_status, "mute", music_count)

        #check the limits and swap dir if needed
	if cycle[COUNT] >= 100:
		cycle[COUNT] = 100
		if cycle[DIRECTION] == 1:
			cycle[DIRECTION] = 0
		else:
			cycle[DIRECTION] = 1
	elif cycle[COUNT] <= 0:
		cycle[COUNT] = 0
		if cycle[DIRECTION] == 1:
			cycle[DIRECTION] = 0
		else:
			cycle[DIRECTION] = 1

	#increment/decrement the counter based on direction
	if cycle[DIRECTION] == 1:
		cycle[COUNT] = cycle[COUNT] + PULSE_RATE
	else:
		cycle[COUNT] = cycle[COUNT] - PULSE_RATE

        return

#function which runs the duty cycles for weather mode inverted
def weatherInvertMode(cycle, duty_cycles, WEATHER):
	"Outputs duty cycle values based on weather outside inverted"
	return

#welcome statements
print "\nCloud Clouds is starting..."

#setup GPIO output pins
print "\nSetting up GPIO pins and libraries..."
leds = [17, 18, 27, 23, 24, 25, 10, 9, 11]
duty_cycles = [0, 0, 0, 0, 0, 0, 0, 0, 0]
cycle = [1, 1];

#start all the leds
startLeds(leds, duty_cycles)

#main program loop
#inifite, just updates the LED duty cycles from the duty_cycles array and drives them up and down
while (1):
	print "\nMain program loop started."
	print MODE

	#check what mode we are in and run appropriate function
	if MODE == "mirror":
		print "\nGetting latest from weather mirror mode"
		weatherMirrorMode(cycle, duty_cycles, WEATHER)
	elif MODE == "invert":
		print "\nGetting latest from weather invert mode"
		weatherInvertMode(cycle, duty_cycles, WEATHER)
	elif MODE == "pulse":
		print "\nGetting latest from weather invert mode"
		pulseMode(cycle, duty_cycles, DEFAULT_COLOUR)
	else:
		print "\nGetting latest from lamp mode"
		lampMode(duty_cycles, DEFAULT_COLOUR)

	#update the LED duty cycles
	print "\nUpdating LED duty cycles."
	updateLeds(leds, duty_cycles)

	time.sleep(0.01)
<commit_msg>some shit<commit_after>#!/usr/bin/env python2
#import all the libraries and elements that we need
import time
import datetime
import sys
import pigpio
import string

import CloudFunctions

#setup a pi object
pi = pigpio.pi()

#define global variables defaults
LOCATION = "CAXX0518"	#location of the weather we want
CITY = "Vancouver"      #location of the city we want to sunrise and sunset data
UNITS = "metric"	#default units for the weather
MODE = "lamp"	#mode we want to be in (default is mirror weather at location)
AUDIO_EN = 1
DEFAULT_COLOUR = [255, 255, 255]	#default colour shown in lamp and pulse mode
DAY_COLOUR = [255, 255, 255]            #colour for the day mode
NIGHT_COLOUR = [50, 100, 200]           #colour for the night mode
DAY_BRIGHTNESS = 1                      #Brightness multiplier for the day
DAY_ACCENT_BRIGHTNESS = 1               #brightness of the accents in day
NIGHT_BRIGHTNESS = 0.1                  #Brightness multiplier for the night
NIGHT_ACCENT_BRIGHTNESS = 0.2           #brightness of the accents at night
WEATHER = ["Clear",26,0700,1900,15,20]	#default weather, clear, 26 degrees, sunrise 7am, 7pm sunset, 15km/h winds, 20km visibility
SUNRISE = WEATHER[2]                    #default sunrise time
SUNSET = WEATHER[3]                     #default sunset time
PULSE_RATE = 1                          #default pulse rate, smaller = faster
COUNT = 0
DIRECTION = 1
current_weather_status = "Clear"
music_count = 0

#setup a location object for weather
location = CloudFunctions.CWeather(CITY, LOCATION, UNITS)

#get the latest weather from location
WEATHER = location.getWeatherData()

#open the settings file and grab all our globals from there
with open("settings.conf", "r") as f:
    for line in f:
    	setting = string.split(line, "=")
        if setting[0] == "location":
        	LOCATION = setting[1].rstrip()
        elif setting[0] == "city":
        	CITY = setting[1].rstrip()
        elif setting[0] == "units":
        	UNITS = setting[1].rstrip()
        elif setting[0] == "mode":
        	MODE = setting[1].rstrip()
        elif setting[0] == "default_colour":
        	DEFAULT_COLOUR = string.split(setting[1].rstrip(), ",")
        elif setting[0] == "audio_enable":
        	AUDIO_EN = int(setting[1].rstrip())
        elif setting[0] == "day_colour":
        	DAY_COLOUR = string.split(setting[1].rstrip(), ",")
        elif setting[0] == "night_colour":
        	NIGHT_COLOUR = string.split(setting[1].rstrip(), ",")
        elif setting[0] == "day_brightness":
        	DAY_BRIGHTNESS = setting[1].rstrip()
        elif setting[0] == "night_brightness":
        	NIGHT_BRIGHTNESS = setting[1].rstrip()
        elif setting[0] == "day_accent_brightness":
        	DAY_ACCENT_BRIGHTNESS = setting[1].rstrip()
        elif setting[0] == "night_accent_brightness":
        	NIGHT_ACCENT_BRIGHTNESS = setting[1].rstrip()
        elif setting[0] == "pulse_rate":
        	PULSE_RATE = float(setting[1].rstrip())
        else:
        	print "\nSetting in config file not recognised %s" % line

#close the file for other programs
f.close()

#define all the functions we need in the program
#function to start all the pins with current duty cycle
def startLeds( leds, duty_cycles ):
	"Function turns on all LEDs in array of LED objects provided"
	print "\nStarting all LEDs!"
	for index in range(len(leds)):
		pi.set_PWM_dutycycle(leds[index], duty_cycles[index])
	return

#function to stop all pins
def stopLeds( leds ):
	"Turns off all LEDs in array of LED objects provided"
	print "\nSwitching off all LEDs!"
	for index in range(len(leds)):
		pi.set_PWM_dutycycle(leds[index], 0)
		pi.stop()
	return

#function to update the pin duty cylces
def updateLeds( leds, duty_cycles ):
	"Updates all leds with latest duty cycle provided"
	print "\nUpdating LED duty cycles!"
	for index in range(len(leds)):
		real_brightness = int(int(duty_cycles[index]) * (float(255) / 255.0))
		pi.set_PWM_dutycycle(leds[index], real_brightness)
	return

#function to define lamp mode
def lampMode(duty_cycles, DEFAULT_COLOUR):
	"Outputs duty cycle values based on lamp mode and default colour"
	for channel in range(0, 9, 3):
		for colour in range (0, 3, 1):
			duty_cycles[channel + colour] = DEFAULT_COLOUR[colour]
	return

#function for pulsing mode
def pulseMode(cycle, duty_cycles, DEFAULT_COLOUR):
	"Pulses a given colour"
	for channel in range(0, 9, 3):
		for colour in range (0, 3, 1):
			duty_cycles[channel + colour] = int((float(cycle[COUNT])/100.0) * float(int(DEFAULT_COLOUR[colour])))

	#check the limits and swap dir if needed
	if cycle[COUNT] >= 100:
		cycle[COUNT] = 100
		if cycle[DIRECTION] == 1:
			cycle[DIRECTION] = 0
		else:
			cycle[DIRECTION] = 1
	elif cycle[COUNT] <= 0:
		cycle[COUNT] = 0
		if cycle[DIRECTION] == 1:
			cycle[DIRECTION] = 0
		else:
			cycle[DIRECTION] = 1

	#increment/decrement the counter based on direction
	if cycle[DIRECTION] == 1:
		cycle[COUNT] = cycle[COUNT] + PULSE_RATE
	else:
		cycle[COUNT] = cycle[COUNT] - PULSE_RATE

        return

#function which runs the duty cycles for weather mode
def weatherMirrorMode(cycle, duty_cycles, WEATHER):
        global current_weather_status
        global music_count

	"Outputs duty cycle values based on weather outside"
	#get the latest weather from the weather object
	WEATHER = location.getWeatherData()
	SUNRISE = WEATHER[2]
	SUNSET = WEATHER[3]

	#get the current time
        time = datetime.datetime.now().time();
        time = string.split(str(time), ':')
        time = int(time[0] + time[1])

        #check where in the day night cycle we are
	if (time < SUNRISE and time < SUNSET) or (time > SUNRISE and time > SUNSET):
            #we are in the night time, put lights into night colour mode
            print "Night time!"

            #set the main lamp colour
            for channel in range(0, 3, 3):
		for colour in range (0, 3, 1):
                    duty_cycles[channel + colour] = int(float(NIGHT_BRIGHTNESS) * float(int(NIGHT_COLOUR[colour])))

            #set the accent channel colours
            for channel in range(3, 9, 3):
		for colour in range (0, 3, 1):
                    duty_cycles[channel + colour] = int((float(cycle[COUNT])/100.0) * float(NIGHT_ACCENT_BRIGHTNESS) * float(int(NIGHT_COLOUR[colour])))
        else:
            #we are in the day time, put lights into day colour mode
            print "Day time!"
            #set the main lamp colour
            for channel in range(0, 3, 3):
		for colour in range (0, 3, 1):
                    duty_cycles[channel + colour] = int(fl636oat(DAY_BRIGHTNESS) * float(int(DAY_COLOUR[colour])))

            #set the accent channel colours
            for channel in range(3, 9, 3):
		for colour in range (0, 3, 1):
                    duty_cycles[channel + colour] = int((float(cycle[COUNT])/100.0) * float(DAY_ACCENT_BRIGHTNESS) * float(int(DAY_COLOUR[colour])))

        #set the sound based on conditions
        if AUDIO_EN == 1:
            current_weather_status, music_count = CloudFunctions.PlayWeatherStatusTrack(current_weather_status, WEATHER[0], music_count)
        else:
            current_weather_status, music_count = CloudFunctions.PlayWeatherStatusTrack(current_weather_status, WEATHER[0], music_count)

        #check the limits and swap dir if needed
	if cycle[COUNT] >= 100:
		cycle[COUNT] = 100
		if cycle[DIRECTION] == 1:
			cycle[DIRECTION] = 0
		else:
			cycle[DIRECTION] = 1
	elif cycle[COUNT] <= 0:
		cycle[COUNT] = 0
		if cycle[DIRECTION] == 1:
			cycle[DIRECTION] = 0
		else:
			cycle[DIRECTION] = 1

	#increment/decrement the counter based on direction
	if cycle[DIRECTION] == 1:
		cycle[COUNT] = cycle[COUNT] + PULSE_RATE
	else:
		cycle[COUNT] = cycle[COUNT] - PULSE_RATE

        return

#function which runs the duty cycles for weather mode inverted
def weatherInvertMode(cycle, duty_cycles, WEATHER):
	"Outputs duty cycle values based on weather outside inverted"
	return

#welcome statements
print "\nCloud Clouds is starting..."

#setup GPIO output pins
print "\nSetting up GPIO pins and libraries..."
leds = [17, 18, 27, 23, 24, 25, 10, 9, 11]
duty_cycles = [0, 0, 0, 0, 0, 0, 0, 0, 0]
cycle = [1, 1];

#start all the leds
startLeds(leds, duty_cycles)

#main program loop
#inifite, just updates the LED duty cycles from the duty_cycles array and drives them up and down
while (1):
	print "\nMain program loop started."
	print MODE

	#check what mode we are in and run appropriate function
	if MODE == "mirror":
		print "\nGetting latest from weather mirror mode"
		weatherMirrorMode(cycle, duty_cycles, WEATHER)
	elif MODE == "invert":
		print "\nGetting latest from weather invert mode"
		weatherInvertMode(cycle, duty_cycles, WEATHER)
	elif MODE == "pulse":
		print "\nGetting latest from weather invert mode"
		pulseMode(cycle, duty_cycles, DEFAULT_COLOUR)
	else:
		print "\nGetting latest from lamp mode"
		lampMode(duty_cycles, DEFAULT_COLOUR)

	#update the LED duty cycles
	print "\nUpdating LED duty cycles."
	updateLeds(leds, duty_cycles)

	time.sleep(0.01)
<|endoftext|>


<commit_before>'''
Knowledge representation

------------------------------------------------------------------------------
SketchNet
Iulius Curt @ 2013
------------------------------------------------------------------------------
'''

class SketchKnowledgeBase(object):
    '''
    SketchKnowledgeBase
    '''
    def __init__(self):
        super(SketchKnowledgeBase, self).__init__()
        self.entities = {}
        self.actions = {}
        # Reversed IS-A actions
        self.asi = {}

        self._idcounter = {}

    def add_entity(self, entity):
        self.entities[entity.name] = entity
        for p in entity.isa:
            if p in self.asi:
                self.asi[p].append(entity.name)
            else:
                self.asi[p] = [entity.name]

    def add_action(self, act):
        unqid = self._unique_act_id(act.name)
        self.actions[unqid] = act
        for p in act.isa:
            punqid = self._unique_act_id(p)
            if p in self.asi:
                self.asi[punqid].append(unqid)
            else:
                self.asi[punqid] = [unqid]

    def _unique_act_id(self, actname):
        if actname not in self._idcounter:
            self._idcounter[actname] = -1
        self._idcounter[actname] += 1
        return actname + str(self._idcounter[actname])

    def __str__(self):
        return '(\n  ENTITIES:\n    ' + str(self.entities) + '\n  ACTIONS:\n    ' + str(self.actions) + '\n)\n'

class SNEntity(object):
    '''
    SketchNet Entity
    '''
    def __init__(self, name, sketch, isa=[], partof=[]):
        super(SNEntity, self).__init__()
        self.name, self.sketch, self.isa, self.partof = \
            name, sketch, isa, partof

    def __repr__(self):
        # TODO: strip str(self.isa) of ' characters
        return '<SNE:' + self.name + '::' + str(self.isa) + '>'

    def __str__(self):
        return self.__repr__()

class SNAction(object):
    '''
    Action over SketchNet entities
    '''
    def __init__(self, name, components, sketch, isa=[], partof=[]):
        super(SNAction, self).__init__()
        self.name, self.components, self.sketch, self.isa, self.partof = \
            name, components, sketch, isa, partof

    def __repr__(self):
        # TODO: strip list reprs of ' characters
        return '<SNR:' + self.name + '(' + str(self.components)[1:-1] + ')::' + str(self.isa) + '>'

    def __str__(self):
        return self.__repr__()
<commit_msg>Solved __repr__ todos<commit_after>'''
Knowledge representation

------------------------------------------------------------------------------
SketchNet
Iulius Curt @ 2013
------------------------------------------------------------------------------
'''

class SketchKnowledgeBase(object):
    '''
    SketchKnowledgeBase
    '''
    def __init__(self):
        super(SketchKnowledgeBase, self).__init__()
        self.entities = {}
        self.actions = {}
        # Reversed IS-A actions
        self.asi = {}

        self._idcounter = {}

    def add_entity(self, entity):
        self.entities[entity.name] = entity
        for p in entity.isa:
            if p in self.asi:
                self.asi[p].append(entity.name)
            else:
                self.asi[p] = [entity.name]

    def add_action(self, act):
        unqid = self._unique_act_id(act.name)
        self.actions[unqid] = act
        for p in act.isa:
            punqid = self._unique_act_id(p)
            if p in self.asi:
                self.asi[punqid].append(unqid)
            else:
                self.asi[punqid] = [unqid]

    def _unique_act_id(self, actname):
        if actname not in self._idcounter:
            self._idcounter[actname] = -1
        self._idcounter[actname] += 1
        return actname + str(self._idcounter[actname])

    def __str__(self):
        return '(\n  ENTITIES:\n    ' + str(self.entities) + '\n  ACTIONS:\n    ' + str(self.actions) + '\n)\n'

class SNEntity(object):
    '''
    SketchNet Entity
    '''
    def __init__(self, name, sketch, isa=[], partof=[]):
        super(SNEntity, self).__init__()
        self.name, self.sketch, self.isa, self.partof = \
            name, sketch, isa, partof

    def __repr__(self):
        # Strips str(self.isa) of ' characters
        return '<SNE:' + self.name + '::' + str(self.isa).replace("'", "") + '>'

    def __str__(self):
        return self.__repr__()

class SNAction(object):
    '''
    Action over SketchNet entities
    '''
    def __init__(self, name, components, sketch, isa=[], partof=[]):
        super(SNAction, self).__init__()
        self.name, self.components, self.sketch, self.isa, self.partof = \
            name, components, sketch, isa, partof

    def __repr__(self):
        # Strips list reprs of ' characters
        return '<SNR:' + self.name + '(' + str(self.components)[1:-1].replace("'", "") + ')::' + str(self.isa).replace("'", "") + '>'

    def __str__(self):
        return self.__repr__()
<|endoftext|>


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

"""
Curses implementation of Conway's Game Of Life with an evolutionary twist.

Any live cell with fewer than two live neighbours dies.
Any live cell with two or three live neighbours lives on.
Any live cell with more than three live neighbours dies.
Any dead cell with exactly three live neighbours becomes a live cell.
"""

import os
import sys
import copy
import curses
import random
import argparse
from time import sleep
from itertools import chain, product

class gol(object):

    def __init__(self, args):
        self.test = args.test
        self.screen = curses.initscr()
        self.screen.keypad(1)
        self.initCurses()
        self.grid = {}
        self.active = []
        max_h, max_w = self.screen.getmaxyx()
        if args.fullscreen:
            self.height = max_h
            self.width = max_w
        else:
            self.height = min(24, max_h)
            self.width = min(80, max_w)
        if args.no_hud:
            self.y_pad = 0
            self.x_pad = 0
            self.hud_pad = 0
            self.hud = False
        else:
            self.y_pad = 1
            self.x_pad = 1
            self.hud_pad = 3
            self.hud = True
        self.traditional = args.traditional
        self.y_grid = self.height - self.y_pad - self.hud_pad
        self.x_grid = self.width - self.x_pad - 1
        self.char = ['-', '+', 'o', '%', '8', '0']
        if args.n:
            self.initsize = args.n
        else:
            self.initsize = int(self.x_grid * self.y_grid * 0.15)
        self.rate = args.r
        self.current_gen = 0
        self.change_gen = [1, 2, 3]
        self.color_max = len(self.char)
        self.state = 'waiting'
        self.win = curses.newwin(self.height, self.width, 0, 0)
        self.win.nodelay(1)
        self.patchCurses()
        self.splash()
        if self.hud:
            self.drawHUD()

    def __del__(self):
        self.win.clear()
        self.win.refresh()
        curses.echo()
        curses.endwin()

    def initCurses(self):
        """
        Set up screen properties
        """
        curses.noecho()
        curses.cbreak()
        curses.curs_set(0)
        curses.start_color()
        curses.use_default_colors()
        curses.init_pair(1, curses.COLOR_WHITE, -1)
        curses.init_pair(2, curses.COLOR_YELLOW, -1)
        curses.init_pair(3, curses.COLOR_MAGENTA, -1)
        curses.init_pair(4, curses.COLOR_CYAN, -1)
        curses.init_pair(5, curses.COLOR_GREEN, -1)
        curses.init_pair(6, curses.COLOR_BLUE, -1)
        curses.init_pair(7, curses.COLOR_RED, -1)

    def patchCurses(self):
        """
        Fix curses addch function for python 3.4.0
        """
        if (sys.version_info)[:3] == (3, 4, 0):
            self.addchar = lambda y, x, *args: self.win.addch(x, y, *args)
        else:
            self.addchar = self.win.addch

    def addstr(self, y, x, text, color=0):
        self.win.addstr(self.height-y, x, str(text), curses.color_pair(color))

    def splash(self):
        """
        Draw splash screen
        """
        dirname = os.path.split(os.path.abspath(__file__))[0]
        try:
            splash = open(os.path.join(dirname, "splash"), "r").readlines()
        except IOError:
            return

        width = len(max(splash, key=len))
        y = int(self.y_grid / 2) - len(splash)
        x = int(self.x_grid / 2) - int(width / 2)

        if self.x_grid > width:
            for i, line in enumerate(splash):
                self.win.addstr(y + i, x, line, curses.color_pair(5))

    def drawHUD(self):
        """
        Draw information on population size and current generation
        """
        self.win.move(self.height - 2, self.x_pad)
        self.win.clrtoeol()
        self.win.box()
        self.addstr(2, self.x_pad + 1, "Population: %i" % len(self.grid))
        self.addstr(3, self.x_pad + 1, "Generation: %s" % self.current_gen)
        self.addstr(3, self.x_grid - 21, "s: start    p: pause")
        self.addstr(2, self.x_grid - 21, "r: restart  q: quit")

    def drawGrid(self):
        """
        Redraw the grid with the new generation
        """
        self.active = list(self.grid.keys())
        for cell in self.active:
            y, x = cell
            y += self.y_pad
            x += self.x_pad

            if self.traditional:
                sprite = '.'
                color = curses.color_pair(4)
            else:
                sprite = self.char[self.grid[cell] - 1]
                color = curses.color_pair(self.grid[cell])

            self.addchar(y, x, sprite, color)

        self.win.refresh()

    def nextGen(self):
        """
        Decide the fate of the cells
        """
        self.current_gen += 1
        self.change_gen[self.current_gen % 3] = copy.copy(self.grid)
        grid_cp = copy.copy(self.grid)
        self.active = list(self.grid.keys())

        for cell in self.active:
            y, x = cell
            y1 = (y - 1) % self.y_grid
            y2 = (y + 1) % self.y_grid
            x1 = (x - 1) % self.x_grid
            x2 = (x + 1) % self.x_grid
            n = self.countNeighbours(cell)

            if n < 2 or n > 3:
                del grid_cp[cell]
                self.addchar(y + self.y_pad, x + self.x_pad, ' ')
            else:
                grid_cp[cell] = min(self.grid[cell] + 1, self.color_max)

            for neighbour in product([y1, y, y2], [x1, x, x2]):
                if neighbour not in self.active:
                    if self.countNeighbours(neighbour) == 3:
                        y, x = neighbour
                        y = y % self.y_grid
                        x = x % self.x_grid
                        neighbour = y, x
                        grid_cp[neighbour] = 1

        self.grid = grid_cp

    def countNeighbours(self, cell):
        """
        Return the number active neighbours within one positions away from cell
        """
        count = 0
        y, x = cell
        y = y % self.y_grid
        x = x % self.x_grid
        y1 = (y - 1) % self.y_grid
        y2 = (y + 1) % self.y_grid
        x1 = (x - 1) % self.x_grid
        x2 = (x + 1) % self.x_grid
        cell = y, x

        for neighbour in product([y1, y, y2], [x1, x, x2]):
            if neighbour in self.active and neighbour != cell:
                count += 1
        return count

    def initGrid(self):
        """
        Initialise the game grid
        """
        blinker = [(4, 4), (4, 5), (4, 6)]
        toad = [(9, 5), (9, 6), (9, 7), (10, 4), (10, 5), (10, 6)]
        glider = [(4, 11), (5, 12), (6, 10), (6, 11), (6, 12)]
        r_pentomino = [(10, 60), (9, 61), (10, 61), (11, 61), (9, 62)]

        self.grid = {}
        self.active = []

        if self.test:
            for cell in chain(blinker, toad, glider, r_pentomino):
                self.grid[cell] = 1
        else:
            for _ in range(self.initsize):
                ry = random.randint(self.y_pad, self.y_grid - 1)
                rx = random.randint(self.x_pad, self.x_grid - 1)
                self.grid[(ry, rx)] = 1

    def start(self):
        """
        Game logic
        """
        self.initGrid()
        self.win.clear()
        self.state = 'running'

        while self.state == 'running':
            if self.hud:
                self.drawHUD()
            self.drawGrid()
            self.nextGen()
            sleep(self.rate)
            # Has life evolved over 2 generations
            # Better stopping condition needed
            if self.change_gen[0] == self.change_gen[2]:
                self.state = 'stopped'
                break
            key = self.win.getch()
            if key == ord('q'):
                exit()
            if key == ord('r'):
                self.restart()
            if key in [ord('p'), ord('s')]:
                self.state = 'paused'
                while self.state == 'paused':
                    key = self.win.getch()
                    if key == ord('q'):
                        exit()
                    if key == ord('r'):
                        self.state = 'running'
                        self.restart()
                    if key in [ord('s'), ord('p')]:
                        self.state = 'running'
        self.end()

    def waiting(self):
        """
        Returns true when waiting for user input
        """
        return self.state == 'waiting'

    def restart(self):
        """
        Restart the game from a new generation 0
        """
        self.initGrid()
        self.win.clear()
        self.current_gen = 1
        self.start()

    def end(self):
        """
        Game Finished - Restart or Quit
        """
        self.addstr(2, self.x_grid / 2 - 4, "GAMEOVER", 7)

        if self.hud:
            self.addstr(2, self.x_pad + 13, len(self.grid), 5)
            self.addstr(3, self.x_pad + 13, self.current_gen, 5)

        if self.test:
            exit()
        while self.state == 'stopped':
            key = self.win.getch()
            if key == ord('q'):
                exit()
            if key in [ord('s'), ord('r')]:
                self.restart()

def main():

    parser = argparse.ArgumentParser()
    parser.add_argument("-f", "--fullscreen", action="store_true",
                        default=False, help="display fullscreen grid")
    parser.add_argument("-n", type=int, metavar="initial_points",
                        help="set the number of initial points")
    parser.add_argument("-r", default=0.05, type=float, metavar="refresh_rate",
                        help="set the refresh rate")
    parser.add_argument("-t", "--traditional", action="store_true",
                        default=False, help="traditional mode")
    parser.add_argument("-s", "--no-spash", action="store_true",
                        default=False, help="don't display splash")
    parser.add_argument("-x", "--no-hud", action="store_true", default=False,
                        help="don't display HUD")
    parser.add_argument('--test', action="store_true", default=False,
                        help=argparse.SUPPRESS)

    game = gol(parser.parse_args())

    while game.waiting():
        key = game.win.getch()
        if key in [ord('s'), ord('r')]:
            game.start()
        elif key == ord('q'):
            exit()

if __name__ == "__main__":
    main()
<commit_msg>made state functions properties and --test autostart<commit_after>#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
Curses implementation of Conway's Game Of Life with an evolutionary twist.

Any live cell with fewer than two live neighbours dies.
Any live cell with two or three live neighbours lives on.
Any live cell with more than three live neighbours dies.
Any dead cell with exactly three live neighbours becomes a live cell.
"""

import os
import sys
import copy
import curses
import random
import argparse
from time import sleep
from itertools import chain, product

class gol(object):

    def __init__(self, args):
        self.test = args.test
        self.screen = curses.initscr()
        self.screen.keypad(1)
        self.initCurses()
        self.grid = {}
        self.active = []
        max_h, max_w = self.screen.getmaxyx()
        if args.fullscreen:
            self.height = max_h
            self.width = max_w
        else:
            self.height = min(24, max_h)
            self.width = min(80, max_w)
        if args.no_hud:
            self.y_pad = 0
            self.x_pad = 0
            self.hud_pad = 0
            self.hud = False
        else:
            self.y_pad = 1
            self.x_pad = 1
            self.hud_pad = 3
            self.hud = True
        self.traditional = args.traditional
        self.y_grid = self.height - self.y_pad - self.hud_pad
        self.x_grid = self.width - self.x_pad - 1
        self.char = ['-', '+', 'o', '%', '8', '0']
        if args.n:
            self.initsize = args.n
        else:
            self.initsize = int(self.x_grid * self.y_grid * 0.15)
        self.rate = args.r
        self.current_gen = 0
        self.change_gen = [1, 2, 3]
        self.color_max = len(self.char)
        self.win = curses.newwin(self.height, self.width, 0, 0)
        self.win.nodelay(1)
        self.patchCurses()
        self.splash()
        if self.hud:
            self.drawHUD()
        if not self.test:
            self.state = 'waiting'
        else:
            self.start

    def __del__(self):
        self.win.clear()
        self.win.refresh()
        curses.echo()
        curses.endwin()

    def initCurses(self):
        """
        Set up screen properties
        """
        curses.noecho()
        curses.cbreak()
        curses.curs_set(0)
        curses.start_color()
        curses.use_default_colors()
        curses.init_pair(1, curses.COLOR_WHITE, -1)
        curses.init_pair(2, curses.COLOR_YELLOW, -1)
        curses.init_pair(3, curses.COLOR_MAGENTA, -1)
        curses.init_pair(4, curses.COLOR_CYAN, -1)
        curses.init_pair(5, curses.COLOR_GREEN, -1)
        curses.init_pair(6, curses.COLOR_BLUE, -1)
        curses.init_pair(7, curses.COLOR_RED, -1)

    def patchCurses(self):
        """
        Fix curses addch function for python 3.4.0
        """
        if (sys.version_info)[:3] == (3, 4, 0):
            self.addchar = lambda y, x, *args: self.win.addch(x, y, *args)
        else:
            self.addchar = self.win.addch

    def addstr(self, y, x, text, color=0):
        self.win.addstr(self.height-y, x, str(text), curses.color_pair(color))

    def splash(self):
        """
        Draw splash screen
        """
        dirname = os.path.split(os.path.abspath(__file__))[0]
        try:
            splash = open(os.path.join(dirname, "splash"), "r").readlines()
        except IOError:
            return

        width = len(max(splash, key=len))
        y = int(self.y_grid / 2) - len(splash)
        x = int(self.x_grid / 2) - int(width / 2)

        if self.x_grid > width:
            for i, line in enumerate(splash):
                self.win.addstr(y + i, x, line, curses.color_pair(5))

    def drawHUD(self):
        """
        Draw information on population size and current generation
        """
        self.win.move(self.height - 2, self.x_pad)
        self.win.clrtoeol()
        self.win.box()
        self.addstr(2, self.x_pad + 1, "Population: %i" % len(self.grid))
        self.addstr(3, self.x_pad + 1, "Generation: %s" % self.current_gen)
        self.addstr(3, self.x_grid - 21, "s: start    p: pause")
        self.addstr(2, self.x_grid - 21, "r: restart  q: quit")

    def drawGrid(self):
        """
        Redraw the grid with the new generation
        """
        self.active = list(self.grid.keys())
        for cell in self.active:
            y, x = cell
            y += self.y_pad
            x += self.x_pad

            if self.traditional:
                sprite = '.'
                color = curses.color_pair(4)
            else:
                sprite = self.char[self.grid[cell] - 1]
                color = curses.color_pair(self.grid[cell])

            self.addchar(y, x, sprite, color)

        self.win.refresh()

    def nextGen(self):
        """
        Decide the fate of the cells
        """
        self.current_gen += 1
        self.change_gen[self.current_gen % 3] = copy.copy(self.grid)
        grid_cp = copy.copy(self.grid)
        self.active = list(self.grid.keys())

        for cell in self.active:
            y, x = cell
            y1 = (y - 1) % self.y_grid
            y2 = (y + 1) % self.y_grid
            x1 = (x - 1) % self.x_grid
            x2 = (x + 1) % self.x_grid
            n = self.countNeighbours(cell)

            if n < 2 or n > 3:
                del grid_cp[cell]
                self.addchar(y + self.y_pad, x + self.x_pad, ' ')
            else:
                grid_cp[cell] = min(self.grid[cell] + 1, self.color_max)

            for neighbour in product([y1, y, y2], [x1, x, x2]):
                if neighbour not in self.active:
                    if self.countNeighbours(neighbour) == 3:
                        y, x = neighbour
                        y = y % self.y_grid
                        x = x % self.x_grid
                        neighbour = y, x
                        grid_cp[neighbour] = 1

        self.grid = grid_cp

    def countNeighbours(self, cell):
        """
        Return the number active neighbours within one positions away from cell
        """
        count = 0
        y, x = cell
        y = y % self.y_grid
        x = x % self.x_grid
        y1 = (y - 1) % self.y_grid
        y2 = (y + 1) % self.y_grid
        x1 = (x - 1) % self.x_grid
        x2 = (x + 1) % self.x_grid
        cell = y, x

        for neighbour in product([y1, y, y2], [x1, x, x2]):
            if neighbour in self.active and neighbour != cell:
                count += 1
        return count

    def initGrid(self):
        """
        Initialise the game grid
        """
        blinker = [(4, 4), (4, 5), (4, 6)]
        toad = [(9, 5), (9, 6), (9, 7), (10, 4), (10, 5), (10, 6)]
        glider = [(4, 11), (5, 12), (6, 10), (6, 11), (6, 12)]
        r_pentomino = [(10, 60), (9, 61), (10, 61), (11, 61), (9, 62)]

        self.grid = {}
        self.active = []

        if self.test:
            for cell in chain(blinker, toad, glider, r_pentomino):
                self.grid[cell] = 1
        else:
            for _ in range(self.initsize):
                ry = random.randint(self.y_pad, self.y_grid - 1)
                rx = random.randint(self.x_pad, self.x_grid - 1)
                self.grid[(ry, rx)] = 1

    @property
    def start(self):
        """
        Game logic
        """
        self.initGrid()
        self.win.clear()
        self.state = 'running'

        while self.state == 'running':
            if self.hud:
                self.drawHUD()
            self.drawGrid()
            self.nextGen()
            sleep(self.rate)
            # Has life evolved over 2 generations
            # Better stopping condition needed
            if self.change_gen[0] == self.change_gen[2]:
                self.state = 'stopped'
                break
            key = self.win.getch()
            if key == ord('q'):
                exit()
            if key == ord('r'):
                self.restart
            if key in [ord('p'), ord('s')]:
                self.state = 'paused'
                while self.state == 'paused':
                    key = self.win.getch()
                    if key == ord('q'):
                        exit()
                    if key == ord('r'):
                        self.state = 'running'
                        self.restart
                    if key in [ord('s'), ord('p')]:
                        self.state = 'running'
        self.end()

    @property
    def waiting(self):
        """
        Returns true when waiting for user input
        """
        return self.state == 'waiting'

    @property
    def restart(self):
        """
        Restart the game from a new generation 0
        """
        self.initGrid()
        self.win.clear()
        self.current_gen = 1
        self.start

    @property
    def end(self):
        """
        Game Finished - Restart or Quit
        """
        self.addstr(2, self.x_grid / 2 - 4, "GAMEOVER", 7)

        if self.hud:
            self.addstr(2, self.x_pad + 13, len(self.grid), 5)
            self.addstr(3, self.x_pad + 13, self.current_gen, 5)

        if self.test:
            exit()
        while self.state == 'stopped':
            key = self.win.getch()
            if key == ord('q'):
                exit()
            if key in [ord('s'), ord('r')]:
                self.restart

def main():

    parser = argparse.ArgumentParser()
    parser.add_argument("-f", "--fullscreen", action="store_true",
                        default=False, help="display fullscreen grid")
    parser.add_argument("-n", type=int, metavar="initial_points",
                        help="set the number of initial points")
    parser.add_argument("-r", default=0.05, type=float, metavar="refresh_rate",
                        help="set the refresh rate")
    parser.add_argument("-t", "--traditional", action="store_true",
                        default=False, help="traditional mode")
    parser.add_argument("-x", "--no-hud", action="store_true", default=False,
                        help="don't display HUD")
    parser.add_argument('--test', action="store_true", default=False,
                        help=argparse.SUPPRESS)

    game = gol(parser.parse_args())

    while game.waiting:
        key = game.win.getch()
        if key in [ord('s'), ord('r')]:
            game.start
        elif key == ord('q'):
            exit()

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


<commit_before>#!/usr/bin/python
"""
Do basic sorting of transactions.

Author: Isaac Hailperin <isaac.hailperin@gmail.com>
"""

"""
usage: ./fina.py input files
"""

import sys
import csv
import hashlib
from collections import defaultdict
from collections import OrderedDict
import calendar
import re

from pprint import pprint

# TODO:
# add csv output

###
# Settings
###

OUTFILE = 'overview.csv'
DEFAULT_GROUP_FILE = 'samples/Umsatz_Gruppen.csv'

# From all input files,
# * create montly sums per recepient and sender
# * create montly sumps per recepient and sender category (to be defined in special input file)

def parse_input():
    """
    Parse all input files and return a dict with the data

    """
    csv.register_dialect('semicolon', delimiter=';')
    transaction_ids = []
    transactions = defaultdict( lambda : defaultdict(float))
    for infile in sys.argv[1:]:
        with open(infile, 'r') as infile_handle:
            reader = csv.DictReader(infile_handle, dialect='semicolon')
            for row in reader:
                # Calculate uniqe transaction id, so that overlapping input files do not
                # corrupt the result.
                transaction_id = hashlib.sha256(''.join(row.values())).hexdigest()
                if not transaction_id in transaction_ids:
                    transaction_ids.append(transaction_id)
                else:
                    continue
                considered_date = 'Valutadatum'
                try:
                    year = '20' + row[considered_date][6:]
                except KeyError:
                    continue
                month = row[considered_date][3:5]
                transaction_key = row['Beguenstigter/Zahlungspflichtiger']
                if not transaction_key:
                    transaction_key = row['Buchungstext']
                transactions[year + ' ' + month][transaction_key] += \
                    float(row['Betrag'].replace(',','.'))
    return transactions

def print_transactions(transactions):
    """
    Print all transactions with some formatting.

    transactions: a dict of dicts, containing all transactions
    """
    for month,tr in transactions.items():
        print
        print month
        print '==========================='
        for key,val in tr.items():
            print key + ' :: ' + str(val)

def print_transactions_as_csv(transactions):
    """
    Print all transactions as csv

    Structure:
    month1,group1,group2, ...,no_group1,nogroup2, ....
    month2,group1,group2, ...,no_group1,nogroup2, ....
    [{},{}]

    groups and no_groups should be a uniq list, built from all months, so that
    it is easy to see how a certain group evolves over the month

    Also, groups should be sorted according to their overall sum, so that the
    largest sums are to the left.

    """
    restructured_transactions = restructure(transactions)
    sorted_transactions = sort_by_value_and_groups(restructured_transactions)
    pprint(restructured_transactions)

def sort_by_value_and_groups(transactions):
    """
    Sort according to grouped and ungroupped, within these sort by
    highest overall sum.

    transactions: output of restructure()

    """
    pass

def restructure(transactions):
    """
    Restructure transactions, so that each month every possible positin gets listed,
    even if its value is zero.

    transactions: ordered dict of transactions
    """
    all_months = [tr.items() for month,tr in transactions.items()]
    all_groups_listed = [[x[0] for x in g] for g in all_months]
    all_groups = set([item for sublist in all_groups_listed for item in sublist])
    all_transactions = []
    for month,tr in transactions.items():
        months_transactions = {month: {}}
        for group in all_groups:
            value = tr.get(group, 0)
            months_transactions[month][group] = value
        all_transactions.append(months_transactions)
    return all_transactions

def get_groups(group_file=DEFAULT_GROUP_FILE):
    """
    Get transactions groups, return a dict of regular expressions

    """
    transaction_groups = defaultdict(list)
    transaction_group_res = {}
    with open(group_file, 'r') as group_file_handle:
        reader = csv.DictReader(group_file_handle)
        for row in reader:
            for group_name,group_re in row.items():
                if group_re:
                    transaction_groups[group_name].append(group_re)
    check_uniquenes(transaction_groups)
    for group_name,group_res in transaction_groups.items():
        transaction_group_res[group_name] = '|'.join(group_res)
    return transaction_group_res

def check_uniquenes(transaction_groups):
    """
    Check for doubles in transaction_groups.

    transaction_groups: dict of transactions groups
    """
    group_members = [i for v in transaction_groups.values() for i in v]
    num_occurence = defaultdict(int)
    for member in group_members:
        num_occurence[member] += 1
    doubles = [k for k,v in num_occurence.items() if v > 1]
    if doubles:
        print 'The following items are not unique in group configuration:'
        print doubles
        exit()
    # now we also check for regex matches
    for member_re in group_members:
        for member in group_members:
            if member_re == member:
                continue
            if re.search(member_re, member, re.IGNORECASE):
                print member + ' is not a unique regular expression, it matches with ' + member_re
                exit()

def group_transactions(transactions):
    """
    Group transactions according to config sheet.

    transactions: all transactions in dict form

    """
    grouped_transactions = defaultdict( lambda : defaultdict(float))
    groups = get_groups()
    for month,m_transactions in transactions.items():
        for who in m_transactions.keys():
            for group_name,group_re in groups.items():
                if re.search(group_re, who, flags=re.IGNORECASE):
                    grouped_transactions[month][group_name] += m_transactions[who]
                    m_transactions.pop(who, None)
        # do something with the rest of m_transactions
        for who in m_transactions.keys():
            grouped_transactions[month]['NOT GROUPED ' + who] = m_transactions[who]
            m_transactions.pop(who, None)
    # sort transactions according to month
    sorted_transactions = OrderedDict()
    months = [m for m,t in grouped_transactions.items()]
    months.sort()
    for month in months:
        month_named = calendar.month_name[int(month.split()[1])] + ' ' + month.split()[0]
        sorted_transactions[month_named] = grouped_transactions[month]
    return sorted_transactions

transactions = parse_input()
grouped_transactions = group_transactions(transactions)
if __name__ == '__main__':
    #print_transactions(grouped_transactions)
    print_transactions_as_csv(grouped_transactions)

<commit_msg>csv output works<commit_after>#!/usr/bin/python
"""
Do basic sorting of transactions.

Author: Isaac Hailperin <isaac.hailperin@gmail.com>
"""

"""
usage: ./fina.py input files
"""

import sys
import csv
import hashlib
from collections import defaultdict
from collections import OrderedDict
import calendar
import re

from pprint import pprint

# TODO:
# add csv output

###
# Settings
###

OUTFILE = 'overview.csv'
DEFAULT_GROUP_FILE = 'samples/Umsatz_Gruppen.csv'

# From all input files,
# * create montly sums per recepient and sender
# * create montly sumps per recepient and sender category (to be defined in special input file)

def parse_input():
    """
    Parse all input files and return a dict with the data

    """
    csv.register_dialect('semicolon', delimiter=';')
    transaction_ids = []
    transactions = defaultdict( lambda : defaultdict(float))
    for infile in sys.argv[1:]:
        with open(infile, 'r') as infile_handle:
            reader = csv.DictReader(infile_handle, dialect='semicolon')
            for row in reader:
                # Calculate uniqe transaction id, so that overlapping input files do not
                # corrupt the result.
                transaction_id = hashlib.sha256(''.join(row.values())).hexdigest()
                if not transaction_id in transaction_ids:
                    transaction_ids.append(transaction_id)
                else:
                    continue
                considered_date = 'Valutadatum'
                try:
                    year = '20' + row[considered_date][6:]
                except KeyError:
                    continue
                month = row[considered_date][3:5]
                transaction_key = row['Beguenstigter/Zahlungspflichtiger']
                if not transaction_key:
                    transaction_key = row['Buchungstext']
                transactions[year + ' ' + month][transaction_key] += \
                    float(row['Betrag'].replace(',','.'))
    return transactions

def print_transactions(transactions):
    """
    Print all transactions with some formatting.

    transactions: a dict of dicts, containing all transactions
    """
    for month,tr in transactions.items():
        print
        print month
        print '==========================='
        for key,val in tr.items():
            print key + ' :: ' + str(val)

def print_transactions_as_csv(transactions):
    """
    Print all transactions as csv

    Structure:
    month1,group1,group2, ...,no_group1,nogroup2, ....
    month2,group1,group2, ...,no_group1,nogroup2, ....
    [{},{}]

    groups and no_groups should be a uniq list, built from all months, so that
    it is easy to see how a certain group evolves over the month

    Also, groups should be sorted according to their overall sum, so that the
    largest sums are to the left.

    """
    restructured_transactions = restructure(transactions)
    sorted_sums = sort_by_value_and_groups(restructured_transactions)
    csv_data = combine(restructured_transactions, sorted_sums)
    field_names = ['Monat'] + [x[0] for x in sorted_sums]
    out_file = 'Ausgaben.csv'
    with open(out_file, 'w') as csvfile:
        writer = csv.DictWriter(csvfile, fieldnames=field_names)
        writer.writeheader()
        for row in csv_data:
            writer.writerow(row)
    print('Ergebnis wurd in die Datei ' + out_file + ' geschrieben.')

def combine(restructured_transactions, sorted_sums):
    """
    Combine restructured_transactions and sorted_sums in way suitable for writing
    with a dict writer.

    """
    csv_data = []
    for month_tr in restructured_transactions:
        month = month_tr.keys()[0]
        transactions = month_tr.values()[0]
        transactions.update({'Monat': month})
        csv_data.append(transactions)
    sums = dict(sorted_sums)
    sums.update({'Monat':'Summe'})
    csv_data.append(sums)
    return csv_data

def sort_by_value_and_groups(transactions):
    """
    Sort according to grouped and ungroupped, within these sort by
    highest overall sum.

    transactions: output of restructure()

    """
    # calculate overall sums
    all_groups = transactions[0].values()[0]
    all_sums = defaultdict(float)
    for month_tr in transactions:
        for group,value in month_tr.values()[0].items():
            all_sums[group] += value
    # devide by grouped and ungrouped
    grouped = [ (k,v) for k,v in all_sums.items() if not k.startswith('NOT GROUPED')]
    ungrouped = [ (k,v) for k,v in all_sums.items() if k.startswith('NOT GROUPED')]
    # sort
    grouped.sort(key=lambda x: x[1])
    ungrouped.sort(key=lambda x: x[1])
    return grouped + ungrouped

def restructure(transactions):
    """
    Restructure transactions, so that each month every possible positin gets listed,
    even if its value is zero.

    transactions: ordered dict of transactions
    """
    all_months = [tr.items() for month,tr in transactions.items()]
    all_groups_listed = [[x[0] for x in g] for g in all_months]
    all_groups = set([item for sublist in all_groups_listed for item in sublist])
    all_transactions = []
    for month,tr in transactions.items():
        months_transactions = {month: {}}
        for group in all_groups:
            value = tr.get(group, 0)
            months_transactions[month][group] = value
        all_transactions.append(months_transactions)
    return all_transactions

def get_groups(group_file=DEFAULT_GROUP_FILE):
    """
    Get transactions groups, return a dict of regular expressions

    """
    transaction_groups = defaultdict(list)
    transaction_group_res = {}
    with open(group_file, 'r') as group_file_handle:
        reader = csv.DictReader(group_file_handle)
        for row in reader:
            for group_name,group_re in row.items():
                if group_re:
                    transaction_groups[group_name].append(group_re)
    check_uniquenes(transaction_groups)
    for group_name,group_res in transaction_groups.items():
        transaction_group_res[group_name] = '|'.join(group_res)
    return transaction_group_res

def check_uniquenes(transaction_groups):
    """
    Check for doubles in transaction_groups.

    transaction_groups: dict of transactions groups
    """
    group_members = [i for v in transaction_groups.values() for i in v]
    num_occurence = defaultdict(int)
    for member in group_members:
        num_occurence[member] += 1
    doubles = [k for k,v in num_occurence.items() if v > 1]
    if doubles:
        print 'The following items are not unique in group configuration:'
        print doubles
        exit()
    # now we also check for regex matches
    for member_re in group_members:
        for member in group_members:
            if member_re == member:
                continue
            if re.search(member_re, member, re.IGNORECASE):
                print member + ' is not a unique regular expression, it matches with ' + member_re
                exit()

def group_transactions(transactions):
    """
    Group transactions according to config sheet.

    transactions: all transactions in dict form

    """
    grouped_transactions = defaultdict( lambda : defaultdict(float))
    groups = get_groups()
    for month,m_transactions in transactions.items():
        for who in m_transactions.keys():
            for group_name,group_re in groups.items():
                if re.search(group_re, who, flags=re.IGNORECASE):
                    grouped_transactions[month][group_name] += m_transactions[who]
                    m_transactions.pop(who, None)
        # do something with the rest of m_transactions
        for who in m_transactions.keys():
            grouped_transactions[month]['NOT GROUPED ' + who] = m_transactions[who]
            m_transactions.pop(who, None)
    # sort transactions according to month
    sorted_transactions = OrderedDict()
    months = [m for m,t in grouped_transactions.items()]
    months.sort()
    for month in months:
        month_named = calendar.month_name[int(month.split()[1])] + ' ' + month.split()[0]
        sorted_transactions[month_named] = grouped_transactions[month]
    return sorted_transactions

transactions = parse_input()
grouped_transactions = group_transactions(transactions)
if __name__ == '__main__':
    #print_transactions(grouped_transactions)
    print_transactions_as_csv(grouped_transactions)

<|endoftext|>