<commit_before>#! /usr/bin/env python
#
# Example program using irc.bot.
#
# Joel Rosdahl <joel@rosdahl.net>

"""A simple example bot.

This is an example bot that uses the SingleServerIRCBot class from
irc.bot.  The bot enters a channel and listens for commands in
private messages and channel traffic.  Commands in channel messages
are given by prefixing the text by the bot name followed by a colon.
It also responds to DCC CHAT invitations and echos data sent in such
sessions.

The known commands are:

    stats -- Prints some channel information.

    disconnect -- Disconnect the bot.  The bot will try to reconnect
                  after 60 seconds.

    die -- Let the bot cease to exist.

    dcc -- Let the bot invite you to a DCC CHAT connection.
"""

import irc.bot
import irc.strings
from irc.client import ip_numstr_to_quad, ip_quad_to_numstr

class TestBot(irc.bot.SingleServerIRCBot):
    def __init__(self, channel, nickname, server, port=6667):
        irc.bot.SingleServerIRCBot.__init__(self, [(server, port)], nickname, nickname)
        self.channel = channel

    def on_nicknameinuse(self, c, e):
        c.nick(c.get_nickname() + "_")

    def on_welcome(self, c, e):
        c.join(self.channel)

    def on_privmsg(self, c, e):
        self.do_command(e, e.arguments[0])

    def on_pubmsg(self, c, e):
        a = e.arguments[0].split(":", 1)
        if len(a) > 1 and irc.strings.lower(a[0]) == irc.strings.lower(self.connection.get_nickname()):
            self.do_command(e, a[1].strip())
        return

    def on_dccmsg(self, c, e):
        c.privmsg("You said: " + e.arguments[0])

    def on_dccchat(self, c, e):
        if len(e.arguments) != 2:
            return
        args = e.arguments[1].split()
        if len(args) == 4:
            try:
                address = ip_numstr_to_quad(args[2])
                port = int(args[3])
            except ValueError:
                return
            self.dcc_connect(address, port)

    def do_command(self, e, cmd):
        nick = e.source.nick
        c = self.connection

        if cmd == "disconnect":
            self.disconnect()
        elif cmd == "die":
            self.die()
        elif cmd == "stats":
            for chname, chobj in self.channels.items():
                c.notice(nick, "--- Channel statistics ---")
                c.notice(nick, "Channel: " + chname)
                users = sorted(chobj.users())
                c.notice(nick, "Users: " + ", ".join(users))
                opers = sorted(chobj.opers())
                c.notice(nick, "Opers: " + ", ".join(opers))
                voiced = sorted(chobj.voiced())
                c.notice(nick, "Voiced: " + ", ".join(voiced))
        elif cmd == "dcc":
            dcc = self.dcc_listen()
            c.ctcp("DCC", nick, "CHAT chat %s %d" % (
                ip_quad_to_numstr(dcc.localaddress),
                dcc.localport))
        else:
            c.notice(nick, "Not understood: " + cmd)

def main():
    import sys
    if len(sys.argv) != 4:
        print("Usage: testbot <server[:port]> <channel> <nickname>")
        sys.exit(1)

    s = sys.argv[1].split(":", 1)
    server = s[0]
    if len(s) == 2:
        try:
            port = int(s[1])
        except ValueError:
            print("Error: Erroneous port.")
            sys.exit(1)
    else:
        port = 6667
    channel = sys.argv[2]
    nickname = sys.argv[3]

    bot = TestBot(channel, nickname, server, port)
    bot.start()

if __name__ == "__main__":
    main()
<commit_msg>Decode raw bytes when handling DCC message. Is this the proper fix? Ref #57.<commit_after>#! /usr/bin/env python
#
# Example program using irc.bot.
#
# Joel Rosdahl <joel@rosdahl.net>

"""A simple example bot.

This is an example bot that uses the SingleServerIRCBot class from
irc.bot.  The bot enters a channel and listens for commands in
private messages and channel traffic.  Commands in channel messages
are given by prefixing the text by the bot name followed by a colon.
It also responds to DCC CHAT invitations and echos data sent in such
sessions.

The known commands are:

    stats -- Prints some channel information.

    disconnect -- Disconnect the bot.  The bot will try to reconnect
                  after 60 seconds.

    die -- Let the bot cease to exist.

    dcc -- Let the bot invite you to a DCC CHAT connection.
"""

import irc.bot
import irc.strings
from irc.client import ip_numstr_to_quad, ip_quad_to_numstr

class TestBot(irc.bot.SingleServerIRCBot):
    def __init__(self, channel, nickname, server, port=6667):
        irc.bot.SingleServerIRCBot.__init__(self, [(server, port)], nickname, nickname)
        self.channel = channel

    def on_nicknameinuse(self, c, e):
        c.nick(c.get_nickname() + "_")

    def on_welcome(self, c, e):
        c.join(self.channel)

    def on_privmsg(self, c, e):
        self.do_command(e, e.arguments[0])

    def on_pubmsg(self, c, e):
        a = e.arguments[0].split(":", 1)
        if len(a) > 1 and irc.strings.lower(a[0]) == irc.strings.lower(self.connection.get_nickname()):
            self.do_command(e, a[1].strip())
        return

    def on_dccmsg(self, c, e):
        # non-chat DCC messages are raw bytes; decode as text
        text = e.arguments[0].decode('utf-8')
        c.privmsg("You said: " + text)

    def on_dccchat(self, c, e):
        if len(e.arguments) != 2:
            return
        args = e.arguments[1].split()
        if len(args) == 4:
            try:
                address = ip_numstr_to_quad(args[2])
                port = int(args[3])
            except ValueError:
                return
            self.dcc_connect(address, port)

    def do_command(self, e, cmd):
        nick = e.source.nick
        c = self.connection

        if cmd == "disconnect":
            self.disconnect()
        elif cmd == "die":
            self.die()
        elif cmd == "stats":
            for chname, chobj in self.channels.items():
                c.notice(nick, "--- Channel statistics ---")
                c.notice(nick, "Channel: " + chname)
                users = sorted(chobj.users())
                c.notice(nick, "Users: " + ", ".join(users))
                opers = sorted(chobj.opers())
                c.notice(nick, "Opers: " + ", ".join(opers))
                voiced = sorted(chobj.voiced())
                c.notice(nick, "Voiced: " + ", ".join(voiced))
        elif cmd == "dcc":
            dcc = self.dcc_listen()
            c.ctcp("DCC", nick, "CHAT chat %s %d" % (
                ip_quad_to_numstr(dcc.localaddress),
                dcc.localport))
        else:
            c.notice(nick, "Not understood: " + cmd)

def main():
    import sys
    if len(sys.argv) != 4:
        print("Usage: testbot <server[:port]> <channel> <nickname>")
        sys.exit(1)

    s = sys.argv[1].split(":", 1)
    server = s[0]
    if len(s) == 2:
        try:
            port = int(s[1])
        except ValueError:
            print("Error: Erroneous port.")
            sys.exit(1)
    else:
        port = 6667
    channel = sys.argv[2]
    nickname = sys.argv[3]

    bot = TestBot(channel, nickname, server, port)
    bot.start()

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


<commit_before>class Scale:
    notes = ['C',  # Do
             'D♭',
             'D',  # Re
             'E♭',
             'E',  # Mi
             'F',  # Fa
             'G♭',
             'G',  # Sol
             'A♭',
             'A',  # La
             'B♭',
             'B']  # Si

    scales = {'major': ['C', 'D', 'E', 'F', 'G', 'A', 'B'],
              'minor': ['C', 'D', 'E♭', 'F', 'G', 'A♭', 'B♭']}

    def __init__(self, scale, fretboard, strings=None):
        self.scale = scale
        self.fretboard = fretboard
        self.strings = strings or {'bass': 4, 'guitar': 6}.get(fretboard)

    def render(self):
        print(" ".join(Scale.scales[self.scale]))

        # print("\n".join(["|··{}{}{}{}{}··".format('·', '·', '·', '·', '·')
        #                  for _ in range(0, self.strings)]))
<commit_msg>print the bass major scale (dead simple)<commit_after>class Scale:
    notes = ['C',  # Do
             'D♭',
             'D',  # Re
             'E♭',
             'E',  # Mi
             'F',  # Fa
             'G♭',
             'G',  # Sol
             'A♭',
             'A',  # La
             'B♭',
             'B']  # Si

    matrix = [('D', 'E♭', 'E', 'F', 'G♭'),
              ('A', 'B♭', 'B', 'C', 'D♭'),
              ('E', 'F', 'G♭', 'G', 'A♭'),
              ('B', 'C', 'D♭', 'D', 'E♭')]

    scales = {'major': ['C', 'D', 'E', 'F', 'G', 'A', 'B'],
              'minor': ['C', 'D', 'E♭', 'F', 'G', 'A♭', 'B♭']}

    def __init__(self, scale, fretboard, strings=None):
        self.scale = scale
        self.fretboard = fretboard
        self.strings = strings or {'bass': 4, 'guitar': 6}.get(fretboard)

    def render(self):
        scale_notes = self.scales[self.scale]
        print(" ".join(scale_notes))

        for line in self.matrix:
            print("|··", end='')

            [print(self._get_note_symbol(note, scale_notes), end='')
             for note in line]

            print("·")

    def _get_note_symbol(self, note, scale_notes):
        if note not in scale_notes:
            return "·"

        return "●" if note == 'C' else '○'
<|endoftext|>


<commit_before>import xlrd

class xls_to_mongodb2():
    def __init__(self, path_to_xls, db):
        self.db = db
        self.workbook = xlrd.open_workbook(path_to_xls)

    def populate_shows(self):
        worksheet = self.workbook.sheet_by_index(0)
        first_row = []  # The row where we stock the name of the column
        for col in range(worksheet.ncols):
            first_row.append(worksheet.cell_value(0, col))
        # transform the workbook to a list of dictionaries
        data = []
        for row in range(1, worksheet.nrows):
            elm = {}
            for col in range(worksheet.ncols):
                elm[first_row[col]] = worksheet.cell_value(row, col)
                elm['sequences'] = []
                elm['ptuid'] = 1
                elm['active'] = False
                elm['assets'] = []
            data.append(elm)
        for document in data:
            if db.shows.find({"name": document['name']}).count() > 0:
                print("{} already exists!".format(document['name']))
            else:
                print("let's insert this bad boy! {}".format(document['name']))
                print("doing it...")
                db.shows.insert_one(document)
                print("bad boy inserted!")

