<commit_before>"""
cancer
"""
from math import floor, ceil

import discord
import rethinkdb as r
from discord.ext import commands
from discord.ext.commands import Context

from joku.bot import Jokusoramame

INCREASING_FACTOR = 50

# Generate levels.
levels = []
current_factor = 50
for x in range(0, 10000):
    levels.append(current_factor)
    current_factor += INCREASING_FACTOR + (x * INCREASING_FACTOR)

def get_level_from_exp(exp: int):
    # I don't get it but ok
    if exp < 50:
        return 0
    return floor(-0.5 + ((-4375 + 100 * exp) ** 0.5) / 50) + 1

def get_next_level(exp: int):
    if exp < 50:
        return 0, 50 - exp

    l = ceil(-0.5 + ((-4375 + 100 * exp) ** 0.5) / 50) + 1
    return l, levels[l] - exp

class Levelling(object):
    def __init__(self, bot: Jokusoramame):
        self.bot = bot
        self.levels = levels

    async def on_message(self, message: discord.Message):
        # Add XP, and show if they levelled up.
        if message.author.bot:
            return

        # Check the spam quotient.
        if not await self.bot.redis.prevent_spam(message.author):
            # The user said more than 15 messages in the last 60 seconds, so don't add XP.
            return

        user = await self.bot.rethinkdb.update_user_xp(message.author)
        # Get the level.
        new_level = get_level_from_exp(user["xp"])

        if user.get("level", 0) < new_level:
            # todo: make this better
            user["level"] = new_level
            await r.table("users").insert(user, conflict="update").run(self.bot.rethinkdb.connection)

            await self.bot.send_message(message.channel, ":up: **{}, you are now level {}!**".format(
                message.author, new_level
            ))

    @commands.group(pass_context=True, invoke_without_command=True)
    async def level(self, ctx, *, target: discord.Member = None):
        """
        Shows the current level for somebody.

        If no user is passed, this will show your level.
        """
        user = target or ctx.message.author
        if user.bot:
            await ctx.bot.say(":no_entry_sign: **Bots cannot have XP.**")
            return

        level = await ctx.bot.rethinkdb.get_level(user)

        await ctx.bot.say("User **{}** is level `{}`.".format(user.name, level))

    @level.command(pass_context=True)
    async def leaderboard(self, ctx: Context):
        """
        Shows the top 10 people in this server.

        This uses the global XP counter.
        """
        users = await ctx.bot.rethinkdb.get_multiple_users(*ctx.message.server.members, order_by=r.desc("xp"))

        base = "**Top 10 users (in this server):**\n\n"

        for n, u in enumerate(users[:10]):
            base += "**{}. {} - {} XP - Level {}**\n".format(
                n + 1,
                ctx.message.server.get_member(u["user_id"]).name,
                u["xp"],
                u["level"]
            )

        await ctx.bot.say(base)

    @level.command(pass_context=True)
    async def next(self, ctx, *, target: discord.Member = None):
        """
        Shows the next level for somebody.

        If no user is passed, this will show yours.
        """
        user = target or ctx.message.author
        if user.bot:
            await ctx.bot.say(":no_entry_sign: **Bots cannot have XP.**")
            return

        level = await ctx.bot.rethinkdb.get_level(user)
        xp = await ctx.bot.rethinkdb.get_user_xp(user)

        exp_required = get_next_level(xp)[1]

        await ctx.bot.say("**{}** needs `{}` XP to advance to level `{}`.".format(user.name, exp_required,
                                                                                level + 1))

    @commands.command(pass_context=True, aliases=["exp"])
    async def xp(self, ctx, *, target: discord.Member = None):
        """
        Shows the current XP for somebody.

        If no user is passed, this will show your XP.
        """
        user = target or ctx.message.author
        if user.bot:
            await ctx.bot.say(":no_entry_sign: **Bots cannot have XP.**")
            return

        exp = await ctx.bot.rethinkdb.get_user_xp(user)

        await ctx.bot.say("User **{}** has `{}` XP.".format(user.name, exp))

def setup(bot: Jokusoramame):
    bot.add_cog(Levelling(bot))
<commit_msg>Ignore Discord Bots in levelling calculations.<commit_after>"""
cancer
"""
from math import floor, ceil

import discord
import rethinkdb as r
from discord.ext import commands
from discord.ext.commands import Context

from joku.bot import Jokusoramame

INCREASING_FACTOR = 50

# Generate levels.
levels = []
current_factor = 50
for x in range(0, 10000):
    levels.append(current_factor)
    current_factor += INCREASING_FACTOR + (x * INCREASING_FACTOR)

def get_level_from_exp(exp: int):
    # I don't get it but ok
    if exp < 50:
        return 0
    return floor(-0.5 + ((-4375 + 100 * exp) ** 0.5) / 50) + 1

def get_next_level(exp: int):
    if exp < 50:
        return 0, 50 - exp

    l = ceil(-0.5 + ((-4375 + 100 * exp) ** 0.5) / 50) + 1
    return l, levels[l] - exp

class Levelling(object):
    def __init__(self, bot: Jokusoramame):
        self.bot = bot
        self.levels = levels

    async def on_message(self, message: discord.Message):
        # Add XP, and show if they levelled up.
        if message.author.bot:
            return

        # No discord bots, thanks.
        if message.server.id == "110373943822540800":
            return

        # Check the spam quotient.
        if not await self.bot.redis.prevent_spam(message.author):
            # The user said more than 15 messages in the last 60 seconds, so don't add XP.
            return

        user = await self.bot.rethinkdb.update_user_xp(message.author)
        # Get the level.
        new_level = get_level_from_exp(user["xp"])

        if user.get("level", 0) < new_level:
            # todo: make this better
            user["level"] = new_level
            await r.table("users").insert(user, conflict="update").run(self.bot.rethinkdb.connection)

            await self.bot.send_message(message.channel, ":up: **{}, you are now level {}!**".format(
                message.author, new_level
            ))

    @commands.group(pass_context=True, invoke_without_command=True)
    async def level(self, ctx, *, target: discord.Member = None):
        """
        Shows the current level for somebody.

        If no user is passed, this will show your level.
        """
        user = target or ctx.message.author
        if user.bot:
            await ctx.bot.say(":no_entry_sign: **Bots cannot have XP.**")
            return

        level = await ctx.bot.rethinkdb.get_level(user)

        await ctx.bot.say("User **{}** is level `{}`.".format(user.name, level))

    @level.command(pass_context=True)
    async def leaderboard(self, ctx: Context):
        """
        Shows the top 10 people in this server.

        This uses the global XP counter.
        """
        users = await ctx.bot.rethinkdb.get_multiple_users(*ctx.message.server.members, order_by=r.desc("xp"))

        base = "**Top 10 users (in this server):**\n\n"

        for n, u in enumerate(users[:10]):
            base += "**{}. {} - {} XP - Level {}**\n".format(
                n + 1,
                ctx.message.server.get_member(u["user_id"]).name,
                u["xp"],
                u["level"]
            )

        await ctx.bot.say(base)

    @level.command(pass_context=True)
    async def next(self, ctx, *, target: discord.Member = None):
        """
        Shows the next level for somebody.

        If no user is passed, this will show yours.
        """
        user = target or ctx.message.author
        if user.bot:
            await ctx.bot.say(":no_entry_sign: **Bots cannot have XP.**")
            return

        level = await ctx.bot.rethinkdb.get_level(user)
        xp = await ctx.bot.rethinkdb.get_user_xp(user)

        exp_required = get_next_level(xp)[1]

        await ctx.bot.say("**{}** needs `{}` XP to advance to level `{}`.".format(user.name, exp_required,
                                                                                level + 1))

    @commands.command(pass_context=True, aliases=["exp"])
    async def xp(self, ctx, *, target: discord.Member = None):
        """
        Shows the current XP for somebody.

        If no user is passed, this will show your XP.
        """
        user = target or ctx.message.author
        if user.bot:
            await ctx.bot.say(":no_entry_sign: **Bots cannot have XP.**")
            return

        exp = await ctx.bot.rethinkdb.get_user_xp(user)

        await ctx.bot.say("User **{}** has `{}` XP.".format(user.name, exp))

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


<commit_before>"""
cancer
"""
from io import BytesIO
from math import floor, ceil

import discord
from asyncio_extras import threadpool

import rethinkdb as r
from discord.ext import commands

import matplotlib as mpl

mpl.use('Agg')

import matplotlib.pyplot as plt
import numpy as np
from numpy.polynomial import Polynomial as P
import seaborn as sns

from joku.bot import Jokusoramame, Context
from joku.cogs._common import Cog
from joku.utils import paginate_table, reject_outliers

INCREASING_FACTOR = 50

def get_level_from_exp(xp: int, a: int = INCREASING_FACTOR) -> int:
    """
    Gets the level from the experience number.

    U(n) = a* (n*(n+1)  / 2), a ∈ ℝ, a > 0
    :param a: The levelling up constant.
    :param xp: The XP this user currently has.
    """
    # Make sure XP is below INCREASING_FACTOR.
    if xp < a:
        # Level 1
        return 1

    # The equation that we need to solve is (a/2)n**2 + (a/2)n - xp = 0.
    # So we get numpy to find our roots.
    ab = a / 2
    # C, B, A
    to_solve = [-xp, ab, ab]
    poly = P(to_solve)

    # Positive root + 1
    root = poly.roots()[1] + 1
    return int(floor(root))

def get_next_exp_required(xp: int, a: int = INCREASING_FACTOR):
    """
    Gets the EXP required for the next level, based on the current EXP.

    :param a: The levelling up constant.
    :param xp: The XP this user currently has.
    :return: The amount of XP required for the next level, and the current level.
    """
    # No complxes
    if xp < a:
        return 1, a - xp

    # Solve the current level.
    current_level = get_level_from_exp(xp, a)

    # Substitute in (n+1) to a* (n*(n+1)  / 2), where n == current_level
    # or not idk
    exp_required = int(a * (current_level * (current_level + 1) / 2))

    return current_level, exp_required - xp

