<commit_before>from discord.ext.commands import bot
import discord

from main import owner_id
from config.config import Config

def owner(ctx):
    return owner_id == ctx.message.author.id

class selfAssign():
    def __init__(self, Bot):
        self.bot = Bot
        self.con = Config(Bot)

    @bot.command(pass_context=True)
    async def listroles(self, ctx):
        """
        List's all roles that can be self-assigned on this server.
        Usage:
            {command_prefix}listroles
        """
        roles = []
        for role in self.con.serverconfig[ctx.message.server.id]["selfAssign"]["roles"]:
            for serverrole in ctx.message.server.roles:
                if role == serverrole.id:
                    roles.append(serverrole.name)
        return await self.bot.say(str(roles).strip("[]'"))

    @bot.command(pass_context=True)
    async def iam(self, ctx, role: discord.Role = None):
        """
        Self-assign yourself a role. Only one role at a time. Doesn't work for roles with spaces.
        Usage:
            {command_prefix}iam [role]
        Example:
            .iam OverwatchPing
        """
        self.con.serverconfig = self.con.load_config()
        if not self.con.serverconfig[ctx.message.server.id]["selfAssign"]["enabled"]:
            return

        user = ctx.message.author
        server = ctx.message.server

        if role not in server.roles:
            return await self.bot.say("That role doesn't exist. Roles are case sensitive. ")

        if role in user.roles:
            return await self.bot.say("You already have that role.")

        if role.id in self.con.serverconfig[ctx.message.server.id]["selfAssign"]["roles"]:
            await self.bot.add_roles(user, role)
            print("{} added {} to themselves in {} on {}".format(user.display_name, role.name, ctx.message.channel,
                                                                 ctx.message.server))
            return await self.bot.say("Yay {}! You now have the {} role!".format(user.mention, role.name))
        else:
            return await self.bot.say("That role is not self-assignable.")

    @bot.command(pass_context=True)
    async def iamn(self, ctx, role: discord.Role = None):
        """
        Remove a self-assigned role
        Usage:
            {command_prefix}iamn [role]
        Example:
            .iamn OverwatchPing
        """
        self.con.serverconfig = self.con.load_config()
        if not self.con.serverconfig[ctx.message.server.id]["selfAssign"]["enabled"]:
            return

        user = ctx.message.author
        server = ctx.message.server

        if role not in server.roles:
            return await self.bot.say("That role doesn't exist. Roles are case sensitive. ")

        elif role in user.roles and role.id in self.con.serverconfig[ctx.message.server.id]["selfAssign"]["roles"]:
            await self.bot.remove_roles(user, role)
            return await self.bot.reply("{} has been successfully removed.".format(role.name))

        elif role not in user.roles and role.id in self.con.serverconfig[ctx.message.server.id]["selfAssign"]["roles"]:
            return await self.bot.reply("You do not have {}.".format(role.name))
        else:
            return await self.bot.say("That role is not self-assignable.")

    @bot.command(pass_context=True, hidden=True)
    async def addrole(self, ctx, role: discord.Role = None):
        if not owner(ctx):
            return await self.bot.reply(self.con.no_perms_reponse, delete_after=self.con.delete_after)
        else:
            if role.id in self.con.serverconfig[ctx.message.server.id]["selfAssign"]["roles"]:
                return await self.bot.say("{} is already a self-assignable role.".format(role.name), delete_after=self.con.delete_after)
            self.con.serverconfig = self.con.load_config()
            self.con.serverconfig[ctx.message.server.id]["selfAssign"]["roles"].append(role.id)
            self.con.updateconfig()
            return await self.bot.say('Role "{}" added'.format(str(role)))

    @bot.command(pass_context=True, hidden=True)
    async def removerole(self, ctx, role: discord.Role = None):
        if not owner(ctx):
            return await self.bot.reply(self.con.no_perms_reponse, delete_after=self.con.delete_after)
        else:
            self.con.serverconfig = self.con.load_config()
            if role.id in self.con.serverconfig[ctx.message.server.id]["selfAssign"]["roles"]:
                self.con.serverconfig[ctx.message.server.id]["selfAssign"]["roles"].remove(role.id)
                self.con.updateconfig()
                return await self.bot.say('"{}" has been removed from the self-assignable roles.'.format(str(role)))
            else:
                return await self.bot.say("That role was not in the list.")

def setup(Bot):
    Bot.add_cog(selfAssign(Bot))<commit_msg>Various bug fixes (twitch shilling, config issues with greets and goodbyes. naming issue in admin.py) some small changes to ux and some extra todos.<commit_after>from discord.ext.commands import bot
import discord

from main import owner_id
from config.config import Config

def owner(ctx):
    return owner_id == ctx.message.author.id

class selfAssign():
    def __init__(self, Bot):
        self.bot = Bot
        self.con = Config(Bot)

    @bot.command(pass_context=True)
    async def listroles(self, ctx):
        """
        List's all roles that can be self-assigned on this server.
        Usage:
            {command_prefix}listroles
        """
        roles = []
        for role in self.con.serverconfig[ctx.message.server.id]["selfAssign"]["roles"]:
            for serverrole in ctx.message.server.roles:
                if role == serverrole.id:
                    roles.append(serverrole.name)
        return await self.bot.say(str(roles).strip("[]"))

    @bot.command(pass_context=True)
    async def iam(self, ctx, role: discord.Role = None):
        """
        Self-assign yourself a role. Only one role at a time. Doesn't work for roles with spaces.
        Usage:
            {command_prefix}iam [role]
        Example:
            .iam OverwatchPing
        """
        self.con.serverconfig = self.con.load_config()
        if not self.con.serverconfig[ctx.message.server.id]["selfAssign"]["enabled"]:
            return

        user = ctx.message.author
        server = ctx.message.server

        if role not in server.roles:
            return await self.bot.say("That role doesn't exist. Roles are case sensitive. ")

        if role in user.roles:
            return await self.bot.say("You already have that role.")

        if role.id in self.con.serverconfig[ctx.message.server.id]["selfAssign"]["roles"]:
            await self.bot.add_roles(user, role)
            print("{} added {} to themselves in {} on {}".format(user.display_name, role.name, ctx.message.channel,
                                                                 ctx.message.server))
            return await self.bot.say("Yay {}! You now have the {} role!".format(user.mention, role.name))
        else:
            return await self.bot.say("That role is not self-assignable.")

    @bot.command(pass_context=True)
    async def iamn(self, ctx, role: discord.Role = None):
        """
        Remove a self-assigned role
        Usage:
            {command_prefix}iamn [role]
        Example:
            .iamn OverwatchPing
        """
        self.con.serverconfig = self.con.load_config()
        if not self.con.serverconfig[ctx.message.server.id]["selfAssign"]["enabled"]:
            return

        user = ctx.message.author
        server = ctx.message.server

        if role not in server.roles:
            return await self.bot.say("That role doesn't exist. Roles are case sensitive. ")

        elif role in user.roles and role.id in self.con.serverconfig[ctx.message.server.id]["selfAssign"]["roles"]:
            await self.bot.remove_roles(user, role)
            return await self.bot.reply("{} has been successfully removed.".format(role.name))

        elif role not in user.roles and role.id in self.con.serverconfig[ctx.message.server.id]["selfAssign"]["roles"]:
            return await self.bot.reply("You do not have {}.".format(role.name))
        else:
            return await self.bot.say("That role is not self-assignable.")

    @bot.command(pass_context=True, hidden=True)
    async def addrole(self, ctx, role: discord.Role = None):
        if not owner(ctx):
            return await self.bot.reply(self.con.no_perms_reponse, delete_after=self.con.delete_after)
        else:
            if role.id in self.con.serverconfig[ctx.message.server.id]["selfAssign"]["roles"]:
                return await self.bot.say("{} is already a self-assignable role.".format(role.name), delete_after=self.con.delete_after)
            self.con.serverconfig = self.con.load_config()
            self.con.serverconfig[ctx.message.server.id]["selfAssign"]["roles"].append(role.id)
            self.con.updateconfig()
            return await self.bot.say('Role "{}" added'.format(str(role)))

    @bot.command(pass_context=True, hidden=True)
    async def removerole(self, ctx, role: discord.Role = None):
        if not owner(ctx):
            return await self.bot.reply(self.con.no_perms_reponse, delete_after=self.con.delete_after)
        else:
            self.con.serverconfig = self.con.load_config()
            if role.id in self.con.serverconfig[ctx.message.server.id]["selfAssign"]["roles"]:
                self.con.serverconfig[ctx.message.server.id]["selfAssign"]["roles"].remove(role.id)
                self.con.updateconfig()
                return await self.bot.say('"{}" has been removed from the self-assignable roles.'.format(str(role)))
            else:
                return await self.bot.say("That role was not in the list.")

def setup(Bot):
    Bot.add_cog(selfAssign(Bot))<|endoftext|>


<commit_before># Copyright 2013 Red Hat, Inc.
#
#    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.

"""
Tests in this module will be skipped unless:

 - ovsdb-client is installed

 - ovsdb-client can be invoked via password-less sudo

 - OS_SUDO_TESTING is set to '1' or 'True' in the test execution
   environment

The jenkins gate does not allow direct sudo invocation during test
runs, but configuring OS_SUDO_TESTING ensures that developers are
still able to execute tests that require the capability.
"""

import eventlet

from neutron.agent.linux import ovsdb_monitor
from neutron.tests.functional.agent.linux import base as base_agent

class BaseMonitorTest(base_agent.BaseOVSLinuxTestCase):

    def setUp(self):
        # Emulate using a rootwrap script with sudo
        super(BaseMonitorTest, self).setUp(root_helper='sudo sudo')

        self._check_test_requirements()
        self.bridge = self.create_ovs_bridge()

    def _check_test_requirements(self):
        self.check_sudo_enabled()
        self.check_command(['which', 'ovsdb-client'],
                           'Exit code: 1', 'ovsdb-client is not installed')
        self.check_command(['sudo', '-n', 'ovsdb-client', 'list-dbs'],
                           'Exit code: 1',
                           'password-less sudo not granted for ovsdb-client')

