<commit_before>import py
defaultconftestpath = py.magic.autopath().dirpath('defaultconftest.py')

class Conftest(object):
    """ the single place for accessing values and interacting
        towards conftest modules from py.test objects.

        Note that triggering Conftest instances to import
        conftest.py files may result in added cmdline options.
        XXX
    """
    def __init__(self, path=None):
        self._path2confmods = {}
        if path is not None:
            self.setinitial([path])

    def setinitial(self, args):
        """ return a Conftest object initialized with a path obtained
            from looking at the first (usually cmdline) argument that points
            to an existing file object.
            XXX note: conftest files may add command line options
            and we thus have no completely safe way of determining
            which parts of the arguments are actually related to options.
        """
        current = py.path.local()
        for arg in args + [current]:
            anchor = current.join(arg, abs=1)
            if anchor.check(): # we found some file object
                print >>py.std.sys.stderr, "initializing conftest from", anchor
                # conftest-lookups without a path actually mean
                # lookups with our initial path.
                self._path2confmods[None] = self.getconftestmodules(anchor)
                #print " -> ", conftest._path2confmods
                break

    def getconftestmodules(self, path):
        """ return a list of imported conftest modules for the given path.  """
        try:
            clist = self._path2confmods[path]
        except KeyError:
            dp = path.dirpath()
            if dp == path:
                return [importconfig(defaultconftestpath)]
            clist = self.getconftestmodules(dp)
            conftestpath = path.join("conftest.py")
            if conftestpath.check(file=1):
                clist.append(importconfig(conftestpath))
            self._path2confmods[path] = clist
        # be defensive: avoid changes from caller side to
        # affect us by always returning a copy of the actual list
        return clist[:]

    # XXX no real use case, may probably go
    #def lget(self, name, path=None):
    #    modules = self.getconftestmodules(path)
    #    return self._get(name, modules)

    def rget(self, name, path=None):
        return self._rget(name, path)[0]

    def _rget(self, name, path=None):
        modules = self.getconftestmodules(path)
        modules.reverse()
        return self._get(name, modules)

    def rget_path(self, name, path=None):
        return self._rget(name, path)

    def _get(self, name, modules):
        for mod in modules:
            try:
                return getattr(mod, name), mod
            except AttributeError:
                continue
        raise KeyError, name

def importconfig(configpath):
    if not configpath.dirpath('__init__.py').check(file=1):
        # HACK: we don't want any "globally" imported conftest.py,
        #       prone to conflicts and subtle problems
        modname = str(configpath).replace('.', configpath.sep)
        return configpath.pyimport(modname=modname)
    else:
        return configpath.pyimport()
<commit_msg>[svn r37439] Sorry, cfbolz, seems the print to stderr breaks some test... :|<commit_after>import py
defaultconftestpath = py.magic.autopath().dirpath('defaultconftest.py')

class Conftest(object):
    """ the single place for accessing values and interacting
        towards conftest modules from py.test objects.

        Note that triggering Conftest instances to import
        conftest.py files may result in added cmdline options.
        XXX
    """
    def __init__(self, path=None):
        self._path2confmods = {}
        if path is not None:
            self.setinitial([path])

    def setinitial(self, args):
        """ return a Conftest object initialized with a path obtained
            from looking at the first (usually cmdline) argument that points
            to an existing file object.
            XXX note: conftest files may add command line options
            and we thus have no completely safe way of determining
            which parts of the arguments are actually related to options.
        """
        current = py.path.local()
        for arg in args + [current]:
            anchor = current.join(arg, abs=1)
            if anchor.check(): # we found some file object
                #print >>py.std.sys.stderr, "initializing conftest from", anchor
                # conftest-lookups without a path actually mean
                # lookups with our initial path.
                self._path2confmods[None] = self.getconftestmodules(anchor)
                #print " -> ", conftest._path2confmods
                break

    def getconftestmodules(self, path):
        """ return a list of imported conftest modules for the given path.  """
        try:
            clist = self._path2confmods[path]
        except KeyError:
            dp = path.dirpath()
            if dp == path:
                return [importconfig(defaultconftestpath)]
            clist = self.getconftestmodules(dp)
            conftestpath = path.join("conftest.py")
            if conftestpath.check(file=1):
                clist.append(importconfig(conftestpath))
            self._path2confmods[path] = clist
        # be defensive: avoid changes from caller side to
        # affect us by always returning a copy of the actual list
        return clist[:]

    # XXX no real use case, may probably go
    #def lget(self, name, path=None):
    #    modules = self.getconftestmodules(path)
    #    return self._get(name, modules)

    def rget(self, name, path=None):
        return self._rget(name, path)[0]

    def _rget(self, name, path=None):
        modules = self.getconftestmodules(path)
        modules.reverse()
        return self._get(name, modules)

    def rget_path(self, name, path=None):
        return self._rget(name, path)

    def _get(self, name, modules):
        for mod in modules:
            try:
                return getattr(mod, name), mod
            except AttributeError:
                continue
        raise KeyError, name

def importconfig(configpath):
    if not configpath.dirpath('__init__.py').check(file=1):
        # HACK: we don't want any "globally" imported conftest.py,
        #       prone to conflicts and subtle problems
        modname = str(configpath).replace('.', configpath.sep)
        return configpath.pyimport(modname=modname)
    else:
        return configpath.pyimport()
<|endoftext|>


<commit_before>import asyncio

import async_timeout
import pytest
from async_generator import async_generator, yield_

from asgiref.sync import async_to_sync
from channels_redis.core import ChannelFull, RedisChannelLayer

TEST_HOSTS = [("localhost", 6379)]

MULTIPLE_TEST_HOSTS = [
    "redis://localhost:6379/0",
    "redis://localhost:6379/1",
    "redis://localhost:6379/2",
    "redis://localhost:6379/3",
    "redis://localhost:6379/4",
    "redis://localhost:6379/5",
    "redis://localhost:6379/6",
    "redis://localhost:6379/7",
    "redis://localhost:6379/8",
    "redis://localhost:6379/9",
]

@pytest.fixture()
@async_generator
async def channel_layer():
    """
    Channel layer fixture that flushes automatically.
    """
    channel_layer = RedisChannelLayer(
        hosts=TEST_HOSTS,
        capacity=3,
        channel_capacity={"tiny": 1},
    )
    await yield_(channel_layer)
    await channel_layer.flush()

@pytest.fixture()
@async_generator
async def channel_layer_multiple_hosts():
    """
    Channel layer fixture that flushes automatically.
    """
    channel_layer = RedisChannelLayer(hosts=MULTIPLE_TEST_HOSTS, capacity=3)
    await yield_(channel_layer)
    await channel_layer.flush()

@pytest.mark.asyncio
async def test_send_receive(channel_layer):
    """
    Makes sure we can send a message to a normal channel then receive it.
    """
    await channel_layer.send(
        "test-channel-1",
        {
            "type": "test.message",
            "text": "Ahoy-hoy!",
        },
    )
    message = await channel_layer.receive("test-channel-1")
    assert message["type"] == "test.message"
    assert message["text"] == "Ahoy-hoy!"

@pytest.mark.parametrize("channel_layer", [None])  # Fixture can't handle sync
def test_double_receive(channel_layer):
    """
    Makes sure we can receive from two different event loops using
    process-local channel names.
    """
    channel_layer = RedisChannelLayer(hosts=TEST_HOSTS, capacity=3)
    channel_name_1 = async_to_sync(channel_layer.new_channel)()
    channel_name_2 = async_to_sync(channel_layer.new_channel)()
    async_to_sync(channel_layer.send)(channel_name_1, {"type": "test.message.1"})
    async_to_sync(channel_layer.send)(channel_name_2, {"type": "test.message.2"})

    # Make things to listen on the loops
    async def listen1():
        message = await channel_layer.receive(channel_name_1)
        assert message["type"] == "test.message.1"

    async def listen2():
        message = await channel_layer.receive(channel_name_2)
        assert message["type"] == "test.message.2"

    # Run them inside threads
    async_to_sync(listen2)()
    async_to_sync(listen1)()
    # Clean up
    async_to_sync(channel_layer.flush)()

@pytest.mark.asyncio
async def test_send_capacity(channel_layer):
    """
    Makes sure we get ChannelFull when we hit the send capacity
    """
    await channel_layer.send("test-channel-1", {"type": "test.message"})
    await channel_layer.send("test-channel-1", {"type": "test.message"})
    await channel_layer.send("test-channel-1", {"type": "test.message"})
    with pytest.raises(ChannelFull):
        await channel_layer.send("test-channel-1", {"type": "test.message"})

@pytest.mark.asyncio
async def test_send_specific_capacity(channel_layer):
    """
    Makes sure we get ChannelFull when we hit the send capacity on a specific channel
    """
    custom_channel_layer = RedisChannelLayer(hosts=TEST_HOSTS, capacity=3, channel_capacity={"one": 1})
    await custom_channel_layer.send("one", {"type": "test.message"})
    with pytest.raises(ChannelFull):
        await custom_channel_layer.send("one", {"type": "test.message"})
    await custom_channel_layer.flush()

@pytest.mark.asyncio
async def test_process_local_send_receive(channel_layer):
    """
    Makes sure we can send a message to a process-local channel then receive it.
    """
    channel_name = await channel_layer.new_channel()
    await channel_layer.send(
        channel_name,
        {
            "type": "test.message",
            "text": "Local only please",
        },
    )
    message = await channel_layer.receive(channel_name)
    assert message["type"] == "test.message"
    assert message["text"] == "Local only please"

@pytest.mark.asyncio
async def test_multi_send_receive(channel_layer):
    """
    Tests overlapping sends and receives, and ordering.
    """
    channel_layer = RedisChannelLayer(hosts=TEST_HOSTS)
    await channel_layer.send("test-channel-3", {"type": "message.1"})
    await channel_layer.send("test-channel-3", {"type": "message.2"})
    await channel_layer.send("test-channel-3", {"type": "message.3"})
    assert (await channel_layer.receive("test-channel-3"))["type"] == "message.1"
    assert (await channel_layer.receive("test-channel-3"))["type"] == "message.2"
    assert (await channel_layer.receive("test-channel-3"))["type"] == "message.3"

@pytest.mark.asyncio
async def test_reject_bad_channel(channel_layer):
    """
    Makes sure sending/receiving on an invalic channel name fails.
    """
    with pytest.raises(TypeError):
        await channel_layer.send("=+135!", {"type": "foom"})
    with pytest.raises(TypeError):
        await channel_layer.receive("=+135!")

@pytest.mark.asyncio
async def test_reject_bad_client_prefix(channel_layer):
    """
    Makes sure receiving on a non-prefixed local channel is not allowed.
    """
    with pytest.raises(AssertionError):
        await channel_layer.receive("not-client-prefix!local_part")