class Levelling(Cog):
    async def on_message(self, message: discord.Message):
        # Add XP, and show if they levelled up.
        if message.author.bot:
            return

        # No discord bots, thanks.
        if message.guild.id == 110373943822540800:
            return

        # Check the spam quotient.
        if not await self.bot.redis.prevent_spam(message.author):
            # The user said more than 15 messages in the last 60 seconds, so don't add XP.
            return

        # Check if this channel should be ignored for levelling.
        if await self.bot.rethinkdb.is_channel_ignored(message.channel, type_="levels"):
            return

        user = await self.bot.rethinkdb.update_user_xp(message.author)
        # Get the level.
        new_level = get_level_from_exp(user["xp"])

        if user.get("level", 0) < new_level:
            # todo: make this better
            user["level"] = new_level
            await r.table("users").insert(user, conflict="update").run(self.bot.rethinkdb.connection)

            all_users = await self.bot.rethinkdb.get_multiple_users(*message.guild.members, order_by=r.desc("xp"))
            index, u = next(filter(lambda j: j[1]["user_id"] == str(message.author.id), enumerate(all_users)))

            if message.channel.permissions_for(message.guild.me).embed_links:
                em = discord.Embed(title="Level up!")
                em.description = "**{} is now level {}!** " \
                                 "Current XP: {}".format(message.author.name, new_level, user["xp"])

                xp = user["xp"]
                required = get_next_exp_required(xp)[1]
                next_xp = xp + required
                em.add_field(name="Required for next level", value="{} XP".format(required))
                em.add_field(name="Rank", value="{} / {}".format(index + 1, len(all_users)))

                em.colour = discord.Colour.green()
                em.set_thumbnail(url=message.author.avatar_url)

                await message.channel.send(embed=em)
            else:
                await message.channel.send(":up: **{} is now level {}!**".format(message.author, user["level"]))

    @commands.group(pass_context=True, invoke_without_command=True)
    async def level(self, ctx: Context, *, target: discord.Member = None):
        """
        Shows the current level for somebody.

        If no user is passed, this will show your level.
        """
        user = target or ctx.message.author
        if user.bot:
            await ctx.channel.send(":no_entry_sign: **Bots cannot have XP.**")
            return

        all_users = await ctx.bot.rethinkdb.get_multiple_users(*ctx.message.guild.members, order_by=r.desc("xp"))

        index, u = next(filter(lambda j: j[1]["user_id"] == str(user.id), enumerate(all_users)))

        embed = discord.Embed(title=user.nick or user.name)
        embed.set_thumbnail(url=user.avatar_url)

        embed.add_field(name="Level", value=str(u["level"]))
        embed.add_field(name="Rank", value="{} / {}".format(index + 1, len(all_users)))
        embed.add_field(name="XP", value=str(u["xp"]))
        required = get_next_exp_required(u["xp"])[1]

        embed.add_field(name="XP required for next level", value=required)

        await ctx.channel.send(embed=embed)

    @level.command(pass_context=True, aliases=["top"])
    async def leaderboard(self, ctx: Context, *, num: int = 10):
        """
        Shows the top 10 people in this server.

        This uses the global XP counter.
        """
        users = await ctx.bot.rethinkdb.get_multiple_users(*ctx.message.guild.members, order_by=r.desc("xp"))

        base = "**Top {} users (in this server):**\n\n".format(num)

        # Create a table using tabulate.
        headers = ["POS", "User", "XP", "Level"]
        table = []

        for n, u in enumerate(users[:num]):
            try:
                member = ctx.message.guild.get_member(int(u["user_id"])).name
                # Unicode and tables suck
                member = member.encode("ascii", errors="replace").decode()
            except AttributeError:
                # Prevent race condition - member leaving between command invocation and here
                continue
            # position, name, xp, level
            table.append([n + 1, member, u["xp"], u["level"]])

        # Format the table.
        pages = paginate_table(table, headers)

        await ctx.channel.send(base)
        for page in pages:
            await ctx.channel.send(page)

    @level.command(pass_context=True)
    async def plot(self, ctx: Context):
        """
        Plots the XP curve for this server.
        """
        users = await ctx.bot.rethinkdb.get_multiple_users(*ctx.message.guild.members, order_by=r.desc("xp"))

        async with ctx.channel.typing():
            async with threadpool():
                with plt.style.context("seaborn-pastel"):
                    lvls = np.array([user["level"] for user in users if user["level"] >= 0])
                    lvls = reject_outliers(lvls)
                    ax = sns.distplot(lvls)

                    # seaborn uses pyplot internally
                    # so we can still set these

                    plt.xlabel("Level")
                    plt.title("Level distribution curve for {}".format(ctx.message.guild.name))

                    buf = BytesIO()
                    plt.savefig(buf, format="png")

                    # Don't send 0-byte files
                    buf.seek(0)

                    # Cleanup.
                    plt.clf()
                    plt.cla()

        await ctx.channel.send(file=buf, filename="plot.png")

    @level.command(pass_context=True)
    async def next(self, ctx, *, target: discord.Member = None):
        """
        Shows the next level for somebody.

        If no user is passed, this will show yours.
        """
        user = target or ctx.message.author
        if user.bot:
            await ctx.channel.send(":no_entry_sign: **Bots cannot have XP.**")
            return

        xp = await ctx.bot.rethinkdb.get_user_xp(user)

        level, exp_required = get_next_exp_required(xp)

        await ctx.channel.send("**{}** needs `{}` XP to advance to level `{}`.".format(user.name, exp_required,
                                                                                level + 1))

    @commands.command(pass_context=True, aliases=["exp"])
    async def xp(self, ctx, *, target: discord.Member = None):
        """
        Shows the current XP for somebody.

        If no user is passed, this will show your XP.
        """
        user = target or ctx.message.author
        if user.bot:
            await ctx.channel.send(":no_entry_sign: **Bots cannot have XP.**")
            return

        exp = await ctx.bot.rethinkdb.get_user_xp(user)

        await ctx.channel.send("User **{}** has `{}` XP.".format(user.name, exp))

def setup(bot: Jokusoramame):
    bot.add_cog(Levelling(bot))
<commit_msg>Disable histogram when plotting levels.<commit_after>"""
cancer
"""
from io import BytesIO
from math import floor, ceil

import discord
from asyncio_extras import threadpool

import rethinkdb as r
from discord.ext import commands

import matplotlib as mpl

mpl.use('Agg')

import matplotlib.pyplot as plt
import numpy as np
from numpy.polynomial import Polynomial as P
import seaborn as sns

from joku.bot import Jokusoramame, Context
from joku.cogs._common import Cog
from joku.utils import paginate_table, reject_outliers

INCREASING_FACTOR = 50

def get_level_from_exp(xp: int, a: int = INCREASING_FACTOR) -> int:
    """
    Gets the level from the experience number.

    U(n) = a* (n*(n+1)  / 2), a ∈ ℝ, a > 0
    :param a: The levelling up constant.
    :param xp: The XP this user currently has.
    """
    # Make sure XP is below INCREASING_FACTOR.
    if xp < a:
        # Level 1
        return 1

    # The equation that we need to solve is (a/2)n**2 + (a/2)n - xp = 0.
    # So we get numpy to find our roots.
    ab = a / 2
    # C, B, A
    to_solve = [-xp, ab, ab]
    poly = P(to_solve)

    # Positive root + 1
    root = poly.roots()[1] + 1
    return int(floor(root))

def get_next_exp_required(xp: int, a: int = INCREASING_FACTOR):
    """
    Gets the EXP required for the next level, based on the current EXP.

    :param a: The levelling up constant.
    :param xp: The XP this user currently has.
    :return: The amount of XP required for the next level, and the current level.
    """
    # No complxes
    if xp < a:
        return 1, a - xp

    # Solve the current level.
    current_level = get_level_from_exp(xp, a)

    # Substitute in (n+1) to a* (n*(n+1)  / 2), where n == current_level
    # or not idk
    exp_required = int(a * (current_level * (current_level + 1) / 2))

    return current_level, exp_required - xp