class TestOvsdbMonitor(BaseMonitorTest):

    def setUp(self):
        super(TestOvsdbMonitor, self).setUp()

        self.monitor = ovsdb_monitor.OvsdbMonitor('Bridge',
                                                  root_helper=self.root_helper)
        self.addCleanup(self.monitor.stop)
        self.monitor.start()

    def collect_initial_output(self):
        while True:
            output = list(self.monitor.iter_stdout())
            if output:
                return output[0]
            eventlet.sleep(0.01)

    def test_killed_monitor_respawns(self):
        with self.assert_max_execution_time():
            self.monitor.respawn_interval = 0
            old_pid = self.monitor._process.pid
            output1 = self.collect_initial_output()
            pid = self.monitor._get_pid_to_kill()
            self.monitor._kill_process(pid)
            self.monitor._reset_queues()
            while (self.monitor._process.pid == old_pid):
                eventlet.sleep(0.01)
            output2 = self.collect_initial_output()
            # Initial output should appear twice
            self.assertEqual(output1, output2)

class TestSimpleInterfaceMonitor(BaseMonitorTest):

    def setUp(self):
        super(TestSimpleInterfaceMonitor, self).setUp()

        self.monitor = ovsdb_monitor.SimpleInterfaceMonitor(
            root_helper=self.root_helper)
        self.addCleanup(self.monitor.stop)
        self.monitor.start(block=True)

    def test_has_updates(self):
        self.assertTrue(self.monitor.has_updates,
                        'Initial call should always be true')
        self.assertFalse(self.monitor.has_updates,
                         'has_updates without port addition should be False')
        self.create_resource('test-port-', self.bridge.add_port)
        with self.assert_max_execution_time():
            # has_updates after port addition should become True
            while not self.monitor.has_updates:
                eventlet.sleep(0.01)
<commit_msg>Ignore variable column widths in ovsdb functional tests<commit_after># Copyright 2013 Red Hat, Inc.
#
#    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.

"""
Tests in this module will be skipped unless:

 - ovsdb-client is installed

 - ovsdb-client can be invoked via password-less sudo

 - OS_SUDO_TESTING is set to '1' or 'True' in the test execution
   environment

The jenkins gate does not allow direct sudo invocation during test
runs, but configuring OS_SUDO_TESTING ensures that developers are
still able to execute tests that require the capability.
"""

import eventlet

from neutron.agent.linux import ovsdb_monitor
from neutron.tests.functional.agent.linux import base as base_agent

class BaseMonitorTest(base_agent.BaseOVSLinuxTestCase):

    def setUp(self):
        # Emulate using a rootwrap script with sudo
        super(BaseMonitorTest, self).setUp(root_helper='sudo sudo')

        self._check_test_requirements()
        self.bridge = self.create_ovs_bridge()

    def _check_test_requirements(self):
        self.check_sudo_enabled()
        self.check_command(['which', 'ovsdb-client'],
                           'Exit code: 1', 'ovsdb-client is not installed')
        self.check_command(['sudo', '-n', 'ovsdb-client', 'list-dbs'],
                           'Exit code: 1',
                           'password-less sudo not granted for ovsdb-client')

class TestOvsdbMonitor(BaseMonitorTest):

    def setUp(self):
        super(TestOvsdbMonitor, self).setUp()

        self.monitor = ovsdb_monitor.OvsdbMonitor('Bridge',
                                                  root_helper=self.root_helper)
        self.addCleanup(self.monitor.stop)
        self.monitor.start()

    def collect_initial_output(self):
        while True:
            output = list(self.monitor.iter_stdout())
            if output:
                # Output[0] is header row with spaces for column separation.
                # The column widths can vary depending on the data in the
                # columns, so compress multiple spaces to one for testing.
                return ' '.join(output[0].split())
            eventlet.sleep(0.01)

    def test_killed_monitor_respawns(self):
        with self.assert_max_execution_time():
            self.monitor.respawn_interval = 0
            old_pid = self.monitor._process.pid
            output1 = self.collect_initial_output()
            pid = self.monitor._get_pid_to_kill()
            self.monitor._kill_process(pid)
            self.monitor._reset_queues()
            while (self.monitor._process.pid == old_pid):
                eventlet.sleep(0.01)
            output2 = self.collect_initial_output()
            # Initial output should appear twice
            self.assertEqual(output1, output2)

class TestSimpleInterfaceMonitor(BaseMonitorTest):

    def setUp(self):
        super(TestSimpleInterfaceMonitor, self).setUp()

        self.monitor = ovsdb_monitor.SimpleInterfaceMonitor(
            root_helper=self.root_helper)
        self.addCleanup(self.monitor.stop)
        self.monitor.start(block=True)

    def test_has_updates(self):
        self.assertTrue(self.monitor.has_updates,
                        'Initial call should always be true')
        self.assertFalse(self.monitor.has_updates,
                         'has_updates without port addition should be False')
        self.create_resource('test-port-', self.bridge.add_port)
        with self.assert_max_execution_time():
            # has_updates after port addition should become True
            while not self.monitor.has_updates:
                eventlet.sleep(0.01)
<|endoftext|>


<commit_before>"""
This runs continuously and serves our sensor readings when requested.

Base script from:
http://ilab.cs.byu.edu/python/socket/echoserver.html
"""
import redis
import socket
import json

class SensorServer:
    def __init__(self, host='', port=8888, size=1024, backlog=5):
        self.host = host
        self.port = port
        self.size = size
        self.backlog = backlog

        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.s.bind((host, port))
        self.s.listen(backlog)

        self.r_server = redis.Redis('localhost')

    def serve_readings(self):
        ir_s = self.r_server.get('ir_s')
        ir_l = self.r_server.get('ir_l')
        ir_r = self.r_server.get('ir_r')
        ir_s = self.r_server.get('s_m')

        readings = {
            'ir_s': ir_s,
            'ir_l': ir_l,
            'ir_r': ir_r,
            'ir_s': ir_s
        }

        client, address = self.s.accept()
        print("Sending: %s" % str(readings))
        b = json.dumps(readings).encode('utf-8')
        client.sendall(b)
        client.close()

if __name__ == '__main__':
    input("Start sensor_run.py then hit enter to start server.")
    ss = SensorServer()
    while 1:
        ss.serve_readings()
<commit_msg>Update sensor server.<commit_after>"""
This runs continuously and serves our sensor readings when requested.

Base script from:
http://ilab.cs.byu.edu/python/socket/echoserver.html
"""
import redis
import socket
import json

class SensorServer:
    def __init__(self, host='', port=8888, size=1024, backlog=5):
        self.host = host
        self.port = port
        self.size = size
        self.backlog = backlog

        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.s.bind((host, port))
        self.s.listen(backlog)

        self.r_server = redis.Redis('localhost')

    def serve_readings(self):
        ir_s = self.r_server.get('ir_s')
        ir_l = self.r_server.get('ir_l')
        ir_r = self.r_server.get('ir_r')
        s_m = json.loads(self.r_server.get('s_m'))

        readings = {
            'ir_s': ir_s,
            'ir_l': ir_l,
            'ir_r': ir_r,
            's_m': s_m
        }

        client, address = self.s.accept()
        print("Sending: %s" % str(readings))
        b = json.dumps(readings).encode('utf-8')
        client.sendall(b)
        client.close()

if __name__ == '__main__':
    input("Start sensor_run.py then hit enter to start server.")
    ss = SensorServer()
    while 1:
        ss.serve_readings()
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

from typing import Dict, List

import subprocess

from . import base

class DockerBackend(base.BaseBackend):
    def __init__(self, container, options: Dict=None):
        super().__init__(container, options)
        self._name = self._options['name']
        self._image = self._options['image']
        self._arch = self._options['arch']
        self._ephemeral = self._options['ephemeral']

    @property
    def name(self) -> str:
        return self._name

    @property
    def image(self) -> str:
        return self._image

    @property
    def arch(self) -> str:
        return self._arch

    @property
    def ephemeral(self) -> bool:
        return self._ephemeral

    @property
    def _default_options(self) -> Dict:
        return {
            'name': self._gen_name(),
            'image': 'ubuntu',
            'arch': 'amd64',
            'ephemeral': True
        }

    def init(self):
        self.log('Checking for container ...')
        # Find existing containers with the requested name
        existing = self._name in self._forgiven_names()
        # Create container or use existing one
        if existing:
            self.log('Launching container ...')
        else:
            self.log('Creating and launching container ...')
            cmd = ['docker', 'create', '-it', '--name', self._name]
            if self._ephemeral:
                cmd += ['--rm']
            cmd += [self._image]
            subprocess.check_call(cmd)
        # Start the container (if not already running)
        subprocess.check_call(['docker', 'start', self._name])
        # Enable most actions
        self._ready = True
        # Prepare system
        self._prepare()

    def destroy(self):
        self.log('Destroying ...')
        subprocess.check_call(['docker', 'rm', '-f', self._name])
        self._ready = False

    def exec(self, command, *args, path: str = None, envvars: Dict[str, str]=None) -> base.CommandResult:
        cmd = base.Command(
            ['docker', 'exec', '-i', self._name], command, *args, path=path, envvars=envvars
        )
        cmd.run()
        return cmd.result

    def log(self, *fragments):
        print(*fragments, end='' if fragments[-1].endswith('\n') else '\n')

    def push(self, source: str, dest: str):
        dest = dest.lstrip('/')
        subprocess.check_call(['docker', 'cp', source, self._name + ':/' + dest])

    def pull(self, source: str, dest: str):
        source = source.lstrip('/')
        subprocess.check_call(['docker', 'cp', self._name + ':/' + source, dest])

    def _prepare(self):
        self.log('Preparing system ...')
        assert self.exec('mkdir', '-p', '/home/grout').exit_code == 0
        self.log('Updating and upgrading system ...')
        assert self.exec('apt-get', 'update').exit_code == 0
        assert self.exec('apt-get', 'update').exit_code == 0
        # Make sure add-apt-repository and others are available
        assert self.exec('apt-get', 'install', '-y', 'software-properties-common').exit_code == 0

    @staticmethod
    def _existing_containers() -> List[Dict[str, str]]:
        out = subprocess.check_output(
            ['docker', 'ps', '-a', '--no-trunc', '--format', '{{.ID}}\t{{.Names}}\t{{.Image}}']
        )
        lines = out.decode('utf-8').splitlines()
        containers = []
        for line in lines:
            id_, names, image = line.split('\t')
            containers.append({
                'id': id_,
                'name': names,
                'image': image
            })
        return containers

    def _forgiven_names(self) -> List[str]:
        names = []
        for container in self._existing_containers():
            names.append(container['name'])
        return names

    def _gen_name(self):
        no = 0
        forgiven = self._forgiven_names()
        name = 'grout-whale-0'
        while name in forgiven:
            name = 'grout-whale-' + str(no)
            no += 1
        return name