load_xls = xls_to_mongodb2("/home/geoff/Downloads/cyc-template.xlsx", db)
load_xls.populate_shows()
<commit_msg>wip on testxls.py<commit_after>import xlrd
from scripts import db_actions as dba

class xls_to_mongodb():
    def __init__(self, path_to_xls, db):
        self.db = db
        self.workbook = xlrd.open_workbook(path_to_xls)

    def pull_data(self, sheet_page):
        worksheet = self.workbook.sheet_by_index(sheet_page)
        first_row = []  # The row where we stock the name of the column
        for col in range(worksheet.ncols):
            first_row.append(worksheet.cell_value(0, col))
        # transform the workbook to a list of dictionaries
        data = []
        for row in range(1, worksheet.nrows):
            elm = {}
            for col in range(worksheet.ncols):
                elm[first_row[col]] = worksheet.cell_value(row, col)
            data.append(elm)
        return data

    def populate_shows(self):
        data = self.pull_data(0)
        for document in data:
            if self.db.shows.find({"name": document['name']}).count() > 0:
                print("{} already exists!".format(document['name']))
            else:
                dba.create_show(document['long_name'], document['name'])
                print("{} will be inserted".format(document['name']))

    def populate_seqs(self):
        data = self.pull_data(1)
        for document in data:
            if self.db.seqs.find({"name": document['name']}).count() > 0:
                print("{} already exists!".format(document['name']))
            else:
#                 dba.create_show(document['long_name'], document['name'])
                print("{} will be inserted".format(document['name']))

# load_xls = xls_to_mongodb("/home/geoff/Downloads/cyc-template.xlsx", db)
# load_xls.populate_shows()
<|endoftext|>


<commit_before>"""
Timer class.

1-14-2017
"""

import time
import sys
import shutil

class EstimateTime():

    def __init__(self, njobs, mode='moving_average'):
        self.njobs = njobs
        self.mode = mode
        self.last_timestamp = time.time()
        # Differential time log that moving average uses
        self.dtime_log = []
        # Number of time points to keep in differential time log for
        #  moving average
        self.__keep_pts = round(0.25 * njobs)
        self.__iteration = 0
        self.__elapsed = 0
        self.__alg = {
            'moving_average': self.__moving_average,
            'average': self.__average
        }

    def __average(self):
        """Returns the average time per iteration"""
        return sum(self.dtime_log) / len(self.dtime_log)

    def __moving_average(self):
        """Returns the moving average time per iteration"""
        if len(self.dtime_log) > self.__keep_pts:
            self.dtime_log.pop(0)
        return sum(self.dtime_log) / len(self.dtime_log)

    def est(self):
        """This method returns the estimated time"""
        try:
            time_per_iteration =  self.__alg[self.mode]()
            return (self.njobs - self.__iteration) * time_per_iteration
        except ZeroDivisionError:
            return 0

    def stop_watch(self):
        """This method needs to be called to initiate another
        round of computation for time estimation
        """
        self.__iteration += 1
        dtime = time.time() - self.last_timestamp
        self.last_timestamp = time.time()
        self.dtime_log.append(dtime)