@pytest.mark.asyncio
async def test_groups_basic(channel_layer):
    """
    Tests basic group operation.
    """
    channel_layer = RedisChannelLayer(hosts=TEST_HOSTS)
    channel_name1 = await channel_layer.new_channel(prefix="test-gr-chan-1")
    channel_name2 = await channel_layer.new_channel(prefix="test-gr-chan-2")
    channel_name3 = await channel_layer.new_channel(prefix="test-gr-chan-3")
    await channel_layer.group_add("test-group", channel_name1)
    await channel_layer.group_add("test-group", channel_name2)
    await channel_layer.group_add("test-group", channel_name3)
    await channel_layer.group_discard("test-group", channel_name2)
    await channel_layer.group_send("test-group", {"type": "message.1"})
    # Make sure we get the message on the two channels that were in
    async with async_timeout.timeout(1):
        assert (await channel_layer.receive(channel_name1))["type"] == "message.1"
        assert (await channel_layer.receive(channel_name3))["type"] == "message.1"
    # Make sure the removed channel did not get the message
    with pytest.raises(asyncio.TimeoutError):
        async with async_timeout.timeout(1):
            await channel_layer.receive(channel_name2)

@pytest.mark.asyncio
async def test_groups_channel_full(channel_layer):
    """
    Tests that group_send ignores ChannelFull
    """
    channel_layer = RedisChannelLayer(hosts=TEST_HOSTS)
    await channel_layer.group_add("test-group", "test-gr-chan-1")
    await channel_layer.group_send("test-group", {"type": "message.1"})
    await channel_layer.group_send("test-group", {"type": "message.1"})
    await channel_layer.group_send("test-group", {"type": "message.1"})
    await channel_layer.group_send("test-group", {"type": "message.1"})
    await channel_layer.group_send("test-group", {"type": "message.1"})

@pytest.mark.asyncio
async def test_groups_multiple_hosts(channel_layer_multiple_hosts):
    """
    Tests advanced group operation with multiple hosts.
    """
    channel_layer = RedisChannelLayer(hosts=MULTIPLE_TEST_HOSTS, capacity=100)
    channel_name1 = await channel_layer.new_channel(prefix="channel1")
    channel_name2 = await channel_layer.new_channel(prefix="channel2")
    channel_name3 = await channel_layer.new_channel(prefix="channel3")
    await channel_layer.group_add("test-group", channel_name1)
    await channel_layer.group_add("test-group", channel_name2)
    await channel_layer.group_add("test-group", channel_name3)
    await channel_layer.group_discard("test-group", channel_name2)
    await channel_layer.group_send("test-group", {"type": "message.1"})
    await channel_layer.group_send("test-group", {"type": "message.1"})

    # Make sure we get the message on the two channels that were in
    async with async_timeout.timeout(1):
        assert (await channel_layer.receive(channel_name1))["type"] == "message.1"
        assert (await channel_layer.receive(channel_name3))["type"] == "message.1"

    with pytest.raises(asyncio.TimeoutError):
        async with async_timeout.timeout(1):
            await channel_layer.receive(channel_name2)

@pytest.mark.asyncio
async def test_groups_same_prefix(channel_layer):
    """
    Tests group_send with multiple channels with same channel prefix
    """
    channel_layer = RedisChannelLayer(hosts=TEST_HOSTS)
    channel_name1 = await channel_layer.new_channel(prefix="test-gr-chan")
    channel_name2 = await channel_layer.new_channel(prefix="test-gr-chan")
    channel_name3 = await channel_layer.new_channel(prefix="test-gr-chan")
    await channel_layer.group_add("test-group", channel_name1)
    await channel_layer.group_add("test-group", channel_name2)
    await channel_layer.group_add("test-group", channel_name3)
    await channel_layer.group_send("test-group", {"type": "message.1"})

    # Make sure we get the message on the channels that were in
    async with async_timeout.timeout(1):
        assert (await channel_layer.receive(channel_name1))["type"] == "message.1"
        assert (await channel_layer.receive(channel_name2))["type"] == "message.1"
        assert (await channel_layer.receive(channel_name3))["type"] == "message.1"

@pytest.mark.parametrize("num_channels,timeout", [
    (1, 1),  # Edge cases - make sure we can send to a single channel
    (10, 1),
    (100, 10),
])
@pytest.mark.asyncio
async def test_groups_multiple_hosts_performance(
    channel_layer_multiple_hosts, num_channels, timeout
):
    """
    Tests advanced group operation: can send efficiently to multiple channels
    with multiple hosts within a certain timeout
    """
    channel_layer = RedisChannelLayer(hosts=MULTIPLE_TEST_HOSTS, capacity=100)

    channels = []
    for i in range(0, num_channels):
        channel = await channel_layer.new_channel(prefix="channel%s" % i)
        await channel_layer.group_add("test-group", channel)
        channels.append(channel)

    async with async_timeout.timeout(timeout):
        await channel_layer.group_send("test-group", {"type": "message.1"})

    # Make sure we get the message all the channels
    async with async_timeout.timeout(timeout):
        for channel in channels:
            assert (await channel_layer.receive(channel))["type"] == "message.1"

@pytest.mark.asyncio
async def test_group_send_capacity(channel_layer):
    """
    Makes sure we dont send messages to groups that are over capacity
    """

    channel = await channel_layer.new_channel()
    await channel_layer.group_add("test-group", channel)

    await channel_layer.group_send("test-group", {"type": "message.1"})
    await channel_layer.group_send("test-group", {"type": "message.2"})
    await channel_layer.group_send("test-group", {"type": "message.3"})
    await channel_layer.group_send("test-group", {"type": "message.4"})

    # We should recieve the first 3 messages
    assert (await channel_layer.receive(channel))["type"] == "message.1"
    assert (await channel_layer.receive(channel))["type"] == "message.2"
    assert (await channel_layer.receive(channel))["type"] == "message.3"

    # Make sure we do NOT recieve message 4
    with pytest.raises(asyncio.TimeoutError):
        async with async_timeout.timeout(1):
            await channel_layer.receive(channel)
<commit_msg>Fix event loop handling in the tests<commit_after>import asyncio

import async_timeout
import pytest
from async_generator import async_generator, yield_

from asgiref.sync import async_to_sync
from channels_redis.core import ChannelFull, RedisChannelLayer

TEST_HOSTS = [("localhost", 6379)]

MULTIPLE_TEST_HOSTS = [
    "redis://localhost:6379/0",
    "redis://localhost:6379/1",
    "redis://localhost:6379/2",
    "redis://localhost:6379/3",
    "redis://localhost:6379/4",
    "redis://localhost:6379/5",
    "redis://localhost:6379/6",
    "redis://localhost:6379/7",
    "redis://localhost:6379/8",
    "redis://localhost:6379/9",
]

@pytest.fixture()
@async_generator
async def channel_layer():
    """
    Channel layer fixture that flushes automatically.
    """
    channel_layer = RedisChannelLayer(
        hosts=TEST_HOSTS,
        capacity=3,
        channel_capacity={"tiny": 1},
    )
    await yield_(channel_layer)
    await channel_layer.flush()

@pytest.fixture()
@async_generator
async def channel_layer_multiple_hosts():
    """
    Channel layer fixture that flushes automatically.
    """
    channel_layer = RedisChannelLayer(hosts=MULTIPLE_TEST_HOSTS, capacity=3)
    await yield_(channel_layer)
    await channel_layer.flush()

@pytest.mark.asyncio
async def test_send_receive(channel_layer):
    """
    Makes sure we can send a message to a normal channel then receive it.
    """
    await channel_layer.send(
        "test-channel-1",
        {
            "type": "test.message",
            "text": "Ahoy-hoy!",
        },
    )
    message = await channel_layer.receive("test-channel-1")
    assert message["type"] == "test.message"
    assert message["text"] == "Ahoy-hoy!"

@pytest.mark.parametrize("channel_layer", [None])  # Fixture can't handle sync
def test_double_receive(channel_layer):
    """
    Makes sure we can receive from two different event loops using
    process-local channel names.
    """
    channel_layer = RedisChannelLayer(hosts=TEST_HOSTS, capacity=3)

    # Aioredis connections can't be used from different event loops, so
    # send and close need to be done in the same async_to_sync call.
    async def send_and_close(*args, **kwargs):
        await channel_layer.send(*args, **kwargs)
        await channel_layer.close_pools()

    channel_name_1 = async_to_sync(channel_layer.new_channel)()
    channel_name_2 = async_to_sync(channel_layer.new_channel)()
    async_to_sync(send_and_close)(channel_name_1, {"type": "test.message.1"})
    async_to_sync(send_and_close)(channel_name_2, {"type": "test.message.2"})

    # Make things to listen on the loops
    async def listen1():
        message = await channel_layer.receive(channel_name_1)
        assert message["type"] == "test.message.1"
        await channel_layer.close_pools()

    async def listen2():
        message = await channel_layer.receive(channel_name_2)
        assert message["type"] == "test.message.2"
        await channel_layer.close_pools()

    # Run them inside threads
    async_to_sync(listen2)()
    async_to_sync(listen1)()
    # Clean up
    async_to_sync(channel_layer.flush)()

@pytest.mark.asyncio
async def test_send_capacity(channel_layer):
    """
    Makes sure we get ChannelFull when we hit the send capacity
    """
    await channel_layer.send("test-channel-1", {"type": "test.message"})
    await channel_layer.send("test-channel-1", {"type": "test.message"})
    await channel_layer.send("test-channel-1", {"type": "test.message"})
    with pytest.raises(ChannelFull):
        await channel_layer.send("test-channel-1", {"type": "test.message"})

@pytest.mark.asyncio
async def test_send_specific_capacity(channel_layer):
    """
    Makes sure we get ChannelFull when we hit the send capacity on a specific channel
    """
    custom_channel_layer = RedisChannelLayer(hosts=TEST_HOSTS, capacity=3, channel_capacity={"one": 1})
    await custom_channel_layer.send("one", {"type": "test.message"})
    with pytest.raises(ChannelFull):
        await custom_channel_layer.send("one", {"type": "test.message"})
    await custom_channel_layer.flush()

@pytest.mark.asyncio
async def test_process_local_send_receive(channel_layer):
    """
    Makes sure we can send a message to a process-local channel then receive it.
    """
    channel_name = await channel_layer.new_channel()
    await channel_layer.send(
        channel_name,
        {
            "type": "test.message",
            "text": "Local only please",
        },
    )
    message = await channel_layer.receive(channel_name)
    assert message["type"] == "test.message"
    assert message["text"] == "Local only please"