<commit_msg>docker: Fix new command execution<commit_after># -*- coding: utf-8 -*-

from typing import Dict, List

import subprocess

from . import base

class DockerBackend(base.BaseBackend):
    def __init__(self, container, options: Dict=None):
        super().__init__(container, options)
        self._name = self._options['name']
        self._image = self._options['image']
        self._arch = self._options['arch']
        self._ephemeral = self._options['ephemeral']

    @property
    def name(self) -> str:
        return self._name

    @property
    def image(self) -> str:
        return self._image

    @property
    def arch(self) -> str:
        return self._arch

    @property
    def ephemeral(self) -> bool:
        return self._ephemeral

    @property
    def _default_options(self) -> Dict:
        return {
            'name': self._gen_name(),
            'image': 'ubuntu',
            'arch': 'amd64',
            'ephemeral': True
        }

    def init(self):
        self.log('Checking for container ...')
        # Find existing containers with the requested name
        existing = self._name in self._forgiven_names()
        # Create container or use existing one
        if existing:
            self.log('Launching container ...')
        else:
            self.log('Creating and launching container ...')
            cmd = ['docker', 'create', '-it', '--name', self._name]
            if self._ephemeral:
                cmd += ['--rm']
            cmd += [self._image]
            subprocess.check_call(cmd)
        # Start the container (if not already running)
        subprocess.check_call(['docker', 'start', self._name])
        # Enable most actions
        self._ready = True
        # Prepare system
        self._prepare()

    def destroy(self):
        self.log('Destroying ...')
        subprocess.check_call(['docker', 'rm', '-f', self._name])
        self._ready = False

    def exec(self, command, *args, path: str = None, envvars: Dict[str, str]=None) -> base.CommandResult:
        cmd = base.Command(
            ['docker', 'exec', '-i', self._name], command, *args,
            path=path, envvars=envvars,
            stdout=self.log, stderr=self.log
        )
        cmd.run()
        return cmd.result

    def log(self, *fragments):
        print(*fragments, end='' if fragments[-1].endswith('\n') else '\n')

    def push(self, source: str, dest: str):
        dest = dest.lstrip('/')
        subprocess.check_call(['docker', 'cp', source, self._name + ':/' + dest])

    def pull(self, source: str, dest: str):
        source = source.lstrip('/')
        subprocess.check_call(['docker', 'cp', self._name + ':/' + source, dest])

    def _prepare(self):
        self.log('Preparing system ...')
        assert self.exec('mkdir', '-p', '/home/grout').exit_code == 0
        self.log('Updating and upgrading system ...')
        assert self.exec('apt-get', 'update').exit_code == 0
        assert self.exec('apt-get', 'update').exit_code == 0
        # Make sure add-apt-repository and others are available
        assert self.exec('apt-get', 'install', '-y', 'software-properties-common').exit_code == 0

    @staticmethod
    def _existing_containers() -> List[Dict[str, str]]:
        out = subprocess.check_output(
            ['docker', 'ps', '-a', '--no-trunc', '--format', '{{.ID}}\t{{.Names}}\t{{.Image}}']
        )
        lines = out.decode('utf-8').splitlines()
        containers = []
        for line in lines:
            id_, names, image = line.split('\t')
            containers.append({
                'id': id_,
                'name': names,
                'image': image
            })
        return containers

    def _forgiven_names(self) -> List[str]:
        names = []
        for container in self._existing_containers():
            names.append(container['name'])
        return names

    def _gen_name(self):
        no = 0
        forgiven = self._forgiven_names()
        name = 'grout-whale-0'
        while name in forgiven:
            name = 'grout-whale-' + str(no)
            no += 1
        return name
<|endoftext|>


<commit_before># This file is part of beets.
# Copyright 2014, Adrian Sampson.
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.

"""The Query type hierarchy for DBCore.
"""
import re
from beets import util
from datetime import datetime, timedelta

class Query(object):
    """An abstract class representing a query into the item database.
    """
    def clause(self):
        """Generate an SQLite expression implementing the query.
        Return a clause string, a sequence of substitution values for
        the clause, and a Query object representing the "remainder"
        Returns (clause, subvals) where clause is a valid sqlite
        WHERE clause implementing the query and subvals is a list of
        items to be substituted for ?s in the clause.
        """
        return None, ()

    def match(self, item):
        """Check whether this query matches a given Item. Can be used to
        perform queries on arbitrary sets of Items.
        """
        raise NotImplementedError

class FieldQuery(Query):
    """An abstract query that searches in a specific field for a
    pattern. Subclasses must provide a `value_match` class method, which
    determines whether a certain pattern string matches a certain value
    string. Subclasses may also provide `col_clause` to implement the
    same matching functionality in SQLite.
    """
    def __init__(self, field, pattern, fast=True):
        self.field = field
        self.pattern = pattern
        self.fast = fast

    def col_clause(self):
        return None, ()

    def clause(self):
        if self.fast:
            return self.col_clause()
        else:
            # Matching a flexattr. This is a slow query.
            return None, ()

    @classmethod
    def value_match(cls, pattern, value):
        """Determine whether the value matches the pattern. Both
        arguments are strings.
        """
        raise NotImplementedError()

    def match(self, item):
        return self.value_match(self.pattern, item.get(self.field))

class MatchQuery(FieldQuery):
    """A query that looks for exact matches in an item field."""
    def col_clause(self):
        return self.field + " = ?", [self.pattern]

    @classmethod
    def value_match(cls, pattern, value):
        return pattern == value

class StringFieldQuery(FieldQuery):
    """A FieldQuery that converts values to strings before matching
    them.
    """
    @classmethod
    def value_match(cls, pattern, value):
        """Determine whether the value matches the pattern. The value
        may have any type.
        """
        return cls.string_match(pattern, util.as_string(value))

    @classmethod
    def string_match(cls, pattern, value):
        """Determine whether the value matches the pattern. Both
        arguments are strings. Subclasses implement this method.
        """
        raise NotImplementedError()

class SubstringQuery(StringFieldQuery):
    """A query that matches a substring in a specific item field."""
    def col_clause(self):
        search = '%' + (self.pattern.replace('\\','\\\\').replace('%','\\%')
                            .replace('_','\\_')) + '%'
        clause = self.field + " like ? escape '\\'"
        subvals = [search]
        return clause, subvals

    @classmethod
    def string_match(cls, pattern, value):
        return pattern.lower() in value.lower()

class RegexpQuery(StringFieldQuery):
    """A query that matches a regular expression in a specific item
    field.
    """
    @classmethod
    def string_match(cls, pattern, value):
        try:
            res = re.search(pattern, value)
        except re.error:
            # Invalid regular expression.
            return False
        return res is not None

class BooleanQuery(MatchQuery):
    """Matches a boolean field. Pattern should either be a boolean or a
    string reflecting a boolean.
    """
    def __init__(self, field, pattern, fast=True):
        super(BooleanQuery, self).__init__(field, pattern, fast)
        if isinstance(pattern, basestring):
            self.pattern = util.str2bool(pattern)
        self.pattern = int(self.pattern)

class BytesQuery(MatchQuery):
    """Match a raw bytes field (i.e., a path). This is a necessary hack
    to work around the `sqlite3` module's desire to treat `str` and
    `unicode` equivalently in Python 2. Always use this query instead of
    `MatchQuery` when matching on BLOB values.
    """
    def __init__(self, field, pattern):
        super(BytesQuery, self).__init__(field, pattern)

        # Use a buffer representation of the pattern for SQLite
        # matching. This instructs SQLite to treat the blob as binary
        # rather than encoded Unicode.
        if isinstance(self.pattern, basestring):
            # Implicitly coerce Unicode strings to their bytes
            # equivalents.
            if isinstance(self.pattern, unicode):
                self.pattern = self.pattern.encode('utf8')
            self.buf_pattern = buffer(self.pattern)
        elif isinstance(self.pattern, buffer):
            self.buf_pattern = self.pattern
            self.pattern = bytes(self.pattern)

    def col_clause(self):
        return self.field + " = ?", [self.buf_pattern]

class NumericQuery(FieldQuery):
    """Matches numeric fields. A syntax using Ruby-style range ellipses
    (``..``) lets users specify one- or two-sided ranges. For example,
    ``year:2001..`` finds music released since the turn of the century.
    """
    def _convert(self, s):
        """Convert a string to a numeric type (float or int). If the
        string cannot be converted, return None.
        """
        # This is really just a bit of fun premature optimization.
        try:
            return int(s)
        except ValueError:
            try:
                return float(s)
            except ValueError:
                return None

    def __init__(self, field, pattern, fast=True):
        super(NumericQuery, self).__init__(field, pattern, fast)

        parts = pattern.split('..', 1)
        if len(parts) == 1:
            # No range.
            self.point = self._convert(parts[0])
            self.rangemin = None
            self.rangemax = None
        else:
            # One- or two-sided range.
            self.point = None
            self.rangemin = self._convert(parts[0])
            self.rangemax = self._convert(parts[1])

    def match(self, item):
        value = getattr(item, self.field)
        if isinstance(value, basestring):
            value = self._convert(value)

        if self.point is not None:
            return value == self.point
        else:
            if self.rangemin is not None and value < self.rangemin:
                return False
            if self.rangemax is not None and value > self.rangemax:
                return False
            return True

    def col_clause(self):
        if self.point is not None:
            return self.field + '=?', (self.point,)
        else:
            if self.rangemin is not None and self.rangemax is not None:
                return (u'{0} >= ? AND {0} <= ?'.format(self.field),
                        (self.rangemin, self.rangemax))
            elif self.rangemin is not None:
                return u'{0} >= ?'.format(self.field), (self.rangemin,)
            elif self.rangemax is not None:
                return u'{0} <= ?'.format(self.field), (self.rangemax,)
            else:
                return '1'

class CollectionQuery(Query):
    """An abstract query class that aggregates other queries. Can be
    indexed like a list to access the sub-queries.
    """
    def __init__(self, subqueries=()):
        self.subqueries = subqueries

    # Act like a sequence.
    def __len__(self):
        return len(self.subqueries)
    def __getitem__(self, key):
        return self.subqueries[key]
    def __iter__(self):
        return iter(self.subqueries)
    def __contains__(self, item):
        return item in self.subqueries

    def clause_with_joiner(self, joiner):
        """Returns a clause created by joining together the clauses of
        all subqueries with the string joiner (padded by spaces).
        """
        clause_parts = []
        subvals = []
        for subq in self.subqueries:
            subq_clause, subq_subvals = subq.clause()
            if not subq_clause:
                # Fall back to slow query.
                return None, ()
            clause_parts.append('(' + subq_clause + ')')
            subvals += subq_subvals
        clause = (' ' + joiner + ' ').join(clause_parts)
        return clause, subvals