class Levelling(Cog):
    async def on_message(self, message: discord.Message):
        # Add XP, and show if they levelled up.
        if message.author.bot:
            return

        # No discord bots, thanks.
        if message.guild.id == 110373943822540800:
            return

        # Check the spam quotient.
        if not await self.bot.redis.prevent_spam(message.author):
            # The user said more than 15 messages in the last 60 seconds, so don't add XP.
            return

        # Check if this channel should be ignored for levelling.
        if await self.bot.rethinkdb.is_channel_ignored(message.channel, type_="levels"):
            return

        user = await self.bot.rethinkdb.update_user_xp(message.author)
        # Get the level.
        new_level = get_level_from_exp(user["xp"])

        if user.get("level", 0) < new_level:
            # todo: make this better
            user["level"] = new_level
            await r.table("users").insert(user, conflict="update").run(self.bot.rethinkdb.connection)

            all_users = await self.bot.rethinkdb.get_multiple_users(*message.guild.members, order_by=r.desc("xp"))
            index, u = next(filter(lambda j: j[1]["user_id"] == str(message.author.id), enumerate(all_users)))

            if message.channel.permissions_for(message.guild.me).embed_links:
                em = discord.Embed(title="Level up!")
                em.description = "**{} is now level {}!** " \
                                 "Current XP: {}".format(message.author.name, new_level, user["xp"])

                xp = user["xp"]
                required = get_next_exp_required(xp)[1]
                next_xp = xp + required
                em.add_field(name="Required for next level", value="{} XP".format(required))
                em.add_field(name="Rank", value="{} / {}".format(index + 1, len(all_users)))

                em.colour = discord.Colour.green()
                em.set_thumbnail(url=message.author.avatar_url)

                await message.channel.send(embed=em)
            else:
                await message.channel.send(":up: **{} is now level {}!**".format(message.author, user["level"]))

    @commands.group(pass_context=True, invoke_without_command=True)
    async def level(self, ctx: Context, *, target: discord.Member = None):
        """
        Shows the current level for somebody.

        If no user is passed, this will show your level.
        """
        user = target or ctx.message.author
        if user.bot:
            await ctx.channel.send(":no_entry_sign: **Bots cannot have XP.**")
            return

        all_users = await ctx.bot.rethinkdb.get_multiple_users(*ctx.message.guild.members, order_by=r.desc("xp"))

        index, u = next(filter(lambda j: j[1]["user_id"] == str(user.id), enumerate(all_users)))

        embed = discord.Embed(title=user.nick or user.name)
        embed.set_thumbnail(url=user.avatar_url)

        embed.add_field(name="Level", value=str(u["level"]))
        embed.add_field(name="Rank", value="{} / {}".format(index + 1, len(all_users)))
        embed.add_field(name="XP", value=str(u["xp"]))
        required = get_next_exp_required(u["xp"])[1]

        embed.add_field(name="XP required for next level", value=required)

        await ctx.channel.send(embed=embed)

    @level.command(pass_context=True, aliases=["top"])
    async def leaderboard(self, ctx: Context, *, num: int = 10):
        """
        Shows the top 10 people in this server.

        This uses the global XP counter.
        """
        users = await ctx.bot.rethinkdb.get_multiple_users(*ctx.message.guild.members, order_by=r.desc("xp"))

        base = "**Top {} users (in this server):**\n\n".format(num)

        # Create a table using tabulate.
        headers = ["POS", "User", "XP", "Level"]
        table = []

        for n, u in enumerate(users[:num]):
            try:
                member = ctx.message.guild.get_member(int(u["user_id"])).name
                # Unicode and tables suck
                member = member.encode("ascii", errors="replace").decode()
            except AttributeError:
                # Prevent race condition - member leaving between command invocation and here
                continue
            # position, name, xp, level
            table.append([n + 1, member, u["xp"], u["level"]])

        # Format the table.
        pages = paginate_table(table, headers)

        await ctx.channel.send(base)
        for page in pages:
            await ctx.channel.send(page)

    @level.command(pass_context=True)
    async def plot(self, ctx: Context):
        """
        Plots the XP curve for this server.
        """
        users = await ctx.bot.rethinkdb.get_multiple_users(*ctx.message.guild.members, order_by=r.desc("xp"))

        async with ctx.channel.typing():
            async with threadpool():
                with plt.style.context("seaborn-pastel"):
                    lvls = np.array([user["level"] for user in users if user["level"] >= 0])
                    lvls = reject_outliers(lvls)
                    ax = sns.distplot(lvls, hist=False)

                    # seaborn uses pyplot internally
                    # so we can still set these

                    plt.xlabel("Level")
                    plt.title("Level distribution curve for {}".format(ctx.message.guild.name))

                    buf = BytesIO()
                    plt.savefig(buf, format="png")

                    # Don't send 0-byte files
                    buf.seek(0)

                    # Cleanup.
                    plt.clf()
                    plt.cla()

        await ctx.channel.send(file=buf, filename="plot.png")

    @level.command(pass_context=True)
    async def next(self, ctx, *, target: discord.Member = None):
        """
        Shows the next level for somebody.

        If no user is passed, this will show yours.
        """
        user = target or ctx.message.author
        if user.bot:
            await ctx.channel.send(":no_entry_sign: **Bots cannot have XP.**")
            return

        xp = await ctx.bot.rethinkdb.get_user_xp(user)

        level, exp_required = get_next_exp_required(xp)

        await ctx.channel.send("**{}** needs `{}` XP to advance to level `{}`.".format(user.name, exp_required,
                                                                                level + 1))

    @commands.command(pass_context=True, aliases=["exp"])
    async def xp(self, ctx, *, target: discord.Member = None):
        """
        Shows the current XP for somebody.

        If no user is passed, this will show your XP.
        """
        user = target or ctx.message.author
        if user.bot:
            await ctx.channel.send(":no_entry_sign: **Bots cannot have XP.**")
            return

        exp = await ctx.bot.rethinkdb.get_user_xp(user)

        await ctx.channel.send("User **{}** has `{}` XP.".format(user.name, exp))

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


<commit_before># Copyright 2017 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Rules to load all dependencies of rules_docker."""

load(
    "@bazel_tools//tools/build_defs/repo:http.bzl",
    "http_archive",
    "http_file",
)
load(
    "@io_bazel_rules_docker//toolchains/docker:toolchain.bzl",
    _docker_toolchain_configure = "toolchain_configure",
)

# The release of the github.com/google/containerregistry to consume.
CONTAINERREGISTRY_RELEASE = "v0.0.36"
RULES_DOCKER_GO_BINARY_RELEASE = "e65f10d1032ad8c56d713696d231338aa87df10a"

_local_tool_build_template = """
sh_binary(
    name = "{name}",
    srcs = ["bin/{name}"],
    visibility = ["//visibility:public"],
)
"""

def _local_tool(repository_ctx):
    rctx = repository_ctx
    realpath = rctx.which(rctx.name)
    rctx.symlink(realpath, "bin/%s" % rctx.name)
    rctx.file(
        "WORKSPACE",
        'workspace(name = "{}")\n'.format(rctx.name),
    )
    rctx.file(
        "BUILD",
        _local_tool_build_template.format(name = rctx.name),
    )

local_tool = repository_rule(
    local = True,
    implementation = _local_tool,
)

def repositories():
    """Download dependencies of container rules."""
    excludes = native.existing_rules().keys()

    # Go binaries.
    if "go_puller_linux" not in excludes:
        http_file(
            name = "go_puller_linux",
            executable = True,
            sha256 = "561e3d59186c55852c0bf5b4fbe9bd728909d7c20085a2538884a3aee8f24bc6",
            urls = [("https://storage.googleapis.com/rules_docker/" + RULES_DOCKER_GO_BINARY_RELEASE + "/puller-linux-amd64")],
        )

    if "go_puller_darwin" not in excludes:
        http_file(
            name = "go_puller_darwin",
            executable = True,
            sha256 = "6ba9a537450d4d5d98b1e8226231f05fb7d7d51b3b23e8c9a4d52f78eb6a5a04",
            urls = [("https://storage.googleapis.com/rules_docker/" + RULES_DOCKER_GO_BINARY_RELEASE + "/puller-darwin-amd64")],
        )

    if "loader_linux" not in excludes:
        http_file(
            name = "loader_linux",
            executable = True,
            sha256 = "5731eacfe4d27c8868f1d8163d0cec52b1d35993fd57fc508da1ca1c10a63a57",
            urls = [("https://storage.googleapis.com/rules_docker/" + RULES_DOCKER_GO_BINARY_RELEASE + "/loader-linux-amd64")],
        )

    if "loader_darwin" not in excludes:
        http_file(
            name = "loader_darwin",
            executable = True,
            sha256 = "80ad854ae1e058d7154c421510a5afebab015ff2d1a49d50ee33842f35c90e44",
            urls = [("https://storage.googleapis.com/rules_docker/" + RULES_DOCKER_GO_BINARY_RELEASE + "/loader-darwin-amd64")],
        )

    # Legacy Python binaries.
    if "puller" not in excludes:
        http_file(
            name = "puller",
            executable = True,
            sha256 = "75ffb6edfee4bfcfbccd7ebee641dd90b4e2f73c773a9cca04cd0ec849576624",
            urls = [("https://storage.googleapis.com/containerregistry-releases/" +
                     CONTAINERREGISTRY_RELEASE + "/puller.par")],
        )

    if "importer" not in excludes:
        http_file(
            name = "importer",
            executable = True,
            sha256 = "4516a7bf62b052693001fd2b649080c4bb5228dcf698f31e77481fcb37b82ab4",
            urls = [("https://storage.googleapis.com/containerregistry-releases/" +
                     CONTAINERREGISTRY_RELEASE + "/importer.par")],
        )

    if "containerregistry" not in excludes:
        http_archive(
            name = "containerregistry",
            sha256 = "a8cdf2452323e0fefa4edb01c08b2ec438c9fa3192bc9f408b89287598c12abc",
            strip_prefix = "containerregistry-" + CONTAINERREGISTRY_RELEASE[1:],
            urls = [("https://github.com/google/containerregistry/archive/" +
                     CONTAINERREGISTRY_RELEASE + ".tar.gz")],
        )

    # TODO(mattmoor): Remove all of this (copied from google/containerregistry)
    # once transitive workspace instantiation lands.

    if "io_bazel_rules_go" not in excludes:
        http_archive(
            name = "io_bazel_rules_go",
            sha256 = "8df59f11fb697743cbb3f26cfb8750395f30471e9eabde0d174c3aebc7a1cd39",
            urls = [
                "https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/rules_go/releases/download/0.19.1/rules_go-0.19.1.tar.gz",
                "https://github.com/bazelbuild/rules_go/releases/download/0.19.1/rules_go-0.19.1.tar.gz",
            ],
        )
    if "rules_python" not in excludes:
        http_archive(
            name = "rules_python",
            sha256 = "e5470e92a18aa51830db99a4d9c492cc613761d5bdb7131c04bd92b9834380f6",
            strip_prefix = "rules_python-4b84ad270387a7c439ebdccfd530e2339601ef27",
            urls = ["https://github.com/bazelbuild/rules_python/archive/4b84ad270387a7c439ebdccfd530e2339601ef27.tar.gz"],
        )

    if "httplib2" not in excludes:
        # TODO(mattmoor): Is there a clean way to override?
        http_archive(
            name = "httplib2",
            build_file_content = """
py_library(
   name = "httplib2",
   srcs = glob(["**/*.py"]),
   data = ["cacerts.txt"],
   visibility = ["//visibility:public"]
)""",
            sha256 = "2dcbd4f20e826d6405593df8c3d6b6e4e369d57586db3ec9bbba0f0e0cdc0916",
            strip_prefix = "httplib2-0.12.1/python2/httplib2/",
            type = "tar.gz",
            urls = ["https://codeload.github.com/httplib2/httplib2/tar.gz/v0.12.1"],
        )

    # Used by oauth2client
    if "six" not in excludes:
        # TODO(mattmoor): Is there a clean way to override?
        http_archive(
            name = "six",
            build_file_content = """
# Rename six.py to __init__.py
genrule(
    name = "rename",
    srcs = ["six.py"],
    outs = ["__init__.py"],
    cmd = "cat $< >$@",
)
py_library(
   name = "six",
   srcs = [":__init__.py"],
   visibility = ["//visibility:public"],
)""",
            sha256 = "e24052411fc4fbd1f672635537c3fc2330d9481b18c0317695b46259512c91d5",
            strip_prefix = "six-1.9.0/",
            type = "tar.gz",
            urls = ["https://pypi.python.org/packages/source/s/six/six-1.9.0.tar.gz"],
        )

    # Used for authentication in containerregistry
    if "oauth2client" not in excludes:
        # TODO(mattmoor): Is there a clean way to override?
        http_archive(
            name = "oauth2client",
            build_file_content = """
py_library(
   name = "oauth2client",
   srcs = glob(["**/*.py"]),
   visibility = ["//visibility:public"],
   deps = [
     "@httplib2//:httplib2",
     "@six//:six",
   ]
)""",
            sha256 = "7230f52f7f1d4566a3f9c3aeb5ffe2ed80302843ce5605853bee1f08098ede46",
            strip_prefix = "oauth2client-4.0.0/oauth2client/",
            type = "tar.gz",
            urls = ["https://codeload.github.com/google/oauth2client/tar.gz/v4.0.0"],
        )

    # Used for parallel execution in containerregistry
    if "concurrent" not in excludes:
        # TODO(mattmoor): Is there a clean way to override?
        http_archive(
            name = "concurrent",
            build_file_content = """
py_library(
   name = "concurrent",
   srcs = glob(["**/*.py"]),
   visibility = ["//visibility:public"]
)""",
            sha256 = "a7086ddf3c36203da7816f7e903ce43d042831f41a9705bc6b4206c574fcb765",
            strip_prefix = "pythonfutures-3.0.5/concurrent/",
            type = "tar.gz",
            urls = ["https://codeload.github.com/agronholm/pythonfutures/tar.gz/3.0.5"],
        )

    # For packaging python tools.
    if "subpar" not in excludes:
        http_archive(
            name = "subpar",
            sha256 = "34bb4dadd86bbdd3b5736952167e20a1a4c27ff739de11532c4ef77c7c6a68d9",
            # Commit from 2019-03-07.
            strip_prefix = "subpar-35bb9f0092f71ea56b742a520602da9b3638a24f",
            urls = ["https://github.com/google/subpar/archive/35bb9f0092f71ea56b742a520602da9b3638a24f.tar.gz"],
        )

    if "structure_test_linux" not in excludes:
        http_file(
            name = "structure_test_linux",
            executable = True,
            sha256 = "cfdfedd77c04becff0ea16a4b8ebc3b57bf404c56e5408b30d4fbb35853db67c",
            urls = ["https://storage.googleapis.com/container-structure-test/v1.8.0/container-structure-test-linux-amd64"],
        )

    if "structure_test_darwin" not in excludes:
        http_file(
            name = "structure_test_darwin",
            executable = True,
            sha256 = "14e94f75112a8e1b08a2d10f2467d27db0b94232a276ddd1e1512593a7b7cf5a",
            urls = ["https://storage.googleapis.com/container-structure-test/v1.8.0/container-structure-test-darwin-amd64"],
        )

    if "container_diff" not in excludes:
        http_file(
            name = "container_diff",
            executable = True,
            sha256 = "65b10a92ca1eb575037c012c6ab24ae6fe4a913ed86b38048781b17d7cf8021b",
            urls = ["https://storage.googleapis.com/container-diff/v0.15.0/container-diff-linux-amd64"],
        )

    # For bzl_library.
    if "bazel_skylib" not in excludes:
        http_archive(
            name = "bazel_skylib",
            sha256 = "2ea8a5ed2b448baf4a6855d3ce049c4c452a6470b1efd1504fdb7c1c134d220a",
            strip_prefix = "bazel-skylib-0.8.0",
            urls = ["https://github.com/bazelbuild/bazel-skylib/archive/0.8.0.tar.gz"],
        )

    if "gzip" not in excludes:
        local_tool(
            name = "gzip",
        )

    if "bazel_gazelle" not in excludes:
        http_archive(
            name = "bazel_gazelle",
            sha256 = "be9296bfd64882e3c08e3283c58fcb461fa6dd3c171764fcc4cf322f60615a9b",
            urls = ["https://github.com/bazelbuild/bazel-gazelle/releases/download/0.18.1/bazel-gazelle-0.18.1.tar.gz"],
        )

    native.register_toolchains(
        # Register the default docker toolchain that expects the 'docker'
        # executable to be in the PATH
        "@io_bazel_rules_docker//toolchains/docker:default_linux_toolchain",
        "@io_bazel_rules_docker//toolchains/docker:default_windows_toolchain",
        "@io_bazel_rules_docker//toolchains/docker:default_osx_toolchain",
    )

    if "docker_config" not in excludes:
        # Automatically configure the docker toolchain rule to use the default
        # docker binary from the system path
        _docker_toolchain_configure(name = "docker_config")