@pytest.mark.asyncio
async def test_multi_send_receive(channel_layer):
    """
    Tests overlapping sends and receives, and ordering.
    """
    channel_layer = RedisChannelLayer(hosts=TEST_HOSTS)
    await channel_layer.send("test-channel-3", {"type": "message.1"})
    await channel_layer.send("test-channel-3", {"type": "message.2"})
    await channel_layer.send("test-channel-3", {"type": "message.3"})
    assert (await channel_layer.receive("test-channel-3"))["type"] == "message.1"
    assert (await channel_layer.receive("test-channel-3"))["type"] == "message.2"
    assert (await channel_layer.receive("test-channel-3"))["type"] == "message.3"
    await channel_layer.flush()

@pytest.mark.asyncio
async def test_reject_bad_channel(channel_layer):
    """
    Makes sure sending/receiving on an invalic channel name fails.
    """
    with pytest.raises(TypeError):
        await channel_layer.send("=+135!", {"type": "foom"})
    with pytest.raises(TypeError):
        await channel_layer.receive("=+135!")

@pytest.mark.asyncio
async def test_reject_bad_client_prefix(channel_layer):
    """
    Makes sure receiving on a non-prefixed local channel is not allowed.
    """
    with pytest.raises(AssertionError):
        await channel_layer.receive("not-client-prefix!local_part")

@pytest.mark.asyncio
async def test_groups_basic(channel_layer):
    """
    Tests basic group operation.
    """
    channel_layer = RedisChannelLayer(hosts=TEST_HOSTS)
    channel_name1 = await channel_layer.new_channel(prefix="test-gr-chan-1")
    channel_name2 = await channel_layer.new_channel(prefix="test-gr-chan-2")
    channel_name3 = await channel_layer.new_channel(prefix="test-gr-chan-3")
    await channel_layer.group_add("test-group", channel_name1)
    await channel_layer.group_add("test-group", channel_name2)
    await channel_layer.group_add("test-group", channel_name3)
    await channel_layer.group_discard("test-group", channel_name2)
    await channel_layer.group_send("test-group", {"type": "message.1"})
    # Make sure we get the message on the two channels that were in
    async with async_timeout.timeout(1):
        assert (await channel_layer.receive(channel_name1))["type"] == "message.1"
        assert (await channel_layer.receive(channel_name3))["type"] == "message.1"
    # Make sure the removed channel did not get the message
    with pytest.raises(asyncio.TimeoutError):
        async with async_timeout.timeout(1):
            await channel_layer.receive(channel_name2)
    await channel_layer.flush()

@pytest.mark.asyncio
async def test_groups_channel_full(channel_layer):
    """
    Tests that group_send ignores ChannelFull
    """
    channel_layer = RedisChannelLayer(hosts=TEST_HOSTS)
    await channel_layer.group_add("test-group", "test-gr-chan-1")
    await channel_layer.group_send("test-group", {"type": "message.1"})
    await channel_layer.group_send("test-group", {"type": "message.1"})
    await channel_layer.group_send("test-group", {"type": "message.1"})
    await channel_layer.group_send("test-group", {"type": "message.1"})
    await channel_layer.group_send("test-group", {"type": "message.1"})
    await channel_layer.flush()

@pytest.mark.asyncio
async def test_groups_multiple_hosts(channel_layer_multiple_hosts):
    """
    Tests advanced group operation with multiple hosts.
    """
    channel_layer = RedisChannelLayer(hosts=MULTIPLE_TEST_HOSTS, capacity=100)
    channel_name1 = await channel_layer.new_channel(prefix="channel1")
    channel_name2 = await channel_layer.new_channel(prefix="channel2")
    channel_name3 = await channel_layer.new_channel(prefix="channel3")
    await channel_layer.group_add("test-group", channel_name1)
    await channel_layer.group_add("test-group", channel_name2)
    await channel_layer.group_add("test-group", channel_name3)
    await channel_layer.group_discard("test-group", channel_name2)
    await channel_layer.group_send("test-group", {"type": "message.1"})
    await channel_layer.group_send("test-group", {"type": "message.1"})

    # Make sure we get the message on the two channels that were in
    async with async_timeout.timeout(1):
        assert (await channel_layer.receive(channel_name1))["type"] == "message.1"
        assert (await channel_layer.receive(channel_name3))["type"] == "message.1"

    with pytest.raises(asyncio.TimeoutError):
        async with async_timeout.timeout(1):
            await channel_layer.receive(channel_name2)

    await channel_layer.flush()

@pytest.mark.asyncio
async def test_groups_same_prefix(channel_layer):
    """
    Tests group_send with multiple channels with same channel prefix
    """
    channel_layer = RedisChannelLayer(hosts=TEST_HOSTS)
    channel_name1 = await channel_layer.new_channel(prefix="test-gr-chan")
    channel_name2 = await channel_layer.new_channel(prefix="test-gr-chan")
    channel_name3 = await channel_layer.new_channel(prefix="test-gr-chan")
    await channel_layer.group_add("test-group", channel_name1)
    await channel_layer.group_add("test-group", channel_name2)
    await channel_layer.group_add("test-group", channel_name3)
    await channel_layer.group_send("test-group", {"type": "message.1"})

    # Make sure we get the message on the channels that were in
    async with async_timeout.timeout(1):
        assert (await channel_layer.receive(channel_name1))["type"] == "message.1"
        assert (await channel_layer.receive(channel_name2))["type"] == "message.1"
        assert (await channel_layer.receive(channel_name3))["type"] == "message.1"

    await channel_layer.flush()

@pytest.mark.parametrize("num_channels,timeout", [
    (1, 1),  # Edge cases - make sure we can send to a single channel
    (10, 1),
    (100, 10),
])
@pytest.mark.asyncio
async def test_groups_multiple_hosts_performance(
    channel_layer_multiple_hosts, num_channels, timeout
):
    """
    Tests advanced group operation: can send efficiently to multiple channels
    with multiple hosts within a certain timeout
    """
    channel_layer = RedisChannelLayer(hosts=MULTIPLE_TEST_HOSTS, capacity=100)

    channels = []
    for i in range(0, num_channels):
        channel = await channel_layer.new_channel(prefix="channel%s" % i)
        await channel_layer.group_add("test-group", channel)
        channels.append(channel)

    async with async_timeout.timeout(timeout):
        await channel_layer.group_send("test-group", {"type": "message.1"})

    # Make sure we get the message all the channels
    async with async_timeout.timeout(timeout):
        for channel in channels:
            assert (await channel_layer.receive(channel))["type"] == "message.1"

    await channel_layer.flush()

@pytest.mark.asyncio
async def test_group_send_capacity(channel_layer):
    """
    Makes sure we dont send messages to groups that are over capacity
    """

    channel = await channel_layer.new_channel()
    await channel_layer.group_add("test-group", channel)

    await channel_layer.group_send("test-group", {"type": "message.1"})
    await channel_layer.group_send("test-group", {"type": "message.2"})
    await channel_layer.group_send("test-group", {"type": "message.3"})
    await channel_layer.group_send("test-group", {"type": "message.4"})

    # We should recieve the first 3 messages
    assert (await channel_layer.receive(channel))["type"] == "message.1"
    assert (await channel_layer.receive(channel))["type"] == "message.2"
    assert (await channel_layer.receive(channel))["type"] == "message.3"

    # Make sure we do NOT recieve message 4
    with pytest.raises(asyncio.TimeoutError):
        async with async_timeout.timeout(1):
            await channel_layer.receive(channel)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
##############################################################################
#
#    OpenERP, Open Source Management Solution
#    Copyright (C) 2004-today OpenERP SA (<http://www.openerp.com>)
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

from openerp.osv import osv, fields
from openerp.http import request

AVAILABLE_PRIORITIES = [
    ('0', 'Very Low'),
    ('1', 'Low'),
    ('2', 'Normal'),
    ('3', 'High'),
    ('4', 'Very High'),
]

class crm_tracking_medium(osv.Model):
    # OLD crm.case.channel
    _name = "crm.tracking.medium"
    _description = "Channels"
    _order = 'name'
    _columns = {
        'name': fields.char('Channel Name', required=True),
        'active': fields.boolean('Active'),
    }
    _defaults = {
        'active': lambda *a: 1,
    }

class crm_tracking_campaign(osv.Model):
    # OLD crm.case.resource.type
    _name = "crm.tracking.campaign"
    _description = "Campaign"
    _rec_name = "name"
    _columns = {
        'name': fields.char('Campaign Name', required=True, translate=True),
        'section_id': fields.many2one('crm.case.section', 'Sales Team'),
    }

class crm_tracking_source(osv.Model):
    _name = "crm.tracking.source"
    _description = "Source"
    _rec_name = "name"
    _columns = {
        'name': fields.char('Source Name', required=True, translate=True),
    }

class crm_tracking_mixin(osv.AbstractModel):
    """Mixin class for objects which can be tracked by marketing. """
    _name = 'crm.tracking.mixin'

    _columns = {
        'campaign_id': fields.many2one('crm.tracking.campaign', 'Campaign',  # old domain ="['|',('section_id','=',section_id),('section_id','=',False)]"
                                       help="This is a name that helps you keep track of your different campaign efforts Ex: Fall_Drive, Christmas_Special"),
        'source_id': fields.many2one('crm.tracking.source', 'Source', help="This is the source of the link Ex: Search Engine, another domain, or name of email list"),
        'medium_id': fields.many2one('crm.tracking.medium', 'Channel', help="This is the method of delivery. Ex: Postcard, Email, or Banner Ad"),
    }

    def tracking_fields(self):
        return [('utm_campaign', 'campaign_id'), ('utm_source', 'source_id'), ('utm_medium', 'medium_id')]

    def tracking_get_values(self, cr, uid, vals, context=None):
        for key, fname in self.tracking_fields():
            field = self._fields[fname]
            value = vals.get(fname) or (request and request.httprequest.cookies.get(key))  # params.get should be always in session by the dispatch from ir_http
            if field.type == 'many2one' and isinstance(value, basestring):
                # if we receive a string for a many2one, we search/create the id
                if value:
                    Model = self.pool[field.comodel_name]
                    rel_id = Model.name_search(cr, uid, value, context=context)
                    if rel_id:
                        rel_id = rel_id[0][0]
                    else:
                        rel_id = Model.create(cr, uid, {'name': value}, context=context)
                vals[fname] = rel_id
            else:
                # Here the code for others cases that many2one
                vals[fname] = value
        return vals

    def _get_default_track(self, cr, uid, field, context=None):
        return self.tracking_get_values(cr, uid, {}, context=context).get(field)

    _defaults = {
        'source_id': lambda self, cr, uid, ctx: self._get_default_track(cr, uid, 'source_id', ctx),
        'campaign_id': lambda self, cr, uid, ctx: self._get_default_track(cr, uid, 'campaign_id', ctx),
        'medium_id': lambda self, cr, uid, ctx: self._get_default_track(cr, uid, 'medium_id', ctx),
    }