class AnyFieldQuery(CollectionQuery):
    """A query that matches if a given FieldQuery subclass matches in
    any field. The individual field query class is provided to the
    constructor.
    """
    def __init__(self, pattern, fields, cls):
        self.pattern = pattern
        self.fields = fields
        self.query_class = cls

        subqueries = []
        for field in self.fields:
            subqueries.append(cls(field, pattern, True))
        super(AnyFieldQuery, self).__init__(subqueries)

    def clause(self):
        return self.clause_with_joiner('or')

    def match(self, item):
        for subq in self.subqueries:
            if subq.match(item):
                return True
        return False

class MutableCollectionQuery(CollectionQuery):
    """A collection query whose subqueries may be modified after the
    query is initialized.
    """
    def __setitem__(self, key, value):
        self.subqueries[key] = value

    def __delitem__(self, key):
        del self.subqueries[key]

class AndQuery(MutableCollectionQuery):
    """A conjunction of a list of other queries."""
    def clause(self):
        return self.clause_with_joiner('and')

    def match(self, item):
        return all([q.match(item) for q in self.subqueries])

class TrueQuery(Query):
    """A query that always matches."""
    def clause(self):
        return '1', ()

    def match(self, item):
        return True

class FalseQuery(Query):
    """A query that never matches."""
    def clause(self):
        return '0', ()

    def match(self, item):
        return False

def _to_epoch_time(date):
    epoch = datetime.utcfromtimestamp(0)
    return int((date - epoch).total_seconds())

def _parse_periods(pattern):
    """Parse two Periods separated by '..'
    """
    parts = pattern.split('..', 1)
    if len(parts) == 1:
        instant = Period.parse(parts[0])
        return (instant, instant)
    else:
        start = Period.parse(parts[0])
        end = Period.parse(parts[1])
        return (start, end)

class Period(object):
    """A period of time given by a date, time and precision.

    Example:
    2014-01-01 10:50:30 with precision 'month' represent all instants of time
    during January 2014.
    """

    precisions = ('year', 'month', 'day')
    date_formats = ('%Y', '%Y-%m', '%Y-%m-%d')

    def __init__(self, date, precision):
        if precision not in Period.precisions:
            raise ValueError('Invalid precision ' + str(precision))
        self.date = date
        self.precision = precision

    @classmethod
    def parse(cls, string):
        """Parse a date into a period.
        """
        if not string: return None
        ordinal = string.count('-')
        if ordinal >= len(cls.date_formats):
            raise ValueError('Date is not in one of the formats '
                                + ', '.join(cls.date_formats))
        date_format = cls.date_formats[ordinal]
        date = datetime.strptime(string, date_format)
        precision = cls.precisions[ordinal]
        return cls(date, precision)

    def open_right_endpoint(self):
        """Based on the precision, convert the period to a precise datetime
        for use as a right endpoint in a right-open interval.
        """
        precision = self.precision
        date = self.date
        if 'year' == self.precision:
            return date.replace(year=date.year + 1, month=1)
        elif 'month' == precision:
            if (date.month < 12):
                return date.replace(month=date.month + 1)
            else:
                return date.replace(year=date.year + 1, month=1)
        elif 'day' == precision:
            return date + timedelta(days=1)
        else:
            raise ValueError('Unhandled precision ' + str(precision))

class DateInterval(object):
    """A closed-open interval of dates.

    A left endpoint of None means since the beginning of time.
    A right endpoint of None means towards infinity.
    """

    def __init__(self, start, end):
        if start is not None and end is not None and not start < end:
            raise ValueError("Start date {} is not before end date {}"
                             .format(start, end))
        self.start = start
        self.end = end

    @classmethod
    def from_periods(cls, start, end):
        """Create an interval with two Periods as the endpoints.
        """
        end_date = end.open_right_endpoint() if end is not None else None
        start_date = start.date if start is not None else None
        return cls(start_date, end_date)

    def contains(self, date):
        if self.start is not None and date < self.start:
            return False
        if self.end is not None and date >= self.end:
            return False
        return True

    def __str__(self):
        return'[{}, {})'.format(self.start, self.end)

class DateQuery(FieldQuery):
    """Matches date fields stored as seconds since Unix epoch time.

    Dates can be specified as year-month-day where only year is mandatory.

    The value of a date field can be matched against a date interval by using
    an ellipses interval syntax similar to that of NumericQuery.
    """
    def __init__(self, field, pattern, fast=True):
        super(DateQuery, self).__init__(field, pattern, fast)
        (start, end) = _parse_periods(pattern)
        self.interval = DateInterval.from_periods(start, end)

    def match(self, item):
        timestamp = float(item[self.field])
        date = datetime.utcfromtimestamp(timestamp)
        return self.interval.contains(date)

    def col_clause(self):
        if self.interval.start is not None and self.interval.end is not None:
            start_epoch_time = _to_epoch_time(self.interval.start)
            end_epoch_time = _to_epoch_time(self.interval.end)
            template = ("date({}, 'unixepoch') >= date(?, 'unixepoch')"
                        " AND date({}, 'unixepoch') < date(?, 'unixepoch')")
            clause = template.format(self.field, self.field)
            return (clause, (start_epoch_time, end_epoch_time))
        elif self.interval.start is not None:
            epoch_time = _to_epoch_time(self.interval.start)
            template = "date({}, 'unixepoch') >= date(?, 'unixepoch')"
            clause = template.format(self.field)
            return clause.format(self.field), (epoch_time,)
        elif self.interval.end is not None:
            epoch_time = _to_epoch_time(self.interval.end)
            template = "date({}, 'unixepoch') < date(?, 'unixepoch')"
            clause = template.format(self.field)
            return clause.format(self.field), (epoch_time,)
        else:
            return '1 = ?', (1,) # match any date
<commit_msg>date queries: light style changes<commit_after># This file is part of beets.
# Copyright 2014, Adrian Sampson.
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.

"""The Query type hierarchy for DBCore.
"""
import re
from beets import util
from datetime import datetime, timedelta

class Query(object):
    """An abstract class representing a query into the item database.
    """
    def clause(self):
        """Generate an SQLite expression implementing the query.
        Return a clause string, a sequence of substitution values for
        the clause, and a Query object representing the "remainder"
        Returns (clause, subvals) where clause is a valid sqlite
        WHERE clause implementing the query and subvals is a list of
        items to be substituted for ?s in the clause.
        """
        return None, ()

    def match(self, item):
        """Check whether this query matches a given Item. Can be used to
        perform queries on arbitrary sets of Items.
        """
        raise NotImplementedError

class FieldQuery(Query):
    """An abstract query that searches in a specific field for a
    pattern. Subclasses must provide a `value_match` class method, which
    determines whether a certain pattern string matches a certain value
    string. Subclasses may also provide `col_clause` to implement the
    same matching functionality in SQLite.
    """
    def __init__(self, field, pattern, fast=True):
        self.field = field
        self.pattern = pattern
        self.fast = fast

    def col_clause(self):
        return None, ()

    def clause(self):
        if self.fast:
            return self.col_clause()
        else:
            # Matching a flexattr. This is a slow query.
            return None, ()

    @classmethod
    def value_match(cls, pattern, value):
        """Determine whether the value matches the pattern. Both
        arguments are strings.
        """
        raise NotImplementedError()

    def match(self, item):
        return self.value_match(self.pattern, item.get(self.field))

class MatchQuery(FieldQuery):
    """A query that looks for exact matches in an item field."""
    def col_clause(self):
        return self.field + " = ?", [self.pattern]

    @classmethod
    def value_match(cls, pattern, value):
        return pattern == value

class StringFieldQuery(FieldQuery):
    """A FieldQuery that converts values to strings before matching
    them.
    """
    @classmethod
    def value_match(cls, pattern, value):
        """Determine whether the value matches the pattern. The value
        may have any type.
        """
        return cls.string_match(pattern, util.as_string(value))

    @classmethod
    def string_match(cls, pattern, value):
        """Determine whether the value matches the pattern. Both
        arguments are strings. Subclasses implement this method.
        """
        raise NotImplementedError()

class SubstringQuery(StringFieldQuery):
    """A query that matches a substring in a specific item field."""
    def col_clause(self):
        search = '%' + (self.pattern.replace('\\','\\\\').replace('%','\\%')
                            .replace('_','\\_')) + '%'
        clause = self.field + " like ? escape '\\'"
        subvals = [search]
        return clause, subvals

    @classmethod
    def string_match(cls, pattern, value):
        return pattern.lower() in value.lower()

class RegexpQuery(StringFieldQuery):
    """A query that matches a regular expression in a specific item
    field.
    """
    @classmethod
    def string_match(cls, pattern, value):
        try:
            res = re.search(pattern, value)
        except re.error:
            # Invalid regular expression.
            return False
        return res is not None

class BooleanQuery(MatchQuery):
    """Matches a boolean field. Pattern should either be a boolean or a
    string reflecting a boolean.
    """
    def __init__(self, field, pattern, fast=True):
        super(BooleanQuery, self).__init__(field, pattern, fast)
        if isinstance(pattern, basestring):
            self.pattern = util.str2bool(pattern)
        self.pattern = int(self.pattern)

class BytesQuery(MatchQuery):
    """Match a raw bytes field (i.e., a path). This is a necessary hack
    to work around the `sqlite3` module's desire to treat `str` and
    `unicode` equivalently in Python 2. Always use this query instead of
    `MatchQuery` when matching on BLOB values.
    """
    def __init__(self, field, pattern):
        super(BytesQuery, self).__init__(field, pattern)

        # Use a buffer representation of the pattern for SQLite
        # matching. This instructs SQLite to treat the blob as binary
        # rather than encoded Unicode.
        if isinstance(self.pattern, basestring):
            # Implicitly coerce Unicode strings to their bytes
            # equivalents.
            if isinstance(self.pattern, unicode):
                self.pattern = self.pattern.encode('utf8')
            self.buf_pattern = buffer(self.pattern)
        elif isinstance(self.pattern, buffer):
            self.buf_pattern = self.pattern
            self.pattern = bytes(self.pattern)

    def col_clause(self):
        return self.field + " = ?", [self.buf_pattern]