<commit_msg>Update subpar commit hash to 2917d27 (#1054)<commit_after># Copyright 2017 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Rules to load all dependencies of rules_docker."""

load(
    "@bazel_tools//tools/build_defs/repo:http.bzl",
    "http_archive",
    "http_file",
)
load(
    "@io_bazel_rules_docker//toolchains/docker:toolchain.bzl",
    _docker_toolchain_configure = "toolchain_configure",
)

# The release of the github.com/google/containerregistry to consume.
CONTAINERREGISTRY_RELEASE = "v0.0.36"
RULES_DOCKER_GO_BINARY_RELEASE = "e65f10d1032ad8c56d713696d231338aa87df10a"

_local_tool_build_template = """
sh_binary(
    name = "{name}",
    srcs = ["bin/{name}"],
    visibility = ["//visibility:public"],
)
"""

def _local_tool(repository_ctx):
    rctx = repository_ctx
    realpath = rctx.which(rctx.name)
    rctx.symlink(realpath, "bin/%s" % rctx.name)
    rctx.file(
        "WORKSPACE",
        'workspace(name = "{}")\n'.format(rctx.name),
    )
    rctx.file(
        "BUILD",
        _local_tool_build_template.format(name = rctx.name),
    )

local_tool = repository_rule(
    local = True,
    implementation = _local_tool,
)

def repositories():
    """Download dependencies of container rules."""
    excludes = native.existing_rules().keys()

    # Go binaries.
    if "go_puller_linux" not in excludes:
        http_file(
            name = "go_puller_linux",
            executable = True,
            sha256 = "561e3d59186c55852c0bf5b4fbe9bd728909d7c20085a2538884a3aee8f24bc6",
            urls = [("https://storage.googleapis.com/rules_docker/" + RULES_DOCKER_GO_BINARY_RELEASE + "/puller-linux-amd64")],
        )

    if "go_puller_darwin" not in excludes:
        http_file(
            name = "go_puller_darwin",
            executable = True,
            sha256 = "6ba9a537450d4d5d98b1e8226231f05fb7d7d51b3b23e8c9a4d52f78eb6a5a04",
            urls = [("https://storage.googleapis.com/rules_docker/" + RULES_DOCKER_GO_BINARY_RELEASE + "/puller-darwin-amd64")],
        )

    if "loader_linux" not in excludes:
        http_file(
            name = "loader_linux",
            executable = True,
            sha256 = "5731eacfe4d27c8868f1d8163d0cec52b1d35993fd57fc508da1ca1c10a63a57",
            urls = [("https://storage.googleapis.com/rules_docker/" + RULES_DOCKER_GO_BINARY_RELEASE + "/loader-linux-amd64")],
        )

    if "loader_darwin" not in excludes:
        http_file(
            name = "loader_darwin",
            executable = True,
            sha256 = "80ad854ae1e058d7154c421510a5afebab015ff2d1a49d50ee33842f35c90e44",
            urls = [("https://storage.googleapis.com/rules_docker/" + RULES_DOCKER_GO_BINARY_RELEASE + "/loader-darwin-amd64")],
        )

    # Legacy Python binaries.
    if "puller" not in excludes:
        http_file(
            name = "puller",
            executable = True,
            sha256 = "75ffb6edfee4bfcfbccd7ebee641dd90b4e2f73c773a9cca04cd0ec849576624",
            urls = [("https://storage.googleapis.com/containerregistry-releases/" +
                     CONTAINERREGISTRY_RELEASE + "/puller.par")],
        )

    if "importer" not in excludes:
        http_file(
            name = "importer",
            executable = True,
            sha256 = "4516a7bf62b052693001fd2b649080c4bb5228dcf698f31e77481fcb37b82ab4",
            urls = [("https://storage.googleapis.com/containerregistry-releases/" +
                     CONTAINERREGISTRY_RELEASE + "/importer.par")],
        )

    if "containerregistry" not in excludes:
        http_archive(
            name = "containerregistry",
            sha256 = "a8cdf2452323e0fefa4edb01c08b2ec438c9fa3192bc9f408b89287598c12abc",
            strip_prefix = "containerregistry-" + CONTAINERREGISTRY_RELEASE[1:],
            urls = [("https://github.com/google/containerregistry/archive/" +
                     CONTAINERREGISTRY_RELEASE + ".tar.gz")],
        )

    # TODO(mattmoor): Remove all of this (copied from google/containerregistry)
    # once transitive workspace instantiation lands.

    if "io_bazel_rules_go" not in excludes:
        http_archive(
            name = "io_bazel_rules_go",
            sha256 = "8df59f11fb697743cbb3f26cfb8750395f30471e9eabde0d174c3aebc7a1cd39",
            urls = [
                "https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/rules_go/releases/download/0.19.1/rules_go-0.19.1.tar.gz",
                "https://github.com/bazelbuild/rules_go/releases/download/0.19.1/rules_go-0.19.1.tar.gz",
            ],
        )
    if "rules_python" not in excludes:
        http_archive(
            name = "rules_python",
            sha256 = "e5470e92a18aa51830db99a4d9c492cc613761d5bdb7131c04bd92b9834380f6",
            strip_prefix = "rules_python-4b84ad270387a7c439ebdccfd530e2339601ef27",
            urls = ["https://github.com/bazelbuild/rules_python/archive/4b84ad270387a7c439ebdccfd530e2339601ef27.tar.gz"],
        )

    if "httplib2" not in excludes:
        # TODO(mattmoor): Is there a clean way to override?
        http_archive(
            name = "httplib2",
            build_file_content = """
py_library(
   name = "httplib2",
   srcs = glob(["**/*.py"]),
   data = ["cacerts.txt"],
   visibility = ["//visibility:public"]
)""",
            sha256 = "2dcbd4f20e826d6405593df8c3d6b6e4e369d57586db3ec9bbba0f0e0cdc0916",
            strip_prefix = "httplib2-0.12.1/python2/httplib2/",
            type = "tar.gz",
            urls = ["https://codeload.github.com/httplib2/httplib2/tar.gz/v0.12.1"],
        )

    # Used by oauth2client
    if "six" not in excludes:
        # TODO(mattmoor): Is there a clean way to override?
        http_archive(
            name = "six",
            build_file_content = """
# Rename six.py to __init__.py
genrule(
    name = "rename",
    srcs = ["six.py"],
    outs = ["__init__.py"],
    cmd = "cat $< >$@",
)
py_library(
   name = "six",
   srcs = [":__init__.py"],
   visibility = ["//visibility:public"],
)""",
            sha256 = "e24052411fc4fbd1f672635537c3fc2330d9481b18c0317695b46259512c91d5",
            strip_prefix = "six-1.9.0/",
            type = "tar.gz",
            urls = ["https://pypi.python.org/packages/source/s/six/six-1.9.0.tar.gz"],
        )

    # Used for authentication in containerregistry
    if "oauth2client" not in excludes:
        # TODO(mattmoor): Is there a clean way to override?
        http_archive(
            name = "oauth2client",
            build_file_content = """
py_library(
   name = "oauth2client",
   srcs = glob(["**/*.py"]),
   visibility = ["//visibility:public"],
   deps = [
     "@httplib2//:httplib2",
     "@six//:six",
   ]
)""",
            sha256 = "7230f52f7f1d4566a3f9c3aeb5ffe2ed80302843ce5605853bee1f08098ede46",
            strip_prefix = "oauth2client-4.0.0/oauth2client/",
            type = "tar.gz",
            urls = ["https://codeload.github.com/google/oauth2client/tar.gz/v4.0.0"],
        )

    # Used for parallel execution in containerregistry
    if "concurrent" not in excludes:
        # TODO(mattmoor): Is there a clean way to override?
        http_archive(
            name = "concurrent",
            build_file_content = """
py_library(
   name = "concurrent",
   srcs = glob(["**/*.py"]),
   visibility = ["//visibility:public"]
)""",
            sha256 = "a7086ddf3c36203da7816f7e903ce43d042831f41a9705bc6b4206c574fcb765",
            strip_prefix = "pythonfutures-3.0.5/concurrent/",
            type = "tar.gz",
            urls = ["https://codeload.github.com/agronholm/pythonfutures/tar.gz/3.0.5"],
        )

    # For packaging python tools.
    if "subpar" not in excludes:
        http_archive(
            name = "subpar",
            sha256 = "accdc89c2349c7f62de79b6e4b6df51449117a8afb21e7a24b706424ab392cac",
            # Commit from 2019-03-07.
            strip_prefix = "subpar-2917d275ee27d7935f7809413c74eddf71a46e5c",
            urls = ["https://github.com/google/subpar/archive/2917d275ee27d7935f7809413c74eddf71a46e5c.tar.gz"],
        )

    if "structure_test_linux" not in excludes:
        http_file(
            name = "structure_test_linux",
            executable = True,
            sha256 = "cfdfedd77c04becff0ea16a4b8ebc3b57bf404c56e5408b30d4fbb35853db67c",
            urls = ["https://storage.googleapis.com/container-structure-test/v1.8.0/container-structure-test-linux-amd64"],
        )

    if "structure_test_darwin" not in excludes:
        http_file(
            name = "structure_test_darwin",
            executable = True,
            sha256 = "14e94f75112a8e1b08a2d10f2467d27db0b94232a276ddd1e1512593a7b7cf5a",
            urls = ["https://storage.googleapis.com/container-structure-test/v1.8.0/container-structure-test-darwin-amd64"],
        )

    if "container_diff" not in excludes:
        http_file(
            name = "container_diff",
            executable = True,
            sha256 = "65b10a92ca1eb575037c012c6ab24ae6fe4a913ed86b38048781b17d7cf8021b",
            urls = ["https://storage.googleapis.com/container-diff/v0.15.0/container-diff-linux-amd64"],
        )

    # For bzl_library.
    if "bazel_skylib" not in excludes:
        http_archive(
            name = "bazel_skylib",
            sha256 = "2ea8a5ed2b448baf4a6855d3ce049c4c452a6470b1efd1504fdb7c1c134d220a",
            strip_prefix = "bazel-skylib-0.8.0",
            urls = ["https://github.com/bazelbuild/bazel-skylib/archive/0.8.0.tar.gz"],
        )

    if "gzip" not in excludes:
        local_tool(
            name = "gzip",
        )

    if "bazel_gazelle" not in excludes:
        http_archive(
            name = "bazel_gazelle",
            sha256 = "be9296bfd64882e3c08e3283c58fcb461fa6dd3c171764fcc4cf322f60615a9b",
            urls = ["https://github.com/bazelbuild/bazel-gazelle/releases/download/0.18.1/bazel-gazelle-0.18.1.tar.gz"],
        )

    native.register_toolchains(
        # Register the default docker toolchain that expects the 'docker'
        # executable to be in the PATH
        "@io_bazel_rules_docker//toolchains/docker:default_linux_toolchain",
        "@io_bazel_rules_docker//toolchains/docker:default_windows_toolchain",
        "@io_bazel_rules_docker//toolchains/docker:default_osx_toolchain",
    )

    if "docker_config" not in excludes:
        # Automatically configure the docker toolchain rule to use the default
        # docker binary from the system path
        _docker_toolchain_configure(name = "docker_config")
<|endoftext|>


<commit_before>import logging
import re

from django.conf import settings
from django.utils.termcolors import colorize
try:
    # Django 1.x
    from django.core.urlresolvers import resolve
except ImportError:
    # Django 2.x
    from django.urls import resolve

DEFAULT_LOG_LEVEL = logging.DEBUG
DEFAULT_COLORIZE = True
DEFAULT_MAX_BODY_LENGTH = 50000  # log no more than 3k bytes of content
SETTING_NAMES = {
    'log_level': 'REQUEST_LOGGING_DATA_LOG_LEVEL',
    'legacy_colorize': 'REQUEST_LOGGING_DISABLE_COLORIZE',
    'colorize': 'REQUEST_LOGGING_ENABLE_COLORIZE',
    'max_body_length': 'REQUEST_LOGGING_MAX_BODY_LENGTH'
}
BINARY_REGEX = re.compile(r'(.+Content-Type:.*?)(\S+)/(\S+)(?:\r\n)*(.+)', re.S | re.I)
BINARY_TYPES = ('image', 'application')
NO_LOGGING_ATTR = 'no_logging'
NO_LOGGING_MSG = 'No logging for this endpoint'
request_logger = logging.getLogger('django.request')

class Logger:
    def log(self, level, msg, logging_context):
        args = logging_context['args']
        kwargs = logging_context['kwargs']
        for line in re.split(r'\r?\n', str(msg)):
            request_logger.log(level, line, *args, **kwargs)

    def log_error(self, level, msg, logging_context):
        self.log(level, msg, logging_context)

class ColourLogger(Logger):
    def __init__(self, log_colour, log_error_colour):
        self.log_colour = log_colour
        self.log_error_colour = log_error_colour

    def log(self, level, msg, logging_context):
        colour = self.log_error_colour if level >= logging.ERROR else self.log_colour
        self._log(level, msg, colour, logging_context)

    def log_error(self, level, msg, logging_context):
        # Forces colour to be log_error_colour no matter what level is
        self._log(level, msg, self.log_error_colour, logging_context)

    def _log(self, level, msg, colour, logging_context):
        args = logging_context['args']
        kwargs = logging_context['kwargs']
        for line in re.split(r'\r?\n', str(msg)):
            line = colorize(line, fg=colour)
            request_logger.log(level, line, *args, **kwargs)

class LoggingMiddleware(object):
    def __init__(self, get_response=None):
        self.get_response = get_response

        self.log_level = getattr(settings, SETTING_NAMES['log_level'], DEFAULT_LOG_LEVEL)
        if self.log_level not in [logging.NOTSET, logging.DEBUG, logging.INFO,
                                  logging.WARNING, logging.ERROR, logging.CRITICAL]:
            raise ValueError("Unknown log level({}) in setting({})".format(self.log_level, SETTING_NAMES['log_level']))

        # TODO: remove deprecated legacy settings
        enable_colorize = getattr(settings, SETTING_NAMES['legacy_colorize'], None)
        if enable_colorize is None:
            enable_colorize = getattr(settings, SETTING_NAMES['colorize'], DEFAULT_COLORIZE)

        if not isinstance(enable_colorize, bool):
            raise ValueError(
                "{} should be boolean. {} is not boolean.".format(SETTING_NAMES['colorize'], enable_colorize)
            )

        self.max_body_length = getattr(settings, SETTING_NAMES['max_body_length'], DEFAULT_MAX_BODY_LENGTH)
        if not isinstance(self.max_body_length, int):
            raise ValueError(
                "{} should be int. {} is not int.".format(SETTING_NAMES['max_body_length'], self.max_body_length)
            )

        self.logger = ColourLogger("cyan", "magenta") if enable_colorize else Logger()
        self.boundary = ''

    def __call__(self, request):
        skip_logging_because = self._should_log_route(request)
        if skip_logging_because:
            return self._skip_logging(request, skip_logging_because)
        else:
            return self._log_cycle(request)

    def _skip_logging(self, request, reason):
        method_path = "{} {}".format(request.method, request.get_full_path())
        no_log_context = {
            'args': (),
            'kwargs': {
                'extra': {
                    'no_logging': reason
                },
            },
        }
        self.logger.log(logging.INFO, method_path + " (not logged because %s)" % reason, no_log_context)

    def _log_cycle(self, request):
        self.process_request(request)
        response = self.get_response(request)
        self.process_response(request, response)
        return response

    def process_request(self, request):
        method_path = "{} {}".format(request.method, request.get_full_path())
        no_logging = self._should_log_route(request)

        logging_context = self._get_logging_context(request, None)
        self.logger.log(logging.INFO, method_path, logging_context)
        self._log_request_headers(request, no_logging, logging_context)
        self._log_request_body(request, no_logging, logging_context)

    def _should_log_route(self, request):
        try:
            route_match = resolve(request.path)
        except:
            return None

        method = request.method.lower()
        view = route_match.func
        func = view
        # This is for "django rest framework"
        if hasattr(view, 'cls'):
            if hasattr(view, 'actions'):
                func = getattr(view.cls, view.actions[method], None)
            else:
                func = getattr(view.cls, method, None)
        elif hasattr(view, 'view_class'):
            # This is for django class-based views
            func = getattr(view.view_class, method, None)
        no_logging = getattr(func, NO_LOGGING_ATTR, None)
        return no_logging

    def _log_request_headers(self, request, no_logging, logging_context):
        headers = {k: v for k, v in request.META.items() if k.startswith('HTTP_')}

        if headers:
            self.logger.log(self.log_level, headers, logging_context)

    def _log_request_body(self, request, no_logging, logging_context):
        if request.body:
            if no_logging is not None:
                self.logger.log(self.log_level, no_logging, logging_context)
            else:
                content_type = request.META.get('CONTENT_TYPE', '')
                is_multipart = content_type.startswith('multipart/form-data')
                if is_multipart:
                    self.boundary = '--' + content_type[30:]  # First 30 characters are "multipart/form-data; boundary="
                if is_multipart:
                    self._log_multipart(self._chunked_to_max(request.body), logging_context)
                else:
                    self.logger.log(self.log_level, self._chunked_to_max(request.body), logging_context)

    def process_response(self, request, response):
        resp_log = "{} {} - {}".format(request.method, request.get_full_path(), response.status_code)
        logging_context = self._get_logging_context(request, response)

        if response.status_code in range(400, 600):
            self.logger.log_error(logging.INFO, resp_log, logging_context)
            self._log_resp(logging.ERROR, response, logging_context)
        else:
            self.logger.log(logging.INFO, resp_log, logging_context)
            self._log_resp(self.log_level, response, logging_context)

        return response

    def _get_logging_context(self, request, response):
        """
        Returns a map with args and kwargs to provide additional context to calls to logging.log().
        This allows the logging context to be created per process request/response call.

        """
        return {
            'args': (),
            'kwargs': {
                'extra': {
                    'request': request,
                    'response': response,
                },
            },
        }

    def _log_multipart(self, body, logging_context):
        """
        Splits multipart body into parts separated by "boundary", then matches each part to BINARY_REGEX
        which searches for existance of "Content-Type" and capture of what type is this part.
        If it is an image or an application replace that content with "(binary data)" string.
        This function will log "(multipart/form)" if body can't be decoded by utf-8.
        """
        try:
            body_str = body if isinstance(body, str) else body.decode()
        except UnicodeDecodeError:
            self.logger.log(self.log_level, "(multipart/form)", logging_context)
            return

        parts = body_str.split(self.boundary)
        last = len(parts) - 1
        for i, part in enumerate(parts):
            if 'Content-Type:' in part:
                match = BINARY_REGEX.search(part)
                if match and match.group(2) in BINARY_TYPES and not match.group(4) in ('', '\r\n'):
                    part = match.expand(r'\1\2/\3\r\n\r\n(binary data)\r\n')

            if i != last:
                part = part + self.boundary

            self.logger.log(self.log_level, part, logging_context)

    def _log_resp(self, level, response, logging_context):
        if re.match('^application/json', response.get('Content-Type', ''), re.I):
            self.logger.log(level, response._headers, logging_context)
            self.logger.log(level, self._chunked_to_max(response.content), logging_context)

    def _chunked_to_max(self, msg):
        return msg[0:self.max_body_length]
<commit_msg>Avoid string interpolation if it's not needed<commit_after>import logging
import re

from django.conf import settings
from django.utils.termcolors import colorize
try:
    # Django 1.x
    from django.core.urlresolvers import resolve
except ImportError:
    # Django 2.x
    from django.urls import resolve

DEFAULT_LOG_LEVEL = logging.DEBUG
DEFAULT_COLORIZE = True
DEFAULT_MAX_BODY_LENGTH = 50000  # log no more than 3k bytes of content
SETTING_NAMES = {
    'log_level': 'REQUEST_LOGGING_DATA_LOG_LEVEL',
    'legacy_colorize': 'REQUEST_LOGGING_DISABLE_COLORIZE',
    'colorize': 'REQUEST_LOGGING_ENABLE_COLORIZE',
    'max_body_length': 'REQUEST_LOGGING_MAX_BODY_LENGTH'
}
BINARY_REGEX = re.compile(r'(.+Content-Type:.*?)(\S+)/(\S+)(?:\r\n)*(.+)', re.S | re.I)
BINARY_TYPES = ('image', 'application')
NO_LOGGING_ATTR = 'no_logging'
NO_LOGGING_MSG = 'No logging for this endpoint'
request_logger = logging.getLogger('django.request')

class Logger:
    def log(self, level, msg, logging_context):
        args = logging_context['args']
        kwargs = logging_context['kwargs']
        for line in re.split(r'\r?\n', str(msg)):
            request_logger.log(level, line, *args, **kwargs)

    def log_error(self, level, msg, logging_context):
        self.log(level, msg, logging_context)

class ColourLogger(Logger):
    def __init__(self, log_colour, log_error_colour):
        self.log_colour = log_colour
        self.log_error_colour = log_error_colour

    def log(self, level, msg, logging_context):
        colour = self.log_error_colour if level >= logging.ERROR else self.log_colour
        self._log(level, msg, colour, logging_context)

    def log_error(self, level, msg, logging_context):
        # Forces colour to be log_error_colour no matter what level is
        self._log(level, msg, self.log_error_colour, logging_context)

    def _log(self, level, msg, colour, logging_context):
        args = logging_context['args']
        kwargs = logging_context['kwargs']
        for line in re.split(r'\r?\n', str(msg)):
            line = colorize(line, fg=colour)
            request_logger.log(level, line, *args, **kwargs)

class LoggingMiddleware(object):
    def __init__(self, get_response=None):
        self.get_response = get_response

        self.log_level = getattr(settings, SETTING_NAMES['log_level'], DEFAULT_LOG_LEVEL)
        if self.log_level not in [logging.NOTSET, logging.DEBUG, logging.INFO,
                                  logging.WARNING, logging.ERROR, logging.CRITICAL]:
            raise ValueError("Unknown log level({}) in setting({})".format(self.log_level, SETTING_NAMES['log_level']))

        # TODO: remove deprecated legacy settings
        enable_colorize = getattr(settings, SETTING_NAMES['legacy_colorize'], None)
        if enable_colorize is None:
            enable_colorize = getattr(settings, SETTING_NAMES['colorize'], DEFAULT_COLORIZE)

        if not isinstance(enable_colorize, bool):
            raise ValueError(
                "{} should be boolean. {} is not boolean.".format(SETTING_NAMES['colorize'], enable_colorize)
            )

        self.max_body_length = getattr(settings, SETTING_NAMES['max_body_length'], DEFAULT_MAX_BODY_LENGTH)
        if not isinstance(self.max_body_length, int):
            raise ValueError(
                "{} should be int. {} is not int.".format(SETTING_NAMES['max_body_length'], self.max_body_length)
            )

        self.logger = ColourLogger("cyan", "magenta") if enable_colorize else Logger()
        self.boundary = ''

    def __call__(self, request):
        skip_logging_because = self._should_log_route(request)
        if skip_logging_because:
            return self._skip_logging(request, skip_logging_because)
        else:
            return self._log_cycle(request)

    def _skip_logging(self, request, reason):
        method_path = "{} {}".format(request.method, request.get_full_path())
        no_log_context = {
            'args': (),
            'kwargs': {
                'extra': {
                    'no_logging': reason
                },
            },
        }
        self.logger.info("{} {} (reason: {})", request.method, request.get_full_path(), reason)

    def _log_cycle(self, request):
        self.process_request(request)
        response = self.get_response(request)
        self.process_response(request, response)
        return response

    def process_request(self, request):
        method_path = "{} {}".format(request.method, request.get_full_path())
        no_logging = self._should_log_route(request)

        logging_context = self._get_logging_context(request, None)
        self.logger.log(logging.INFO, method_path, logging_context)
        self._log_request_headers(request, no_logging, logging_context)
        self._log_request_body(request, no_logging, logging_context)

    def _should_log_route(self, request):
        try:
            route_match = resolve(request.path)
        except:
            return None

        method = request.method.lower()
        view = route_match.func
        func = view
        # This is for "django rest framework"
        if hasattr(view, 'cls'):
            if hasattr(view, 'actions'):
                func = getattr(view.cls, view.actions[method], None)
            else:
                func = getattr(view.cls, method, None)
        elif hasattr(view, 'view_class'):
            # This is for django class-based views
            func = getattr(view.view_class, method, None)
        no_logging = getattr(func, NO_LOGGING_ATTR, None)
        return no_logging

    def _log_request_headers(self, request, no_logging, logging_context):
        headers = {k: v for k, v in request.META.items() if k.startswith('HTTP_')}

        if headers:
            self.logger.log(self.log_level, headers, logging_context)

    def _log_request_body(self, request, no_logging, logging_context):
        if request.body:
            if no_logging is not None:
                self.logger.log(self.log_level, no_logging, logging_context)
            else:
                content_type = request.META.get('CONTENT_TYPE', '')
                is_multipart = content_type.startswith('multipart/form-data')
                if is_multipart:
                    self.boundary = '--' + content_type[30:]  # First 30 characters are "multipart/form-data; boundary="
                if is_multipart:
                    self._log_multipart(self._chunked_to_max(request.body), logging_context)
                else:
                    self.logger.log(self.log_level, self._chunked_to_max(request.body), logging_context)

    def process_response(self, request, response):
        resp_log = "{} {} - {}".format(request.method, request.get_full_path(), response.status_code)
        logging_context = self._get_logging_context(request, response)

        if response.status_code in range(400, 600):
            self.logger.log_error(logging.INFO, resp_log, logging_context)
            self._log_resp(logging.ERROR, response, logging_context)
        else:
            self.logger.log(logging.INFO, resp_log, logging_context)
            self._log_resp(self.log_level, response, logging_context)

        return response

    def _get_logging_context(self, request, response):
        """
        Returns a map with args and kwargs to provide additional context to calls to logging.log().
        This allows the logging context to be created per process request/response call.

        """
        return {
            'args': (),
            'kwargs': {
                'extra': {
                    'request': request,
                    'response': response,
                },
            },
        }

    def _log_multipart(self, body, logging_context):
        """
        Splits multipart body into parts separated by "boundary", then matches each part to BINARY_REGEX
        which searches for existance of "Content-Type" and capture of what type is this part.
        If it is an image or an application replace that content with "(binary data)" string.
        This function will log "(multipart/form)" if body can't be decoded by utf-8.
        """
        try:
            body_str = body if isinstance(body, str) else body.decode()
        except UnicodeDecodeError:
            self.logger.log(self.log_level, "(multipart/form)", logging_context)
            return

        parts = body_str.split(self.boundary)
        last = len(parts) - 1
        for i, part in enumerate(parts):
            if 'Content-Type:' in part:
                match = BINARY_REGEX.search(part)
                if match and match.group(2) in BINARY_TYPES and not match.group(4) in ('', '\r\n'):
                    part = match.expand(r'\1\2/\3\r\n\r\n(binary data)\r\n')

            if i != last:
                part = part + self.boundary

            self.logger.log(self.log_level, part, logging_context)

    def _log_resp(self, level, response, logging_context):
        if re.match('^application/json', response.get('Content-Type', ''), re.I):
            self.logger.log(level, response._headers, logging_context)
            self.logger.log(level, self._chunked_to_max(response.content), logging_context)

    def _chunked_to_max(self, msg):
        return msg[0:self.max_body_length]
<|endoftext|>


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

"""
Test variable expansion of '<!()' syntax commands.

This is complicated by the fact that the output changes if the
user has a ~/.gyp/include.gpi file.  A variable expansion shows
up in the "--debug variables" output, and the include.gypi file
shows up in the 'included_files' list in the commands.gypd output.
We do some regular expression substitutions to strip those before
comparing against our expected output, which is somewhat grungy
but probably less of a hassle overall than trying to massage the
expected output.
"""

import re

import TestGyp

test = TestGyp.TestGyp(format='gypd')

test.run_gyp('commands.gyp', '--debug', 'variables', '--debug', 'general')

# Strip the variable expansion line from the output
# before we compare it by hand.

include_gypi_line = r"^VARIABLES: Expanding .*\.gyp/include\.gypi'$\n"
include_gypi = re.compile(include_gypi_line, re.M)
output = include_gypi.sub('', test.stdout())

expect = test.read('commands.gyp.stdout')

if output != expect:
  test.diff(expect, output, 'STDOUT ')
  test.fail_test()

# Strip the include.gypi string from commands.gypd output
# before we compare it by hand.

include_gypi = re.compile(",[^']*'[^']*\.gyp/include\.gypi',[^']*'", re.M)
contents = include_gypi.sub(", '", test.read('commands.gypd'))

expect = test.read('commands.gypd.golden')

if contents != expect:
  test.diff(expect, contents, 'commands.gypd ')
  test.fail_test()

test.pass_test()
<commit_msg>Much better fix for ~/.gyp/include.gypi affecting command output: just set the $HOME variable so the test doesn't read the user's. Review URL: http://codereview.chromium.org/174607<commit_after>#!/usr/bin/env python

"""
Test variable expansion of '<!()' syntax commands.
"""

import os

import TestGyp

test = TestGyp.TestGyp(format='gypd')

expect = test.read('commands.gyp.stdout')

# Set $HOME so that gyp doesn't read the user's actual
# ~/.gyp/include.gypi file, which may contain variables
# and other settings that would change the output.
os.environ['HOME'] = test.workpath()

test.run_gyp('commands.gyp',
             '--debug', 'variables', '--debug', 'general',
             stdout=expect)

test.must_match('commands.gypd', test.read('commands.gypd.golden'))

test.pass_test()
<|endoftext|>


<commit_before>#!/usr/bin/env python2
# -*- coding: utf-8-*-
import os
import sys

if os.environ.get('JASPER_HOME') is None:
    os.environ['JASPER_HOME'] = '/home/pi'

import unittest
import argparse
from mock import patch
from urllib2 import URLError, urlopen
import test_mic
import vocabcompiler
import g2p
import brain
from diagnose import Diagnostics

DEFAULT_PROFILE = {
    'prefers_email': False,
    'location': '08544',
    'timezone': 'US/Eastern',
    'phone_number': '012344321'
}

def activeInternet():
    return Diagnostics.check_network_connection()

class UnorderedList(list):

    def __eq__(self, other):
        return sorted(self) == sorted(other)

class TestVocabCompiler(unittest.TestCase):

    def testWordExtraction(self):
        sentences = "temp_sentences.txt"
        dictionary = "temp_dictionary.dic"
        languagemodel = "temp_languagemodel.lm"

        words = [
            'HACKER', 'LIFE', 'FACEBOOK', 'THIRD', 'NO', 'JOKE',
            'NOTIFICATION', 'MEANING', 'TIME', 'TODAY', 'SECOND',
            'BIRTHDAY', 'KNOCK KNOCK', 'INBOX', 'OF', 'NEWS', 'YES',
            'TOMORROW', 'EMAIL', 'WEATHER', 'FIRST', 'MUSIC', 'SPOTIFY'
        ]

        with patch.object(g2p, 'translateWords') as translateWords:
            with patch.object(vocabcompiler, 'text2lm') as text2lm:
                vocabcompiler.compile(sentences, dictionary, languagemodel)

                # 'words' is appended with ['MUSIC', 'SPOTIFY']
                # so must be > 2 to have received WORDS from modules
                translateWords.assert_called_once_with(UnorderedList(words))
                self.assertTrue(text2lm.called)
        os.remove(sentences)
        os.remove(dictionary)

class TestMic(unittest.TestCase):

    def setUp(self):
        self.jasper_clip = "../static/audio/jasper.wav"
        self.time_clip = "../static/audio/time.wav"

        from stt import PocketSphinxSTT
        self.stt = PocketSphinxSTT()

    def testTranscribeJasper(self):
        """Does Jasper recognize his name (i.e., passive listen)?"""
        transcription = self.stt.transcribe(self.jasper_clip, PERSONA_ONLY=True)
        self.assertTrue("JASPER" in transcription)

    def testTranscribe(self):
        """Does Jasper recognize 'time' (i.e., active listen)?"""
        transcription = self.stt.transcribe(self.time_clip)
        self.assertTrue("TIME" in transcription)

class TestG2P(unittest.TestCase):

    def setUp(self):
        self.translations = {
            'GOOD': 'G UH D',
            'BAD': 'B AE D',
            'UGLY': 'AH G L IY'
        }

    def testTranslateWord(self):
        for word in self.translations:
            translation = self.translations[word]
            self.assertEqual(g2p.translateWord(word), translation)

    def testTranslateWords(self):
        words = self.translations.keys()
        # preserve ordering
        translations = [self.translations[w] for w in words]
        self.assertEqual(g2p.translateWords(words), translations)

class TestModules(unittest.TestCase):

    def setUp(self):
        self.profile = DEFAULT_PROFILE
        self.send = False

    def runConversation(self, query, inputs, module):
        """Generic method for spoofing conversation.

        Arguments:
        query -- The initial input to the server.
        inputs -- Additional input, if conversation is extended.

        Returns:
        The server's responses, in a list.
        """
        self.assertTrue(module.isValid(query))
        mic = test_mic.Mic(inputs)
        module.handle(query, mic, self.profile)
        return mic.outputs

    def testLife(self):
        from modules import Life

        query = "What is the meaning of life?"
        inputs = []
        outputs = self.runConversation(query, inputs, Life)
        self.assertEqual(len(outputs), 1)
        self.assertTrue("42" in outputs[0])

    def testJoke(self):
        from modules import Joke

        query = "Tell me a joke."
        inputs = ["Who's there?", "Random response"]
        outputs = self.runConversation(query, inputs, Joke)
        self.assertEqual(len(outputs), 3)
        allJokes = open("../static/text/JOKES.txt", "r").read()
        self.assertTrue(outputs[2] in allJokes)

    def testTime(self):
        from modules import Time

        query = "What time is it?"
        inputs = []
        self.runConversation(query, inputs, Time)

    @unittest.skipIf(not activeInternet(), "No internet connection")
    def testGmail(self):
        key = 'gmail_password'
        if not key in self.profile or not self.profile[key]:
            return

        from modules import Gmail

        query = "Check my email"
        inputs = []
        self.runConversation(query, inputs, Gmail)

    @unittest.skipIf(not activeInternet(), "No internet connection")
    def testHN(self):
        from modules import HN

        query = "find me some of the top hacker news stories"
        if self.send:
            inputs = ["the first and third"]
        else:
            inputs = ["no"]
        outputs = self.runConversation(query, inputs, HN)
        self.assertTrue("front-page articles" in outputs[1])

    @unittest.skipIf(not activeInternet(), "No internet connection")
    def testNews(self):
        from modules import News

        query = "find me some of the top news stories"
        if self.send:
            inputs = ["the first"]
        else:
            inputs = ["no"]
        outputs = self.runConversation(query, inputs, News)
        self.assertTrue("top headlines" in outputs[1])

    @unittest.skipIf(not activeInternet(), "No internet connection")
    def testWeather(self):
        from modules import Weather

        query = "what's the weather like tomorrow"
        inputs = []
        outputs = self.runConversation(query, inputs, Weather)
        self.assertTrue(
            "can't see that far ahead" in outputs[0]
            or "Tomorrow" in outputs[0])

class TestBrain(unittest.TestCase):

    @staticmethod
    def _emptyBrain():
        mic = test_mic.Mic([])
        profile = DEFAULT_PROFILE
        return brain.Brain(mic, profile)

    @patch.object(brain, 'logError')
    def testLog(self, logError):
        """Does Brain correctly log errors when raised by modules?"""
        my_brain = TestBrain._emptyBrain()
        unclear = my_brain.modules[-1]
        with patch.object(unclear, 'handle') as mocked_handle:
            mocked_handle.side_effect = KeyError('foo')
            my_brain.query("zzz gibberish zzz")
            logError.assert_called_with()

    def testSortByPriority(self):
        """Does Brain sort modules by priority?"""
        my_brain = TestBrain._emptyBrain()
        priorities = filter(lambda m: hasattr(m, 'PRIORITY'), my_brain.modules)
        target = sorted(priorities, key=lambda m: m.PRIORITY, reverse=True)
        self.assertEqual(target, priorities)

    def testPriority(self):
        """Does Brain correctly send query to higher-priority module?"""
        my_brain = TestBrain._emptyBrain()
        hn_module = 'modules.HN'
        hn = filter(lambda m: m.__name__ == hn_module, my_brain.modules)[0]

        with patch.object(hn, 'handle') as mocked_handle:
            my_brain.query("hacker news")
            self.assertTrue(mocked_handle.called)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description='Test suite for the Jasper client code.')
    parser.add_argument('--light', action='store_true',
                        help='runs a subset of the tests (only requires Python dependencies)')
    args = parser.parse_args()

    test_cases = [TestBrain, TestModules, TestVocabCompiler]
    if not args.light:
        test_cases.append(TestG2P)
        test_cases.append(TestMic)

    suite = unittest.TestSuite()

    for test_case in test_cases:
        suite.addTests(unittest.TestLoader().loadTestsFromTestCase(test_case))

    result = unittest.TextTestRunner(verbosity=2).run(suite)

    if not result.wasSuccessful():
        sys.exit("Tests failed")