class crm_case_stage(osv.osv):
    """ Model for case stages. This models the main stages of a document
        management flow. Main CRM objects (leads, opportunities, project
        issues, ...) will now use only stages, instead of state and stages.
        Stages are for example used to display the kanban view of records.
    """
    _name = "crm.case.stage"
    _description = "Stage of case"
    _rec_name = 'name'
    _order = "sequence"

    _columns = {
        'name': fields.char('Stage Name', required=True, translate=True),
        'sequence': fields.integer('Sequence', help="Used to order stages. Lower is better."),
        'probability': fields.float('Probability (%)', required=True, help="This percentage depicts the default/average probability of the Case for this stage to be a success"),
        'on_change': fields.boolean('Change Probability Automatically', help="Setting this stage will change the probability automatically on the opportunity."),
        'requirements': fields.text('Requirements'),
        'section_ids': fields.many2many('crm.case.section', 'section_stage_rel', 'stage_id', 'section_id', string='Sections',
                                        help="Link between stages and sales teams. When set, this limitate the current stage to the selected sales teams."),
        'case_default': fields.boolean('Default to New Sales Team',
                                       help="If you check this field, this stage will be proposed by default on each sales team. It will not assign this stage to existing teams."),
        'fold': fields.boolean('Folded in Kanban View',
                               help='This stage is folded in the kanban view when'
                               'there are no records in that stage to display.'),
        'type': fields.selection([('lead', 'Lead'), ('opportunity', 'Opportunity'), ('both', 'Both')],
                                 string='Type', required=True,
                                 help="This field is used to distinguish stages related to Leads from stages related to Opportunities, or to specify stages available for both types."),
    }

    _defaults = {
        'sequence': 1,
        'probability': 0.0,
        'on_change': True,
        'fold': False,
        'type': 'both',
        'case_default': True,
    }

class crm_case_categ(osv.osv):
    """ Category of Case """
    _name = "crm.case.categ"
    _description = "Category of Case"
    _columns = {
        'name': fields.char('Name', required=True, translate=True),
        'section_id': fields.many2one('crm.case.section', 'Sales Team'),
        'object_id': fields.many2one('ir.model', 'Object Name'),
    }

    def _find_object_id(self, cr, uid, context=None):
        """Finds id for case object"""
        context = context or {}
        object_id = context.get('object_id', False)
        ids = self.pool.get('ir.model').search(cr, uid, ['|', ('id', '=', object_id), ('model', '=', context.get('object_name', False))])
        return ids and ids[0] or False
    _defaults = {
        'object_id': _find_object_id
    }

class crm_payment_mode(osv.osv):
    """ Payment Mode for Fund """
    _name = "crm.payment.mode"
    _description = "CRM Payment Mode"
    _columns = {
        'name': fields.char('Name', required=True),
        'section_id': fields.many2one('crm.case.section', 'Sales Team'),
    }

# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
<commit_msg>[FIX] crm: set the oldname of field crm.lead.medium_id<commit_after># -*- coding: utf-8 -*-
##############################################################################
#
#    OpenERP, Open Source Management Solution
#    Copyright (C) 2004-today OpenERP SA (<http://www.openerp.com>)
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

from openerp.osv import osv, fields
from openerp.http import request

AVAILABLE_PRIORITIES = [
    ('0', 'Very Low'),
    ('1', 'Low'),
    ('2', 'Normal'),
    ('3', 'High'),
    ('4', 'Very High'),
]

class crm_tracking_medium(osv.Model):
    # OLD crm.case.channel
    _name = "crm.tracking.medium"
    _description = "Channels"
    _order = 'name'
    _columns = {
        'name': fields.char('Channel Name', required=True),
        'active': fields.boolean('Active'),
    }
    _defaults = {
        'active': lambda *a: 1,
    }

class crm_tracking_campaign(osv.Model):
    # OLD crm.case.resource.type
    _name = "crm.tracking.campaign"
    _description = "Campaign"
    _rec_name = "name"
    _columns = {
        'name': fields.char('Campaign Name', required=True, translate=True),
        'section_id': fields.many2one('crm.case.section', 'Sales Team'),
    }

class crm_tracking_source(osv.Model):
    _name = "crm.tracking.source"
    _description = "Source"
    _rec_name = "name"
    _columns = {
        'name': fields.char('Source Name', required=True, translate=True),
    }

class crm_tracking_mixin(osv.AbstractModel):
    """Mixin class for objects which can be tracked by marketing. """
    _name = 'crm.tracking.mixin'

    _columns = {
        'campaign_id': fields.many2one('crm.tracking.campaign', 'Campaign',  # old domain ="['|',('section_id','=',section_id),('section_id','=',False)]"
                                       help="This is a name that helps you keep track of your different campaign efforts Ex: Fall_Drive, Christmas_Special"),
        'source_id': fields.many2one('crm.tracking.source', 'Source', help="This is the source of the link Ex: Search Engine, another domain, or name of email list"),
        'medium_id': fields.many2one('crm.tracking.medium', 'Channel', help="This is the method of delivery. Ex: Postcard, Email, or Banner Ad", oldname='channel_id'),
    }

    def tracking_fields(self):
        return [('utm_campaign', 'campaign_id'), ('utm_source', 'source_id'), ('utm_medium', 'medium_id')]

    def tracking_get_values(self, cr, uid, vals, context=None):
        for key, fname in self.tracking_fields():
            field = self._fields[fname]
            value = vals.get(fname) or (request and request.httprequest.cookies.get(key))  # params.get should be always in session by the dispatch from ir_http
            if field.type == 'many2one' and isinstance(value, basestring):
                # if we receive a string for a many2one, we search/create the id
                if value:
                    Model = self.pool[field.comodel_name]
                    rel_id = Model.name_search(cr, uid, value, context=context)
                    if rel_id:
                        rel_id = rel_id[0][0]
                    else:
                        rel_id = Model.create(cr, uid, {'name': value}, context=context)
                vals[fname] = rel_id
            else:
                # Here the code for others cases that many2one
                vals[fname] = value
        return vals

    def _get_default_track(self, cr, uid, field, context=None):
        return self.tracking_get_values(cr, uid, {}, context=context).get(field)

    _defaults = {
        'source_id': lambda self, cr, uid, ctx: self._get_default_track(cr, uid, 'source_id', ctx),
        'campaign_id': lambda self, cr, uid, ctx: self._get_default_track(cr, uid, 'campaign_id', ctx),
        'medium_id': lambda self, cr, uid, ctx: self._get_default_track(cr, uid, 'medium_id', ctx),
    }

class crm_case_stage(osv.osv):
    """ Model for case stages. This models the main stages of a document
        management flow. Main CRM objects (leads, opportunities, project
        issues, ...) will now use only stages, instead of state and stages.
        Stages are for example used to display the kanban view of records.
    """
    _name = "crm.case.stage"
    _description = "Stage of case"
    _rec_name = 'name'
    _order = "sequence"

    _columns = {
        'name': fields.char('Stage Name', required=True, translate=True),
        'sequence': fields.integer('Sequence', help="Used to order stages. Lower is better."),
        'probability': fields.float('Probability (%)', required=True, help="This percentage depicts the default/average probability of the Case for this stage to be a success"),
        'on_change': fields.boolean('Change Probability Automatically', help="Setting this stage will change the probability automatically on the opportunity."),
        'requirements': fields.text('Requirements'),
        'section_ids': fields.many2many('crm.case.section', 'section_stage_rel', 'stage_id', 'section_id', string='Sections',
                                        help="Link between stages and sales teams. When set, this limitate the current stage to the selected sales teams."),
        'case_default': fields.boolean('Default to New Sales Team',
                                       help="If you check this field, this stage will be proposed by default on each sales team. It will not assign this stage to existing teams."),
        'fold': fields.boolean('Folded in Kanban View',
                               help='This stage is folded in the kanban view when'
                               'there are no records in that stage to display.'),
        'type': fields.selection([('lead', 'Lead'), ('opportunity', 'Opportunity'), ('both', 'Both')],
                                 string='Type', required=True,
                                 help="This field is used to distinguish stages related to Leads from stages related to Opportunities, or to specify stages available for both types."),
    }

    _defaults = {
        'sequence': 1,
        'probability': 0.0,
        'on_change': True,
        'fold': False,
        'type': 'both',
        'case_default': True,
    }

class crm_case_categ(osv.osv):
    """ Category of Case """
    _name = "crm.case.categ"
    _description = "Category of Case"
    _columns = {
        'name': fields.char('Name', required=True, translate=True),
        'section_id': fields.many2one('crm.case.section', 'Sales Team'),
        'object_id': fields.many2one('ir.model', 'Object Name'),
    }

    def _find_object_id(self, cr, uid, context=None):
        """Finds id for case object"""
        context = context or {}
        object_id = context.get('object_id', False)
        ids = self.pool.get('ir.model').search(cr, uid, ['|', ('id', '=', object_id), ('model', '=', context.get('object_name', False))])
        return ids and ids[0] or False
    _defaults = {
        'object_id': _find_object_id
    }

class crm_payment_mode(osv.osv):
    """ Payment Mode for Fund """
    _name = "crm.payment.mode"
    _description = "CRM Payment Mode"
    _columns = {
        'name': fields.char('Name', required=True),
        'section_id': fields.many2one('crm.case.section', 'Sales Team'),
    }

# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
<|endoftext|>


<commit_before>import sys
sys.path.append('..')
import disaggregator as da
import unittest
import pandas as pd
import numpy as np

class ApplianceInstanceTestCase(unittest.TestCase):

    def setUp(self):
        indices = [pd.date_range('1/1/2013', periods=96, freq='15T'),
                   pd.date_range('1/2/2013', periods=96, freq='15T')]
        data = [np.zeros(96),np.zeros(96)]
        series = [pd.Series(d, index=i) for d,i in zip(data,indices)]
        self.traces = [da.ApplianceTrace(s,{}) for s in series]
        self.normal_instance = da.ApplianceInstance(self.traces)

    def test_get_traces(self):
        self.assertIsNotNone(self.normal_instance.get_traces(),
                      'instance should have traces')

if __name__ == "__main__":
    unittest.main()
<commit_msg>update tests for appliance instances<commit_after>import sys
sys.path.append('..')
import disaggregator as da
import unittest
import pandas as pd
import numpy as np