class NumericQuery(FieldQuery):
    """Matches numeric fields. A syntax using Ruby-style range ellipses
    (``..``) lets users specify one- or two-sided ranges. For example,
    ``year:2001..`` finds music released since the turn of the century.
    """
    def _convert(self, s):
        """Convert a string to a numeric type (float or int). If the
        string cannot be converted, return None.
        """
        # This is really just a bit of fun premature optimization.
        try:
            return int(s)
        except ValueError:
            try:
                return float(s)
            except ValueError:
                return None

    def __init__(self, field, pattern, fast=True):
        super(NumericQuery, self).__init__(field, pattern, fast)

        parts = pattern.split('..', 1)
        if len(parts) == 1:
            # No range.
            self.point = self._convert(parts[0])
            self.rangemin = None
            self.rangemax = None
        else:
            # One- or two-sided range.
            self.point = None
            self.rangemin = self._convert(parts[0])
            self.rangemax = self._convert(parts[1])

    def match(self, item):
        value = getattr(item, self.field)
        if isinstance(value, basestring):
            value = self._convert(value)

        if self.point is not None:
            return value == self.point
        else:
            if self.rangemin is not None and value < self.rangemin:
                return False
            if self.rangemax is not None and value > self.rangemax:
                return False
            return True

    def col_clause(self):
        if self.point is not None:
            return self.field + '=?', (self.point,)
        else:
            if self.rangemin is not None and self.rangemax is not None:
                return (u'{0} >= ? AND {0} <= ?'.format(self.field),
                        (self.rangemin, self.rangemax))
            elif self.rangemin is not None:
                return u'{0} >= ?'.format(self.field), (self.rangemin,)
            elif self.rangemax is not None:
                return u'{0} <= ?'.format(self.field), (self.rangemax,)
            else:
                return '1'

class CollectionQuery(Query):
    """An abstract query class that aggregates other queries. Can be
    indexed like a list to access the sub-queries.
    """
    def __init__(self, subqueries=()):
        self.subqueries = subqueries

    # Act like a sequence.
    def __len__(self):
        return len(self.subqueries)
    def __getitem__(self, key):
        return self.subqueries[key]
    def __iter__(self):
        return iter(self.subqueries)
    def __contains__(self, item):
        return item in self.subqueries

    def clause_with_joiner(self, joiner):
        """Returns a clause created by joining together the clauses of
        all subqueries with the string joiner (padded by spaces).
        """
        clause_parts = []
        subvals = []
        for subq in self.subqueries:
            subq_clause, subq_subvals = subq.clause()
            if not subq_clause:
                # Fall back to slow query.
                return None, ()
            clause_parts.append('(' + subq_clause + ')')
            subvals += subq_subvals
        clause = (' ' + joiner + ' ').join(clause_parts)
        return clause, subvals

class AnyFieldQuery(CollectionQuery):
    """A query that matches if a given FieldQuery subclass matches in
    any field. The individual field query class is provided to the
    constructor.
    """
    def __init__(self, pattern, fields, cls):
        self.pattern = pattern
        self.fields = fields
        self.query_class = cls

        subqueries = []
        for field in self.fields:
            subqueries.append(cls(field, pattern, True))
        super(AnyFieldQuery, self).__init__(subqueries)

    def clause(self):
        return self.clause_with_joiner('or')

    def match(self, item):
        for subq in self.subqueries:
            if subq.match(item):
                return True
        return False

class MutableCollectionQuery(CollectionQuery):
    """A collection query whose subqueries may be modified after the
    query is initialized.
    """
    def __setitem__(self, key, value):
        self.subqueries[key] = value

    def __delitem__(self, key):
        del self.subqueries[key]

class AndQuery(MutableCollectionQuery):
    """A conjunction of a list of other queries."""
    def clause(self):
        return self.clause_with_joiner('and')

    def match(self, item):
        return all([q.match(item) for q in self.subqueries])

class TrueQuery(Query):
    """A query that always matches."""
    def clause(self):
        return '1', ()

    def match(self, item):
        return True

class FalseQuery(Query):
    """A query that never matches."""
    def clause(self):
        return '0', ()

    def match(self, item):
        return False

# Time/date queries.

def _to_epoch_time(date):
    epoch = datetime.utcfromtimestamp(0)
    return int((date - epoch).total_seconds())

def _parse_periods(pattern):
    """Parse a string containing two dates separated by two dots (..).
    Return a pair of `Period` objects.
    """
    parts = pattern.split('..', 1)
    if len(parts) == 1:
        instant = Period.parse(parts[0])
        return (instant, instant)
    else:
        start = Period.parse(parts[0])
        end = Period.parse(parts[1])
        return (start, end)

class Period(object):
    """A period of time given by a date, time and precision.

    Example: 2014-01-01 10:50:30 with precision 'month' represents all
    instants of time during January 2014.
    """

    precisions = ('year', 'month', 'day')
    date_formats = ('%Y', '%Y-%m', '%Y-%m-%d')

    def __init__(self, date, precision):
        """Create a period with the given date (a `datetime` object) and
        precision (a string, one of "year", "month", or "day").
        """
        if precision not in Period.precisions:
            raise ValueError('Invalid precision ' + str(precision))
        self.date = date
        self.precision = precision

    @classmethod
    def parse(cls, string):
        """Parse a date and return a `Period` object or `None` if the
        string is empty.
        """
        if not string:
            return None
        ordinal = string.count('-')
        if ordinal >= len(cls.date_formats):
            raise ValueError('date is not in one of the formats '
                             + ', '.join(cls.date_formats))
        date_format = cls.date_formats[ordinal]
        date = datetime.strptime(string, date_format)
        precision = cls.precisions[ordinal]
        return cls(date, precision)

    def open_right_endpoint(self):
        """Based on the precision, convert the period to a precise
        `datetime` for use as a right endpoint in a right-open interval.
        """
        precision = self.precision
        date = self.date
        if 'year' == self.precision:
            return date.replace(year=date.year + 1, month=1)
        elif 'month' == precision:
            if (date.month < 12):
                return date.replace(month=date.month + 1)
            else:
                return date.replace(year=date.year + 1, month=1)
        elif 'day' == precision:
            return date + timedelta(days=1)
        else:
            raise ValueError('unhandled precision ' + str(precision))

class DateInterval(object):
    """A closed-open interval of dates.

    A left endpoint of None means since the beginning of time.
    A right endpoint of None means towards infinity.
    """

    def __init__(self, start, end):
        if start is not None and end is not None and not start < end:
            raise ValueError("start date {0} is not before end date {1}"
                             .format(start, end))
        self.start = start
        self.end = end

    @classmethod
    def from_periods(cls, start, end):
        """Create an interval with two Periods as the endpoints.
        """
        end_date = end.open_right_endpoint() if end is not None else None
        start_date = start.date if start is not None else None
        return cls(start_date, end_date)

    def contains(self, date):
        if self.start is not None and date < self.start:
            return False
        if self.end is not None and date >= self.end:
            return False
        return True

    def __str__(self):
        return'[{0}, {1})'.format(self.start, self.end)

class DateQuery(FieldQuery):
    """Matches date fields stored as seconds since Unix epoch time.

    Dates can be specified as ``year-month-day`` strings where only year
    is mandatory.

    The value of a date field can be matched against a date interval by
    using an ellipsis interval syntax similar to that of NumericQuery.
    """
    def __init__(self, field, pattern, fast=True):
        super(DateQuery, self).__init__(field, pattern, fast)
        start, end = _parse_periods(pattern)
        self.interval = DateInterval.from_periods(start, end)

    def match(self, item):
        timestamp = float(item[self.field])
        date = datetime.utcfromtimestamp(timestamp)
        return self.interval.contains(date)

    _clause_tmpl = "date({0}, 'unixepoch') {1} date(?, 'unixepoch')"

    def col_clause(self):
        clause_parts = []
        subvals = []

        if self.interval.start:
            clause_parts.append(self._clause_tmpl.format(self.field, ">="))
            subvals.append(_to_epoch_time(self.interval.start))

        if self.interval.end:
            clause_parts.append(self._clause_tmpl.format(self.field, "<"))
            subvals.append(_to_epoch_time(self.interval.end))

        if clause_parts:
            # One- or two-sided interval.
            clause = ' AND '.join(clause_parts)
        else:
            # Match any date.
            clause = '1'

        return clause, subvals
<|endoftext|>


<commit_before>#! /usr/bin/env python
##
## (C) 2004 British Broadcasting Corporation and Kamaelia Contributors(1)
##     All Rights Reserved.
##
## You may only modify and redistribute this under the terms of any of the
## following licenses(2): Mozilla Public License, V1.1, GNU General
## Public License, V2.0, GNU Lesser General Public License, V2.1
##
## (1) Kamaelia Contributors are listed in the AUTHORS file and at
##     http://kamaelia.sourceforge.net/AUTHORS - please extend this file,
##     not this notice.
## (2) Reproduced in the COPYING file, and at:
##     http://kamaelia.sourceforge.net/COPYING
## Under section 3.5 of the MPL, we are using this text since we deem the MPL
## notice inappropriate for this file. As per MPL/GPL/LGPL removal of this
## notice is prohibited.
##
## Please contact us via: kamaelia-list-owner@lists.sourceforge.net
## to discuss alternative licensing.
## -------------------------------------------------------------------------
"""\
================
AIM Client
================

Deals with post-login messages from the AIM server, mostly by parsing them and
sending them out to its "heard" outbox in a slightly more useable form. Also
sends messages to the server based on commands coming through its "talk" inbox.

How it works:
------------
ChatManager expects to receive FLAPs containing SNACs through its "inbox". It
recognizes certain types of SNACs. For these SNACS, ChatManager parses them, and
sends the relevant data out to its "heard" outbox in tuple format. The following
is a list of SNACs ChatManager understands and the tuples that it consequently
sends out:

SNAC        DESCRIPTION         TUPLE SENT TO "heard"
(03, 0b)    Buddy is online     ("buddy online", {name: buddy name})
(04, 07)    Incoming message    ("message", sender, message text)

The "buddy online" message contains a dictionary instead of just a text field
for the buddy name because this will make it easier to add more buddy data
to a "buddy online" message, such as online time or alias. The server sends this
data, but right now ChatManager just discards it.

ChatManager also understands tuple-based commands sent to its "talk" inbox. The
following is a list of commands it understands, and the corresponding SNACs it
sends to its "outbox":

COMMAND                                             SNAC
("message", recipient's screenname, message text)   (04, 06)

Example Usage
-------------
Simple client with a truly horrible interface::

    class AIMHarness(component):
        def main(self):
            self.loginer = LoginHandler('sitar63112', 'sitar63112').activate()
            self.link((self.loginer, "signal"), (self, "internal inbox"))
            self.addChildren(self.loginer)
            while not self.dataReady("internal inbox"): yield 1
            self.oscar = self.recv("internal inbox")
            queued = self.recv("internal inbox")
            self.unlink(self.oscar)

            self.chatter = ChatManager().activate()
            self.link((self.chatter, "heard"), (self, "outbox"), passthrough=2)
            self.link((self, "inbox"), (self.chatter, "talk"), passthrough=1)
            self.link((self.chatter, "outbox"), (self.oscar, "inbox"))
            self.link((self.oscar, "outbox"), (self.chatter, "inbox"))
            self.link((self, "internal outbox"), (self.chatter, "inbox"))
            while len(queued):
                self.send(queued[0], "internal outbox")
                del(queued[0])
            while True:
                yield 1

    def tuplefy(data):
        data = data.split()
        if len(data) > 1:
            data = ("message", data[0], " ".join(data[1:]))
            return data

    Pipeline(ConsoleReader(),
             PureTransformer(tuplefy),
             AIMHarness(),
             ConsoleEchoer()
            ).run()

"""