<commit_msg>Use jasperpath in client/test.py<commit_after>#!/usr/bin/env python2
# -*- coding: utf-8-*-
import os
import sys

if os.environ.get('JASPER_HOME') is None:
    os.environ['JASPER_HOME'] = '/home/pi'

import unittest
import argparse
from mock import patch
from urllib2 import URLError, urlopen
import test_mic
import vocabcompiler
import g2p
import brain
import jasperpath
from diagnose import Diagnostics

DEFAULT_PROFILE = {
    'prefers_email': False,
    'location': '08544',
    'timezone': 'US/Eastern',
    'phone_number': '012344321'
}

def activeInternet():
    return Diagnostics.check_network_connection()

class UnorderedList(list):

    def __eq__(self, other):
        return sorted(self) == sorted(other)

class TestVocabCompiler(unittest.TestCase):

    def testWordExtraction(self):
        sentences = "temp_sentences.txt"
        dictionary = "temp_dictionary.dic"
        languagemodel = "temp_languagemodel.lm"

        words = [
            'HACKER', 'LIFE', 'FACEBOOK', 'THIRD', 'NO', 'JOKE',
            'NOTIFICATION', 'MEANING', 'TIME', 'TODAY', 'SECOND',
            'BIRTHDAY', 'KNOCK KNOCK', 'INBOX', 'OF', 'NEWS', 'YES',
            'TOMORROW', 'EMAIL', 'WEATHER', 'FIRST', 'MUSIC', 'SPOTIFY'
        ]

        with patch.object(g2p, 'translateWords') as translateWords:
            with patch.object(vocabcompiler, 'text2lm') as text2lm:
                vocabcompiler.compile(sentences, dictionary, languagemodel)

                # 'words' is appended with ['MUSIC', 'SPOTIFY']
                # so must be > 2 to have received WORDS from modules
                translateWords.assert_called_once_with(UnorderedList(words))
                self.assertTrue(text2lm.called)
        os.remove(sentences)
        os.remove(dictionary)