class ApplianceInstanceTestCase(unittest.TestCase):

    def setUp(self):
        indices = [pd.date_range('1/1/2013', periods=96, freq='15T'),
                   pd.date_range('1/2/2013', periods=96, freq='15T')]
        data = [np.zeros(96),np.zeros(96)]
        series = [pd.Series(d, index=i) for d,i in zip(data,indices)]
        self.traces = [da.ApplianceTrace(s,{}) for s in series]
        self.normal_instance = da.ApplianceInstance(self.traces)

    def test_get_traces(self):
        self.assertIsNotNone(self.normal_instance.get_traces(),
                      'instance should have traces')

    def test_traces_in_order(self):
        traces = self.normal_instance.get_traces()
        self.assertLess(traces[0].series.index[0],
                        traces[1].series.index[0],
                        'traces should be in order')

    def test_traces_should_not_overlap(self):
        traces = self.normal_instance.get_traces()
        times = set()
        for trace in traces:
            for time in trace.series.index:
                self.assertNotIn(time, times,
                                 'traces should not overlap')
                times.add(time)

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


<commit_before>from primitiv import Optimizer, Parameter, Device, Graph, Shape
from primitiv import initializers as I
from primitiv import devices as D
from primitiv import operators as F
from primitiv import tensor_operators as tF
from primitiv._parameter import _ParameterStatistics

import unittest

import numpy as np