from OSCARClient import *
from OscarUtil import *
from OscarUtil2 import *
from Kamaelia.Internet.TCPClient import TCPClient
from Axon.Component import component
import re

class ChatManager(SNACExchanger):
    """
    ChatManager() -> new ChatManager component.
    """
    Inboxes = {"inbox" : "incoming FLAPs on channel 2",
               "errors" : "error messages",
               "control" : "NOT USED",
               "talk" : "outgoing messages",
               }

    Outboxes = {"outbox" : "outgoing FLAPs",
                "signal" : "NOT USED",
                "heard" : "echoes peer messages to this box."
                }

    def __init__(self):
        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
        super(ChatManager, self).__init__()
        debugSections = {"ChatManager.main" : 5,
                        "ChatManager.receiveMessage" : 5,
                         "ChatManager.sendMessage" : 4,}
        self.debugger.addDebug(**debugSections)

    def main(self):
        "Main loop."
        while True:
            yield 1
            while self.dataReady():
                header, body = self.recvSnac()
                kind = (header[0], header[1])
                if kind == (0x03, 0x0b):
                    l, = struct.unpack('!B', body[0])
                    buddy = body[1:1+l]
                    assert self.debugger.note("ChatManager.main", 7, buddy + " came online")
                    buddyinfo = {"name" : buddy}
                    self.send(("buddy online", buddyinfo), "heard")
                elif kind == (0x04, 0x07):
                    self.receiveMessage(body)
##                else:
##                    self.send(("unknown message", header[0], header[1]), "heard")
            while self.dataReady("talk"):
                data = self.recv("talk")
                assert self.debugger.note("ChatManager.main", 7, "received " + str(data))
                if data[0] == "message" :
                    self.sendMessage(data[1], data[2])

    def receiveMessage(self, body):
        """
        Extracts the sender and message text from SNAC body, and sends the tuple
        ("message", sender, message) to "heard".
        """
        msgid, msgchan, l = struct.unpack('!QHB', body[:11])
        sender = body[11:11+l]
        assert self.debugger.note("ChatManager.receiveMessage", 7, "message from %s on channel %i" % (sender, msgchan))
        TLVchain = body[11 + l + 4:]
        parsed = readTLVs(TLVchain)
        if msgchan == 1:
            fragments = readTLVs(parsed[0x02])
            msgText = fragments[0x0101]
            charSetID, charSubset = struct.unpack("!HH", msgText[:4]) #ignoring these for now, but they might come in handy
            message = msgText[4:]
            message = self.cleanMessage(message)
        elif msgchan == 2:
            message = "%s requesting unsupported function" % sender
        elif msgchan == 3:
            message = parsed[0x05][8:]

        self.send(("message", sender, message), "heard")

    def sendMessage(self, buddyname, text):
        """
        constructs SNAC (04, 06), the "send message" SNAC and sends it to "outbox"
        """
        frag = TLV(0x0501, struct.pack("!i", 0))
        frag2 = TLV(0x0101, struct.pack("!HH", 0, 0) + text)
        msgCookie = '\x32\x36\x37\x31\x34\x36\x36\x00'
        msgChan = 1
        buddyinfo = Single(len(buddyname)) + buddyname
        body = msgCookie + Double(msgChan) + buddyinfo + TLV(0x02, frag + frag2)
        self.sendSnac(0x04, 0x06, body)

    def cleanMessage(self, message):
        """strips HTML tags off messages"""
        p = re.compile("<[^<^>]*>")
        message = p.sub("", message)
        return message

if __name__ == '__main__':
    from Kamaelia.Chassis.Graphline import Graphline
    from Kamaelia.Util.Console import ConsoleEchoer
    import sys
    sys.path.append('..')
    from likefile import *

    flap = open('/home/jlei/aim/snacs/0407').read()
    class Chargen(component):
        def main(self):
            self.send((2, flap[6:]))
            yield 1

    p = Graphline(chargen = Chargen(),
                  cm = ChatManager(),
                  ce = ConsoleEchoer(),
                  linkages = {("chargen", "outbox") : ("cm", "inbox"),
                              ("cm", "heard") : ("ce", "inbox"),
                              }
                  )
    p.run()
<commit_msg>ReST and other documentation requirements compliant<commit_after>#! /usr/bin/env python
##
## (C) 2004 British Broadcasting Corporation and Kamaelia Contributors(1)
##     All Rights Reserved.
##
## You may only modify and redistribute this under the terms of any of the
## following licenses(2): Mozilla Public License, V1.1, GNU General
## Public License, V2.0, GNU Lesser General Public License, V2.1
##
## (1) Kamaelia Contributors are listed in the AUTHORS file and at
##     http://kamaelia.sourceforge.net/AUTHORS - please extend this file,
##     not this notice.
## (2) Reproduced in the COPYING file, and at:
##     http://kamaelia.sourceforge.net/COPYING
## Under section 3.5 of the MPL, we are using this text since we deem the MPL
## notice inappropriate for this file. As per MPL/GPL/LGPL removal of this
## notice is prohibited.
##
## Please contact us via: kamaelia-list-owner@lists.sourceforge.net
## to discuss alternative licensing.
## -------------------------------------------------------------------------
"""\
================
AIM Client
================

Deals with post-login messages from the AIM server, mostly by parsing them and
sending them out to its "heard" outbox in a slightly more useable form. Also
sends messages to the server based on commands coming through its "talk" inbox.

How it works:
-------------
ChatManager expects to receive FLAPs containing SNACs through its "inbox". It
recognizes certain types of SNACs. For these SNACS, ChatManager parses them, and
sends the relevant data out to its "heard" outbox in tuple format. The following
lists the SNACs ChatManager understands and the tuples that it consequently
sends out:

=========   ================    ====================================
SNAC        DESCRIPTION         TUPLE SENT TO "heard"
=========   ================    ====================================
(03, 0b)    Buddy is online     ("buddy online", {name: buddy name})
(04, 07)    Incoming message    ("message", sender, message text)
=========   ================    ====================================

The "buddy online" message contains a dictionary instead of just a text field
for the buddy name because this will make it easier to add more buddy data
to a "buddy online" message, such as online time or alias. The server sends this
data, but right now ChatManager just discards it.

ChatManager also understands tuple-based commands sent to its "talk" inbox. The
following lists the commands it understands, and the corresponding actions it
takes.

=================================================   ======================
COMMAND                                             ACTION
=================================================   ======================
("message", recipient's screenname, message text)   Sends instant message to
                                                    server (SNAC (04, 07))
=================================================   ======================

Example Usage
-------------
Simple client with a truly horrible interface::

    class AIMHarness(component):
        def main(self):
            self.loginer = LoginHandler('sitar63112', 'sitar63112').activate()
            self.link((self.loginer, "signal"), (self, "internal inbox"))
            self.addChildren(self.loginer)
            while not self.dataReady("internal inbox"): yield 1
            self.oscar = self.recv("internal inbox")
            queued = self.recv("internal inbox")
            self.unlink(self.oscar)

            self.chatter = ChatManager().activate()
            self.link((self.chatter, "heard"), (self, "outbox"), passthrough=2)
            self.link((self, "inbox"), (self.chatter, "talk"), passthrough=1)
            self.link((self.chatter, "outbox"), (self.oscar, "inbox"))
            self.link((self.oscar, "outbox"), (self.chatter, "inbox"))
            self.link((self, "internal outbox"), (self.chatter, "inbox"))
            while len(queued):
                self.send(queued[0], "internal outbox")
                del(queued[0])
            while True:
                yield 1

    def tuplefy(data):
        data = data.split()
        if len(data) > 1:
            data = ("message", data[0], " ".join(data[1:]))
            return data

    Pipeline(ConsoleReader(),
             PureTransformer(tuplefy),
             AIMHarness(),
             ConsoleEchoer()
            ).run()

"""

from OSCARClient import *
from OscarUtil import *
from OscarUtil2 import *
from Kamaelia.Internet.TCPClient import TCPClient
from Axon.Component import component
import re

__kamaelia_components__ = (OSCARClient, TCPClient)

class ChatManager(SNACExchanger):
    """
    ChatManager() -> new ChatManager component.
    """
    Inboxes = {"inbox" : "incoming FLAPs on channel 2",
               "errors" : "error messages",
               "control" : "NOT USED",
               "talk" : "outgoing messages",
               }

    Outboxes = {"outbox" : "outgoing FLAPs",
                "signal" : "NOT USED",
                "heard" : "echoes peer messages to this box."
                }

    def __init__(self):
        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
        super(ChatManager, self).__init__()
        debugSections = {"ChatManager.main" : 5,
                        "ChatManager.receiveMessage" : 5,
                         "ChatManager.sendMessage" : 4,}
        self.debugger.addDebug(**debugSections)

    def main(self):
        "Main loop."
        while True:
            yield 1
            while self.dataReady():
                header, body = self.recvSnac()
                kind = (header[0], header[1])
                if kind == (0x03, 0x0b):
                    l, = struct.unpack('!B', body[0])
                    buddy = body[1:1+l]
                    assert self.debugger.note("ChatManager.main", 7, buddy + " came online")
                    buddyinfo = {"name" : buddy}
                    self.send(("buddy online", buddyinfo), "heard")
                elif kind == (0x04, 0x07):
                    self.receiveMessage(body)