class TestMic(unittest.TestCase):

    def setUp(self):
        self.jasper_clip = jasperpath.data('audio', 'jasper.wav')
        self.time_clip = jasperpath.data('audio', 'time.wav')

        from stt import PocketSphinxSTT
        self.stt = PocketSphinxSTT()

    def testTranscribeJasper(self):
        """Does Jasper recognize his name (i.e., passive listen)?"""
        transcription = self.stt.transcribe(self.jasper_clip, PERSONA_ONLY=True)
        self.assertTrue("JASPER" in transcription)

    def testTranscribe(self):
        """Does Jasper recognize 'time' (i.e., active listen)?"""
        transcription = self.stt.transcribe(self.time_clip)
        self.assertTrue("TIME" in transcription)

class TestG2P(unittest.TestCase):

    def setUp(self):
        self.translations = {
            'GOOD': 'G UH D',
            'BAD': 'B AE D',
            'UGLY': 'AH G L IY'
        }

    def testTranslateWord(self):
        for word in self.translations:
            translation = self.translations[word]
            self.assertEqual(g2p.translateWord(word), translation)

    def testTranslateWords(self):
        words = self.translations.keys()
        # preserve ordering
        translations = [self.translations[w] for w in words]
        self.assertEqual(g2p.translateWords(words), translations)