class ParameterTest(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        pass

    @classmethod
    def tearDownClass(cls):
        pass

    def setUp(self):
        self.dev = D.Naive()
        Device.set_default(self.dev)
        self.p = Parameter([8], I.Constant(0))
        self.p.value.reset_by_vector([1, 2, 3, 4, 5, 6, 7, 8])

    def tearDown(self):
         pass

    def test_parameter_stats(self):
        self.p.add_stats("stat1", Shape([2, 3]))
        self.p.add_stats("stat2", Shape([2, 4]))
        st1 = self.p.stats["stat1"]
        st1.reset(0)
        self.assertTrue((st1.to_ndarrays()[0] == np.zeros([2, 3])).all())
        self.p.stats["stat1"] = tF.input(np.ones([2, 3]))
        self.assertTrue((st1.to_ndarrays()[0] == np.ones([2, 3])).all())
        self.assertIn("stat1", self.p.stats)
        self.assertIn("stat2", self.p.stats)
        self.assertNotIn("stat3", self.p.stats)
        with self.assertRaises(NotImplementedError):
            del self.p.stats["stat1"]
        with self.assertRaises(AttributeError):
            self.p.stats = _ParameterStatistics(self.p)

    def test_parameter_value(self):
        self.assertTrue((self.p.value.to_ndarrays() == np.array([1, 2, 3, 4, 5, 6, 7, 8])).all())
        val = self.p.value
        self.p.value += tF.input(np.ones([8]))
        self.assertTrue((val.to_ndarrays()[0] == np.array([2, 3, 4, 5, 6, 7, 8, 9])).all())
        with self.assertRaises(NotImplementedError):
            del self.p.value

    def test_parameter_gradient(self):
        self.p.reset_gradient()
        self.assertTrue((self.p.gradient.to_ndarrays() == np.zeros([8])).all())
        grad = self.p.gradient
        self.p.gradient += tF.input(np.ones([8]))
        self.assertTrue((grad.to_ndarrays()[0] == np.ones([8])).all())
        with self.assertRaises(NotImplementedError):
            del self.p.gradient
<commit_msg>Update a test<commit_after>from primitiv import Optimizer, Parameter, Device, Graph, Shape
from primitiv import initializers as I
from primitiv import devices as D
from primitiv import operators as F
from primitiv import tensor_operators as tF
from primitiv._parameter import ParameterStatistics

import unittest

import numpy as np

class ParameterTest(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        pass

    @classmethod
    def tearDownClass(cls):
        pass

    def setUp(self):
        self.dev = D.Naive()
        Device.set_default(self.dev)
        self.p = Parameter([8], I.Constant(0))
        self.p.value.reset_by_vector([1, 2, 3, 4, 5, 6, 7, 8])

    def tearDown(self):
         pass

    def test_parameter_stats(self):
        self.p.add_stats("stat1", Shape([2, 3]))
        self.p.add_stats("stat2", Shape([2, 4]))
        st1 = self.p.stats["stat1"]
        st1.reset(0)
        self.assertTrue((st1.to_ndarrays()[0] == np.zeros([2, 3])).all())
        self.p.stats["stat1"] = tF.input(np.ones([2, 3]))
        self.assertTrue((st1.to_ndarrays()[0] == np.ones([2, 3])).all())
        self.assertIn("stat1", self.p.stats)
        self.assertIn("stat2", self.p.stats)
        self.assertNotIn("stat3", self.p.stats)
        with self.assertRaises(NotImplementedError):
            del self.p.stats["stat1"]
        with self.assertRaises(AttributeError):
            self.p.stats = ParameterStatistics(self.p)

    def test_parameter_value(self):
        self.assertTrue((self.p.value.to_ndarrays() == np.array([1, 2, 3, 4, 5, 6, 7, 8])).all())
        val = self.p.value
        self.p.value += tF.input(np.ones([8]))
        self.assertTrue((val.to_ndarrays()[0] == np.array([2, 3, 4, 5, 6, 7, 8, 9])).all())
        with self.assertRaises(NotImplementedError):
            del self.p.value

    def test_parameter_gradient(self):
        self.p.reset_gradient()
        self.assertTrue((self.p.gradient.to_ndarrays() == np.zeros([8])).all())
        grad = self.p.gradient
        self.p.gradient += tF.input(np.ones([8]))
        self.assertTrue((grad.to_ndarrays()[0] == np.ones([8])).all())
        with self.assertRaises(NotImplementedError):
            del self.p.gradient
<|endoftext|>


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

# kb_builder builts keyboard plate and case CAD files using JSON input.
#
# Copyright (C) 2015  Will Stevens (swill)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import lib.builder as builder
import hashlib
import json
import logging
import pprint
import time
import tornado.gen
import tornado.httpclient
import tornado.ioloop
import tornado.options
import tornado.web

from config import config

builder_timeout = 7200

class IndexHandler(tornado.web.RequestHandler):
    def get(self):
        self.render('index.html')

    @tornado.gen.coroutine
    def post(self):
        data = json.loads(self.request.body)
        data_hash = hashlib.sha1(json.dumps(data, sort_keys=True)).hexdigest()
        cad = {}
        build_start = time.time()
        logging.info("Processing: %s" % (data_hash))
        cad = builder.build(data_hash, data, config, logging.getLogger())
        logging.info("Finished: %s" % (data_hash))
        logging.info("Processing took: {0:.2f} seconds".format(time.time()-build_start))
        self.write(cad)

def make_app():
    settings = {
        'template_path':'templates',
        'static_path':config['app']['static'],
        'debug':config['app']['debug']
    }
    return tornado.web.Application([
        (r"/", IndexHandler)
    ], **settings)

def main():
    tornado.options.options.log_file_prefix = config['app']['log']
    tornado.options.parse_command_line()
    logging.info("Started the kb_builder...")
    app = make_app()
    app.listen(config['app']['port'])
    tornado.ioloop.IOLoop.current().start()

if __name__ == '__main__':
    main()
<commit_msg>troubleshooting<commit_after>#!/usr/bin/env python

# kb_builder builts keyboard plate and case CAD files using JSON input.
#
# Copyright (C) 2015  Will Stevens (swill)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import lib.builder as builder
import hashlib
import json
import logging
import pprint
import time
import tornado.gen
import tornado.httpclient
import tornado.ioloop
import tornado.options
import tornado.web

from config import config

builder_timeout = 7200

class IndexHandler(tornado.web.RequestHandler):
    def get(self):
        self.render('index.html')

    @tornado.gen.coroutine
    def post(self):
        pprint.pprint(self.request.body)
        data = json.loads(self.request.body)
        pprint.pprint(data)
        data_hash = hashlib.sha1(json.dumps(data, sort_keys=True)).hexdigest()
        cad = {}
        build_start = time.time()
        logging.info("Processing: %s" % (data_hash))
        cad = builder.build(data_hash, data, config, logging.getLogger())
        logging.info("Finished: %s" % (data_hash))
        logging.info("Processing took: {0:.2f} seconds".format(time.time()-build_start))
        self.write(cad)

def make_app():
    settings = {
        'template_path':'templates',
        'static_path':config['app']['static'],
        'debug':config['app']['debug']
    }
    return tornado.web.Application([
        (r"/", IndexHandler)
    ], **settings)

def main():
    tornado.options.options.log_file_prefix = config['app']['log']
    tornado.options.parse_command_line()
    logging.info("Started the kb_builder...")
    app = make_app()
    app.listen(config['app']['port'])
    tornado.ioloop.IOLoop.current().start()

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


<commit_before># Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.

# Helper class for loading large fixture data
from __future__ import with_statement

import os

from libcloud.utils.py3 import u

FIXTURES_ROOT = {
    'compute': 'compute/fixtures',
    'storage': 'storage/fixtures',
    'loadbalancer': 'loadbalancer/fixtures',
    'dns': 'dns/fixtures',
    'openstack': 'compute/fixtures/openstack',
}

class FileFixtures(object):
    def __init__(self, fixtures_type, sub_dir=''):
        script_dir = os.path.abspath(os.path.split(__file__)[0])
        self.root = os.path.join(script_dir, FIXTURES_ROOT[fixtures_type],
                                 sub_dir)

    def load(self, file):
        path = os.path.join(self.root, file)
        if os.path.exists(path):
            with open(path, 'r') as fh:
                content = fh.read()
            return u(content)
        else:
            raise IOError(path)

class ComputeFileFixtures(FileFixtures):
    def __init__(self, sub_dir=''):
        super(ComputeFileFixtures, self).__init__(fixtures_type='compute',
                                                  sub_dir=sub_dir)

class StorageFileFixtures(FileFixtures):
    def __init__(self, sub_dir=''):
        super(StorageFileFixtures, self).__init__(fixtures_type='storage',
                                                  sub_dir=sub_dir)

class LoadBalancerFileFixtures(FileFixtures):
    def __init__(self, sub_dir=''):
        super(LoadBalancerFileFixtures, self).__init__(fixtures_type='loadbalancer',
                                                  sub_dir=sub_dir)

class DNSFileFixtures(FileFixtures):
    def __init__(self, sub_dir=''):
        super(DNSFileFixtures, self).__init__(fixtures_type='dns',
                                              sub_dir=sub_dir)

class OpenStackFixtures(FileFixtures):
  def __init__(self, sub_dir=''):
      super(OpenStackFixtures, self).__init__(fixtures_type='openstack',
                                                sub_dir=sub_dir)
<commit_msg>Explicitly pass encoding to file.open when using Python 3. Otherwise tests might fail in some circumstances when locate is not set.<commit_after># Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.

# Helper class for loading large fixture data
from __future__ import with_statement

import os

from libcloud.utils.py3 import PY3
from libcloud.utils.py3 import u

FIXTURES_ROOT = {
    'compute': 'compute/fixtures',
    'storage': 'storage/fixtures',
    'loadbalancer': 'loadbalancer/fixtures',
    'dns': 'dns/fixtures',
    'openstack': 'compute/fixtures/openstack',
}

class FileFixtures(object):
    def __init__(self, fixtures_type, sub_dir=''):
        script_dir = os.path.abspath(os.path.split(__file__)[0])
        self.root = os.path.join(script_dir, FIXTURES_ROOT[fixtures_type],
                                 sub_dir)

    def load(self, file):
        path = os.path.join(self.root, file)
        if os.path.exists(path):
            if PY3:
                kwargs = {'encoding': 'utf-8'}
            else:
                kwargs = {}

            with open(path, 'r', **kwargs) as fh:
                content = fh.read()
            return u(content)
        else:
            raise IOError(path)

class ComputeFileFixtures(FileFixtures):
    def __init__(self, sub_dir=''):
        super(ComputeFileFixtures, self).__init__(fixtures_type='compute',
                                                  sub_dir=sub_dir)

class StorageFileFixtures(FileFixtures):
    def __init__(self, sub_dir=''):
        super(StorageFileFixtures, self).__init__(fixtures_type='storage',
                                                  sub_dir=sub_dir)

class LoadBalancerFileFixtures(FileFixtures):
    def __init__(self, sub_dir=''):
        super(LoadBalancerFileFixtures, self).__init__(fixtures_type='loadbalancer',
                                                  sub_dir=sub_dir)

class DNSFileFixtures(FileFixtures):
    def __init__(self, sub_dir=''):
        super(DNSFileFixtures, self).__init__(fixtures_type='dns',
                                              sub_dir=sub_dir)

class OpenStackFixtures(FileFixtures):
  def __init__(self, sub_dir=''):
      super(OpenStackFixtures, self).__init__(fixtures_type='openstack',
                                                sub_dir=sub_dir)
<|endoftext|>


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

import unittest
import intercoop
from . import crypto
import os
from yamlns import namespace as ns

class KeyRingMock(object):
    def __init__(self, keys):
        self.keys = keys
    def get(self, key):
        return self.keys[key]

class IntercoopMessage_Test(unittest.TestCase):

    yaml=u"""\
intercoopVersion: '1.0'
originpeer: testpeer
origincode: 666
name: Perico de los Palotes
address: Percebe, 13
city: Villarriba del Alcornoque
state: Albacete
postalcode: '01001'
country: ES
"""
    def setUp(self):
        self.maxDiff = None
        self.keyfile = 'testkey.pem'
        self.pubfile = 'testkey-public.pem'

        if not os.access(self.keyfile, os.F_OK):
            intercoop.generateKey(self.keyfile, self.pubfile)

        self.key = crypto.loadKey(self.keyfile)
        self.public = crypto.loadKey(self.pubfile)
        self.values = ns.loads(self.yaml)
        self.encodedPayload1 = crypto.encode(self.yaml)
        self.signedPayload1 = crypto.sign(self.key, self.yaml)
        self.keyring = KeyRingMock(dict(
            testpeer=self.public,
            ))

    def test_produce(self):
        g = intercoop.Generator(ownKeyPair = self.key)
        message = g.produce(self.values)
        self.assertEqual(
            dict(ns.loads(message)),
            dict(
                intercoopVersion = '1.0',
                signature = self.signedPayload1,
                payload = self.encodedPayload1,
            ))

    def setupMessage(self,
            values=None,
            yaml=None,
            signedyaml=None,
            payload=None,
            removedFromMessage=[],
            version=None,
            ):
        values = ns(values or self.values)
        yaml = yaml or values.dump()
        messageValues =  ns(
            intercoopVersion = version or intercoop.protocolVersion,
            signature = crypto.sign(self.key, signedyaml or yaml),
            payload = payload or crypto.encode(yaml),
            )

        for field in removedFromMessage:
            del messageValues[field]
        return messageValues.dump()

    def assertParseRaises(self, parser, message, exception, errorMessage):
        with self.assertRaises(exception) as ctx:
            parser.parse(message)
        self.assertEqual(ctx.exception.args[0], errorMessage)

    def test_parse(self):
        message = self.setupMessage()

        g = intercoop.Parser(keyring = self.keyring)
        values = g.parse(message)
        self.assertEqual(
            dict(self.values),
            dict(values),
            )

    def test_parse_invalidSignature(self):
        g = intercoop.Parser(keyring = self.keyring)
        message = self.setupMessage(
            signedyaml = self.yaml + "\n",
            )
        self.assertParseRaises(g, message,
            intercoop.BadSignature,
            "Signature verification failed, untrusted content")

    def test_parse_unrecognizedPeer(self):
        g = intercoop.Parser(keyring = self.keyring)
        message = self.setupMessage(
            values=ns(self.values, originpeer='badpeer')
            )
        self.assertParseRaises(g,message,
            intercoop.BadPeer,
            "The entity 'badpeer' is not a recognized one")

    def test_parse_missingPeerField(self):
        g = intercoop.Parser(keyring = self.keyring)
        values= ns(self.values)
        del values.originpeer
        message = self.setupMessage(values=values)
        self.assertParseRaises(g, message,
            intercoop.MissingField,
            "Required field 'originpeer' missing on the payload")

    def test_parse_badYaml(self):
        g = intercoop.Parser(keyring = self.keyring)
        message = self.setupMessage(yaml='\t')
        self.assertParseRaises(g, message,
            intercoop.BadFormat,
            "Error while parsing message as YAML:\n"
            "while scanning for the next token\n"
            "found character '\\t' that cannot start any token\n"
            "  in \"<file>\", line 1, column 1"
            )

    def test_parse_missingPayload(self):
        g = intercoop.Parser(keyring = self.keyring)
        message = self.setupMessage(
            removedFromMessage=['payload']
            )
        self.assertParseRaises(g, message,
            intercoop.BadMessage,
            "Malformed message: missing payload"
            )

    def test_parse_missingSignature(self):
        g = intercoop.Parser(keyring = self.keyring)
        message = self.setupMessage(
            removedFromMessage=['signature']
            )
        self.assertParseRaises(g, message,
            intercoop.BadMessage,
            "Malformed message: missing signature"
            )

    def test_parse_wrongVersion(self):
        g = intercoop.Parser(keyring = self.keyring)
        message = self.setupMessage(
            version='0.0',
            )
        self.assertParseRaises(g, message,
            intercoop.WrongVersion,
            "Wrong protocol version, expected 1.0, received 0.0"
            )

    def test_parse_missingVersion(self):
        g = intercoop.Parser(keyring = self.keyring)
        message = self.setupMessage(
            removedFromMessage=['intercoopVersion']
            )
        self.assertParseRaises(g, message,
            intercoop.BadMessage,
            "Malformed message: missing intercoopVersion"
            )

    def test_parse_badContainerYaml(self):
        g = intercoop.Parser(keyring = self.keyring)
        self.assertParseRaises(g, '\t',
            intercoop.BadMessage,
            "Malformed message: Bad message YAML format\n"
            "while scanning for the next token\n"
            "found character '\\t' that cannot start any token\n"
            "  in \"<file>\", line 1, column 1"
            )

    def test_parse_badContainerUnicode(self):
        g = intercoop.Parser(keyring = self.keyring)
        message = self.setupMessage(
            payload = "SAFASLDFKJASLK==",
            )
        self.assertParseRaises(g, message,
            intercoop.BadMessage,
            'Malformed message: Payload is not base64 coded UTF8'
            )

    def test_parse_badPayloadBase64(self):
        g = intercoop.Parser(keyring = self.keyring)
        message = self.setupMessage(
            payload = "SO",
            )
        self.assertParseRaises(g, message,
            intercoop.BadMessage,
            'Malformed message: Payload is invalid Base64: Incorrect padding'
            )

unittest.TestCase.__str__ = unittest.TestCase.id

if __name__ == "__main__":
    import sys
    unittest.main()

# vim: ts=4 sw=4 et
<commit_msg>take crypto symbols from crypto<commit_after># -*- encoding: utf-8 -*-

import unittest
import intercoop
from . import crypto
import os
from yamlns import namespace as ns

class KeyRingMock(object):
    def __init__(self, keys):
        self.keys = keys
    def get(self, key):
        return self.keys[key]

class IntercoopMessage_Test(unittest.TestCase):

    yaml=u"""\
intercoopVersion: '1.0'
originpeer: testpeer
origincode: 666
name: Perico de los Palotes
address: Percebe, 13
city: Villarriba del Alcornoque
state: Albacete
postalcode: '01001'
country: ES
"""
    def setUp(self):
        self.maxDiff = None
        self.keyfile = 'testkey.pem'
        self.pubfile = 'testkey-public.pem'

        if not os.access(self.keyfile, os.F_OK):
            crypto.generateKey(self.keyfile, self.pubfile)

        self.key = crypto.loadKey(self.keyfile)
        self.public = crypto.loadKey(self.pubfile)
        self.values = ns.loads(self.yaml)
        self.encodedPayload1 = crypto.encode(self.yaml)
        self.signedPayload1 = crypto.sign(self.key, self.yaml)
        self.keyring = KeyRingMock(dict(
            testpeer=self.public,
            ))

    def test_produce(self):
        g = intercoop.Generator(ownKeyPair = self.key)
        message = g.produce(self.values)
        self.assertEqual(
            dict(ns.loads(message)),
            dict(
                intercoopVersion = '1.0',
                signature = self.signedPayload1,
                payload = self.encodedPayload1,
            ))

    def setupMessage(self,
            values=None,
            yaml=None,
            signedyaml=None,
            payload=None,
            removedFromMessage=[],
            version=None,
            ):
        values = ns(values or self.values)
        yaml = yaml or values.dump()
        messageValues =  ns(
            intercoopVersion = version or intercoop.protocolVersion,
            signature = crypto.sign(self.key, signedyaml or yaml),
            payload = payload or crypto.encode(yaml),
            )

        for field in removedFromMessage:
            del messageValues[field]
        return messageValues.dump()

    def assertParseRaises(self, parser, message, exception, errorMessage):
        with self.assertRaises(exception) as ctx:
            parser.parse(message)
        self.assertEqual(ctx.exception.args[0], errorMessage)

    def test_parse(self):
        message = self.setupMessage()

        g = intercoop.Parser(keyring = self.keyring)
        values = g.parse(message)
        self.assertEqual(
            dict(self.values),
            dict(values),
            )

    def test_parse_invalidSignature(self):
        g = intercoop.Parser(keyring = self.keyring)
        message = self.setupMessage(
            signedyaml = self.yaml + "\n",
            )
        self.assertParseRaises(g, message,
            intercoop.BadSignature,
            "Signature verification failed, untrusted content")

    def test_parse_unrecognizedPeer(self):
        g = intercoop.Parser(keyring = self.keyring)
        message = self.setupMessage(
            values=ns(self.values, originpeer='badpeer')
            )
        self.assertParseRaises(g,message,
            intercoop.BadPeer,
            "The entity 'badpeer' is not a recognized one")

    def test_parse_missingPeerField(self):
        g = intercoop.Parser(keyring = self.keyring)
        values= ns(self.values)
        del values.originpeer
        message = self.setupMessage(values=values)
        self.assertParseRaises(g, message,
            intercoop.MissingField,
            "Required field 'originpeer' missing on the payload")

    def test_parse_badYaml(self):
        g = intercoop.Parser(keyring = self.keyring)
        message = self.setupMessage(yaml='\t')
        self.assertParseRaises(g, message,
            intercoop.BadFormat,
            "Error while parsing message as YAML:\n"
            "while scanning for the next token\n"
            "found character '\\t' that cannot start any token\n"
            "  in \"<file>\", line 1, column 1"
            )

    def test_parse_missingPayload(self):
        g = intercoop.Parser(keyring = self.keyring)
        message = self.setupMessage(
            removedFromMessage=['payload']
            )
        self.assertParseRaises(g, message,
            intercoop.BadMessage,
            "Malformed message: missing payload"
            )

    def test_parse_missingSignature(self):
        g = intercoop.Parser(keyring = self.keyring)
        message = self.setupMessage(
            removedFromMessage=['signature']
            )
        self.assertParseRaises(g, message,
            intercoop.BadMessage,
            "Malformed message: missing signature"
            )

    def test_parse_wrongVersion(self):
        g = intercoop.Parser(keyring = self.keyring)
        message = self.setupMessage(
            version='0.0',
            )
        self.assertParseRaises(g, message,
            intercoop.WrongVersion,
            "Wrong protocol version, expected 1.0, received 0.0"
            )

    def test_parse_missingVersion(self):
        g = intercoop.Parser(keyring = self.keyring)
        message = self.setupMessage(
            removedFromMessage=['intercoopVersion']
            )
        self.assertParseRaises(g, message,
            intercoop.BadMessage,
            "Malformed message: missing intercoopVersion"
            )

    def test_parse_badContainerYaml(self):
        g = intercoop.Parser(keyring = self.keyring)
        self.assertParseRaises(g, '\t',
            intercoop.BadMessage,
            "Malformed message: Bad message YAML format\n"
            "while scanning for the next token\n"
            "found character '\\t' that cannot start any token\n"
            "  in \"<file>\", line 1, column 1"
            )

    def test_parse_badContainerUnicode(self):
        g = intercoop.Parser(keyring = self.keyring)
        message = self.setupMessage(
            payload = "SAFASLDFKJASLK==",
            )
        self.assertParseRaises(g, message,
            intercoop.BadMessage,
            'Malformed message: Payload is not base64 coded UTF8'
            )

    def test_parse_badPayloadBase64(self):
        g = intercoop.Parser(keyring = self.keyring)
        message = self.setupMessage(
            payload = "SO",
            )
        self.assertParseRaises(g, message,
            intercoop.BadMessage,
            'Malformed message: Payload is invalid Base64: Incorrect padding'
            )

unittest.TestCase.__str__ = unittest.TestCase.id

if __name__ == "__main__":
    import sys
    unittest.main()

# vim: ts=4 sw=4 et
<|endoftext|>


<commit_before>from pathed import *
import os
import shutil
import sys

class Shell(Pathed):
    """Base class for command line tests"""
    def execute(self,command,*p,**k):
        """Return the fd of a command; can get output (stdout/err) and exitcode"""
        # We might be passed a file descriptor for some reason; if so, just return it
        if type(command) is file:
            return command
        # Redirect stderr to stdout
        # This is a bit of a hack, but I've not found a better way
        fd=os.popen(command+' 2>&1',*p,**k)
        return fd
    def output_and_exitcode(self,*p,**k):
        fd=self.execute(*p,**k)
        output = fd.read().strip()
        exitcode = fd.close()
        if k.pop('emit',False):
            print output
        return (output,exitcode)
    def exitcode(self,*p,**k):
        """Execute a command and return its exit code
        ...without printing its output/errors
        """
        ret = self.output_and_exitcode(*p,**k)
        return ret[1]

    def assertFailure(self,*p,**k):
        output,exitcode = self.output_and_exitcode(*p,**k)
        assert (exitcode), output
    def assertSuccess(self,*p,**k):
        output,exitcode = self.output_and_exitcode(*p,**k)
        #self.assert_(not exitcode, output)
        assert (not exitcode), output
<commit_msg>applied patch for shell test by Toshio Kuramoti<commit_after>from pathed import *
import os
import shutil
import sys

class Shell(Pathed):
    """Base class for command line tests"""
    def execute(self,command,*p,**k):
        """Return the fd of a command; can get output (stdout/err) and exitcode"""
        # We might be passed a file descriptor for some reason; if so, just return it
        if type(command) is file:
            return command
        # Redirect stderr to stdout
        # This is a bit of a hack, but I've not found a better way
        py_path = os.environ.get('PYTHONPATH', '')
        py_path_list = py_path.split(':')
        py_path_list.append(os.path.abspath('.'))
        os.environ['PYTHONPATH'] = ':'.join(py_path_list)
        fd=os.popen(command+' 2>&1',*p,**k)
        if py_path:
            py_path = os.environ['PYTHONPATH'] = py_path
        else:
            del os.environ['PYTHONPATH']
        return fd
    def output_and_exitcode(self,*p,**k):
        fd=self.execute(*p,**k)
        output = fd.read().strip()
        exitcode = fd.close()
        if k.pop('emit',False):
            print output
        return (output,exitcode)
    def exitcode(self,*p,**k):
        """Execute a command and return its exit code
        ...without printing its output/errors
        """
        ret = self.output_and_exitcode(*p,**k)
        return ret[1]

    def assertFailure(self,*p,**k):
        output,exitcode = self.output_and_exitcode(*p,**k)
        assert (exitcode), output
    def assertSuccess(self,*p,**k):
        output,exitcode = self.output_and_exitcode(*p,**k)
        #self.assert_(not exitcode, output)
        assert (not exitcode), output
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""
Display WiFi bit rate, quality, signal and SSID using iw.

Configuration parameters:
    bitrate_bad: Bad bit rate in Mbit/s (default 26)
    bitrate_degraded: Degraded bit rate in Mbit/s (default 53)
    blocks: a string, where each character represents quality level
        (default "_▁▂▃▄▅▆▇█")
    cache_timeout: Update interval in seconds (default 10)
    device: Wireless device name (default "wlan0")
    down_color: Output color when disconnected, possible values:
        "good", "degraded", "bad" (default "bad")
    format_down: Output when disconnected (default "W: down")
    format_up: See placeholders below
        (default "W: {bitrate} {signal_percent} {ssid}")
    round_bitrate: If true, bit rate is rounded to the nearest whole number
        (default True)
    signal_bad: Bad signal strength in percent (default 29)
    signal_degraded: Degraded signal strength in percent (default 49)
    use_sudo: Use sudo to run iw, make sure iw requires some root rights
        without a password by adding a sudoers entry.
        Example: "<username> ALL=(ALL) NOPASSWD: /usr/bin/iw dev wl* link"
        (default False)

Format placeholders:
    {bitrate} Display bit rate
    {device} Display device name
    {icon} Character representing the quality based on bitrate,
        as defined by the 'blocks'
    {ip} Display IP address
    {signal_dbm} Display signal in dBm
    {signal_percent} Display signal in percent
    {ssid} Display SSID

Color options:
    color_bad: Signal strength signal_bad or lower
    color_degraded: Signal strength signal_degraded or lower
    color_good: Signal strength above signal_degraded

Requires:
    iw: cli configuration utility for wireless devices
    ip: only for {ip}. may be part of iproute2: ip routing utilities

__Note: Some distributions eg Debian require `iw` to be run with privileges.
In this case you will need to use the `use_sudo` configuration parameter.__

@author Markus Weimar <mail@markusweimar.de>
@license BSD

SAMPLE OUTPUT
{'color': '#00FF00', 'full_text': u'W: 54.0 MBit/s 100% Chicken Remixed'}
"""
import re
import math
STRING_ERROR = "iw: command failed"

class Py3status:
    """
    """
    # available configuration parameters
    bitrate_bad = 26
    bitrate_degraded = 53
    blocks = u"_▁▂▃▄▅▆▇█"
    cache_timeout = 10
    device = 'wlan0'
    down_color = 'bad'
    format_down = 'W: down'
    format_up = 'W: {bitrate} {signal_percent} {ssid}'
    round_bitrate = True
    signal_bad = 29
    signal_degraded = 49
    use_sudo = False

    def post_config_hook(self):
        self._ssid = None
        self._max_bitrate = 0
        # Try and guess the wifi interface
        cmd = ['iw', 'dev']
        if self.use_sudo:
            cmd.insert(0, 'sudo')
        try:
            iw = self.py3.command_output(cmd)
            devices = re.findall('Interface\s*([^\s]+)', iw)
            if not devices or 'wlan0' in devices:
                self.device = 'wlan0'
            else:
                self.device = devices[0]
        except:
            pass

    def wifi(self):
        """
        Get WiFi status using iw.
        """
        self.signal_dbm_bad = self._percent_to_dbm(self.signal_bad)
        self.signal_dbm_degraded = self._percent_to_dbm(self.signal_degraded)
        cmd = ['iw', 'dev', self.device, 'link']
        if self.use_sudo:
            cmd.insert(0, 'sudo')
        try:
            iw = self.py3.command_output(cmd)
        except:
            return {'cache_until': self.py3.CACHE_FOREVER,
                    'color': self.py3.COLOR_ERROR or self.py3.COLOR_BAD,
                    'full_text': STRING_ERROR}
        # bitrate
        bitrate_out = re.search('tx bitrate: ([^\s]+) ([^\s]+)', iw)
        if bitrate_out:
            bitrate = float(bitrate_out.group(1))
            if self.round_bitrate:
                bitrate = round(bitrate)
            bitrate_unit = bitrate_out.group(2)
            if bitrate_unit == 'Gbit/s':
                bitrate *= 1000
        else:
            bitrate = None
            bitrate_unit = None

        # signal
        signal_out = re.search('signal: ([\-0-9]+)', iw)
        if signal_out:
            signal_dbm = int(signal_out.group(1))
            signal_percent = min(self._dbm_to_percent(signal_dbm), 100)
        else:
            signal_dbm = None
            signal_percent = None
        ssid_out = re.search('SSID: (.+)', iw)
        if ssid_out:
            ssid = ssid_out.group(1)
            # `iw` command would prints unicode SSID like `\xe8\x8b\x9f`
            # the the `ssid` here would be '\\xe8\\x8b\\x9f' (note the escape)
            # it needs to be decoded using 'unicode_escape', to '苟'
            ssid = ssid.encode('latin-1').decode('unicode_escape')
            ssid = ssid.encode('latin-1').decode('utf-8')
        else:
            ssid = None

        # check command
        if self.py3.format_contains(self.format_up, 'ip'):
            cmd = ['ip', 'addr', 'list', self.device]
            if self.use_sudo:
                cmd.insert(0, 'sudo')
            ip_info = self.py3.command_output(cmd)
            ip_match = re.search('inet\s+([0-9.]+)', ip_info)
            if ip_match:
                ip = ip_match.group(1)
            else:
                ip = None
        else:
            ip = ''

        # reset _max_bitrate if we have changed network
        if self._ssid != ssid:
            self._ssid = ssid
            self._max_bitrate = self.bitrate_degraded
        if bitrate:
            if bitrate > self._max_bitrate:
                self._max_bitrate = bitrate
            quality = int((bitrate / self._max_bitrate) * 100)
        else:
            quality = 0
        icon = self.blocks[int(math.ceil(quality / 100 * (len(self.blocks) - 1)))]

        if ssid is None:
            full_text = self.py3.safe_format(self.format_down)
            color = getattr(self.py3, 'COLOR_{}'.format(self.down_color.upper()))
        else:
            color = self.py3.COLOR_GOOD
            if bitrate:
                if bitrate <= self.bitrate_bad:
                    color = self.py3.COLOR_BAD
                elif bitrate <= self.bitrate_degraded:
                    color = self.py3.COLOR_DEGRADED
                bitrate = '{} {}'.format(bitrate, bitrate_unit)
            else:
                bitrate = '? MBit/s'
            if signal_dbm:
                if signal_dbm <= self.signal_dbm_bad:
                    color = self.py3.COLOR_BAD
                elif signal_dbm <= self.signal_dbm_degraded:
                    color = self.py3.COLOR_DEGRADED
                signal_dbm = '{} dBm'.format(signal_dbm)
                signal_percent = '{}%'.format(signal_percent)
            else:
                signal_dbm = '? dBm'
                signal_percent = '?%'

            full_text = self.py3.safe_format(
                self.format_up,
                dict(
                    bitrate=bitrate,
                    signal_dbm=signal_dbm,
                    signal_percent=signal_percent,
                    ip=ip,
                    device=self.device,
                    icon=icon,
                    ssid=ssid,
                ))

        return {'cache_until': self.py3.time_in(self.cache_timeout),
                'color': color,
                'full_text': full_text}

    def _dbm_to_percent(self, dbm):
        return 2 * (dbm + 100)

    def _percent_to_dbm(self, percent):
        return (percent / 2) - 100

if __name__ == "__main__":
    """
    Run module in test mode.
    """
    from py3status.module_test import module_test
    module_test(Py3status)
<commit_msg>wifi: add format<commit_after># -*- coding: utf-8 -*-
"""
Display WiFi bit rate, quality, signal and SSID using iw.

Configuration parameters:
    bitrate_bad: Bad bit rate in Mbit/s (default 26)
    bitrate_degraded: Degraded bit rate in Mbit/s (default 53)
    blocks: a string, where each character represents quality level
        (default "_▁▂▃▄▅▆▇█")
    cache_timeout: Update interval in seconds (default 10)
    device: Wireless device name (default "wlan0")
    down_color: Output color when disconnected, possible values:
        "good", "degraded", "bad" (default "bad")
    format: Display format for this module (default 'W[: {status}]')
    format_down: Output when disconnected (default 'down')
    format_up: Output when connected (default '{bitrate} {signal_percent} {ssid}')
    round_bitrate: If true, bit rate is rounded to the nearest whole number
        (default True)
    signal_bad: Bad signal strength in percent (default 29)
    signal_degraded: Degraded signal strength in percent (default 49)
    use_sudo: Use sudo to run iw, make sure iw requires some root rights
        without a password by adding a sudoers entry.
        Example: "<username> ALL=(ALL) NOPASSWD: /usr/bin/iw dev wl* link"
        (default False)

Format placeholders:
    {bitrate} Display bit rate
    {device} Display device name
    {icon} Character representing the quality based on bitrate,
        as defined by the 'blocks'
    {ip} Display IP address
    {signal_dbm} Display signal in dBm
    {signal_percent} Display signal in percent
    {ssid} Display SSID

Color options:
    color_bad: Signal strength signal_bad or lower
    color_degraded: Signal strength signal_degraded or lower
    color_good: Signal strength above signal_degraded

Requires:
    iw: cli configuration utility for wireless devices
    ip: only for {ip}. may be part of iproute2: ip routing utilities

__Note: Some distributions eg Debian require `iw` to be run with privileges.
In this case you will need to use the `use_sudo` configuration parameter.__

@author Markus Weimar <mail@markusweimar.de>
@license BSD

SAMPLE OUTPUT
{'color': '#00FF00', 'full_text': u'W: 54.0 MBit/s 100% Chicken Remixed'}
"""

import re
import math

STRING_ERROR = "iw: command failed"

class Py3status:
    """
    """
    # available configuration parameters
    bitrate_bad = 26
    bitrate_degraded = 53
    blocks = u"_▁▂▃▄▅▆▇█"
    cache_timeout = 10
    device = 'wlan0'
    down_color = 'bad'
    format = 'W[: {status}]'
    format_down = 'down'
    format_up = '{bitrate} {signal_percent} {ssid}'
    round_bitrate = True
    signal_bad = 29
    signal_degraded = 49
    use_sudo = False

    def post_config_hook(self):
        self._ssid = None
        self._max_bitrate = 0
        # Try and guess the wifi interface
        cmd = ['iw', 'dev']
        if self.use_sudo:
            cmd.insert(0, 'sudo')
        try:
            iw = self.py3.command_output(cmd)
            devices = re.findall('Interface\s*([^\s]+)', iw)
            if not devices or 'wlan0' in devices:
                self.device = 'wlan0'
            else:
                self.device = devices[0]
        except:
            pass

    def wifi(self):
        """
        Get WiFi status using iw.
        """
        self.signal_dbm_bad = self._percent_to_dbm(self.signal_bad)
        self.signal_dbm_degraded = self._percent_to_dbm(self.signal_degraded)
        cmd = ['iw', 'dev', self.device, 'link']
        if self.use_sudo:
            cmd.insert(0, 'sudo')
        try:
            iw = self.py3.command_output(cmd)
        except:
            return {'cache_until': self.py3.CACHE_FOREVER,
                    'color': self.py3.COLOR_ERROR or self.py3.COLOR_BAD,
                    'full_text': STRING_ERROR}
        # bitrate
        bitrate_out = re.search('tx bitrate: ([^\s]+) ([^\s]+)', iw)
        if bitrate_out:
            bitrate = float(bitrate_out.group(1))
            if self.round_bitrate:
                bitrate = round(bitrate)
            bitrate_unit = bitrate_out.group(2)
            if bitrate_unit == 'Gbit/s':
                bitrate *= 1000
        else:
            bitrate = None
            bitrate_unit = None

        # signal
        signal_out = re.search('signal: ([\-0-9]+)', iw)
        if signal_out:
            signal_dbm = int(signal_out.group(1))
            signal_percent = min(self._dbm_to_percent(signal_dbm), 100)
        else:
            signal_dbm = None
            signal_percent = None
        ssid_out = re.search('SSID: (.+)', iw)
        if ssid_out:
            ssid = ssid_out.group(1)
            # `iw` command would prints unicode SSID like `\xe8\x8b\x9f`
            # the the `ssid` here would be '\\xe8\\x8b\\x9f' (note the escape)
            # it needs to be decoded using 'unicode_escape', to '苟'
            ssid = ssid.encode('latin-1').decode('unicode_escape')
            ssid = ssid.encode('latin-1').decode('utf-8')
        else:
            ssid = None

        # check command
        if self.py3.format_contains(self.format_up, 'ip'):
            cmd = ['ip', 'addr', 'list', self.device]
            if self.use_sudo:
                cmd.insert(0, 'sudo')
            ip_info = self.py3.command_output(cmd)
            ip_match = re.search('inet\s+([0-9.]+)', ip_info)
            if ip_match:
                ip = ip_match.group(1)
            else:
                ip = None
        else:
            ip = ''

        # reset _max_bitrate if we have changed network
        if self._ssid != ssid:
            self._ssid = ssid
            self._max_bitrate = self.bitrate_degraded
        if bitrate:
            if bitrate > self._max_bitrate:
                self._max_bitrate = bitrate
            quality = int((bitrate / self._max_bitrate) * 100)
        else:
            quality = 0
        icon = self.blocks[int(math.ceil(quality / 100 * (len(self.blocks) - 1)))]

        # wifi down
        if ssid is None:
            full_text = self.py3.safe_format(self.format_down)
            color = getattr(self.py3, 'COLOR_{}'.format(self.down_color.upper()))
        # wifi up
        else:
            color = self.py3.COLOR_GOOD
            if bitrate:
                if bitrate <= self.bitrate_bad:
                    color = self.py3.COLOR_BAD
                elif bitrate <= self.bitrate_degraded:
                    color = self.py3.COLOR_DEGRADED
                bitrate = '{} {}'.format(bitrate, bitrate_unit)
            else:
                bitrate = '? MBit/s'
            if signal_dbm:
                if signal_dbm <= self.signal_dbm_bad:
                    color = self.py3.COLOR_BAD
                elif signal_dbm <= self.signal_dbm_degraded:
                    color = self.py3.COLOR_DEGRADED
                signal_dbm = '{} dBm'.format(signal_dbm)
                signal_percent = '{}%'.format(signal_percent)
            else:
                signal_dbm = '? dBm'
                signal_percent = '?%'

            full_text = self.py3.safe_format(
                self.format_up,
                dict(
                    bitrate=bitrate,
                    signal_dbm=signal_dbm,
                    signal_percent=signal_percent,
                    ip=ip,
                    device=self.device,
                    icon=icon,
                    ssid=ssid,
                ))

        return {'cache_until': self.py3.time_in(self.cache_timeout),
                'color': color,
                'full_text': self.py3.safe_format(
                    self.format, {'status': full_text})}

    def _dbm_to_percent(self, dbm):
        return 2 * (dbm + 100)

    def _percent_to_dbm(self, percent):
        return (percent / 2) - 100

if __name__ == "__main__":
    """
    Run module in test mode.
    """
    from py3status.module_test import module_test
    module_test(Py3status)
<|endoftext|>