##                else:
##                    self.send(("unknown message", header[0], header[1]), "heard")
            while self.dataReady("talk"):
                data = self.recv("talk")
                assert self.debugger.note("ChatManager.main", 7, "received " + str(data))
                if data[0] == "message" :
                    self.sendMessage(data[1], data[2])

    def receiveMessage(self, body):
        """
        Extracts the sender and message text from SNAC body, and sends the tuple
        ("message", sender, message) to "heard".
        """
        msgid, msgchan, l = struct.unpack('!QHB', body[:11])
        sender = body[11:11+l]
        assert self.debugger.note("ChatManager.receiveMessage", 7, "message from %s on channel %i" % (sender, msgchan))
        TLVchain = body[11 + l + 4:]
        parsed = readTLVs(TLVchain)
        if msgchan == 1:
            fragments = readTLVs(parsed[0x02])
            msgText = fragments[0x0101]
            charSetID, charSubset = struct.unpack("!HH", msgText[:4]) #ignoring these for now, but they might come in handy
            message = msgText[4:]
            message = self.cleanMessage(message)
        elif msgchan == 2:
            message = "%s requesting unsupported function" % sender
        elif msgchan == 3:
            message = parsed[0x05][8:]

        self.send(("message", sender, message), "heard")

    def sendMessage(self, buddyname, text):
        """
        constructs SNAC (04, 06), the "send message" SNAC and sends it to "outbox"
        """
        frag = TLV(0x0501, struct.pack("!i", 0))
        frag2 = TLV(0x0101, struct.pack("!HH", 0, 0) + text)
        msgCookie = '\x32\x36\x37\x31\x34\x36\x36\x00'
        msgChan = 1
        buddyinfo = Single(len(buddyname)) + buddyname
        body = msgCookie + Double(msgChan) + buddyinfo + TLV(0x02, frag + frag2)
        self.sendSnac(0x04, 0x06, body)

    def cleanMessage(self, message):
        """strips HTML tags off messages"""
        p = re.compile("<[^<^>]*>")
        message = p.sub("", message)
        return message

if __name__ == '__main__':
    from Kamaelia.Chassis.Graphline import Graphline
    from Kamaelia.Util.Console import ConsoleEchoer
    import sys
    sys.path.append('..')
    from likefile import *

    flap = open('/home/jlei/aim/snacs/0407').read()
    class Chargen(component):
        def main(self):
            self.send((2, flap[6:]))
            yield 1

    p = Graphline(chargen = Chargen(),
                  cm = ChatManager(),
                  ce = ConsoleEchoer(),
                  linkages = {("chargen", "outbox") : ("cm", "inbox"),
                              ("cm", "heard") : ("ce", "inbox"),
                              }
                  )
    p.run()
<|endoftext|>


<commit_before>from django.contrib import admin

# Register your models here.
<commit_msg>Registers location for the admin site<commit_after>from django.contrib import admin
from facility.models import Building, Room, Location, User

admin.site.register(Building)
admin.site.register(Room)
admin.site.register(User)
admin.site.register(Location)

<|endoftext|>


<commit_before>import os
import sys
import csv
from io import BytesIO
from openpyxl import Workbook
from .csvfile import TileCsvWriter
from .format import Writer

class ExcelWriter(TileCsvWriter):
    def __init__(self, **kwargs):
        super(TileCsvWriter, self).__init__(**kwargs)

    def write_resources(self, graph_id=None, resourceinstanceids=None, **kwargs):
        super(TileCsvWriter, self).write_resources(graph_id=graph_id, resourceinstanceids=resourceinstanceids, **kwargs)

        csv_files = TileCsvWriter().write_resources(graph_id=graph_id)
        wb = Workbook()

        for csv_file in csv_files:
            # create a tab/worksheet for every csv file
            ws = wb.create_sheet(title=csv_file["name"].split(".csv")[0])
            for row in csv.reader(csv_file["outputfile"].getvalue().split("\r\n")):
                ws.append(row)
        # delete default blank first sheet in workbook
        del wb["Sheet"]

        # save virtual workbook so
        virtual_workbook = BytesIO()
        wb.save(virtual_workbook)

        excel_file_for_export = []
        excel_file_for_export.append({"name": self.file_name + ".xlsx", "outputfile": wb})

        return excel_file_for_export
<commit_msg>Switches split for splitext to parse file name. re #7192<commit_after>import os
import sys
import csv
from io import BytesIO
from openpyxl import Workbook
from .csvfile import TileCsvWriter
from .format import Writer

class ExcelWriter(TileCsvWriter):
    def __init__(self, **kwargs):
        super(TileCsvWriter, self).__init__(**kwargs)

    def write_resources(self, graph_id=None, resourceinstanceids=None, **kwargs):
        super(TileCsvWriter, self).write_resources(graph_id=graph_id, resourceinstanceids=resourceinstanceids, **kwargs)

        csv_files = TileCsvWriter().write_resources(graph_id=graph_id)
        wb = Workbook()

        for csv_file in csv_files:
            # create a tab/worksheet for every csv file
            csv_file_name, extension = os.path.splitext(csv_file["name"])
            ws = wb.create_sheet(title=csv_file_name)
            for row in csv.reader(csv_file["outputfile"].getvalue().split("\r\n")):
                ws.append(row)
        # delete default blank first sheet in workbook
        del wb["Sheet"]

        virtual_workbook = BytesIO()
        wb.save(virtual_workbook)

        excel_file_for_export = []
        excel_file_for_export.append({"name": self.file_name + ".xlsx", "outputfile": wb})

        return excel_file_for_export
<|endoftext|>


<commit_before>from django import template

__author__ = "SmileyChris"

#==============================================================================
# Calculation objects
#==============================================================================

class BaseCalc(object):
    def __init__(self, var1, var2 = None, negate = False):
        self.var1 = var1
        self.var2 = var2
        self.negate = negate

    def resolve(self, context):
        try:
            var1, var2 = self.resolve_vars(context)
            outcome = self.calculate(var1, var2)
        except:
            outcome = False
        if self.negate:
            return not outcome
        return outcome

    def resolve_vars(self, context):
        var2 = self.var2 and self.var2.resolve(context)
        return self.var1.resolve(context), var2

    def calculate(self, var1, var2):
        raise NotImplementedError()

class Or(BaseCalc):
    def calculate(self, var1, var2):
        return var1 or var2

class And(BaseCalc):
    def calculate(self, var1, var2):
        return var1 and var2

class Equals(BaseCalc):
    def calculate(self, var1, var2):
        return var1 == var2

class Greater(BaseCalc):
    def calculate(self, var1, var2):
        return var1 > var2

class GreaterOrEqual(BaseCalc):
    def calculate(self, var1, var2):
        return var1 >= var2

class In(BaseCalc):
    def calculate(self, var1, var2):
        return var1 in var2

OPERATORS = {
    '=': (Equals, True),
    '==': (Equals, True),
    '!=': (Equals, False),
    '>': (Greater, True),
    '>=': (GreaterOrEqual, True),
    '<=': (Greater, False),
    '<': (GreaterOrEqual, False),
    'or': (Or, True),
    'and': (And, True),
    'in': (In, True),
}
BOOL_OPERATORS = ('or', 'and')

class IfParser(object):
    error_class = ValueError

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

    def _get_tokens(self):
        return self._tokens

    def _set_tokens(self, tokens):
        self._tokens = tokens
        self.len = len(tokens)
        self.pos = 0

    tokens = property(_get_tokens, _set_tokens)

    def parse(self):
        if self.at_end():
            raise self.error_class('No variables provided.')
        var1 = self.get_bool_var()
        while not self.at_end():
            op, negate = self.get_operator()
            var2 = self.get_bool_var()
            var1 = op(var1, var2, negate = negate)
        return var1

    def get_token(self, eof_message = None, lookahead = False):
        negate = True
        token = None
        pos = self.pos
        while token is None or token == 'not':
            if pos >= self.len:
                if eof_message is None:
                    raise self.error_class()
                raise self.error_class(eof_message)
            token = self.tokens[pos]
            negate = not negate
            pos += 1
        if not lookahead:
            self.pos = pos
        return token, negate

    def at_end(self):
        return self.pos >= self.len

    def create_var(self, value):
        return TestVar(value)

    def get_bool_var(self):
        """
        Returns either a variable by itself or a non-boolean operation (such as
        ``x == 0`` or ``x < 0``).

        This is needed to keep correct precedence for boolean operations (i.e.
        ``x or x == 0`` should be ``x or (x == 0)``, not ``(x or x) == 0``).
        """
        var = self.get_var()
        if not self.at_end():
            op_token = self.get_token(lookahead = True)[0]
            if isinstance(op_token, basestring) and (op_token not in
                                                     BOOL_OPERATORS):
                op, negate = self.get_operator()
                return op(var, self.get_var(), negate = negate)
        return var

    def get_var(self):
        token, negate = self.get_token('Reached end of statement, still '
                                       'expecting a variable.')
        if isinstance(token, basestring) and token in OPERATORS:
            raise self.error_class('Expected variable, got operator (%s).' %
                                   token)
        var = self.create_var(token)
        if negate:
            return Or(var, negate = True)
        return var

    def get_operator(self):
        token, negate = self.get_token('Reached end of statement, still '
                                       'expecting an operator.')
        if not isinstance(token, basestring) or token not in OPERATORS:
            raise self.error_class('%s is not a valid operator.' % token)
        if self.at_end():
            raise self.error_class('No variable provided after "%s".' % token)
        op, true = OPERATORS[token]
        if not true:
            negate = not negate
        return op, negate

#==============================================================================
# Actual templatetag code.
#==============================================================================

class TemplateIfParser(IfParser):
    error_class = template.TemplateSyntaxError

    def __init__(self, parser, *args, **kwargs):
        self.template_parser = parser
        return super(TemplateIfParser, self).__init__(*args, **kwargs)

    def create_var(self, value):
        return self.template_parser.compile_filter(value)