class TestModules(unittest.TestCase):

    def setUp(self):
        self.profile = DEFAULT_PROFILE
        self.send = False

    def runConversation(self, query, inputs, module):
        """Generic method for spoofing conversation.

        Arguments:
        query -- The initial input to the server.
        inputs -- Additional input, if conversation is extended.

        Returns:
        The server's responses, in a list.
        """
        self.assertTrue(module.isValid(query))
        mic = test_mic.Mic(inputs)
        module.handle(query, mic, self.profile)
        return mic.outputs

    def testLife(self):
        from modules import Life

        query = "What is the meaning of life?"
        inputs = []
        outputs = self.runConversation(query, inputs, Life)
        self.assertEqual(len(outputs), 1)
        self.assertTrue("42" in outputs[0])

    def testJoke(self):
        from modules import Joke

        query = "Tell me a joke."
        inputs = ["Who's there?", "Random response"]
        outputs = self.runConversation(query, inputs, Joke)
        self.assertEqual(len(outputs), 3)
        allJokes = open(jasperpath.data('text','JOKES.txt'), 'r').read()
        self.assertTrue(outputs[2] in allJokes)

    def testTime(self):
        from modules import Time

        query = "What time is it?"
        inputs = []
        self.runConversation(query, inputs, Time)

    @unittest.skipIf(not activeInternet(), "No internet connection")
    def testGmail(self):
        key = 'gmail_password'
        if not key in self.profile or not self.profile[key]:
            return

        from modules import Gmail

        query = "Check my email"
        inputs = []
        self.runConversation(query, inputs, Gmail)

    @unittest.skipIf(not activeInternet(), "No internet connection")
    def testHN(self):
        from modules import HN

        query = "find me some of the top hacker news stories"
        if self.send:
            inputs = ["the first and third"]
        else:
            inputs = ["no"]
        outputs = self.runConversation(query, inputs, HN)
        self.assertTrue("front-page articles" in outputs[1])

    @unittest.skipIf(not activeInternet(), "No internet connection")
    def testNews(self):
        from modules import News

        query = "find me some of the top news stories"
        if self.send:
            inputs = ["the first"]
        else:
            inputs = ["no"]
        outputs = self.runConversation(query, inputs, News)
        self.assertTrue("top headlines" in outputs[1])

    @unittest.skipIf(not activeInternet(), "No internet connection")
    def testWeather(self):
        from modules import Weather

        query = "what's the weather like tomorrow"
        inputs = []
        outputs = self.runConversation(query, inputs, Weather)
        self.assertTrue(
            "can't see that far ahead" in outputs[0]
            or "Tomorrow" in outputs[0])