class Timer():
    """
    The timer object times the operations and prints out a nice progress bar.
    At the end of the operation, the timer will print out the total time
    taken so far.

    Usage: Initialize the class by calling timer = Timer(total_number_of_jobs),
           then at the end of each job (such as in a for loop after every
           task) invoke timer.progress() and the progress bar and the time
           estimation will be updated.

           At the end of the program, that is after all specified jobs
           are finished, the total elapsed time will be automatically shown
           unless the show_elapsed option is set to False.
    """

    def __init__(self, total, jname='', mode='auto'):
        """
        Initializes the timer object

        Args: "total" is the total number of jobs that would take roughly
              the same amount of time to finish.
              "barlength" is the length of the bar that will be shown
              on screen. The default is 25.
              "show_elapsed" controls whether the final elapsed time is shown
              after the program finishes. The default is "True."
        """
        self.__start_time = time.time()
        self.iteration = 0
        self.total = total

        # Initiate EstimateTime class to enable precise time estimation.
        self.estimatetime = EstimateTime(self.total, mode)

        # Prints the job name on screen if a name was given, then show the
        #  progress bar.
        if jname is not '':
            print(jname.title())
        self.__show_progress()

    def __update_progress(self):
        """
        Increments self.iteration by 1 every time this method is called.
        """
        self.iteration += 1

    def __sec_to_human_readable_format(self, time):
        """
        Converts time (in seconds) into the HHMMSS format. Returns a string.
        """
        Days = str(int(time // 86400))
        Hr = int((time % 86400) // 3600)
        if Hr < 10:
            Hr = "0" + str(Hr)
        else:
            Hr = str(Hr)
        Min = int((time % 3600) // 60)
        if Min < 10:
            Min = "0" + str(Min)
        else:
            Min = str(Min)
        Sec = round(time % 60)
        if Sec < 10:
            Sec = "0" + str(Sec)
        else:
            Sec = str(Sec)
        if Days == str(0):
            elapsed_time = Hr + ":" + Min + ":" + Sec + "        "
        elif Days == str(1):
            elapsed_time = Days + " Day " + Hr + ":" + Min + ":" + Sec + "  "
        else:
            elapsed_time = Days + " Days " + Hr + ":" + Min + ":" + Sec

        return elapsed_time

    def __show_progress(self):
        """
        Shows the progress bar on screen. When being called after the
        first time, it updates the progress bar.
        """
        term_width = list(shutil.get_terminal_size())[0]
        if self.iteration == 0:
            report_time = ""
            barlength = term_width - 49
            filledlength = 0
            percent = 0
        else:
            # Calculate time used for progress report purposes.
            elapsed = self.elapsed_time()
            est_time = self.estimatetime.est()

            if self.iteration == self.total:
                est_time = 0
            ET = self.__sec_to_human_readable_format(est_time)

            report_time = "Est. time: {}  Elapsed: {}".format(ET, elapsed)
            barlength = term_width - len(report_time) - 1
            filledlength = int(round(barlength * (self.iteration) / self.total))
            percent = round(100.00 * ((self.iteration) / self.total), 1)

        bar = '\u2588' * filledlength + '\u00B7' * (barlength - filledlength)
        sys.stdout.write('\r%s |%s| %s%s %s' % ('Progress:', bar,
                                                percent, '%  ', report_time)),
        sys.stdout.flush()
        if self.iteration == self.total:
            sys.stdout.write('\n')
            sys.stdout.flush()

    def elapsed_time(self):
        """Prints the total elapsed time."""
        elapsed = time.time() - self.__start_time
        elapsed_time = self.__sec_to_human_readable_format(elapsed)
        return elapsed_time

    def progress(self):
        """Prints the progress on screen"""
        # Update the progress.
        if self.iteration < self.total:
            self.estimatetime.stop_watch()
            self.__update_progress()
            self.__show_progress()
<commit_msg>Fixed the progress bar length<commit_after>"""
Timer class.

1-14-2017
"""

import time
import sys
import shutil

class EstimateTime():

    def __init__(self, njobs, mode='moving_average'):
        self.njobs = njobs
        self.mode = mode
        self.last_timestamp = time.time()
        # Differential time log that moving average uses
        self.dtime_log = []
        # Number of time points to keep in differential time log for
        #  moving average
        self.__keep_pts = round(0.25 * njobs)
        self.__iteration = 0
        self.__elapsed = 0
        self.__alg = {
            'moving_average': self.__moving_average,
            'average': self.__average
        }

    def __average(self):
        """Returns the average time per iteration"""
        return sum(self.dtime_log) / len(self.dtime_log)

    def __moving_average(self):
        """Returns the moving average time per iteration"""
        if len(self.dtime_log) > self.__keep_pts:
            self.dtime_log.pop(0)
        return sum(self.dtime_log) / len(self.dtime_log)

    def est(self):
        """This method returns the estimated time"""
        try:
            time_per_iteration =  self.__alg[self.mode]()
            return (self.njobs - self.__iteration) * time_per_iteration
        except ZeroDivisionError:
            return 0

    def stop_watch(self):
        """This method needs to be called to initiate another
        round of computation for time estimation
        """
        self.__iteration += 1
        dtime = time.time() - self.last_timestamp
        self.last_timestamp = time.time()
        self.dtime_log.append(dtime)

class Timer():
    """
    The timer object times the operations and prints out a nice progress bar.
    At the end of the operation, the timer will print out the total time
    taken so far.

    Usage: Initialize the class by calling timer = Timer(total_number_of_jobs),
           then at the end of each job (such as in a for loop after every
           task) invoke timer.progress() and the progress bar and the time
           estimation will be updated.

           At the end of the program, that is after all specified jobs
           are finished, the total elapsed time will be automatically shown
           unless the show_elapsed option is set to False.
    """

    def __init__(self, total, jname='', mode='auto'):
        """
        Initializes the timer object

        Args: "total" is the total number of jobs that would take roughly
              the same amount of time to finish.
              "barlength" is the length of the bar that will be shown
              on screen. The default is 25.
              "show_elapsed" controls whether the final elapsed time is shown
              after the program finishes. The default is "True."
        """
        self.__start_time = time.time()
        self.iteration = 0
        self.total = total

        # Initiate EstimateTime class to enable precise time estimation.
        self.estimatetime = EstimateTime(self.total, mode)

        # Prints the job name on screen if a name was given, then show the
        #  progress bar.
        if jname is not '':
            print(jname.title())
        self.__show_progress()

    def __update_progress(self):
        """
        Increments self.iteration by 1 every time this method is called.
        """
        self.iteration += 1

    def __sec_to_human_readable_format(self, time):
        """
        Converts time (in seconds) into the HHMMSS format. Returns a string.
        """
        Days = str(int(time // 86400))
        Hr = int((time % 86400) // 3600)
        if Hr < 10:
            Hr = "0" + str(Hr)
        else:
            Hr = str(Hr)
        Min = int((time % 3600) // 60)
        if Min < 10:
            Min = "0" + str(Min)
        else:
            Min = str(Min)
        Sec = round(time % 60)
        if Sec < 10:
            Sec = "0" + str(Sec)
        else:
            Sec = str(Sec)
        if Days == str(0):
            elapsed_time = Hr + ":" + Min + ":" + Sec + "        "
        elif Days == str(1):
            elapsed_time = Days + " Day " + Hr + ":" + Min + ":" + Sec + "  "
        else:
            elapsed_time = Days + " Days " + Hr + ":" + Min + ":" + Sec

        return elapsed_time

    def __show_progress(self):
        """
        Shows the progress bar on screen. When being called after the
        first time, it updates the progress bar.
        """
        term_width = list(shutil.get_terminal_size())[0]
        if self.iteration == 0:
            report_time = ""
            barlength = term_width - 72
            filledlength = 0
            percent = 0
        else:
            # Calculate time used for progress report purposes.
            elapsed = self.elapsed_time()
            est_time = self.estimatetime.est()

            if self.iteration == self.total:
                est_time = 0
            ET = self.__sec_to_human_readable_format(est_time)

            report_time = "Est. time: {}  Elapsed: {}".format(ET, elapsed)
            barlength = term_width - len(report_time) - 22
            filledlength = int(round(barlength * (self.iteration) / self.total))
            percent = round(100.00 * ((self.iteration) / self.total), 1)

        bar = '\u2588' * filledlength + '\u00B7' * (barlength - filledlength)
        sys.stdout.write('\r%s |%s| %s%s %s' % ('Progress:', bar,
                                                percent, '%  ', report_time)),
        sys.stdout.flush()
        if self.iteration == self.total:
            sys.stdout.write('\n')
            sys.stdout.flush()

    def elapsed_time(self):
        """Prints the total elapsed time."""
        elapsed = time.time() - self.__start_time
        elapsed_time = self.__sec_to_human_readable_format(elapsed)
        return elapsed_time

    def progress(self):
        """Prints the progress on screen"""
        # Update the progress.
        if self.iteration < self.total:
            self.estimatetime.stop_watch()
            self.__update_progress()
            self.__show_progress()
<|endoftext|>


<commit_before>"""
Script to write a JSON file containing relevant meta information.

Each grid type and property is stored in a separate file.
Due to JSON not supporting NaN and Infinity, such values are
converted into strings and then stored in JSON. The receiving
code will need to handle those values appropriately.

The JSON file will be a dict mapping a unique identifier to the property.

    states
        id: fips, 2-character string

    counties
        id: geoid, 5-character string

    squares
        id: _id, integer specifying the i^th cell in the enumeration
        from the lower-left corner of the bounding box

Properties:

    demographics.json
        state fips
            name : state name
            abbr : state abbreviation
        county geoid
            name  : county name
            state : state fips

    grids.states.bot_filtered.{property}.json
    grids.counties.bot_filtered.{property}.json
        Keyed by state fips or county geoid.

        property                description
        --------------------------------------------------------------------
        respop72013             resident population 07/2013
        landarea                total land area
        tweeted_hashtags        the number of tweeted hashtags
        distinct_hashtags       the number of distinct hashtags
        users                   the number of users that tweeted in an area
        mle_entropy             entropy of hashtag distribution
        top5000ratios           missing ratios using top 5000 hashtags
        topX70ratios            included ratios for top X=70% hashtags

    grids.squares.bot_filtered.{property}.json
        Keyed by cell id as string

        property                description
        ------------------------------------------------------------------
        area                    total area (land+water)
        tweeted_hashtags        the number of tweeted hashtags
        distinct_hashtags       the number of distinct hashtags
        users                   the number of users that tweeted in an area
        mle_entropy             entropy of hashtag distribution
        top5000ratios           missing ratios using top 5000 hashtags
        topX70ratios            included ratios for top X=70% hashtags

"""
from collections import OrderedDict, defaultdict
import us
import fiona
import pandas
import dit
import twitterproj
import numpy as np
import json

def entropy(place):
    """
    Return the entropy of a county's hashtag counts.

    """
    pmf = np.array( place['counts'].values(), dtype=float)
    pmf /= pmf.sum()
    H = dit.shannon.entropy_pmf(pmf)
    # Handle NaN since json can't.
    if np.isnan(H):
        H = "NaN"
    return H

def names():
    # We use a single file for this one.

    data = defaultdict(dict)

    # The abbreviations of the contiguous states
    desired = us.states.mapping('abbr', 'fips', us.STATES_CONTIGUOUS)

    # States
    with fiona.open('../tiger/tl_2014_us_state.shp') as f:
        for state in f:
            state = state['properties']
            fips = state['STATEFP']
            abbr = state['STUSPS']
            if abbr not in desired:
                continue
            data[fips]['name'] = state['NAME']
            data[fips]['abbr'] = abbr

    # Counties
    with fiona.open('../tiger/tl_2014_us_county.shp') as f:
        for county in f:
            county = county['properties']
            # Keep only counties in contiguous states.
            state_fips = county['STATEFP']
            if state_fips not in data:
                continue
            geoid = county['GEOID']
            data[geoid]['name'] = county['NAMELSAD']
            data[geoid]['state'] = state_fips

    with open('json/names.json', 'w') as f:
        json.dump(data, f)

    return data

def population():

    # State
    data_state = {}
    df = pandas.read_csv('../census/state/PEP_2013_PEPANNRES_with_ann.csv')
    for state in df.values[1:]: # Skip column headers
        fips = state[1]
        data_state[fips] = int(state[-1])

    vals = np.array(data_state.values())
    data_state['norm'] = vals.sum()
    data_state['min'] = vals.min()
    data_state['max'] = vals.max()

    with open('json/grids.states.bot_filtered.respop72013.json', 'w') as f:
        json.dump(data_state, f)

    # County
    data_county = {}
    df = pandas.read_csv('../census/county/PEP_2013_PEPANNRES_with_ann.csv')
    for county in df.values[1:]: # Skip column headers
        geoid = county[1]
        data_county[geoid] = int(county[-1])

    vals = np.array(data_county.values())
    data_county['norm'] = vals.sum()
    data_county['min'] = vals.min()
    data_county['max'] = vals.max()

    with open('json/grids.counties.bot_filtered.respop72013.json', 'w') as f:
        json.dump(data_county, f)

    return data_state, data_county

def landarea():

    # The abbreviations of the contiguous states
    desired = us.states.mapping('abbr', 'fips', us.STATES_CONTIGUOUS)

    # State
    data_state = {}
    with fiona.open('../tiger/tl_2014_us_state.shp') as f:
        for state in f:
            state = state['properties']
            fips = state['STATEFP']
            abbr = state['STUSPS']
            if abbr not in desired:
                continue
            data_state[fips] = state['ALAND']

    vals = np.array(data_state.values())
    data_state['norm'] = vals.sum()
    data_state['min'] = vals.min()
    data_state['max'] = vals.max()

    with open('json/grids.states.bot_filtered.landarea.json', 'w') as f:
        json.dump(data_state, f)

    # County
    data_county = {}
    with fiona.open('../tiger/tl_2014_us_county.shp') as f:
        for county in f:
            county = county['properties']
            # Keep only counties in contiguous states.
            state_fips = county['STATEFP']
            if state_fips not in data_state:
                continue
            geoid = county['GEOID']
            data_county[geoid] = county['ALAND']

    vals = np.array(data_county.values())
    data_county['norm'] = vals.sum()
    data_county['min'] = vals.min()
    data_county['max'] = vals.max()

    with open('json/grids.counties.bot_filtered.landarea.json', 'w') as f:
        json.dump(data_county, f)

    return data_state, data_county

def hashtags_and_entropy():

    db = twitterproj.connect()
    collkeys = [
        [twitterproj.hashtag_counts__states, 'fips'],
        [twitterproj.hashtag_counts__counties, 'geoid'],
        [twitterproj.hashtag_counts__squares, '_id'],
    ]
    # tweeted_hashtags, distint_hashtags, mle_entropy
    # for state, counties, squares
    dicts = [{}, {}, {}, {}, {}, {}, {}, {}, {}]

    for i, (coll, key) in enumerate(collkeys):
        print(coll)
        for region in coll(db, bot_filtered=True):
            region_id = region[key]
            dicts[3*i + 0][region_id] = sum(region['counts'].values())
            dicts[3*i + 1][region_id] = len(region['counts'])
            dicts[3*i + 2][region_id] = entropy(region)

    for i, data in enumerate(dicts):
        if (i+1) % 3 == 0:
            # This is an entropy dict
            # Need to remap "NaN" to np.nan
            vals = [v if v != 'NaN' else np.nan for v in data.values()]
        else:
            vals = data.values()
        vals = np.array(vals)
        data['norm'] = np.nansum(vals)
        data['min'] = np.nanmin(vals)
        data['max'] = np.nanmax(vals)

    filenames = [
        'json/grids.states.bot_filtered.tweeted_hashtags.json',
        'json/grids.states.bot_filtered.distinct_hashtags.json',
        'json/grids.states.bot_filtered.mle_entropy.json',
        'json/grids.counties.bot_filtered.tweeted_hashtags.json',
        'json/grids.counties.bot_filtered.distinct_hashtags.json',
        'json/grids.counties.bot_filtered.mle_entropy.json',
        'json/grids.squares.bot_filtered.tweeted_hashtags.json',
        'json/grids.squares.bot_filtered.distinct_hashtags.json',
        'json/grids.squares.bot_filtered.mle_entropy.json',
    ]

    for i, (fn, data) in enumerate(zip(filenames, dicts)):
        with open(fn, 'w') as f:
            json.dump(data, f)

def top5000ratios():

    filenames = [
        'top5000ratios_states.json',
        'top5000ratios_counties.json',
        'top5000ratios_squares.json',
    ]

    data = [{}, {}, {}]
    for i, filename in enumerate(filenames):
        with open(filename) as f:
            ratios = json.load(f)

        for key, ratio in ratios.items():
            # Store included ratio, not missing ratio
            ratio = 1 - ratio

            # Python allows NaN storage in json.
            if np.isnan(ratio):
                # Convert to string NaN for the web
                ratio = "NaN"

            data[i][key] = ratio

        vals = ratios.values()
        data[i]['norm'] = np.nansum(vals)
        data[i]['min'] = np.nanmin(vals)
        data[i]['max'] = np.nanmax(vals)
        data[i]['min'] = 0
        data[i]['max'] = 1

    out_filenames = [
        'json/grids.states.bot_filtered.top5000ratios.json',
        'json/grids.counties.bot_filtered.top5000ratios.json',
        'json/grids.squares.bot_filtered.top5000ratios.json',
    ]
    for data, outfn in zip(data, out_filenames):
        with open(outfn, 'w') as f:
            json.dump(data, f)

def state_final():
    state = state_info()

    # Now also provide normalization info
    vals = np.array([ [p['respop72013'],
                       p['tweeted_hashtags'],
                       p['distinct_hashtags'],
                       p['landarea'],
                       p['mle_entropy']
                        if p['mle_entropy']!='NaN' else np.nan,
                       p['top5000ratios']
                        if p['top5000ratios']!='NaN' else np.nan]
                       for p in state.values() ])
    norms = vals.sum(axis=0)
    mins = vals.min(axis=0)
    maxs = vals.max(axis=0)
    state['norms_state'] = {'respop72013': norms[0],
                            'tweeted_hashtags': norms[1],
                            'landarea': norms[2]};
    state['min_state'] = {'respop72013': mins[0],
                          'tweeted_hashtags': mins[1],
                          'distinct_hashtags': mins[2],
                          'landarea': mins[3],
                          'mle_entropy': mins[4],
                          'top5000ratios': mins[5]};
    state['max_state'] = {'respop72013': maxs[0],
                          'tweeted_hashtags': maxs[1],
                          'distinct_hashtags': maxs[2],
                          'landarea': maxs[3],
                          'mle_entropy': maxs[4],
                          'top5000ratios': maxs[5]}
    return state

def county_final():
    county = county_info()
    # County
    vals = np.array([ [p['respop72013'],
                        p['tweeted_hashtags'],
                        p['distinct_hashtags'],
                        p['landarea'],
                        p['mle_entropy'],
                        p['top5000ratios'],]
                      for p in county.values() ])
    norms = vals.sum(axis=0)
    mins = vals.min(axis=0)
    maxs = vals.max(axis=0)
    county['norms_county'] = {'respop72013': norms[0],
                              'tweeted_hashtags': norms[1],
                              'landarea': norms[2]}
    county['min_county'] = {'respop72013': mins[0],
                            'tweeted_hashtags': mins[1],
                            'distinct_hashtags': mins[2],
                            'landarea': mins[3],
                            'mle_entropy': mins[4],
                            'top5000ratios': mins[5]};
    county['max_county'] = {'respop72013': maxs[0],
                            'tweeted_hashtags': maxs[1],
                            'distinct_hashtags': maxs[2],
                            'landarea': maxs[3],
                            'mle_entropy': maxs[4],
                            'top5000ratios': maxs[5]};
    return county

def square_final():
    square = square_info()

    vals = np.array([ [ p['tweeted_hashtags'],
                        p['distinct_hashtags'],
                        #p['landarea'],
                       p['mle_entropy']
                        if p['mle_entropy']!='NaN' else np.nan,
                       p['top5000ratios']
                        if p['top5000ratios']!='NaN' else np.nan,
                      ]
                      for p in square.values() ])
    norms = np.nansum(vals, axis=0)
    mins = np.nanmin(vals, axis=0)
    maxs = np.nanmax(vals, axis=0)
    square['norms_square'] = {'tweeted_hashtags': norms[0],
                              #'landarea': norms[2]
                             }
    square['min_square'] = {'tweeted_hashtags': mins[0],
                            'distinct_hashtags': mins[1],
                            #'landarea': mins[3],
                            'mle_entropy': mins[2],
                            'top5000ratios': mins[3]};
    square['max_square'] = {'tweeted_hashtags': maxs[0],
                            'distinct_hashtags': maxs[1],
                            #'landarea': maxs[3],
                            'mle_entropy': maxs[2],
                            'top5000ratios': maxs[3]};
    return square

def make_all():
    names()
    population()
    landarea()
    hashtags_and_entropy()
    top5000ratios()

if __name__ == '__main__':
    top5000ratios()
<commit_msg>Add code for generating unionX hashtags at X=.7, .8, .9.<commit_after>"""
Script to write a JSON file containing relevant meta information.

Each grid type and property is stored in a separate file.
Due to JSON not supporting NaN and Infinity, such values are
converted into strings and then stored in JSON. The receiving
code will need to handle those values appropriately.

The JSON file will be a dict mapping a unique identifier to the property.

    states
        id: fips, 2-character string

    counties
        id: geoid, 5-character string

    squares
        id: _id, integer specifying the i^th cell in the enumeration
        from the lower-left corner of the bounding box

Properties:

    demographics.json
        state fips
            name : state name
            abbr : state abbreviation
        county geoid
            name  : county name
            state : state fips

    grids.states.bot_filtered.{property}.json
    grids.counties.bot_filtered.{property}.json
        Keyed by state fips or county geoid.

        property                description
        --------------------------------------------------------------------
        respop72013             resident population 07/2013
        landarea                total land area
        tweeted_hashtags        the number of tweeted hashtags
        distinct_hashtags       the number of distinct hashtags
        users                   the number of users that tweeted in an area
        mle_entropy             entropy of hashtag distribution
        top5000ratios           missing ratios using top 5000 hashtags
        topX70ratios            included ratios for top X=70% hashtags

    grids.squares.bot_filtered.{property}.json
        Keyed by cell id as string

        property                description
        ------------------------------------------------------------------
        area                    total area (land+water)
        tweeted_hashtags        the number of tweeted hashtags
        distinct_hashtags       the number of distinct hashtags
        users                   the number of users that tweeted in an area
        mle_entropy             entropy of hashtag distribution
        top5000ratios           missing ratios using top 5000 hashtags
        topX70ratios            included ratios for top X=70% hashtags

"""
from collections import OrderedDict, defaultdict
import us
import fiona
import pandas
import dit
import twitterproj
import numpy as np
import json

def entropy(place):
    """
    Return the entropy of a county's hashtag counts.

    """
    pmf = np.array( place['counts'].values(), dtype=float)
    pmf /= pmf.sum()
    H = dit.shannon.entropy_pmf(pmf)
    # Handle NaN since json can't.
    if np.isnan(H):
        H = "NaN"
    return H

def names():
    # We use a single file for this one.

    data = defaultdict(dict)

    # The abbreviations of the contiguous states
    desired = us.states.mapping('abbr', 'fips', us.STATES_CONTIGUOUS)

    # States
    with fiona.open('../tiger/tl_2014_us_state.shp') as f:
        for state in f:
            state = state['properties']
            fips = state['STATEFP']
            abbr = state['STUSPS']
            if abbr not in desired:
                continue
            data[fips]['name'] = state['NAME']
            data[fips]['abbr'] = abbr

    # Counties
    with fiona.open('../tiger/tl_2014_us_county.shp') as f:
        for county in f:
            county = county['properties']
            # Keep only counties in contiguous states.
            state_fips = county['STATEFP']
            if state_fips not in data:
                continue
            geoid = county['GEOID']
            data[geoid]['name'] = county['NAMELSAD']
            data[geoid]['state'] = state_fips

    with open('json/names.json', 'w') as f:
        json.dump(data, f)

    return data

def population():

    # State
    data_state = {}
    df = pandas.read_csv('../census/state/PEP_2013_PEPANNRES_with_ann.csv')
    for state in df.values[1:]: # Skip column headers
        fips = state[1]
        data_state[fips] = int(state[-1])

    vals = np.array(data_state.values())
    data_state['norm'] = vals.sum()
    data_state['min'] = vals.min()
    data_state['max'] = vals.max()

    with open('json/grids.states.bot_filtered.respop72013.json', 'w') as f:
        json.dump(data_state, f)

    # County
    data_county = {}
    df = pandas.read_csv('../census/county/PEP_2013_PEPANNRES_with_ann.csv')
    for county in df.values[1:]: # Skip column headers
        geoid = county[1]
        data_county[geoid] = int(county[-1])

    vals = np.array(data_county.values())
    data_county['norm'] = vals.sum()
    data_county['min'] = vals.min()
    data_county['max'] = vals.max()

    with open('json/grids.counties.bot_filtered.respop72013.json', 'w') as f:
        json.dump(data_county, f)

    return data_state, data_county

def landarea():

    # The abbreviations of the contiguous states
    desired = us.states.mapping('abbr', 'fips', us.STATES_CONTIGUOUS)

    # State
    data_state = {}
    with fiona.open('../tiger/tl_2014_us_state.shp') as f:
        for state in f:
            state = state['properties']
            fips = state['STATEFP']
            abbr = state['STUSPS']
            if abbr not in desired:
                continue
            data_state[fips] = state['ALAND']

    vals = np.array(data_state.values())
    data_state['norm'] = vals.sum()
    data_state['min'] = vals.min()
    data_state['max'] = vals.max()

    with open('json/grids.states.bot_filtered.landarea.json', 'w') as f:
        json.dump(data_state, f)

    # County
    data_county = {}
    with fiona.open('../tiger/tl_2014_us_county.shp') as f:
        for county in f:
            county = county['properties']
            # Keep only counties in contiguous states.
            state_fips = county['STATEFP']
            if state_fips not in data_state:
                continue
            geoid = county['GEOID']
            data_county[geoid] = county['ALAND']

    vals = np.array(data_county.values())
    data_county['norm'] = vals.sum()
    data_county['min'] = vals.min()
    data_county['max'] = vals.max()

    with open('json/grids.counties.bot_filtered.landarea.json', 'w') as f:
        json.dump(data_county, f)

    return data_state, data_county

def hashtags_and_entropy():

    db = twitterproj.connect()
    collkeys = [
        [twitterproj.hashtag_counts__states, 'fips'],
        [twitterproj.hashtag_counts__counties, 'geoid'],
        [twitterproj.hashtag_counts__squares, '_id'],
    ]
    # tweeted_hashtags, distint_hashtags, mle_entropy
    # for state, counties, squares
    dicts = [{}, {}, {}, {}, {}, {}, {}, {}, {}]

    for i, (coll, key) in enumerate(collkeys):
        print(coll)
        for region in coll(db, bot_filtered=True):
            region_id = region[key]
            dicts[3*i + 0][region_id] = sum(region['counts'].values())
            dicts[3*i + 1][region_id] = len(region['counts'])
            dicts[3*i + 2][region_id] = entropy(region)

    for i, data in enumerate(dicts):
        if (i+1) % 3 == 0:
            # This is an entropy dict
            # Need to remap "NaN" to np.nan
            vals = [v if v != 'NaN' else np.nan for v in data.values()]
        else:
            vals = data.values()
        vals = np.array(vals)
        data['norm'] = np.nansum(vals)
        data['min'] = np.nanmin(vals)
        data['max'] = np.nanmax(vals)

    filenames = [
        'json/grids.states.bot_filtered.tweeted_hashtags.json',
        'json/grids.states.bot_filtered.distinct_hashtags.json',
        'json/grids.states.bot_filtered.mle_entropy.json',
        'json/grids.counties.bot_filtered.tweeted_hashtags.json',
        'json/grids.counties.bot_filtered.distinct_hashtags.json',
        'json/grids.counties.bot_filtered.mle_entropy.json',
        'json/grids.squares.bot_filtered.tweeted_hashtags.json',
        'json/grids.squares.bot_filtered.distinct_hashtags.json',
        'json/grids.squares.bot_filtered.mle_entropy.json',
    ]

    for i, (fn, data) in enumerate(zip(filenames, dicts)):
        with open(fn, 'w') as f:
            json.dump(data, f)

def top5000ratios():

    filenames = [
        'top5000ratios_states.json',
        'top5000ratios_counties.json',
        'top5000ratios_squares.json',
    ]

    data = [{}, {}, {}]
    for i, filename in enumerate(filenames):
        with open(filename) as f:
            ratios = json.load(f)

        for key, ratio in ratios.items():
            # Python allows NaN storage in json.
            if np.isnan(ratio):
                # Convert to string NaN for the web
                ratio = "NaN"

            data[i][key] = ratio

        vals = ratios.values()
        data[i]['norm'] = np.nansum(vals)
        data[i]['min'] = np.nanmin(vals)
        data[i]['max'] = np.nanmax(vals)
        data[i]['min'] = 0
        data[i]['max'] = 1

    out_filenames = [
        'json/grids.states.bot_filtered.top5000ratios.json',
        'json/grids.counties.bot_filtered.top5000ratios.json',
        'json/grids.squares.bot_filtered.top5000ratios.json',
    ]
    for data, outfn in zip(data, out_filenames):
        with open(outfn, 'w') as f:
            json.dump(data, f)

def unionX():
    db = twitterproj.connect()
    collkeys = [
        [twitterproj.hashtag_counts__states, 'fips', 'states'],
        [twitterproj.hashtag_counts__counties, 'geoid', 'counties'],
        [twitterproj.hashtag_counts__squares, '_id', 'squares'],
    ]

    Xvals = [.7, .8, .9]
    for i, X in enumerate(Xvals):
        print i, X
        for region_iter, key, suffix in collkeys:
            filename = 'json/grids.{}.bot_filtered.unionX{}.json'
            filename = filename.format(suffix, int(X * 100))
            print filename

            hashtags = twitterproj.sorted_hashtags_unionX(X, region_iter())
            d = collections.OrderedDict()
            norm = 0
            for region in region_iter():
                ratio, tagged = twitterproj.included_ratio(region['counts'],
                                                           hashtags)
                idx = region[key]
                if np.isnan(ratio):
                    ratio = "NaN"
                else:
                    norm += ratio
                d[idx] = ratio

                # Norm makes no sense for this...but whatever
                d['norm'] = norm
                d['min'] = 0
                d['max'] = 1

            with open(filename, 'w') as fobj:
                json.dump(d, fobj)

def make_all():
    names()
    population()
    landarea()
    hashtags_and_entropy()
    top5000ratios()
    unionX()

if __name__ == '__main__':
    #top5000ratios()
    unionX()
<|endoftext|>


<commit_before>from . import forms
from crispy_forms import helper, layout
from django import forms as django_forms, http
from django.contrib.auth import views as auth_views
from django.contrib.messages import views as messages_views
from django.core import exceptions, urlresolvers
from django.utils import six
from django.views import generic
from django.views.generic import edit as edit_views
from entities import models as entities_models
from rules.contrib import views as rules_views

class DeleteView(edit_views.FormMixin, generic.DeleteView):
    pass

class GestaltMixin:
    def get_context_data(self, **kwargs):
        kwargs['gestalt'] = self.get_gestalt()
        return super().get_context_data(**kwargs)

    def get_gestalt(self):
        if 'gestalt_pk' in self.kwargs:
            return entities_models.Gestalt.objects.get(pk=self.kwargs['gestalt_pk'])
        if 'gestalt_slug' in self.kwargs:
            return entities_models.Gestalt.objects.get(user__username=self.kwargs['gestalt_slug'])
        return None

class GroupMixin:
    def get_context_data(self, **kwargs):
        kwargs['group'] = self.get_group()
        return super().get_context_data(**kwargs)

    def get_group(self):
        if hasattr(self, 'object'):
            if isinstance(self.object, entities_models.Group):
                return self.object
            if hasattr(self.object, 'group'):
                return self.object.group
            if hasattr(self.object, 'groups'):
                return self.object.groups.first()
        if 'group_pk' in self.kwargs:
            return entities_models.Group.objects.get(pk=self.kwargs['group_pk'])
        if 'group_slug' in self.kwargs:
            return entities_models.Group.objects.get(slug=self.kwargs['group_slug'])
        if 'group' in self.request.GET:
            return entities_models.Group.objects.get(slug=self.request.GET['group'])
        return None

class FormMixin(forms.LayoutMixin):
    def get_form(self, form_class=None):
        form = super().get_form(form_class)
        if not hasattr(form, 'helper'):
            form.helper = self.get_helper()
        return form

    def get_form_class(self):
        return super().get_form_class() or django_forms.Form

    def get_layout(self):
        layout = super().get_layout()
        layout += (forms.Submit(self.action),)
        return layout

class MenuMixin:
    def get_context_data(self, **kwargs):
        kwargs['menu'] = self.get_menu()
        return super().get_context_data(**kwargs)

    def get_menu(self):
        if hasattr(self, 'menu'):
            return self.menu

class MessageMixin(messages_views.SuccessMessageMixin):
    def get_success_message(self, cleaned_data):
        if hasattr(self, 'message'):
            return self.message
        else:
            return None

class NavigationMixin:
    def get_back_url(self):
        if hasattr(self, 'back_url'):
            try:
                return urlresolvers.reverse(self.back_url)
            except urlresolvers.NoReverseMatch:
                return self.back_url
        else:
            return self.get_success_url()

    def get_context_data(self, **kwargs):
        kwargs['back_url'] = self.get_back_url()
        return super().get_context_data(**kwargs)

    def get_parent(self):
        if hasattr(self, 'parent'):
            return self.parent
        else:
            return None

    def get_success_url(self):
        parent = self.get_parent()
        if parent:
            if isinstance(parent, six.string_types):
                try:
                    return urlresolvers.reverse(parent)
                except urlresolvers.NoReverseMatch:
                    return parent
            else:
                return parent.get_absolute_url()
        else:
            try:
                return super().get_success_url()
            except AttributeError:
                return None

class PaginationMixin:
    paginate_by = 3

    def get_context_data(self, **kwargs):
        kwargs['params'] = self.request.GET.copy()
        if 'page' in kwargs['params']:
            del kwargs['params']['page']
        return super().get_context_data(**kwargs)

class PermissionMixin(rules_views.PermissionRequiredMixin):
    def get_permissions(self):
        return {self.permission: self.get_permission_object()}

    def handle_no_permission(self):
        if self.request.user.is_authenticated():
            raise exceptions.PermissionDenied(self.get_permission_denied_message())
        else:
            return auth_views.redirect_to_login(self.request.get_full_path(), self.get_login_url(), self.get_redirect_field_name())

    def has_permission(self, permission=None):
        permissions = self.get_permissions()
        if permission in permissions:
            permissions = {permission: permissions[permission]}
        for permission, object in permissions.items():
            if self.request.user.has_perm(permission, object):
                return True
        return False

class SidebarMixin:
    sidebar = ('calendar', 'groups')

    def get_context_data(self, **kwargs):
        kwargs['sidebar'] = self.sidebar
        return super().get_context_data(**kwargs)

class TemplateMixin:
    ignore_base_templates = False

    def get_template_names(self):
        if not self.ignore_base_templates:
            try:
                names = super().get_template_names()
            except exceptions.ImproperlyConfigured:
                names = []
        else:
            names = []
        names += [self.fallback_template_name]
        return names

class TitleMixin:
    def get_context_data(self, **kwargs):
        kwargs['title'] = self.get_title()
        return super().get_context_data(**kwargs)

    def get_title(self):
        if hasattr(self, 'title'):
            return self.title
        elif hasattr(self, 'action'):
            return self.action
        else:
            return None

class ActionMixin(
        FormMixin,
        GestaltMixin,
        GroupMixin,
        MenuMixin,
        MessageMixin,
        NavigationMixin,
        PermissionMixin,
        SidebarMixin,
        TemplateMixin,
        TitleMixin,
        ):
    fallback_template_name = 'stadt/form.html'
    sidebar = tuple()

class PageMixin(
        GestaltMixin,
        GroupMixin,
        MenuMixin,
        NavigationMixin,
        PaginationMixin,
        PermissionMixin,
        SidebarMixin,
        TemplateMixin,
        TitleMixin,
        ):
    fallback_template_name = 'stadt/list.html'
    sidebar = ('calendar', 'groups')

class List(PageMixin, generic.ListView):
    pass
<commit_msg>Paginate by 10 entries (closes #31)<commit_after>from . import forms
from crispy_forms import helper, layout
from django import forms as django_forms, http
from django.contrib.auth import views as auth_views
from django.contrib.messages import views as messages_views
from django.core import exceptions, urlresolvers
from django.utils import six
from django.views import generic
from django.views.generic import edit as edit_views
from entities import models as entities_models
from rules.contrib import views as rules_views

class DeleteView(edit_views.FormMixin, generic.DeleteView):
    pass

class GestaltMixin:
    def get_context_data(self, **kwargs):
        kwargs['gestalt'] = self.get_gestalt()
        return super().get_context_data(**kwargs)

    def get_gestalt(self):
        if 'gestalt_pk' in self.kwargs:
            return entities_models.Gestalt.objects.get(pk=self.kwargs['gestalt_pk'])
        if 'gestalt_slug' in self.kwargs:
            return entities_models.Gestalt.objects.get(user__username=self.kwargs['gestalt_slug'])
        return None

class GroupMixin:
    def get_context_data(self, **kwargs):
        kwargs['group'] = self.get_group()
        return super().get_context_data(**kwargs)

    def get_group(self):
        if hasattr(self, 'object'):
            if isinstance(self.object, entities_models.Group):
                return self.object
            if hasattr(self.object, 'group'):
                return self.object.group
            if hasattr(self.object, 'groups'):
                return self.object.groups.first()
        if 'group_pk' in self.kwargs:
            return entities_models.Group.objects.get(pk=self.kwargs['group_pk'])
        if 'group_slug' in self.kwargs:
            return entities_models.Group.objects.get(slug=self.kwargs['group_slug'])
        if 'group' in self.request.GET:
            return entities_models.Group.objects.get(slug=self.request.GET['group'])
        return None

class FormMixin(forms.LayoutMixin):
    def get_form(self, form_class=None):
        form = super().get_form(form_class)
        if not hasattr(form, 'helper'):
            form.helper = self.get_helper()
        return form

    def get_form_class(self):
        return super().get_form_class() or django_forms.Form

    def get_layout(self):
        layout = super().get_layout()
        layout += (forms.Submit(self.action),)
        return layout

class MenuMixin:
    def get_context_data(self, **kwargs):
        kwargs['menu'] = self.get_menu()
        return super().get_context_data(**kwargs)

    def get_menu(self):
        if hasattr(self, 'menu'):
            return self.menu

class MessageMixin(messages_views.SuccessMessageMixin):
    def get_success_message(self, cleaned_data):
        if hasattr(self, 'message'):
            return self.message
        else:
            return None

class NavigationMixin:
    def get_back_url(self):
        if hasattr(self, 'back_url'):
            try:
                return urlresolvers.reverse(self.back_url)
            except urlresolvers.NoReverseMatch:
                return self.back_url
        else:
            return self.get_success_url()

    def get_context_data(self, **kwargs):
        kwargs['back_url'] = self.get_back_url()
        return super().get_context_data(**kwargs)

    def get_parent(self):
        if hasattr(self, 'parent'):
            return self.parent
        else:
            return None

    def get_success_url(self):
        parent = self.get_parent()
        if parent:
            if isinstance(parent, six.string_types):
                try:
                    return urlresolvers.reverse(parent)
                except urlresolvers.NoReverseMatch:
                    return parent
            else:
                return parent.get_absolute_url()
        else:
            try:
                return super().get_success_url()
            except AttributeError:
                return None

class PaginationMixin:
    paginate_by = 10

    def get_context_data(self, **kwargs):
        kwargs['params'] = self.request.GET.copy()
        if 'page' in kwargs['params']:
            del kwargs['params']['page']
        return super().get_context_data(**kwargs)

class PermissionMixin(rules_views.PermissionRequiredMixin):
    def get_permissions(self):
        return {self.permission: self.get_permission_object()}

    def handle_no_permission(self):
        if self.request.user.is_authenticated():
            raise exceptions.PermissionDenied(self.get_permission_denied_message())
        else:
            return auth_views.redirect_to_login(self.request.get_full_path(), self.get_login_url(), self.get_redirect_field_name())

    def has_permission(self, permission=None):
        permissions = self.get_permissions()
        if permission in permissions:
            permissions = {permission: permissions[permission]}
        for permission, object in permissions.items():
            if self.request.user.has_perm(permission, object):
                return True
        return False

class SidebarMixin:
    sidebar = ('calendar', 'groups')

    def get_context_data(self, **kwargs):
        kwargs['sidebar'] = self.sidebar
        return super().get_context_data(**kwargs)

class TemplateMixin:
    ignore_base_templates = False

    def get_template_names(self):
        if not self.ignore_base_templates:
            try:
                names = super().get_template_names()
            except exceptions.ImproperlyConfigured:
                names = []
        else:
            names = []
        names += [self.fallback_template_name]
        return names

class TitleMixin:
    def get_context_data(self, **kwargs):
        kwargs['title'] = self.get_title()
        return super().get_context_data(**kwargs)

    def get_title(self):
        if hasattr(self, 'title'):
            return self.title
        elif hasattr(self, 'action'):
            return self.action
        else:
            return None

class ActionMixin(
        FormMixin,
        GestaltMixin,
        GroupMixin,
        MenuMixin,
        MessageMixin,
        NavigationMixin,
        PermissionMixin,
        SidebarMixin,
        TemplateMixin,
        TitleMixin,
        ):
    fallback_template_name = 'stadt/form.html'
    sidebar = tuple()

class PageMixin(
        GestaltMixin,
        GroupMixin,
        MenuMixin,
        NavigationMixin,
        PaginationMixin,
        PermissionMixin,
        SidebarMixin,
        TemplateMixin,
        TitleMixin,
        ):
    fallback_template_name = 'stadt/list.html'
    sidebar = ('calendar', 'groups')

class List(PageMixin, generic.ListView):
    pass
<|endoftext|>


<commit_before>from django.shortcuts import render
from rest_framework import viewsets, generics
from rest_framework.filters import BaseFilterBackend
from rest_framework.decorators import list_route, detail_route
from rest_framework.response import Response

from songs.models import Song
from songs.serializers import SongSerializer
from users.models import Member
from artists.models import Artist

from .models import Scrobble
from .serializers import ScrobbleSerializer, CreateScrobbleSerializer

def song_exists(title):
    check = Song.objects.filter(title=title)
    if len(check) != 0:
        return True
    else:
        return False

def artist_exists(name):
    check = Artist.objects.filter(name=name)
    if len(check) != 0:
        return True
    else:
        return False

class ScrobbleView(viewsets.ModelViewSet):
    queryset = Scrobble.objects.all()
    serializer_class = ScrobbleSerializer

    def get_serializer_class(self):
        if self.action == 'create':
            return CreateScrobbleSerializer
        return ScrobbleSerializer

    def create(self, request):
        data = self.request.data
        serializer = self.get_serializer_class()

        if artist_exists(data['artist']):
            artist = Artist.objects.get(name=data['artist'])
        else:
            print(data)
            artist = Artist.objects.create(name=data['artist'])

        if song_exists(data['song']):
            song = Song.objects.get(title=data['song'])
        else:
            song = Song.objects.create(
                title=data['song'], artist=artist)

        # obj = Scrobble.objects.create(song=song, member=self.request.user)
        obj = Scrobble.objects.create(
            song=song, member=Member.objects.get(id=2))
        created = serializer(instance=obj)
        return Response(created.data)

    # In a perfect world, these 3 functions would be
    # in a BaseFilterBackend. Screws fall out all the time,
    # the world's an imperfect place.
    @detail_route(methods=['GET'])
    def by_artist(self, request, pk=None):
        """List all scrobbles from one artist(pk)"""
        if pk is not None:
            queryset = Scrobble.objects.filter(artist__name__iexact=pk)
            serializer = ScrobbleSerializer(instance=queryset, many=True)
            return Response(serializer.data)

    @detail_route(methods=['GET'])
    def by_album(self, request, pk=None):
        """Lists all scrobbles from one album(pk)"""
        if pk is not None:
            queryset = Scrobble.objects.filter(song__album__title__iexact=pk)
            serializer = ScrobbleSerializer(instance=queryset, many=True)
            return Response(serializer.data)

    @detail_route(methods=['GET'])
    def by_song(self, request, pk=None):
        """Lists all scrobbles from one song(pk)"""
        if pk is not None:
            queryset = Scrobble.objects.filter(song__title__iexact=pk)
            serializer = ScrobbleSerializer(instance=queryset, many=True)
            return Response(serializer.data)

    @detail_route(methods=['GET'])
    def by_user(self, request, pk=None):
        """Lists all scrobbles from one user(pk)"""
        if pk is not None:
            print(pk)
            queryset = Scrobble.objects.all()
            print(queryset)
            queryset = queryset.order_by('-date_scrobbled')
            serializer = ScrobbleSerializer(instance=queryset, many=True)
            return Response(serializer.data)

    @detail_route(methods=['GET'])
    def by_user_id(self, request, pk=None):
        queryset = Scrobble.objects.filter(member=pk)
        serializer = ScrobbleSerializer(instance=queryset, many=True)
        return Response(serializer.data)
<commit_msg>by_user queryset fix<commit_after>from django.shortcuts import render
from rest_framework import viewsets, generics
from rest_framework.filters import BaseFilterBackend
from rest_framework.decorators import list_route, detail_route
from rest_framework.response import Response

from songs.models import Song
from songs.serializers import SongSerializer
from users.models import Member
from artists.models import Artist

from .models import Scrobble
from .serializers import ScrobbleSerializer, CreateScrobbleSerializer

def song_exists(title):
    check = Song.objects.filter(title=title)
    if len(check) != 0:
        return True
    else:
        return False

def artist_exists(name):
    check = Artist.objects.filter(name=name)
    if len(check) != 0:
        return True
    else:
        return False

class ScrobbleView(viewsets.ModelViewSet):
    queryset = Scrobble.objects.all()
    serializer_class = ScrobbleSerializer

    def get_serializer_class(self):
        if self.action == 'create':
            return CreateScrobbleSerializer
        return ScrobbleSerializer

    def create(self, request):
        data = self.request.data
        serializer = self.get_serializer_class()

        if artist_exists(data['artist']):
            artist = Artist.objects.get(name=data['artist'])
        else:
            print(data)
            artist = Artist.objects.create(name=data['artist'])

        if song_exists(data['song']):
            song = Song.objects.get(title=data['song'])
        else:
            song = Song.objects.create(
                title=data['song'], artist=artist)

        # obj = Scrobble.objects.create(song=song, member=self.request.user)
        obj = Scrobble.objects.create(
            song=song, member=Member.objects.get(id=2))
        created = serializer(instance=obj)
        return Response(created.data)

    # In a perfect world, these 3 functions would be
    # in a BaseFilterBackend. Screws fall out all the time,
    # the world's an imperfect place.
    @detail_route(methods=['GET'])
    def by_artist(self, request, pk=None):
        """List all scrobbles from one artist(pk)"""
        if pk is not None:
            queryset = Scrobble.objects.filter(artist__name__iexact=pk)
            serializer = ScrobbleSerializer(instance=queryset, many=True)
            return Response(serializer.data)

    @detail_route(methods=['GET'])
    def by_album(self, request, pk=None):
        """Lists all scrobbles from one album(pk)"""
        if pk is not None:
            queryset = Scrobble.objects.filter(song__album__title__iexact=pk)
            serializer = ScrobbleSerializer(instance=queryset, many=True)
            return Response(serializer.data)

    @detail_route(methods=['GET'])
    def by_song(self, request, pk=None):
        """Lists all scrobbles from one song(pk)"""
        if pk is not None:
            queryset = Scrobble.objects.filter(song__title__iexact=pk)
            serializer = ScrobbleSerializer(instance=queryset, many=True)
            return Response(serializer.data)

    @detail_route(methods=['GET'])
    def by_user(self, request, pk=None):
        """Lists all scrobbles from one user(pk)"""
        if pk is not None:
            print(pk)
            queryset = Scrobble.objects.filter(member__nick_name__iexact=pk)
            print(queryset)
            queryset = queryset.order_by('-date_scrobbled')
            serializer = ScrobbleSerializer(instance=queryset, many=True)
            return Response(serializer.data)

    @detail_route(methods=['GET'])
    def by_user_id(self, request, pk=None):
        queryset = Scrobble.objects.filter(member=pk)
        serializer = ScrobbleSerializer(instance=queryset, many=True)
        return Response(serializer.data)
<|endoftext|>


<commit_before>from django.db import models
from django.contrib.contenttypes.generic import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import ugettext as _

import uuid

class Email(models.Model):
    created = models.DateTimeField(_('created'), auto_now_add=True)
    updated = models.DateTimeField(_('updated'), auto_now=True)

    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

    email = models.CharField(_('addressee'), max_length=512)
    event = models.CharField(_('event type'), max_length=32)
    timestamp = models.DateTimeField(_('timestamp'))
    uuid = models.CharField(_('reference UUID'), max_length=64, default=lambda: str(uuid.uuid4()))

    def __unicode__(self):
        return '%s: %s' % (self.email, self.event)
<commit_msg>lazy translations to have a working django 1.7 testing<commit_after>from django.db import models
from django.contrib.contenttypes.generic import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import ugettext_lazy as _

import uuid

class Email(models.Model):
    created = models.DateTimeField(_('created'), auto_now_add=True)
    updated = models.DateTimeField(_('updated'), auto_now=True)

    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

    email = models.CharField(_('addressee'), max_length=512)
    event = models.CharField(_('event type'), max_length=32)
    timestamp = models.DateTimeField(_('timestamp'))
    uuid = models.CharField(_('reference UUID'), max_length=64, default=lambda: str(uuid.uuid4()))

    def __unicode__(self):
        return '%s: %s' % (self.email, self.event)
<|endoftext|>


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

import sys
import os

from subprocess import call

import platform

def puaq():
    print("Usage: %s contents" % os.path.basename(__file__))
    sys.exit(1)

def getplat():
    ps = platform.system().lower()
    if ps == "linux":
        return "linux"
    elif ps == "windows":
        return "windows"
    elif ps == "cygwin_nt-10.0":
        return "cygwin"
    elif ps == "darwin":
        return "macosx"

def sendtoclipboard(contents):

    clipboard_app = ""
    plat = getplat()

    if plat == "linux":
        clipboard_app = "xclip -sel clip" # for linux
    elif plat == "windows" or plat == "cygwin":
        clipboard_app = "clip"
    elif plat == "macosx":
        clipboard_app = "pbcopy"
    else:
        print("UNsupported platform")
        return

    call("inline_echo.py '%s' | %s" % (contents, clipboard_app), shell=True)

if __name__ == "__main__":

    if len(sys.argv) < 2:
        puaq()

    contents = ""
    for c in sys.argv[1:]:
        contents += c + " "
    contents = contents.strip()

    sendtoclipboard(contents)
<commit_msg>messed permissions<commit_after>#!/usr/bin/env python

import sys
import os

from subprocess import call

import platform

def puaq():
    print("Usage: %s contents" % os.path.basename(__file__))
    sys.exit(1)

def getplat():
    ps = platform.system().lower()
    if ps == "linux":
        return "linux"
    elif ps == "windows":
        return "windows"
    elif ps == "cygwin_nt-10.0":
        return "cygwin"
    elif ps == "darwin":
        return "macosx"

def sendtoclipboard(contents):

    clipboard_app = ""
    plat = getplat()

    if plat == "linux":
        clipboard_app = "xclip -sel clip" # for linux
    elif plat == "windows" or plat == "cygwin":
        clipboard_app = "clip"
    elif plat == "macosx":
        clipboard_app = "pbcopy"
    else:
        print("UNsupported platform")
        return

    call("inline_echo.py '%s' | %s" % (contents, clipboard_app), shell=True)

if __name__ == "__main__":

    if len(sys.argv) < 2:
        puaq()

    contents = ""
    for c in sys.argv[1:]:
        contents += c + " "
    contents = contents.strip()

    sendtoclipboard(contents)
<|endoftext|>


<commit_before>from google.appengine.api import memcache

from app import app
from app.constants import API_PREFIX, ADMIN_ROLE
from app.utils import create_api_response
from app.decorators import handle_error
from app.authenticator import AuthenticationException

from flask import request
from functools import wraps

MC_NAMESPACE = "access-token"

def requires_authenticated_user(admin=False):
    """Decorator that determines which user made the request
    and passes it to the decorated function. The wrapped function
    is called with keyword arg called 'user' that is a user object."""
    def requires_user_with_privileges(func):
        """Higher order function that takes into account admin permissions"""
        @wraps(func)
        def decorated(*args, **kwargs):  #pylint: disable=too-many-return-statements
            authenticator = app.config["AUTHENTICATOR"]
            if 'access_token' not in request.args:
                return create_api_response(401,
                                           "access token required "
                                           "for this method")
            access_token = request.args['access_token']
            mc_key = "%s-%s" % (MC_NAMESPACE, access_token)
            email = memcache.get(mc_key) # pylint: disable=no-member
            if not email:
                try:
                    email = authenticator.authenticate(access_token)
                except AuthenticationException as e:
                    return create_api_response(401, e.message)
                memcache.set(mc_key, email,  # pylint: disable=no-member
                             time=60)
            try:
                user = authenticator.get_user(email)
            except AuthenticationException as e:
                return create_api_response(401, e.message)
            if admin and user.role != ADMIN_ROLE:
                return create_api_response(401,
                                           "user lacks permission for this request")
            return func(*args, user=user, **kwargs)
        return decorated
    return requires_user_with_privileges

@app.route("%s/me" % API_PREFIX)
@handle_error
@requires_authenticated_user
def authenticate(user=None):
    return create_api_response(200, "success", user)
<commit_msg>Changed auth.<commit_after>from google.appengine.api import memcache

from app import app
from app.constants import API_PREFIX, ADMIN_ROLE
from app.utils import create_api_response
from app.decorators import handle_error
from app.authenticator import AuthenticationException

from flask import request
from functools import wraps

MC_NAMESPACE = "access-token"

def requires_authenticated_user(admin=False, required=False):
    """Decorator that determines which user made the request
    and passes it to the decorated function. The wrapped function
    is called with keyword arg called 'user' that is a user object."""
    def requires_user_with_privileges(func):
        """Higher order function that takes into account admin permissions"""
        @wraps(func)
        def decorated(*args, **kwargs):  #pylint: disable=too-many-return-statements
            authenticator = app.config["AUTHENTICATOR"]
            if 'access_token' not in request.args:
                if required:
                    return create_api_response(401,
                                               "access token required "
                                               "for this method")
                else:
                    user = None
            else:
                access_token = request.args['access_token']
                mc_key = "%s-%s" % (MC_NAMESPACE, access_token)
                email = memcache.get(mc_key) # pylint: disable=no-member
                if not email:
                    try:
                        email = authenticator.authenticate(access_token)
                    except AuthenticationException as e:
                        return create_api_response(401, e.message)
                    memcache.set(mc_key, email,  # pylint: disable=no-member
                                 time=60)
                try:
                    user = authenticator.get_user(email)
                except AuthenticationException as e:
                    return create_api_response(401, e.message)
            if admin and (not user or (user.role != ADMIN_ROLE)):
                return create_api_response(401,
                                           "user lacks permission for this request")
            return func(*args, user=user, **kwargs)
        return decorated
    return requires_user_with_privileges

@app.route("%s/me" % API_PREFIX)
@handle_error
@requires_authenticated_user
def authenticate(user=None):
    return create_api_response(200, "success", user)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""A recipe to implement named gauge. Named gauge keeps momenta and their
names. You can manipulate a specific momentum by the name you named.

Test it by `py.test <http://pytest.org/>`_:

.. sourcecode:: console

   $ py.test recipes/namedgauge.py

"""
from collections import namedtuple

from gauge import Gauge, Momentum

class NamedMomentum(namedtuple('_', 'velocity, since, until, name'), Momentum):

    pass

class NamedGauge(Gauge):

    def _make_momentum(self, velocity_or_momentum,
                       since=None, until=None, name=None):
        base = super(NamedGauge, self)
        momentum = base._make_momentum(velocity_or_momentum, since, until)
        if not isinstance(momentum, NamedMomentum):
            velocity, since, until = momentum
            momentum = NamedMomentum(velocity, since, until, name)
        return momentum

    def get_momentum_by_name(self, name):
        """Gets a momentum by the given name.

        :param name: the momentum name.

        :returns: a momentum found.

        :raises TypeError: `name` is ``None``.
        :raises KeyError: failed to find a momentum named `name`.
        """
        if name is None:
            raise TypeError('\'name\' should not be None')
        for momentum in self.momenta:
            if momentum.name == name:
                return momentum
        raise KeyError('No such momentum named {0}'.format(name))

    def pop_momentum_by_name(self, name):
        """Removes and returns a momentum by the given name.

        :param name: the momentum name.

        :returns: a momentum removed.

        :raises TypeError: `name` is ``None``.
        :raises KeyError: failed to find a momentum named `name`.
        """
        momentum = self.get_momentum_by_name(name)
        self.remove_momentum(momentum)
        return momentum

    def update_momentum_by_name(self, name, **kwargs):
        """Updates a momentum by the given name.

        :param name: the momentum name.
        :param velocity: (keyword-only) a new value for `velocity`.
        :param since: (keyword-only) a new value for `since`.
        :param until: (keyword-only) a new value for `until`.

        :returns: a momentum updated.

        :raises TypeError: `name` is ``None``.
        :raises KeyError: failed to find a momentum named `name`.
        """
        momentum = self.pop_momentum_by_name(name)
        velocity, since, until = momentum[:3]
        velocity = kwargs.get('velocity', velocity)
        since = kwargs.get('since', since)
        until = kwargs.get('until', until)
        return self.add_momentum(velocity, since, until, name)

def test_basic():
    g = NamedGauge(50, 100, at=0)
    g.add_momentum(+1, since=0, until=10)
    assert g.get(0) == 50
    assert g.get(1) == 51
    assert g.get(10) == 60

def test_consistency():
    g = NamedGauge(50, 100, at=0)
    g.add_momentum(+1, since=0, until=10, name='test')
    assert g.get(0) == 50
    assert g.get(1) == 51
    assert g.get(10) == 60

def test_named_momentum():
    g = NamedGauge(50, 100, at=0)
    m = g.add_momentum(+1, since=0, until=10)
    assert isinstance(m, NamedMomentum)

def test_get_momentum_by_name():
    import pytest
    g = NamedGauge(50, 100, at=0)
    g.add_momentum(+1, since=0, until=10)
    g.add_momentum(+2, since=0, until=10)
    g.add_momentum(+3, since=0, until=10, name='test')
    with pytest.raises(TypeError):
        g.get_momentum_by_name(None)
    m = g.get_momentum_by_name('test')
    assert m.velocity == +3
    assert m.name == 'test'

def test_pop_momentum_by_name():
    g = NamedGauge(50, 100, at=0)
    g.add_momentum(+1, since=0, until=10, name='test')
    assert g.get(10) == 60
    g.pop_momentum_by_name('test')
    assert g.get(10) == 50

def test_update_momentum_by_name():
    g = NamedGauge(50, 100, at=0)
    g.add_momentum(+1, since=0, until=10, name='test')
    assert g.get(15) == 60
    g.update_momentum_by_name('test', until=20)
    assert g.get(15) == 65

def test_multiple_momenta():
    import pytest
    g = NamedGauge(50, 100, at=0)
    g.add_momentum(+1, since=0, until=10, name='foo')
    g.add_momentum(-1, since=1, until=11, name='bar')
    g.add_momentum(-1, since=1, until=11, name='baz')
    assert g.velocity(5) == -1
    g.pop_momentum_by_name('foo')
    assert g.velocity(5) == -2
    with pytest.raises(ValueError):
        g.remove_momentum(-1, since=1, until=11)
    g.remove_momentum(-1, since=1, until=11, name='bar')
    assert g.velocity(5) == -1

def test_snap():
    g = NamedGauge(50, 100, at=0)
    g.add_momentum(-1)
    g.add_momentum(+2, since=0, until=10, name='test')
    assert g.get(5) == 55
    assert g.get(10) == 60
    assert g.get(20) == 50
    g.incr(0, at=5)
    assert g.get(5) == 55
    g.update_momentum_by_name('test', velocity=+3, since=5)
    assert g.get(5) == 55
    assert g.get(10) == 65
    assert g.get(20) == 55
<commit_msg>implement snap_momentum_by_name() for NamedGauge<commit_after># -*- coding: utf-8 -*-
"""A recipe to implement named gauge. Named gauge keeps momenta and their
names. You can manipulate a specific momentum by the name you named.

Test it by `py.test <http://pytest.org/>`_:

.. sourcecode:: console

   $ py.test recipes/namedgauge.py

"""
from collections import namedtuple

from gauge import Gauge, Momentum, now_or

class NamedMomentum(namedtuple('_', 'velocity, since, until, name'), Momentum):

    pass

class NamedGauge(Gauge):

    def _make_momentum(self, velocity_or_momentum,
                       since=None, until=None, name=None):
        base = super(NamedGauge, self)
        momentum = base._make_momentum(velocity_or_momentum, since, until)
        if not isinstance(momentum, NamedMomentum):
            velocity, since, until = momentum
            momentum = NamedMomentum(velocity, since, until, name)
        return momentum

    def get_momentum_by_name(self, name):
        """Gets a momentum by the given name.

        :param name: the momentum name.

        :returns: a momentum found.

        :raises TypeError: `name` is ``None``.
        :raises KeyError: failed to find a momentum named `name`.
        """
        if name is None:
            raise TypeError('\'name\' should not be None')
        for momentum in self.momenta:
            if momentum.name == name:
                return momentum
        raise KeyError('No such momentum named {0}'.format(name))

    def pop_momentum_by_name(self, name):
        """Removes and returns a momentum by the given name.

        :param name: the momentum name.

        :returns: a momentum removed.

        :raises TypeError: `name` is ``None``.
        :raises KeyError: failed to find a momentum named `name`.
        """
        momentum = self.get_momentum_by_name(name)
        self.remove_momentum(momentum)
        return momentum

    def update_momentum_by_name(self, name, **kwargs):
        """Updates a momentum by the given name.

        :param name: the momentum name.
        :param velocity: (keyword-only) a new value for `velocity`.
        :param since: (keyword-only) a new value for `since`.
        :param until: (keyword-only) a new value for `until`.

        :returns: a momentum updated.

        :raises TypeError: `name` is ``None``.
        :raises KeyError: failed to find a momentum named `name`.
        """
        momentum = self.pop_momentum_by_name(name)
        velocity, since, until = momentum[:3]
        velocity = kwargs.get('velocity', velocity)
        since = kwargs.get('since', since)
        until = kwargs.get('until', until)
        return self.add_momentum(velocity, since, until, name)

    def snap_momentum_by_name(self, name, velocity, at=None):
        """Changes the velocity of a momentum named `name`.

        :param name: the momentum name.
        :param velocity: a new velocity.
        :param at: the time to snap. (default: now)

        :returns: a momentum updated.

        :raises TypeError: `name` is ``None``.
        :raises KeyError: failed to find a momentum named `name`.
        """
        at = now_or(at)
        self.incr(0, at=at)
        return self.update_momentum_by_name(name, velocity=velocity, since=at)

def test_basic():
    g = NamedGauge(50, 100, at=0)
    g.add_momentum(+1, since=0, until=10)
    assert g.get(0) == 50
    assert g.get(1) == 51
    assert g.get(10) == 60

def test_consistency():
    g = NamedGauge(50, 100, at=0)
    g.add_momentum(+1, since=0, until=10, name='test')
    assert g.get(0) == 50
    assert g.get(1) == 51
    assert g.get(10) == 60

def test_named_momentum():
    g = NamedGauge(50, 100, at=0)
    m = g.add_momentum(+1, since=0, until=10)
    assert isinstance(m, NamedMomentum)

def test_get_momentum_by_name():
    import pytest
    g = NamedGauge(50, 100, at=0)
    g.add_momentum(+1, since=0, until=10)
    g.add_momentum(+2, since=0, until=10)
    g.add_momentum(+3, since=0, until=10, name='test')
    with pytest.raises(TypeError):
        g.get_momentum_by_name(None)
    m = g.get_momentum_by_name('test')
    assert m.velocity == +3
    assert m.name == 'test'

def test_pop_momentum_by_name():
    g = NamedGauge(50, 100, at=0)
    g.add_momentum(+1, since=0, until=10, name='test')
    assert g.get(10) == 60
    g.pop_momentum_by_name('test')
    assert g.get(10) == 50

def test_update_momentum_by_name():
    g = NamedGauge(50, 100, at=0)
    g.add_momentum(+1, since=0, until=10, name='test')
    assert g.get(15) == 60
    g.update_momentum_by_name('test', until=20)
    assert g.get(15) == 65

def test_snap_momentum_by_name():
    g = NamedGauge(50, 100, at=0)
    g.add_momentum(-1)
    g.add_momentum(+2, since=0, until=10, name='test')
    assert g.get(5) == 55
    assert g.get(10) == 60
    assert g.get(20) == 50
    g.snap_momentum_by_name('test', +3, at=5)
    assert g.get(5) == 55
    assert g.get(10) == 65
    assert g.get(20) == 55

def test_multiple_momenta():
    import pytest
    g = NamedGauge(50, 100, at=0)
    g.add_momentum(+1, since=0, until=10, name='foo')
    g.add_momentum(-1, since=1, until=11, name='bar')
    g.add_momentum(-1, since=1, until=11, name='baz')
    assert g.velocity(5) == -1
    g.pop_momentum_by_name('foo')
    assert g.velocity(5) == -2
    with pytest.raises(ValueError):
        g.remove_momentum(-1, since=1, until=11)
    g.remove_momentum(-1, since=1, until=11, name='bar')
    assert g.velocity(5) == -1
<|endoftext|>