class SmartIfNode(template.Node):
    def __init__(self, var, nodelist_true, nodelist_false = None):
        self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
        self.var = var

    def render(self, context):
        if self.var.resolve(context):
            return self.nodelist_true.render(context)
        if self.nodelist_false:
            return self.nodelist_false.render(context)
        return ''

    def __repr__(self):
        return "<Smart If node>"

    def __iter__(self):
        for node in self.nodelist_true:
            yield node
        if self.nodelist_false:
            for node in self.nodelist_false:
                yield node

    def get_nodes_by_type(self, nodetype):
        nodes = []
        if isinstance(self, nodetype):
            nodes.append(self)
        nodes.extend(self.nodelist_true.get_nodes_by_type(nodetype))
        if self.nodelist_false:
            nodes.extend(self.nodelist_false.get_nodes_by_type(nodetype))
        return nodes

def smart_if(parser, token):
    """
    A smarter {% if %} tag for django templates.

    While retaining current Django functionality, it also handles equality,
    greater than and less than operators. Some common case examples::

        {% if articles|length >= 5 %}...{% endif %}
        {% if "ifnotequal tag" != "beautiful" %}...{% endif %}

    Arguments and operators _must_ have a space between them, so
    ``{% if 1>2 %}`` is not a valid smart if tag.

    All supported operators are: ``or``, ``and``, ``in``, ``=`` (or ``==``),
    ``!=``, ``>``, ``>=``, ``<`` and ``<=``.
    """
    bits = token.split_contents()[1:]
    var = TemplateIfParser(parser, bits).parse()
    nodelist_true = parser.parse(('else', 'endif'))
    token = parser.next_token()
    if token.contents == 'else':
        nodelist_false = parser.parse(('endif',))
        parser.delete_first_token()
    else:
        nodelist_false = None
    return SmartIfNode(var, nodelist_true, nodelist_false)

try:
    if int(django.get_version()[-5:]) < 11806:
        register.tag('if', smart_if)
except ValueError:
    pass
<commit_msg>correction smart if<commit_after>'''
A smarter {% if %} tag for django templates.

While retaining current Django functionality, it also handles equality,
greater than and less than operators. Some common case examples::

    {% if articles|length >= 5 %}...{% endif %}
    {% if "ifnotequal tag" != "beautiful" %}...{% endif %}
'''
import unittest
from django import template

register = template.Library()

#===============================================================================
# Calculation objects
#===============================================================================

class BaseCalc(object):
    def __init__(self, var1, var2 = None, negate = False):
        self.var1 = var1
        self.var2 = var2
        self.negate = negate

    def resolve(self, context):
        try:
            var1, var2 = self.resolve_vars(context)
            outcome = self.calculate(var1, var2)
        except:
            outcome = False
        if self.negate:
            return not outcome
        return outcome

    def resolve_vars(self, context):
        var2 = self.var2 and self.var2.resolve(context)
        return self.var1.resolve(context), var2

    def calculate(self, var1, var2):
        raise NotImplementedError()

class Or(BaseCalc):
    def calculate(self, var1, var2):
        return var1 or var2

class And(BaseCalc):
    def calculate(self, var1, var2):
        return var1 and var2

class Equals(BaseCalc):
    def calculate(self, var1, var2):
        return var1 == var2

class Greater(BaseCalc):
    def calculate(self, var1, var2):
        return var1 > var2

class GreaterOrEqual(BaseCalc):
    def calculate(self, var1, var2):
        return var1 >= var2

class In(BaseCalc):
    def calculate(self, var1, var2):
        return var1 in var2

#===============================================================================
# Tests
#===============================================================================

class TestVar(object):
    """
    A basic self-resolvable object similar to a Django template variable. Used
    to assist with tests.
    """
    def __init__(self, value):
        self.value = value

    def resolve(self, context):
        return self.value

class SmartIfTests(unittest.TestCase):
    def setUp(self):
        self.true = TestVar(True)
        self.false = TestVar(False)
        self.high = TestVar(9000)
        self.low = TestVar(1)

    def assertCalc(self, calc, context = None):
        """
        Test a calculation is True, also checking the inverse "negate" case.
        """
        context = context or {}
        self.assert_(calc.resolve(context))
        calc.negate = not calc.negate
        self.assertFalse(calc.resolve(context))

    def assertCalcFalse(self, calc, context = None):
        """
        Test a calculation is False, also checking the inverse "negate" case.
        """
        context = context or {}
        self.assertFalse(calc.resolve(context))
        calc.negate = not calc.negate
        self.assert_(calc.resolve(context))

    def test_or(self):
        self.assertCalc(Or(self.true))
        self.assertCalcFalse(Or(self.false))
        self.assertCalc(Or(self.true, self.true))
        self.assertCalc(Or(self.true, self.false))
        self.assertCalc(Or(self.false, self.true))
        self.assertCalcFalse(Or(self.false, self.false))

    def test_and(self):
        self.assertCalc(And(self.true, self.true))
        self.assertCalcFalse(And(self.true, self.false))
        self.assertCalcFalse(And(self.false, self.true))
        self.assertCalcFalse(And(self.false, self.false))

    def test_equals(self):
        self.assertCalc(Equals(self.low, self.low))
        self.assertCalcFalse(Equals(self.low, self.high))

    def test_greater(self):
        self.assertCalc(Greater(self.high, self.low))
        self.assertCalcFalse(Greater(self.low, self.low))
        self.assertCalcFalse(Greater(self.low, self.high))

    def test_greater_or_equal(self):
        self.assertCalc(GreaterOrEqual(self.high, self.low))
        self.assertCalc(GreaterOrEqual(self.low, self.low))
        self.assertCalcFalse(GreaterOrEqual(self.low, self.high))

    def test_in(self):
        list_ = TestVar([1, 2, 3])
        invalid_list = TestVar(None)
        self.assertCalc(In(self.low, list_))
        self.assertCalcFalse(In(self.low, invalid_list))

    def test_parse_bits(self):
        var = IfParser([True]).parse()
        self.assert_(var.resolve({}))
        var = IfParser([False]).parse()
        self.assertFalse(var.resolve({}))

        var = IfParser([False, 'or', True]).parse()
        self.assert_(var.resolve({}))

        var = IfParser([False, 'and', True]).parse()
        self.assertFalse(var.resolve({}))

        var = IfParser(['not', False, 'and', 'not', False]).parse()
        self.assert_(var.resolve({}))

        var = IfParser([1, '=', 1]).parse()
        self.assert_(var.resolve({}))

        var = IfParser([1, '!=', 1]).parse()
        self.assertFalse(var.resolve({}))

        var = IfParser([3, '>', 2]).parse()
        self.assert_(var.resolve({}))

        var = IfParser([1, '<', 2]).parse()
        self.assert_(var.resolve({}))

        var = IfParser([2, 'not', 'in', [2, 3]]).parse()
        self.assertFalse(var.resolve({}))

OPERATORS = {
    '=': (Equals, True),
    '==': (Equals, True),
    '!=': (Equals, False),
    '>': (Greater, True),
    '>=': (GreaterOrEqual, True),
    '<=': (Greater, False),
    '<': (GreaterOrEqual, False),
    'or': (Or, True),
    'and': (And, True),
    'in': (In, True),
}

class IfParser(object):
    error_class = ValueError

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

    def _get_tokens(self):
        return self._tokens

    def _set_tokens(self, tokens):
        self._tokens = tokens
        self.len = len(tokens)
        self.pos = 0

    tokens = property(_get_tokens, _set_tokens)

    def parse(self):
        if self.at_end():
            raise self.error_class('No variables provided.')
        var1 = self.get_var()
        while not self.at_end():
            token = self.get_token()
            if token == 'not':
                if self.at_end():
                    raise self.error_class('No variable provided after "not".')
                token = self.get_token()
                negate = True
            else:
                negate = False
            if token not in OPERATORS:
                raise self.error_class('%s is not a valid operator.' % token)
            if self.at_end():
                raise self.error_class('No variable provided after "%s"' % token)
            op, true = OPERATORS[token]
            if not true:
                negate = not negate
            var2 = self.get_var()
            var1 = op(var1, var2, negate = negate)
        return var1

    def get_token(self):
        token = self.tokens[self.pos]
        self.pos += 1
        return token

    def at_end(self):
        return self.pos >= self.len

    def create_var(self, value):
        return TestVar(value)

    def get_var(self):
        token = self.get_token()
        if token == 'not':
            if self.at_end():
                raise self.error_class('No variable provided after "not".')
            token = self.get_token()
            return Or(self.create_var(token), negate = True)
        return self.create_var(token)

#===============================================================================
# Actual templatetag code.
#===============================================================================

class TemplateIfParser(IfParser):
    error_class = template.TemplateSyntaxError

    def __init__(self, parser, *args, **kwargs):
        self.template_parser = parser
        return super(TemplateIfParser, self).__init__(*args, **kwargs)

    def create_var(self, value):
        return self.template_parser.compile_filter(value)

class SmartIfNode(template.Node):
    def __init__(self, var, nodelist_true, nodelist_false = None):
        self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
        self.var = var

    def render(self, context):
        if self.var.resolve(context):
            return self.nodelist_true.render(context)
        if self.nodelist_false:
            return self.nodelist_false.render(context)
        return ''

    def __repr__(self):
        return "<Smart If node>"

    def __iter__(self):
        for node in self.nodelist_true:
            yield node
        if self.nodelist_false:
            for node in self.nodelist_false:
                yield node

    def get_nodes_by_type(self, nodetype):
        nodes = []
        if isinstance(self, nodetype):
            nodes.append(self)
        nodes.extend(self.nodelist_true.get_nodes_by_type(nodetype))
        if self.nodelist_false:
            nodes.extend(self.nodelist_false.get_nodes_by_type(nodetype))
        return nodes

@register.tag('if')
def smart_if(parser, token):
    '''
    A smarter {% if %} tag for django templates.

    While retaining current Django functionality, it also handles equality,
    greater than and less than operators. Some common case examples::

        {% if articles|length >= 5 %}...{% endif %}
        {% if "ifnotequal tag" != "beautiful" %}...{% endif %}

    Arguments and operators _must_ have a space between them, so
    ``{% if 1>2 %}`` is not a valid smart if tag.

    All supported operators are: ``or``, ``and``, ``in``, ``=`` (or ``==``),
    ``!=``, ``>``, ``>=``, ``<`` and ``<=``.
    '''
    bits = token.split_contents()[1:]
    var = TemplateIfParser(parser, bits).parse()
    nodelist_true = parser.parse(('else', 'endif'))
    token = parser.next_token()
    if token.contents == 'else':
        nodelist_false = parser.parse(('endif',))
        parser.delete_first_token()
    else:
        nodelist_false = None
    return SmartIfNode(var, nodelist_true, nodelist_false)

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