class TestBrain(unittest.TestCase):

    @staticmethod
    def _emptyBrain():
        mic = test_mic.Mic([])
        profile = DEFAULT_PROFILE
        return brain.Brain(mic, profile)

    @patch.object(brain, 'logError')
    def testLog(self, logError):
        """Does Brain correctly log errors when raised by modules?"""
        my_brain = TestBrain._emptyBrain()
        unclear = my_brain.modules[-1]
        with patch.object(unclear, 'handle') as mocked_handle:
            mocked_handle.side_effect = KeyError('foo')
            my_brain.query("zzz gibberish zzz")
            logError.assert_called_with()

    def testSortByPriority(self):
        """Does Brain sort modules by priority?"""
        my_brain = TestBrain._emptyBrain()
        priorities = filter(lambda m: hasattr(m, 'PRIORITY'), my_brain.modules)
        target = sorted(priorities, key=lambda m: m.PRIORITY, reverse=True)
        self.assertEqual(target, priorities)

    def testPriority(self):
        """Does Brain correctly send query to higher-priority module?"""
        my_brain = TestBrain._emptyBrain()
        hn_module = 'modules.HN'
        hn = filter(lambda m: m.__name__ == hn_module, my_brain.modules)[0]

        with patch.object(hn, 'handle') as mocked_handle:
            my_brain.query("hacker news")
            self.assertTrue(mocked_handle.called)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description='Test suite for the Jasper client code.')
    parser.add_argument('--light', action='store_true',
                        help='runs a subset of the tests (only requires Python dependencies)')
    args = parser.parse_args()

    test_cases = [TestBrain, TestModules, TestVocabCompiler]
    if not args.light:
        test_cases.append(TestG2P)
        test_cases.append(TestMic)

    suite = unittest.TestSuite()

    for test_case in test_cases:
        suite.addTests(unittest.TestLoader().loadTestsFromTestCase(test_case))

    result = unittest.TextTestRunner(verbosity=2).run(suite)

    if not result.wasSuccessful():
        sys.exit("Tests failed")
<|endoftext|>


<commit_before>from rest_framework import serializers
from rest_framework.renderers import JSONRenderer
from drf_compound_fields.fields import DictField

class KLPGeoSerializer(serializers.ModelSerializer):

    renderer_classes = (JSONRenderer,)

    #this will get geometry as a dict from a get_geometry method on the model being serialized
    geometry = DictField(source='get_geometry')

    def __init__(self, *args, **kwargs):
        super(KLPGeoSerializer, self).__init__(*args, **kwargs)
        request = kwargs['context']['request']
        geometry = request.GET.get('geometry', 'no')
        #remove geometry field if geometry=yes param not set
        if geometry != 'yes':
            self.fields.pop('geometry')

<commit_msg>remove renderer_classes property from serializer since we put that in settings<commit_after>from rest_framework import serializers
from rest_framework.renderers import JSONRenderer
from drf_compound_fields.fields import DictField

class KLPGeoSerializer(serializers.ModelSerializer):

    #this will get geometry as a dict from a get_geometry method on the model being serialized
    geometry = DictField(source='get_geometry')

    def __init__(self, *args, **kwargs):
        super(KLPGeoSerializer, self).__init__(*args, **kwargs)
        request = kwargs['context']['request']
        geometry = request.GET.get('geometry', 'no')
        #remove geometry field if geometry=yes param not set
        if geometry != 'yes':
            self.fields.pop('geometry')

<|endoftext|>