<commit_before>from operator import attrgetter

import pytest

from bonobo.constants import BEGIN
from bonobo.structs.graphs import Graph, GraphCursor
from bonobo.util.testing import get_pseudo_nodes

def test_get_cursor():
    g = Graph()
    cursor = g.get_cursor()

    assert cursor.graph is g
    assert cursor.first is BEGIN
    assert cursor.last is BEGIN

def test_get_cursor_in_a_vacuum():
    g = Graph()
    cursor = g.get_cursor(None)

    assert cursor.graph is g
    assert cursor.first is None
    assert cursor.last is None

def test_cursor_usage_to_add_a_chain():
    a, b, c = get_pseudo_nodes(*"abc")

    g = Graph()

    g.get_cursor() >> a >> b >> c

    assert len(g) == 3
    assert g.outputs_of(BEGIN) == {g.index_of(a)}
    assert g.outputs_of(a) == {g.index_of(b)}
    assert g.outputs_of(b) == {g.index_of(c)}
    assert g.outputs_of(c) == set()

def test_cursor_usage_to_add_a_chain_in_a_context_manager():
    a, b, c = get_pseudo_nodes(*"abc")

    g = Graph()
    with g as cur:
        cur >> a >> b >> c

    assert len(g) == 3
    assert g.outputs_of(BEGIN) == {g.index_of(a)}
    assert g.outputs_of(a) == {g.index_of(b)}
    assert g.outputs_of(b) == {g.index_of(c)}
    assert g.outputs_of(c) == set()

def test_implicit_cursor_usage():
    a, b, c = get_pseudo_nodes(*"abc")

    g = Graph()
    g >> a >> b >> c

    assert len(g) == 3
    assert g.outputs_of(BEGIN) == {g.index_of(a)}
    assert g.outputs_of(a) == {g.index_of(b)}
    assert g.outputs_of(b) == {g.index_of(c)}
    assert g.outputs_of(c) == set()

def test_cursor_to_fork_a_graph():
    a, b, c, d, e = get_pseudo_nodes(*"abcde")

    g = Graph()
    g >> a >> b >> c
    g.get_cursor(b) >> d >> e

    assert len(g) == 5
    assert g.outputs_of(BEGIN) == {g.index_of(a)}
    assert g.outputs_of(a) == {g.index_of(b)}
    assert g.outputs_of(b) == {g.index_of(c), g.index_of(d)}
    assert g.outputs_of(c) == set()
    assert g.outputs_of(d) == {g.index_of(e)}
    assert g.outputs_of(e) == set()

def test_cursor_to_fork_at_the_end():
    a, b, c, d, e = get_pseudo_nodes(*"abcde")

    g = Graph()
    c0 = g >> a >> b
    c1 = c0 >> c
    c2 = c0 >> d >> e

    assert len(g) == 5
    assert g.outputs_of(BEGIN) == {g.index_of(a)}
    assert g.outputs_of(a) == {g.index_of(b)}
    assert g.outputs_of(b) == {g.index_of(c), g.index_of(d)}
    assert g.outputs_of(c) == set()
    assert g.outputs_of(d) == {g.index_of(e)}
    assert g.outputs_of(e) == set()

    assert c0.first == g.index_of(BEGIN)
    assert c0.last == g.index_of(b)
    assert c1.first == g.index_of(BEGIN)
    assert c1.last == g.index_of(c)
    assert c2.first == g.index_of(BEGIN)
    assert c2.last == g.index_of(e)

def test_cursor_merge():
    a, b, c = get_pseudo_nodes(*"abc")
    g = Graph()

    c1 = g >> a >> c
    c2 = g >> b >> c

    assert len(g) == 3
    assert g.outputs_of(BEGIN) == g.indexes_of(a, b)
    assert g.outputs_of(a) == g.indexes_of(c)
    assert g.outputs_of(b) == g.indexes_of(c)
    assert g.outputs_of(c) == set()

    assert c1 == c2

def test_cursor_merge_orphan_in_between():
    a, b, c, v, w, x, y = get_pseudo_nodes(*"abcdefg")
    g = Graph()
    g >> a >> b >> c
    assert len(g) == 3
    g.orphan() >> v >> w >> b
    assert len(g) == 5
    g.orphan() >> x >> y >> b
    assert len(g) == 7

    assert g.outputs_of(BEGIN) == g.indexes_of(a)
    assert g.outputs_of(a) == g.indexes_of(b)
    assert g.outputs_of(b) == g.indexes_of(c)
    assert g.outputs_of(c) == set()
    assert g.outputs_of(v) == g.indexes_of(w)
    assert g.outputs_of(w) == g.indexes_of(b)
    assert g.outputs_of(x) == g.indexes_of(y)
    assert g.outputs_of(y) == g.indexes_of(b)

def test_using_same_cursor_many_times_for_fork():
    a, b, c, d, e = get_pseudo_nodes(5)
    g = Graph()

    c0 = g >> a >> b

    c0 >> c
    c0 >> d
    c0 >> e

    assert g.outputs_of(BEGIN) == g.indexes_of(a)
    assert g.outputs_of(a) == g.indexes_of(b)
    assert g.outputs_of(b) == g.indexes_of(c, d, e)
    assert g.outputs_of(c) == set()
    assert g.outputs_of(d) == set()
    assert g.outputs_of(e) == set()

def test_concat_branches():
    a, b, c, d = get_pseudo_nodes(4)
    g = Graph()

    c0 = g.orphan() >> a >> b
    c1 = g >> c >> d
    c2 = c1 >> c0

    assert c0.first == g.index_of(a)
    assert c2.first == BEGIN
    assert c2.last == g.index_of(b)

    assert g.outputs_of(BEGIN) == g.indexes_of(c)
    assert g.outputs_of(a) == g.indexes_of(b)
    assert g.outputs_of(b) == set()
    assert g.outputs_of(c) == g.indexes_of(d)
    assert g.outputs_of(d) == g.indexes_of(a)

def test_add_branch_inbetween():
    a, b, c, d, e, f = get_pseudo_nodes(6)
    g = Graph()
    c0 = g.orphan() >> a >> b
    c1 = g.orphan() >> c >> d
    c2 = g.orphan() >> e >> f
    c3 = c0 >> c1 >> c2

    assert c0.range == g.indexes_of(a, b, _type=tuple)
    assert c1.range == g.indexes_of(c, d, _type=tuple)
    assert c2.range == g.indexes_of(e, f, _type=tuple)
    assert c3.range == g.indexes_of(a, f, _type=tuple)

    assert g.outputs_of(b) == g.indexes_of(c)
    assert g.outputs_of(d) == g.indexes_of(e)
    assert g.outputs_of(f) == set()

def test_add_more_branches_inbetween():
    a, b, c, d, e, f, x, y = get_pseudo_nodes(8)
    g = Graph()
    c0 = g.orphan() >> a >> b
    c1 = g.orphan() >> c >> d
    c2 = g.orphan() >> e >> f
    c3 = g.orphan() >> x >> y
    c4 = c0 >> c1 >> c3
    c5 = c0 >> c2 >> c3

    assert c0.range == g.indexes_of(a, b, _type=tuple)
    assert c1.range == g.indexes_of(c, d, _type=tuple)
    assert c2.range == g.indexes_of(e, f, _type=tuple)
    assert c3.range == g.indexes_of(x, y, _type=tuple)
    assert c4.range == g.indexes_of(a, y, _type=tuple)
    assert c5.range == g.indexes_of(a, y, _type=tuple)

    assert g.outputs_of(b) == g.indexes_of(c, e)
    assert g.outputs_of(d) == g.indexes_of(x)
    assert g.outputs_of(f) == g.indexes_of(x)
    assert g.outputs_of(y) == set()
<commit_msg>Make sure that we can also add nodes inbetween branches.<commit_after>from operator import attrgetter

import pytest

from bonobo.constants import BEGIN
from bonobo.structs.graphs import Graph, GraphCursor
from bonobo.util.testing import get_pseudo_nodes

def test_get_cursor():
    g = Graph()
    cursor = g.get_cursor()

    assert cursor.graph is g
    assert cursor.first is BEGIN
    assert cursor.last is BEGIN

def test_get_cursor_in_a_vacuum():
    g = Graph()
    cursor = g.get_cursor(None)

    assert cursor.graph is g
    assert cursor.first is None
    assert cursor.last is None

def test_cursor_usage_to_add_a_chain():
    a, b, c = get_pseudo_nodes(*"abc")

    g = Graph()

    g.get_cursor() >> a >> b >> c

    assert len(g) == 3
    assert g.outputs_of(BEGIN) == {g.index_of(a)}
    assert g.outputs_of(a) == {g.index_of(b)}
    assert g.outputs_of(b) == {g.index_of(c)}
    assert g.outputs_of(c) == set()

def test_cursor_usage_to_add_a_chain_in_a_context_manager():
    a, b, c = get_pseudo_nodes(*"abc")

    g = Graph()
    with g as cur:
        cur >> a >> b >> c

    assert len(g) == 3
    assert g.outputs_of(BEGIN) == {g.index_of(a)}
    assert g.outputs_of(a) == {g.index_of(b)}
    assert g.outputs_of(b) == {g.index_of(c)}
    assert g.outputs_of(c) == set()

def test_implicit_cursor_usage():
    a, b, c = get_pseudo_nodes(*"abc")

    g = Graph()
    g >> a >> b >> c

    assert len(g) == 3
    assert g.outputs_of(BEGIN) == {g.index_of(a)}
    assert g.outputs_of(a) == {g.index_of(b)}
    assert g.outputs_of(b) == {g.index_of(c)}
    assert g.outputs_of(c) == set()

def test_cursor_to_fork_a_graph():
    a, b, c, d, e = get_pseudo_nodes(*"abcde")

    g = Graph()
    g >> a >> b >> c
    g.get_cursor(b) >> d >> e

    assert len(g) == 5
    assert g.outputs_of(BEGIN) == {g.index_of(a)}
    assert g.outputs_of(a) == {g.index_of(b)}
    assert g.outputs_of(b) == {g.index_of(c), g.index_of(d)}
    assert g.outputs_of(c) == set()
    assert g.outputs_of(d) == {g.index_of(e)}
    assert g.outputs_of(e) == set()

def test_cursor_to_fork_at_the_end():
    a, b, c, d, e = get_pseudo_nodes(*"abcde")

    g = Graph()
    c0 = g >> a >> b
    c1 = c0 >> c
    c2 = c0 >> d >> e

    assert len(g) == 5
    assert g.outputs_of(BEGIN) == {g.index_of(a)}
    assert g.outputs_of(a) == {g.index_of(b)}
    assert g.outputs_of(b) == {g.index_of(c), g.index_of(d)}
    assert g.outputs_of(c) == set()
    assert g.outputs_of(d) == {g.index_of(e)}
    assert g.outputs_of(e) == set()

    assert c0.first == g.index_of(BEGIN)
    assert c0.last == g.index_of(b)
    assert c1.first == g.index_of(BEGIN)
    assert c1.last == g.index_of(c)
    assert c2.first == g.index_of(BEGIN)
    assert c2.last == g.index_of(e)

def test_cursor_merge():
    a, b, c = get_pseudo_nodes(*"abc")
    g = Graph()

    c1 = g >> a >> c
    c2 = g >> b >> c

    assert len(g) == 3
    assert g.outputs_of(BEGIN) == g.indexes_of(a, b)
    assert g.outputs_of(a) == g.indexes_of(c)
    assert g.outputs_of(b) == g.indexes_of(c)
    assert g.outputs_of(c) == set()

    assert c1 == c2

def test_cursor_merge_orphan_in_between():
    a, b, c, v, w, x, y = get_pseudo_nodes(*"abcdefg")
    g = Graph()
    g >> a >> b >> c
    assert len(g) == 3
    g.orphan() >> v >> w >> b
    assert len(g) == 5
    g.orphan() >> x >> y >> b
    assert len(g) == 7

    assert g.outputs_of(BEGIN) == g.indexes_of(a)
    assert g.outputs_of(a) == g.indexes_of(b)
    assert g.outputs_of(b) == g.indexes_of(c)
    assert g.outputs_of(c) == set()
    assert g.outputs_of(v) == g.indexes_of(w)
    assert g.outputs_of(w) == g.indexes_of(b)
    assert g.outputs_of(x) == g.indexes_of(y)
    assert g.outputs_of(y) == g.indexes_of(b)

def test_using_same_cursor_many_times_for_fork():
    a, b, c, d, e = get_pseudo_nodes(5)
    g = Graph()

    c0 = g >> a >> b

    c0 >> c
    c0 >> d
    c0 >> e

    assert g.outputs_of(BEGIN) == g.indexes_of(a)
    assert g.outputs_of(a) == g.indexes_of(b)
    assert g.outputs_of(b) == g.indexes_of(c, d, e)
    assert g.outputs_of(c) == set()
    assert g.outputs_of(d) == set()
    assert g.outputs_of(e) == set()

def test_concat_branches():
    a, b, c, d = get_pseudo_nodes(4)
    g = Graph()

    c0 = g.orphan() >> a >> b
    c1 = g >> c >> d
    c2 = c1 >> c0

    assert c0.first == g.index_of(a)
    assert c2.first == BEGIN
    assert c2.last == g.index_of(b)

    assert g.outputs_of(BEGIN) == g.indexes_of(c)
    assert g.outputs_of(a) == g.indexes_of(b)
    assert g.outputs_of(b) == set()
    assert g.outputs_of(c) == g.indexes_of(d)
    assert g.outputs_of(d) == g.indexes_of(a)

def test_add_branch_inbetween():
    a, b, c, d, e, f = get_pseudo_nodes(6)
    g = Graph()
    c0 = g.orphan() >> a >> b
    c1 = g.orphan() >> c >> d
    c2 = g.orphan() >> e >> f
    c3 = c0 >> c1 >> c2

    assert c0.range == g.indexes_of(a, b, _type=tuple)
    assert c1.range == g.indexes_of(c, d, _type=tuple)
    assert c2.range == g.indexes_of(e, f, _type=tuple)
    assert c3.range == g.indexes_of(a, f, _type=tuple)

    assert g.outputs_of(b) == g.indexes_of(c)
    assert g.outputs_of(d) == g.indexes_of(e)
    assert g.outputs_of(f) == set()

def test_add_more_branches_inbetween():
    a, b, c, d, e, f, x, y = get_pseudo_nodes(8)
    g = Graph()
    c0 = g.orphan() >> a >> b
    c1 = g.orphan() >> c >> d
    c2 = g.orphan() >> e >> f
    c3 = g.orphan() >> x >> y
    c4 = c0 >> c1 >> c3
    c5 = c0 >> c2 >> c3

    assert c0.range == g.indexes_of(a, b, _type=tuple)
    assert c1.range == g.indexes_of(c, d, _type=tuple)
    assert c2.range == g.indexes_of(e, f, _type=tuple)
    assert c3.range == g.indexes_of(x, y, _type=tuple)
    assert c4.range == g.indexes_of(a, y, _type=tuple)
    assert c5.range == g.indexes_of(a, y, _type=tuple)

    assert g.outputs_of(b) == g.indexes_of(c, e)
    assert g.outputs_of(d) == g.indexes_of(x)
    assert g.outputs_of(f) == g.indexes_of(x)
    assert g.outputs_of(y) == set()

def test_add_nodes_inbetween_branches():
    a, b, c, d, e, f, x, y = get_pseudo_nodes(8)
    g = Graph()
    c0 = g.orphan() >> a >> b
    c1 = g.orphan() >> x >> y
    c2 = c0 >> c >> d >> c1
    c3 = c0 >> e >> f >> c1

    assert c0.range == g.indexes_of(a, b, _type=tuple)
    assert c1.range == g.indexes_of(x, y, _type=tuple)
    assert c2.range == g.indexes_of(a, y, _type=tuple)
    assert c3.range == g.indexes_of(a, y, _type=tuple)

    assert g.outputs_of(b) == g.indexes_of(c, e)
    assert g.outputs_of(d) == g.indexes_of(x)
    assert g.outputs_of(f) == g.indexes_of(x)
    assert g.outputs_of(y) == set()
<|endoftext|>


<commit_before>"""test_resources"""
import unittest
from nose.tools import eq_, assert_raises

from routes import *

class TestSubmapper(unittest.TestCase):
    def test_submapper(self):
        m = Mapper()
        c = m.submapper(path_prefix='/entries', requirements=dict(id='\d+'))
        c.connect('entry', '/{id}')

        eq_('/entries/1', url_for('entry', id=1))
        assert_raises(Exception, url_for, 'entry', id='foo')

    def test_submapper_nesting(self):
        m = Mapper()
        c = m.submapper(path_prefix='/entries', controller='entry',
                        requirements=dict(id='\d+'))
        e = c.submapper(path_prefix='/{id}')

        eq_('entry', c.resource_name)
        eq_('entry', e.resource_name)

        e.connect('entry', '')
        e.connect('edit_entry', '/edit')

        eq_('/entries/1', url_for('entry', id=1))
        eq_('/entries/1/edit', url_for('edit_entry', id=1))
        assert_raises(Exception, url_for, 'entry', id='foo')

    def test_submapper_action(self):
        m = Mapper(explicit=True)
        c = m.submapper(path_prefix='/entries', controller='entry')

        c.action(name='entries', action='list')
        c.action(action='create', method='POST')

        eq_('/entries', url_for('entries', method='GET'))
        eq_('/entries', url_for('create_entry', method='POST'))
        eq_('/entries', url_for(controller='entry', action='list', method='GET'))
        eq_('/entries', url_for(controller='entry', action='create', method='POST'))
        assert_raises(Exception, url_for, 'entries', method='DELETE')

    def test_submapper_link(self):
        m = Mapper(explicit=True)
        c = m.submapper(path_prefix='/entries', controller='entry')

        c.link(rel='new')
        c.link(rel='ping', method='POST')

        eq_('/entries/new', url_for('new_entry', method='GET'))
        eq_('/entries/ping', url_for('ping_entry', method='POST'))
        eq_('/entries/new', url_for(controller='entry', action='new', method='GET'))
        eq_('/entries/ping', url_for(controller='entry', action='ping', method='POST'))
        assert_raises(Exception, url_for, 'new_entry', method='PUT')
        assert_raises(Exception, url_for, 'ping_entry', method='PUT')

    def test_submapper_standard_actions(self):
        m = Mapper()
        c = m.submapper(path_prefix='/entries', collection_name='entries',
                        controller='entry')
        e = c.submapper(path_prefix='/{id}')

        c.index()
        c.create()
        e.show()
        e.update()
        e.delete()

        eq_('/entries', url_for('entries', method='GET'))
        eq_('/entries', url_for('create_entry', method='POST'))
        assert_raises(Exception, url_for, 'entries', method='DELETE')

        eq_('/entries/1', url_for('entry', id=1, method='GET'))
        eq_('/entries/1', url_for('update_entry', id=1, method='PUT'))
        eq_('/entries/1', url_for('delete_entry', id=1, method='DELETE'))
        assert_raises(Exception, url_for, 'entry', id=1, method='POST')

    def test_submapper_standard_links(self):
        m = Mapper()
        c = m.submapper(path_prefix='/entries', controller='entry')
        e = c.submapper(path_prefix='/{id}')

        c.new()
        e.edit()

        eq_('/entries/new', url_for('new_entry', method='GET'))
        assert_raises(Exception, url_for, 'new_entry', method='POST')

        eq_('/entries/1/edit', url_for('edit_entry', id=1, method='GET'))
        assert_raises(Exception, url_for, 'edit_entry', id=1, method='POST')

    def test_submapper_action_and_link_generation(self):
        m = Mapper()
        c = m.submapper(path_prefix='/entries', controller='entry',
                        collection_name='entries',
                        actions=['index', 'new', 'create'])
        e = c.submapper(path_prefix='/{id}',
                       actions=['show', 'edit', 'update', 'delete'])

        eq_('/entries', url_for('entries', method='GET'))
        eq_('/entries', url_for('create_entry', method='POST'))
        assert_raises(Exception, url_for, 'entries', method='DELETE')

        eq_('/entries/1', url_for('entry', id=1, method='GET'))
        eq_('/entries/1', url_for('update_entry', id=1, method='PUT'))
        eq_('/entries/1', url_for('delete_entry', id=1, method='DELETE'))
        assert_raises(Exception, url_for, 'entry', id=1, method='POST')

        eq_('/entries/new', url_for('new_entry', method='GET'))
        assert_raises(Exception, url_for, 'new_entry', method='POST')

        eq_('/entries/1/edit', url_for('edit_entry', id=1, method='GET'))
        assert_raises(Exception, url_for, 'edit_entry', id=1, method='POST')

    def test_collection(self):
        m = Mapper()
        c = m.collection('entries', 'entry')

        eq_('/entries', url_for('entries', method='GET'))
        eq_('/entries', url_for('create_entry', method='POST'))
        assert_raises(Exception, url_for, 'entries', method='DELETE')

        eq_('/entries/1', url_for('entry', id=1, method='GET'))
        eq_('/entries/1', url_for('update_entry', id=1, method='PUT'))
        eq_('/entries/1', url_for('delete_entry', id=1, method='DELETE'))
        assert_raises(Exception, url_for, 'entry', id=1, method='POST')

        eq_('/entries/new', url_for('new_entry', method='GET'))
        assert_raises(Exception, url_for, 'new_entry', method='POST')

        eq_('/entries/1/edit', url_for('edit_entry', id=1, method='GET'))
        assert_raises(Exception, url_for, 'edit_entry', id=1, method='POST')

if __name__ == '__main__':
    unittest.main()
<commit_msg>Add test for collection-level conditions and requirements<commit_after>"""test_resources"""
import unittest
from nose.tools import eq_, assert_raises

from routes import *

class TestSubmapper(unittest.TestCase):
    def test_submapper(self):
        m = Mapper()
        c = m.submapper(path_prefix='/entries', requirements=dict(id='\d+'))
        c.connect('entry', '/{id}')

        eq_('/entries/1', url_for('entry', id=1))
        assert_raises(Exception, url_for, 'entry', id='foo')

    def test_submapper_nesting(self):
        m = Mapper()
        c = m.submapper(path_prefix='/entries', controller='entry',
                        requirements=dict(id='\d+'))
        e = c.submapper(path_prefix='/{id}')

        eq_('entry', c.resource_name)
        eq_('entry', e.resource_name)

        e.connect('entry', '')
        e.connect('edit_entry', '/edit')

        eq_('/entries/1', url_for('entry', id=1))
        eq_('/entries/1/edit', url_for('edit_entry', id=1))
        assert_raises(Exception, url_for, 'entry', id='foo')

    def test_submapper_action(self):
        m = Mapper(explicit=True)
        c = m.submapper(path_prefix='/entries', controller='entry')

        c.action(name='entries', action='list')
        c.action(action='create', method='POST')

        eq_('/entries', url_for('entries', method='GET'))
        eq_('/entries', url_for('create_entry', method='POST'))
        eq_('/entries', url_for(controller='entry', action='list', method='GET'))
        eq_('/entries', url_for(controller='entry', action='create', method='POST'))
        assert_raises(Exception, url_for, 'entries', method='DELETE')

    def test_submapper_link(self):
        m = Mapper(explicit=True)
        c = m.submapper(path_prefix='/entries', controller='entry')

        c.link(rel='new')
        c.link(rel='ping', method='POST')

        eq_('/entries/new', url_for('new_entry', method='GET'))
        eq_('/entries/ping', url_for('ping_entry', method='POST'))
        eq_('/entries/new', url_for(controller='entry', action='new', method='GET'))
        eq_('/entries/ping', url_for(controller='entry', action='ping', method='POST'))
        assert_raises(Exception, url_for, 'new_entry', method='PUT')
        assert_raises(Exception, url_for, 'ping_entry', method='PUT')

    def test_submapper_standard_actions(self):
        m = Mapper()
        c = m.submapper(path_prefix='/entries', collection_name='entries',
                        controller='entry')
        e = c.submapper(path_prefix='/{id}')

        c.index()
        c.create()
        e.show()
        e.update()
        e.delete()

        eq_('/entries', url_for('entries', method='GET'))
        eq_('/entries', url_for('create_entry', method='POST'))
        assert_raises(Exception, url_for, 'entries', method='DELETE')

        eq_('/entries/1', url_for('entry', id=1, method='GET'))
        eq_('/entries/1', url_for('update_entry', id=1, method='PUT'))
        eq_('/entries/1', url_for('delete_entry', id=1, method='DELETE'))
        assert_raises(Exception, url_for, 'entry', id=1, method='POST')

    def test_submapper_standard_links(self):
        m = Mapper()
        c = m.submapper(path_prefix='/entries', controller='entry')
        e = c.submapper(path_prefix='/{id}')

        c.new()
        e.edit()

        eq_('/entries/new', url_for('new_entry', method='GET'))
        assert_raises(Exception, url_for, 'new_entry', method='POST')

        eq_('/entries/1/edit', url_for('edit_entry', id=1, method='GET'))
        assert_raises(Exception, url_for, 'edit_entry', id=1, method='POST')

    def test_submapper_action_and_link_generation(self):
        m = Mapper()
        c = m.submapper(path_prefix='/entries', controller='entry',
                        collection_name='entries',
                        actions=['index', 'new', 'create'])
        e = c.submapper(path_prefix='/{id}',
                       actions=['show', 'edit', 'update', 'delete'])

        eq_('/entries', url_for('entries', method='GET'))
        eq_('/entries', url_for('create_entry', method='POST'))
        assert_raises(Exception, url_for, 'entries', method='DELETE')

        eq_('/entries/1', url_for('entry', id=1, method='GET'))
        eq_('/entries/1', url_for('update_entry', id=1, method='PUT'))
        eq_('/entries/1', url_for('delete_entry', id=1, method='DELETE'))
        assert_raises(Exception, url_for, 'entry', id=1, method='POST')

        eq_('/entries/new', url_for('new_entry', method='GET'))
        assert_raises(Exception, url_for, 'new_entry', method='POST')

        eq_('/entries/1/edit', url_for('edit_entry', id=1, method='GET'))
        assert_raises(Exception, url_for, 'edit_entry', id=1, method='POST')

    def test_collection(self):
        m = Mapper()
        c = m.collection('entries', 'entry')

        eq_('/entries', url_for('entries', method='GET'))
        eq_('/entries', url_for('create_entry', method='POST'))
        assert_raises(Exception, url_for, 'entries', method='DELETE')

        eq_('/entries/1', url_for('entry', id=1, method='GET'))
        eq_('/entries/1', url_for('update_entry', id=1, method='PUT'))
        eq_('/entries/1', url_for('delete_entry', id=1, method='DELETE'))
        assert_raises(Exception, url_for, 'entry', id=1, method='POST')

        eq_('/entries/new', url_for('new_entry', method='GET'))
        assert_raises(Exception, url_for, 'new_entry', method='POST')

        eq_('/entries/1/edit', url_for('edit_entry', id=1, method='GET'))
        assert_raises(Exception, url_for, 'edit_entry', id=1, method='POST')

    def test_collection_options(self):
        m = Mapper()
        condition=dict(sub_domain=True)
        requirement=dict(id='\d+')
        c = m.collection('entries', 'entry', conditions=condition,
                         requirements=requirement)
        for r in m.matchlist:
            eq_(condition, r.conditions)
            eq_(requirement, r.requirement)

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


<commit_before>__author__ = "John Kirkham <kirkhamj@janelia.hhmi.org>"
__date__ = "$Aug 04, 2014 14:48:56 EDT$"

import collections
import itertools
import json
import os
import os.path
import shutil
import tempfile

import numpy
import h5py

import vigra
import vigra.impex

import nanshe.util.iters
import nanshe.util.xnumpy

import nanshe.io.xtiff
import nanshe.converter

class TestXTiff(object):
    def setup(self):
        self.temp_dir = ""
        self.filedata = collections.OrderedDict()
        self.offsets = None
        self.data = None

        self.data = numpy.random.random_integers(0, 255, (500, 1, 102, 101, 2)).astype(numpy.uint8)

        self.offsets = list(xrange(0, self.data.shape[0] + 100 - 1, 100))

        self.temp_dir = tempfile.mkdtemp()
        for i, i_str, (a_b, a_e) in nanshe.util.iters.filled_stringify_enumerate(
                                        itertools.izip(
                                                *nanshe.util.iters.lagged_generators(
                                                    self.offsets
                                                )
                                        )
                                    ):
            each_filename = os.path.join(self.temp_dir, "test_tiff_" + str(i) + ".tif")
            each_data = self.data[a_b:a_e]

            self.filedata[each_filename] = each_data

            each_data_shaped = nanshe.util.xnumpy.tagging_reorder_array(each_data, to_axis_order="zyxtc")
            each_data_shaped = each_data_shaped.reshape(each_data_shaped.shape[:-2] + (-1,))
            vigra.impex.writeVolume(each_data_shaped[0],
                                    os.path.join(self.temp_dir, "test_tiff_" + str(i) + ".tif"), "")

        self.offsets = self.offsets[:-1]

    def test_get_multipage_tiff_shape_dtype(self):
        for each_filename, each_filedata in self.filedata.items():
            each_shape_dtype = nanshe.io.xtiff.get_multipage_tiff_shape_dtype(each_filename)

            each_filedata = nanshe.util.xnumpy.tagging_reorder_array(each_filedata, to_axis_order="zyxtc")[0]

            assert (each_shape_dtype["shape"] == each_filedata.shape)
            assert (each_shape_dtype["dtype"] == each_filedata.dtype.type)

    def test_get_multipage_tiff_shape_dtype_transformed(self):
        for each_filename, each_filedata in self.filedata.items():
            each_shape_dtype = nanshe.io.xtiff.get_multipage_tiff_shape_dtype_transformed(
                each_filename,
                axis_order="tzyxc"
            )

            assert (each_shape_dtype["shape"] == each_filedata.shape)
            assert (each_shape_dtype["dtype"] == each_filedata.dtype.type)

    def test_get_standard_tiff_array(self):
        for each_filename, each_filedata in self.filedata.items():
            each_data = nanshe.io.xtiff.get_standard_tiff_array(each_filename)

            assert (each_data.shape == each_filedata.shape)
            assert (each_data.dtype == each_filedata.dtype)

            assert (each_data == each_filedata).all()

    def test_convert_tiffs(self):
        hdf5_filename = os.path.join(self.temp_dir, "test.h5")
        hdf5_filepath = hdf5_filename + "/data"

        nanshe.io.xtiff.convert_tiffs(self.filedata.keys(), hdf5_filepath)

        assert os.path.exists(hdf5_filename)

        filenames = None
        offsets = None
        descriptions = None
        data = None
        with h5py.File(hdf5_filename, "r") as hdf5_handle:
            assert "filenames" in hdf5_handle["data"].attrs
            assert "offsets" in hdf5_handle["data"].attrs
            assert "descriptions" in hdf5_handle["data"].attrs

            filenames = hdf5_handle["data"].attrs["filenames"]
            offsets = hdf5_handle["data"].attrs["offsets"]
            descriptions = hdf5_handle["data"].attrs["descriptions"]
            descriptions = hdf5_handle[descriptions.split(".h5/")[-1]][...]

            data = hdf5_handle["data"].value

        self_data_h5 = nanshe.util.xnumpy.tagging_reorder_array(
            self.data, to_axis_order="cztyx"
        )[0, 0]
        self_filenames = numpy.array(self.filedata.keys())

        assert len(filenames) == len(self_filenames)
        assert (filenames == self_filenames).all()

        assert len(offsets) == len(self.offsets)
        assert numpy.equal(offsets, self.offsets).all()

        assert len(descriptions) == len(self.data)
        assert all(_ == u"" for _ in descriptions)

        assert (data == self_data_h5).all()

        os.remove(hdf5_filename)

    def teardown(self):
        shutil.rmtree(self.temp_dir)

        self.temp_dir = ""
        self.filedata = collections.OrderedDict()
        self.data = None
<commit_msg>tests/test_nanshe/test_io/test_xtiff.py: Update tests for multichannel data.<commit_after>__author__ = "John Kirkham <kirkhamj@janelia.hhmi.org>"
__date__ = "$Aug 04, 2014 14:48:56 EDT$"

import collections
import itertools
import json
import os
import os.path
import shutil
import tempfile

import numpy
import h5py

import vigra
import vigra.impex

import nanshe.util.iters
import nanshe.util.xnumpy

import nanshe.io.xtiff
import nanshe.converter

class TestXTiff(object):
    def setup(self):
        self.temp_dir = ""
        self.filedata = collections.OrderedDict()
        self.offsets = None
        self.data = None
        self.pages_to_channel = 2

        self.data = numpy.random.random_integers(0, 255, (500, 1, 102, 101, 2)).astype(numpy.uint8)

        self.offsets = list(xrange(0, self.data.shape[0] + 100 - 1, 100))

        self.temp_dir = tempfile.mkdtemp()
        for i, i_str, (a_b, a_e) in nanshe.util.iters.filled_stringify_enumerate(
                                        itertools.izip(
                                                *nanshe.util.iters.lagged_generators(
                                                    self.offsets
                                                )
                                        )
                                    ):
            each_filename = os.path.join(self.temp_dir, "test_tiff_" + str(i) + ".tif")
            each_data = self.data[a_b:a_e]

            self.filedata[each_filename] = each_data

            each_data_shaped = nanshe.util.xnumpy.tagging_reorder_array(each_data, to_axis_order="zyxtc")
            each_data_shaped = each_data_shaped.reshape(each_data_shaped.shape[:-2] + (-1,))
            vigra.impex.writeVolume(each_data_shaped[0],
                                    os.path.join(self.temp_dir, "test_tiff_" + str(i) + ".tif"), "")

        self.offsets = self.offsets[:-1]

    def test_get_multipage_tiff_shape_dtype(self):
        for each_filename, each_filedata in self.filedata.items():
            each_shape_dtype = nanshe.io.xtiff.get_multipage_tiff_shape_dtype(each_filename)

            each_filedata = nanshe.util.xnumpy.tagging_reorder_array(each_filedata, to_axis_order="zyxtc")[0]

            print(each_shape_dtype["shape"])
            print(each_filedata.shape)
            assert (each_shape_dtype["shape"][:-2] == each_filedata.shape[:-2])
            assert (
                each_shape_dtype["shape"][-2] == numpy.prod(
                    each_filedata.shape[-2:]
                )
            )
            assert (each_shape_dtype["shape"][-1] == 1)
            assert (each_shape_dtype["dtype"] == each_filedata.dtype.type)

    def test_get_multipage_tiff_shape_dtype_transformed(self):
        for each_filename, each_filedata in self.filedata.items():
            each_shape_dtype = nanshe.io.xtiff.get_multipage_tiff_shape_dtype_transformed(
                each_filename,
                axis_order="tzyxc",
                pages_to_channel=self.pages_to_channel
            )

            assert (each_shape_dtype["shape"] == each_filedata.shape)
            assert (each_shape_dtype["dtype"] == each_filedata.dtype.type)

    def test_get_standard_tiff_array(self):
        for each_filename, each_filedata in self.filedata.items():
            each_data = nanshe.io.xtiff.get_standard_tiff_array(
                each_filename, pages_to_channel=self.pages_to_channel
            )

            assert (each_data.shape == each_filedata.shape)
            assert (each_data.dtype == each_filedata.dtype)

            assert (each_data == each_filedata).all()

    def test_convert_tiffs(self):
        hdf5_filename = os.path.join(self.temp_dir, "test.h5")
        hdf5_filepath = hdf5_filename + "/data"

        nanshe.io.xtiff.convert_tiffs(
            self.filedata.keys(),
            hdf5_filepath,
            pages_to_channel=self.pages_to_channel
        )

        assert os.path.exists(hdf5_filename)

        filenames = None
        offsets = None
        descriptions = None
        data = None
        with h5py.File(hdf5_filename, "r") as hdf5_handle:
            assert "filenames" in hdf5_handle["data"].attrs
            assert "offsets" in hdf5_handle["data"].attrs
            assert "descriptions" in hdf5_handle["data"].attrs

            filenames = hdf5_handle["data"].attrs["filenames"]
            offsets = hdf5_handle["data"].attrs["offsets"]
            descriptions = hdf5_handle["data"].attrs["descriptions"]
            descriptions = hdf5_handle[descriptions.split(".h5/")[-1]][...]

            data = hdf5_handle["data"].value

        self_data_h5 = nanshe.util.xnumpy.tagging_reorder_array(
            self.data, to_axis_order="cztyx"
        )[0, 0]
        self_filenames = numpy.array(self.filedata.keys())

        assert len(filenames) == len(self_filenames)
        assert (filenames == self_filenames).all()

        assert len(offsets) == len(self.offsets)
        assert numpy.equal(offsets, self.offsets).all()

        assert len(descriptions) == len(self.data)
        assert all(_ == u"" for _ in descriptions)

        assert (data == self_data_h5).all()

        os.remove(hdf5_filename)

    def teardown(self):
        shutil.rmtree(self.temp_dir)

        self.temp_dir = ""
        self.filedata = collections.OrderedDict()
        self.data = None
<|endoftext|>


<commit_before>import json
import sys
import unittest

from contextlib import contextmanager

from django.core.management import call_command
from django.db import connection, DatabaseError
from django.test import TestCase
from django.utils import six

from boardinghouse.schema import get_active_schema, get_schema_model
from boardinghouse.exceptions import TemplateSchemaActivation, SchemaNotFound, SchemaRequiredException

from ..models import AwareModel, NaiveModel

Schema = get_schema_model()

SCHEMA_QUERY = "SELECT schema_name FROM information_schema.schemata WHERE schema_name = %s"

@contextmanager
def capture(command, *args, **kwargs):
    out, sys.stdout = sys.stdout, six.StringIO()
    command(*args, **kwargs)
    sys.stdout.seek(0)
    yield sys.stdout.read()
    sys.stdout = out

@contextmanager
def capture_err(command, *args, **kwargs):
    err, sys.stderr = sys.stderr, six.StringIO()
    command(*args, **kwargs)
    sys.stderr.seek(0)
    yield sys.stderr.read()
    sys.stderr = err

class TestLoadData(TestCase):
    def test_invalid_schema_causes_error(self):
        with self.assertRaises(SchemaNotFound):
            call_command('loaddata', 'foo', schema='foo')

    def test_loading_schemata_creates_pg_schemata(self):
        self.assertEqual(0, Schema.objects.count())
        # Need to use commit=False, else the data will be in a different transaction.
        with capture(call_command, 'loaddata', 'tests/fixtures/schemata.json', commit=False) as output:
            self.assertEqual('Installed 2 object(s) from 1 fixture(s)\n', output)
        self.assertEqual(2, Schema.objects.count())
        Schema.objects.all()[0].activate()
        self.assertTrue(get_active_schema())
        cursor = connection.cursor()
        for schema in Schema.objects.all():
            cursor.execute(SCHEMA_QUERY, [schema.schema])
            data = cursor.fetchone()
            self.assertEqual((schema.schema,), data)
        cursor.close()

    def test_loading_naive_data_does_not_require_schema_arg(self):
        with capture(call_command, 'loaddata', 'tests/fixtures/naive.json', commit=False) as output:
            self.assertEqual('Installed 2 object(s) from 1 fixture(s)\n', output)
        NaiveModel.objects.get(name="naive1")

    def test_loading_naive_data_works_with_schema_passed_in(self):
        Schema.objects.create(name='a', schema='a')
        with capture(call_command, 'loaddata', 'tests/fixtures/naive.json', schema='a', commit=False) as output:
            self.assertEqual('Installed 2 object(s) from 1 fixture(s)\n', output)
        NaiveModel.objects.get(name="naive1")

    def test_loading_aware_data_without_a_schema_fails(self):
        with self.assertRaises(DatabaseError):
            with capture_err(call_command, 'loaddata', 'tests/fixtures/aware.json', commit=False) as output:
                self.assertIn('DatabaseError: Could not load tests.AwareModel(pk=None): relation "tests_awaremodel" does not exist\n', output)

    def test_loading_aware_data_with_template_schema_fails(self):
        with self.assertRaises(TemplateSchemaActivation):
            with capture_err(call_command, 'loaddata', 'tests/fixtures/aware.json', schema="__template__", commit=False) as output:
                self.assertIn('DatabaseError: Could not load tests.AwareModel(pk=None): relation "tests_awaremodel" does not exist\n', output)

    def test_loading_aware_data_works(self):
        Schema.objects.mass_create('a', 'b')
        with capture(call_command, 'loaddata', 'tests/fixtures/aware.json', schema='a', commit=False) as output:
            self.assertEqual('Installed 2 object(s) from 1 fixture(s)\n', output)

        Schema.objects.get(schema='a').activate()
        AwareModel.objects.get(name='aware1')

        Schema.objects.get(pk='b').activate()
        self.assertRaises(AwareModel.DoesNotExist, AwareModel.objects.get, name='aware1')

    @unittest.expectedFailure
    def test_loaddata_containing_schema_data_works(self):
        """
        This one is a fair way off: it would be great to be able to dump
        and load data from multiple schemata at once. I'm thinking the
        loading may be easier:)

        One solution would be to extract the fixture data, and then put it into N+1 files,
        where the first file is any fixtures without a referred-to schema, and all other
        files are all fixtures grouped by schema.

        This might require us to parse the file first, if --schema is not supplied, and look for
        any private models that don't have a schema attribute.

        We can't seem to inject anything into the deserialisation process, as it's a function,
        and there isn't really anywhere to inject code.
        """
        Schema.objects.mass_create('a', 'b')
        call_command('loaddata', 'tests/fixtures/aware_plus_schemata.json')
        with capture(call_command, 'loaddata', 'tests/fixtures/aware_plus_schemata.json', commit=False) as output:
            self.assertEqual('Installed 2 object(s) from 1 fixture(s)\n', output)

        Schema.objects.get(schema='a').activate()
        self.assertEqual('aware1', AwareModel.objects.get().name)

        Schema.objects.get(schema='b').activate()
        self.assertEqual('🌊🌊🌊🌊🌊', AwareModel.objects.get().name)

class TestDumpData(TestCase):
    def test_invalid_schema_raises_exception(self):
        with self.assertRaises(SchemaNotFound):
            call_command('dumpdata', 'tests', schema='foo')

    def test_dumpdata_on_naive_models_does_not_require_schema(self):
        with capture(call_command, 'dumpdata', 'boardinghouse') as output:
            self.assertEqual('[]', output)

    def test_dumpdata_on_aware_model(self):
        Schema.objects.mass_create('a', 'b')
        Schema.objects.get(schema='a').activate()
        AwareModel.objects.create(name='foo')

        with capture(call_command, 'dumpdata', 'tests.AwareModel', schema='a') as output:
            data = sorted(json.loads(output))

        self.assertEqual(1, len(data))
        self.assertEqual({"factor": 7, "status": False, "name": "foo"}, data[0]['fields'])

        with capture(call_command, 'dumpdata', 'tests.AwareModel', schema='b') as output:
            data = sorted(json.loads(output))

        self.assertEqual(0, len(data))

    def test_dumpdata_on_aware_model_requires_schema(self):
        with self.assertRaises(SchemaRequiredException):
            call_command('dumpdata', 'tests.awaremodel')
<commit_msg>Fix for python 2.7<commit_after># -*- coding: utf-8 -*-

import json
import sys
import unittest

from contextlib import contextmanager

from django.core.management import call_command
from django.db import connection, DatabaseError
from django.test import TestCase
from django.utils import six

from boardinghouse.schema import get_active_schema, get_schema_model
from boardinghouse.exceptions import TemplateSchemaActivation, SchemaNotFound, SchemaRequiredException

from ..models import AwareModel, NaiveModel

Schema = get_schema_model()

SCHEMA_QUERY = "SELECT schema_name FROM information_schema.schemata WHERE schema_name = %s"

@contextmanager
def capture(command, *args, **kwargs):
    out, sys.stdout = sys.stdout, six.StringIO()
    command(*args, **kwargs)
    sys.stdout.seek(0)
    yield sys.stdout.read()
    sys.stdout = out

@contextmanager
def capture_err(command, *args, **kwargs):
    err, sys.stderr = sys.stderr, six.StringIO()
    command(*args, **kwargs)
    sys.stderr.seek(0)
    yield sys.stderr.read()
    sys.stderr = err

class TestLoadData(TestCase):
    def test_invalid_schema_causes_error(self):
        with self.assertRaises(SchemaNotFound):
            call_command('loaddata', 'foo', schema='foo')

    def test_loading_schemata_creates_pg_schemata(self):
        self.assertEqual(0, Schema.objects.count())
        # Need to use commit=False, else the data will be in a different transaction.
        with capture(call_command, 'loaddata', 'tests/fixtures/schemata.json', commit=False) as output:
            self.assertEqual('Installed 2 object(s) from 1 fixture(s)\n', output)
        self.assertEqual(2, Schema.objects.count())
        Schema.objects.all()[0].activate()
        self.assertTrue(get_active_schema())
        cursor = connection.cursor()
        for schema in Schema.objects.all():
            cursor.execute(SCHEMA_QUERY, [schema.schema])
            data = cursor.fetchone()
            self.assertEqual((schema.schema,), data)
        cursor.close()

    def test_loading_naive_data_does_not_require_schema_arg(self):
        with capture(call_command, 'loaddata', 'tests/fixtures/naive.json', commit=False) as output:
            self.assertEqual('Installed 2 object(s) from 1 fixture(s)\n', output)
        NaiveModel.objects.get(name="naive1")

    def test_loading_naive_data_works_with_schema_passed_in(self):
        Schema.objects.create(name='a', schema='a')
        with capture(call_command, 'loaddata', 'tests/fixtures/naive.json', schema='a', commit=False) as output:
            self.assertEqual('Installed 2 object(s) from 1 fixture(s)\n', output)
        NaiveModel.objects.get(name="naive1")

    def test_loading_aware_data_without_a_schema_fails(self):
        with self.assertRaises(DatabaseError):
            with capture_err(call_command, 'loaddata', 'tests/fixtures/aware.json', commit=False) as output:
                self.assertIn('DatabaseError: Could not load tests.AwareModel(pk=None): relation "tests_awaremodel" does not exist\n', output)

    def test_loading_aware_data_with_template_schema_fails(self):
        with self.assertRaises(TemplateSchemaActivation):
            with capture_err(call_command, 'loaddata', 'tests/fixtures/aware.json', schema="__template__", commit=False) as output:
                self.assertIn('DatabaseError: Could not load tests.AwareModel(pk=None): relation "tests_awaremodel" does not exist\n', output)

    def test_loading_aware_data_works(self):
        Schema.objects.mass_create('a', 'b')
        with capture(call_command, 'loaddata', 'tests/fixtures/aware.json', schema='a', commit=False) as output:
            self.assertEqual('Installed 2 object(s) from 1 fixture(s)\n', output)

        Schema.objects.get(schema='a').activate()
        AwareModel.objects.get(name='aware1')

        Schema.objects.get(pk='b').activate()
        self.assertRaises(AwareModel.DoesNotExist, AwareModel.objects.get, name='aware1')

    @unittest.expectedFailure
    def test_loaddata_containing_schema_data_works(self):
        """
        This one is a fair way off: it would be great to be able to dump
        and load data from multiple schemata at once. I'm thinking the
        loading may be easier:)

        One solution would be to extract the fixture data, and then put it into N+1 files,
        where the first file is any fixtures without a referred-to schema, and all other
        files are all fixtures grouped by schema.

        This might require us to parse the file first, if --schema is not supplied, and look for
        any private models that don't have a schema attribute.

        We can't seem to inject anything into the deserialisation process, as it's a function,
        and there isn't really anywhere to inject code.
        """
        Schema.objects.mass_create('a', 'b')
        call_command('loaddata', 'tests/fixtures/aware_plus_schemata.json')
        with capture(call_command, 'loaddata', 'tests/fixtures/aware_plus_schemata.json', commit=False) as output:
            self.assertEqual('Installed 2 object(s) from 1 fixture(s)\n', output)

        Schema.objects.get(schema='a').activate()
        self.assertEqual('aware1', AwareModel.objects.get().name)

        Schema.objects.get(schema='b').activate()
        self.assertEqual('🌊🌊🌊🌊🌊', AwareModel.objects.get().name)

class TestDumpData(TestCase):
    def test_invalid_schema_raises_exception(self):
        with self.assertRaises(SchemaNotFound):
            call_command('dumpdata', 'tests', schema='foo')

    def test_dumpdata_on_naive_models_does_not_require_schema(self):
        with capture(call_command, 'dumpdata', 'boardinghouse') as output:
            self.assertEqual('[]', output)

    def test_dumpdata_on_aware_model(self):
        Schema.objects.mass_create('a', 'b')
        Schema.objects.get(schema='a').activate()
        AwareModel.objects.create(name='foo')

        with capture(call_command, 'dumpdata', 'tests.AwareModel', schema='a') as output:
            data = sorted(json.loads(output))

        self.assertEqual(1, len(data))
        self.assertEqual({"factor": 7, "status": False, "name": "foo"}, data[0]['fields'])

        with capture(call_command, 'dumpdata', 'tests.AwareModel', schema='b') as output:
            data = sorted(json.loads(output))

        self.assertEqual(0, len(data))

    def test_dumpdata_on_aware_model_requires_schema(self):
        with self.assertRaises(SchemaRequiredException):
            call_command('dumpdata', 'tests.awaremodel')
<|endoftext|>


<commit_before>"""Test stream initiation fallback."""

import base64
import errno
import os

import dbus
from dbus.connection import Connection
from dbus.lowlevel import SignalMessage

from servicetest import call_async, EventPattern, tp_name_prefix, watch_tube_signals, EventProtocolClientFactory
from gabbletest import exec_test, acknowledge_iq

from twisted.words.xish import domish, xpath
from twisted.internet.protocol import Factory, Protocol
from twisted.internet import reactor
from twisted.words.protocols.jabber.client import IQ

from gabbleconfig import HAVE_DBUS_TUBES

NS_TUBES = 'http://telepathy.freedesktop.org/xmpp/tubes'
NS_SI = 'http://jabber.org/protocol/si'
NS_FEATURE_NEG = 'http://jabber.org/protocol/feature-neg'
NS_IBB = 'http://jabber.org/protocol/ibb'
NS_X_DATA = 'jabber:x:data'
NS_BYTESTREAMS = 'http://jabber.org/protocol/bytestreams'

class Echo(Protocol):
    def dataReceived(self, data):
        self.transport.write(data)

def set_up_echo():
    factory = Factory()
    factory.protocol = Echo
    try:
        os.remove(os.getcwd() + '/stream')
    except OSError, e:
        if e.errno != errno.ENOENT:
            raise
    reactor.listenUNIX(os.getcwd() + '/stream', factory)

def test(q, bus, conn, stream):
    set_up_echo()

    conn.Connect()

    _, vcard_event, roster_event = q.expect_many(
        EventPattern('dbus-signal', signal='StatusChanged', args=[0, 1]),
        EventPattern('stream-iq', to=None, query_ns='vcard-temp',
            query_name='vCard'),
        EventPattern('stream-iq', query_ns='jabber:iq:roster'))

    acknowledge_iq(stream, vcard_event.stanza)

    roster = roster_event.stanza
    roster['type'] = 'result'
    item = roster_event.query.addElement('item')
    item['jid'] = 'bob@localhost'
    item['subscription'] = 'both'
    stream.send(roster)

    presence = domish.Element(('jabber:client', 'presence'))
    presence['from'] = 'bob@localhost/Bob'
    presence['to'] = 'test@localhost/Resource'
    c = presence.addElement('c')
    c['xmlns'] = 'http://jabber.org/protocol/caps'
    c['node'] = 'http://example.com/ICantBelieveItsNotTelepathy'
    c['ver'] = '1.2.3'
    stream.send(presence)

    event = q.expect('stream-iq', iq_type='get',
        query_ns='http://jabber.org/protocol/disco#info',
        to='bob@localhost/Bob')
    result = event.stanza
    result['type'] = 'result'
    assert event.query['node'] == \
        'http://example.com/ICantBelieveItsNotTelepathy#1.2.3'
    feature = event.query.addElement('feature')
    feature['var'] = NS_TUBES
    stream.send(result)

    requestotron = dbus.Interface(conn,
            'org.freedesktop.Telepathy.Connection.Interface.Requests')
    bob_handle = conn.RequestHandles(1, ['bob@localhost'])[0]

    # Offer a tube
    call_async(q, requestotron, 'CreateChannel',
            {'org.freedesktop.Telepathy.Channel.ChannelType':
                'org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT',
             'org.freedesktop.Telepathy.Channel.TargetHandleType':
                1,
             'org.freedesktop.Telepathy.Channel.TargetHandle':
                bob_handle,
             'org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT.Service':
                'echo',
             'org.freedesktop.Telepathy.Channel.Interface.Tube.DRAFT.Parameters':
                dbus.Dictionary({'foo': 'bar'}, signature='sv'),
            })
    ret, _, _ = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'),
        EventPattern('dbus-signal', signal='NewChannel'),
        EventPattern('dbus-signal', signal='NewChannels'),
        )

    chan_path = ret.value[0]
    channels = filter(lambda x:
      x[1] == "org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT" and
      x[0] == chan_path,
      conn.ListChannels())
    tube_chan = bus.get_object(conn.bus_name, channels[0][0])
    tube_iface = dbus.Interface(tube_chan,
        tp_name_prefix + '.Channel.Type.StreamTube.DRAFT')

    path = os.getcwd() + '/stream'
    call_async(q, tube_iface, 'OfferStreamTube',
        0, dbus.ByteArray(path), 0, "")

    event = q.expect('stream-message')
    message = event.stanza
    tube_nodes = xpath.queryForNodes('/message/tube[@xmlns="%s"]' % NS_TUBES,
        message)
    assert tube_nodes is not None
    assert len(tube_nodes) == 1
    tube = tube_nodes[0]

    assert tube['service'] == 'echo'
    assert tube['type'] == 'stream'
    assert not tube.hasAttribute('initiator')
    stream_tube_id = long(tube['id'])

    # The CM is the server, so fake a client wanting to talk to it
    iq = IQ(stream, 'set')
    iq['to'] = 'test@localhost/Resource'
    iq['from'] = 'bob@localhost/Bob'
    si = iq.addElement((NS_SI, 'si'))
    si['id'] = 'alpha'
    si['profile'] = NS_TUBES
    feature = si.addElement((NS_FEATURE_NEG, 'feature'))
    x = feature.addElement((NS_X_DATA, 'x'))
    x['type'] = 'form'
    field = x.addElement((None, 'field'))
    field['var'] = 'stream-method'
    field['type'] = 'list-multiple'
    option = field.addElement((None, 'option'))
    value = option.addElement((None, 'value'))
    value.addContent(NS_BYTESTREAMS)
    option = field.addElement((None, 'option'))
    value = option.addElement((None, 'value'))
    value.addContent(NS_IBB)

    stream_node = si.addElement((NS_TUBES, 'stream'))
    stream_node['tube'] = str(stream_tube_id)
    stream.send(iq)

    si_reply_event, _ = q.expect_many(
            EventPattern('stream-iq', iq_type='result'),
            EventPattern('dbus-signal', signal='TubeChannelStateChanged',
                args=[2])) # 2 == OPEN
    iq = si_reply_event.stanza
    si = xpath.queryForNodes('/iq/si[@xmlns="%s"]' % NS_SI,
        iq)[0]
    value = xpath.queryForNodes('/si/feature/x/field/value', si)
    assert len(value) == 1
    proto = value[0]
    assert str(proto) == NS_BYTESTREAMS
    tube = xpath.queryForNodes('/si/tube[@xmlns="%s"]' % NS_TUBES, si)
    assert len(tube) == 1

    q.expect('dbus-signal', signal='StreamTubeNewConnection',
        args=[bob_handle])

    # Send the non-working streamhost
    iq = IQ(stream, 'set')
    iq['to'] = 'test@localhost/Resource'
    iq['from'] = 'bob@localhost/Bob'
    query = iq.addElement((NS_BYTESTREAMS, 'query'))
    query['sid'] = 'alpha'
    query['mode'] = 'tcp'
    streamhost = query.addElement('streamhost')
    streamhost['jid'] = 'bob@localhost/Bob'
    streamhost['host'] = 'invalid.invalid'
    streamhost['port'] = '1234'
    stream.send(iq)

    event = q.expect('stream-iq', iq_type='set', to='bob@localhost/Bob')
    iq = event.stanza
    open = xpath.queryForNodes('/iq/open', iq)[0]
    assert open.uri == NS_IBB
    assert open['sid'] == 'alpha'

    result = IQ(stream, 'result')
    result['id'] = iq['id']
    result['from'] = iq['to']
    result['to'] = 'test@localhost/Resource'

    stream.send(result)

    # have the fake client send us some data
    message = domish.Element(('jabber:client', 'message'))
    message['to'] = 'test@localhost/Resource'
    message['from'] = 'bob@localhost/Bob'
    data_node = message.addElement((NS_IBB, 'data'))
    data_node['sid'] = 'alpha'
    data_node['seq'] = '0'
    data_node.addContent(base64.b64encode('hello world'))
    stream.send(message)

    event = q.expect('stream-message', to='bob@localhost/Bob')
    message = event.stanza

    data_nodes = xpath.queryForNodes('/message/data[@xmlns="%s"]' % NS_IBB,
        message)
    assert data_nodes is not None
    assert len(data_nodes) == 1
    ibb_data = data_nodes[0]
    assert ibb_data['sid'] == 'alpha'
    binary = base64.b64decode(str(ibb_data))
    assert binary == 'hello world'

    # Accepting a tube
    message = domish.Element(('jabber:client', 'message'))
    message['to'] = 'test@localhost/Resource'
    message['from'] = 'bob@localhost/Bob'
    message['id'] = 'msg-id'
    tube = message.addElement((NS_TUBES, 'tube'))
    tube['type'] = 'stream'
    tube['id'] = '42'
    tube['service'] = 'foo-service'
    parameters = tube.addElement((None, 'parameters'))
    parameter = parameters.addElement((None, 'parameter'))
    parameter['type'] = 'str'
    parameter['name'] = 'foo'
    parameter.addContent('bar')

    stream.send (message)

    event = q.expect('dbus-signal', signal='NewTube')
    id = event.args[0]
    initiator = event.args[1]
    type = event.args[2]
    service = event.args[3]
    parameters = event.args[4]
    state = event.args[5]

    assert id == 42
    initiator_jid = conn.InspectHandles(1, [initiator])[0]
    assert initiator_jid == 'bob@localhost'
    assert type == 1 # Stream tube
    assert service == 'foo-service'
    assert parameters == {'foo': 'bar'}
    assert state == 0 # local pending

    # accept the tube
    channels = filter(lambda x:
      x[1] == "org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT" and
      '42' in x[0],
      conn.ListChannels())
    assert len(channels) == 1

    tube_chan = bus.get_object(conn.bus_name, channels[0][0])
    tube_iface = dbus.Interface(tube_chan,
        tp_name_prefix + '.Channel.Type.StreamTube.DRAFT')

    call_async(q, tube_iface, 'AcceptStreamTube', 0, 0, '')

    event = q.expect('dbus-return', method='AcceptStreamTube')
    path2 = event.value[0]
    path2 = ''.join([chr(c) for c in path2])

    factory = EventProtocolClientFactory(q)
    reactor.connectUNIX(path2, factory)

    event = q.expect('stream-iq', iq_type='set', to='bob@localhost/Bob')
    iq = event.stanza
    si_nodes = xpath.queryForNodes('/iq/si', iq)
    assert si_nodes is not None
    assert len(si_nodes) == 1
    si = si_nodes[0]
    assert si['profile'] == NS_TUBES
    dbus_stream_id = si['id']

    feature = xpath.queryForNodes('/si/feature', si)[0]
    x = xpath.queryForNodes('/feature/x', feature)[0]
    assert x['type'] == 'form'
    field = xpath.queryForNodes('/x/field', x)[0]
    assert field['var'] == 'stream-method'
    assert field['type'] == 'list-multiple'
    value = xpath.queryForNodes('/field/option/value', field)[0]
    assert str(value) == NS_BYTESTREAMS
    value = xpath.queryForNodes('/field/option/value', field)[1]
    assert str(value) == NS_IBB

    result = IQ(stream, 'result')
    result['id'] = iq['id']
    result['from'] = iq['to']
    result['to'] = 'test@localhost/Resource'
    res_si = result.addElement((NS_SI, 'si'))
    res_feature = res_si.addElement((NS_FEATURE_NEG, 'feature'))
    res_x = res_feature.addElement((NS_X_DATA, 'x'))
    res_x['type'] = 'submit'
    res_field = res_x.addElement((None, 'field'))
    res_field['var'] = 'stream-method'
    res_value = res_field.addElement((None, 'value'))
    res_value.addContent(NS_BYTESTREAMS)
    res_value = res_field.addElement((None, 'value'))
    res_value.addContent(NS_IBB)

    stream.send(result)

    event = q.expect('stream-iq', iq_type='set', to='bob@localhost/Bob')
    iq = event.stanza
    query = xpath.queryForNodes('/iq/query', iq)[0]
    assert query.uri == NS_BYTESTREAMS
    sid = query['sid']
    streamhost = xpath.queryForNodes('/iq/query/streamhost', iq)[0]
    assert streamhost

    iq = IQ(stream, 'set')
    iq['to'] = 'test@localhost/Resource'
    iq['from'] = 'bob@localhost/Bob'
    open = iq.addElement((NS_IBB, 'open'))
    open['sid'] = sid
    open['block-size'] = '4096'
    stream.send(iq)

    q.expect('stream-iq', iq_type='result')

    return

if __name__ == '__main__':
    exec_test(test)
<commit_msg>Remove a useless return<commit_after>"""Test stream initiation fallback."""

import base64
import errno
import os

import dbus
from dbus.connection import Connection
from dbus.lowlevel import SignalMessage

from servicetest import call_async, EventPattern, tp_name_prefix, watch_tube_signals, EventProtocolClientFactory
from gabbletest import exec_test, acknowledge_iq

from twisted.words.xish import domish, xpath
from twisted.internet.protocol import Factory, Protocol
from twisted.internet import reactor
from twisted.words.protocols.jabber.client import IQ

from gabbleconfig import HAVE_DBUS_TUBES

NS_TUBES = 'http://telepathy.freedesktop.org/xmpp/tubes'
NS_SI = 'http://jabber.org/protocol/si'
NS_FEATURE_NEG = 'http://jabber.org/protocol/feature-neg'
NS_IBB = 'http://jabber.org/protocol/ibb'
NS_X_DATA = 'jabber:x:data'
NS_BYTESTREAMS = 'http://jabber.org/protocol/bytestreams'

class Echo(Protocol):
    def dataReceived(self, data):
        self.transport.write(data)

def set_up_echo():
    factory = Factory()
    factory.protocol = Echo
    try:
        os.remove(os.getcwd() + '/stream')
    except OSError, e:
        if e.errno != errno.ENOENT:
            raise
    reactor.listenUNIX(os.getcwd() + '/stream', factory)

def test(q, bus, conn, stream):
    set_up_echo()

    conn.Connect()

    _, vcard_event, roster_event = q.expect_many(
        EventPattern('dbus-signal', signal='StatusChanged', args=[0, 1]),
        EventPattern('stream-iq', to=None, query_ns='vcard-temp',
            query_name='vCard'),
        EventPattern('stream-iq', query_ns='jabber:iq:roster'))

    acknowledge_iq(stream, vcard_event.stanza)

    roster = roster_event.stanza
    roster['type'] = 'result'
    item = roster_event.query.addElement('item')
    item['jid'] = 'bob@localhost'
    item['subscription'] = 'both'
    stream.send(roster)

    presence = domish.Element(('jabber:client', 'presence'))
    presence['from'] = 'bob@localhost/Bob'
    presence['to'] = 'test@localhost/Resource'
    c = presence.addElement('c')
    c['xmlns'] = 'http://jabber.org/protocol/caps'
    c['node'] = 'http://example.com/ICantBelieveItsNotTelepathy'
    c['ver'] = '1.2.3'
    stream.send(presence)

    event = q.expect('stream-iq', iq_type='get',
        query_ns='http://jabber.org/protocol/disco#info',
        to='bob@localhost/Bob')
    result = event.stanza
    result['type'] = 'result'
    assert event.query['node'] == \
        'http://example.com/ICantBelieveItsNotTelepathy#1.2.3'
    feature = event.query.addElement('feature')
    feature['var'] = NS_TUBES
    stream.send(result)

    requestotron = dbus.Interface(conn,
            'org.freedesktop.Telepathy.Connection.Interface.Requests')
    bob_handle = conn.RequestHandles(1, ['bob@localhost'])[0]

    # Offer a tube
    call_async(q, requestotron, 'CreateChannel',
            {'org.freedesktop.Telepathy.Channel.ChannelType':
                'org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT',
             'org.freedesktop.Telepathy.Channel.TargetHandleType':
                1,
             'org.freedesktop.Telepathy.Channel.TargetHandle':
                bob_handle,
             'org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT.Service':
                'echo',
             'org.freedesktop.Telepathy.Channel.Interface.Tube.DRAFT.Parameters':
                dbus.Dictionary({'foo': 'bar'}, signature='sv'),
            })
    ret, _, _ = q.expect_many(
        EventPattern('dbus-return', method='CreateChannel'),
        EventPattern('dbus-signal', signal='NewChannel'),
        EventPattern('dbus-signal', signal='NewChannels'),
        )

    chan_path = ret.value[0]
    channels = filter(lambda x:
      x[1] == "org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT" and
      x[0] == chan_path,
      conn.ListChannels())
    tube_chan = bus.get_object(conn.bus_name, channels[0][0])
    tube_iface = dbus.Interface(tube_chan,
        tp_name_prefix + '.Channel.Type.StreamTube.DRAFT')

    path = os.getcwd() + '/stream'
    call_async(q, tube_iface, 'OfferStreamTube',
        0, dbus.ByteArray(path), 0, "")

    event = q.expect('stream-message')
    message = event.stanza
    tube_nodes = xpath.queryForNodes('/message/tube[@xmlns="%s"]' % NS_TUBES,
        message)
    assert tube_nodes is not None
    assert len(tube_nodes) == 1
    tube = tube_nodes[0]

    assert tube['service'] == 'echo'
    assert tube['type'] == 'stream'
    assert not tube.hasAttribute('initiator')
    stream_tube_id = long(tube['id'])

    # The CM is the server, so fake a client wanting to talk to it
    iq = IQ(stream, 'set')
    iq['to'] = 'test@localhost/Resource'
    iq['from'] = 'bob@localhost/Bob'
    si = iq.addElement((NS_SI, 'si'))
    si['id'] = 'alpha'
    si['profile'] = NS_TUBES
    feature = si.addElement((NS_FEATURE_NEG, 'feature'))
    x = feature.addElement((NS_X_DATA, 'x'))
    x['type'] = 'form'
    field = x.addElement((None, 'field'))
    field['var'] = 'stream-method'
    field['type'] = 'list-multiple'
    option = field.addElement((None, 'option'))
    value = option.addElement((None, 'value'))
    value.addContent(NS_BYTESTREAMS)
    option = field.addElement((None, 'option'))
    value = option.addElement((None, 'value'))
    value.addContent(NS_IBB)

    stream_node = si.addElement((NS_TUBES, 'stream'))
    stream_node['tube'] = str(stream_tube_id)
    stream.send(iq)

    si_reply_event, _ = q.expect_many(
            EventPattern('stream-iq', iq_type='result'),
            EventPattern('dbus-signal', signal='TubeChannelStateChanged',
                args=[2])) # 2 == OPEN
    iq = si_reply_event.stanza
    si = xpath.queryForNodes('/iq/si[@xmlns="%s"]' % NS_SI,
        iq)[0]
    value = xpath.queryForNodes('/si/feature/x/field/value', si)
    assert len(value) == 1
    proto = value[0]
    assert str(proto) == NS_BYTESTREAMS
    tube = xpath.queryForNodes('/si/tube[@xmlns="%s"]' % NS_TUBES, si)
    assert len(tube) == 1

    q.expect('dbus-signal', signal='StreamTubeNewConnection',
        args=[bob_handle])

    # Send the non-working streamhost
    iq = IQ(stream, 'set')
    iq['to'] = 'test@localhost/Resource'
    iq['from'] = 'bob@localhost/Bob'
    query = iq.addElement((NS_BYTESTREAMS, 'query'))
    query['sid'] = 'alpha'
    query['mode'] = 'tcp'
    streamhost = query.addElement('streamhost')
    streamhost['jid'] = 'bob@localhost/Bob'
    streamhost['host'] = 'invalid.invalid'
    streamhost['port'] = '1234'
    stream.send(iq)

    event = q.expect('stream-iq', iq_type='set', to='bob@localhost/Bob')
    iq = event.stanza
    open = xpath.queryForNodes('/iq/open', iq)[0]
    assert open.uri == NS_IBB
    assert open['sid'] == 'alpha'

    result = IQ(stream, 'result')
    result['id'] = iq['id']
    result['from'] = iq['to']
    result['to'] = 'test@localhost/Resource'

    stream.send(result)

    # have the fake client send us some data
    message = domish.Element(('jabber:client', 'message'))
    message['to'] = 'test@localhost/Resource'
    message['from'] = 'bob@localhost/Bob'
    data_node = message.addElement((NS_IBB, 'data'))
    data_node['sid'] = 'alpha'
    data_node['seq'] = '0'
    data_node.addContent(base64.b64encode('hello world'))
    stream.send(message)

    event = q.expect('stream-message', to='bob@localhost/Bob')
    message = event.stanza

    data_nodes = xpath.queryForNodes('/message/data[@xmlns="%s"]' % NS_IBB,
        message)
    assert data_nodes is not None
    assert len(data_nodes) == 1
    ibb_data = data_nodes[0]
    assert ibb_data['sid'] == 'alpha'
    binary = base64.b64decode(str(ibb_data))
    assert binary == 'hello world'

    # Accepting a tube
    message = domish.Element(('jabber:client', 'message'))
    message['to'] = 'test@localhost/Resource'
    message['from'] = 'bob@localhost/Bob'
    message['id'] = 'msg-id'
    tube = message.addElement((NS_TUBES, 'tube'))
    tube['type'] = 'stream'
    tube['id'] = '42'
    tube['service'] = 'foo-service'
    parameters = tube.addElement((None, 'parameters'))
    parameter = parameters.addElement((None, 'parameter'))
    parameter['type'] = 'str'
    parameter['name'] = 'foo'
    parameter.addContent('bar')

    stream.send (message)

    event = q.expect('dbus-signal', signal='NewTube')
    id = event.args[0]
    initiator = event.args[1]
    type = event.args[2]
    service = event.args[3]
    parameters = event.args[4]
    state = event.args[5]

    assert id == 42
    initiator_jid = conn.InspectHandles(1, [initiator])[0]
    assert initiator_jid == 'bob@localhost'
    assert type == 1 # Stream tube
    assert service == 'foo-service'
    assert parameters == {'foo': 'bar'}
    assert state == 0 # local pending

    # accept the tube
    channels = filter(lambda x:
      x[1] == "org.freedesktop.Telepathy.Channel.Type.StreamTube.DRAFT" and
      '42' in x[0],
      conn.ListChannels())
    assert len(channels) == 1

    tube_chan = bus.get_object(conn.bus_name, channels[0][0])
    tube_iface = dbus.Interface(tube_chan,
        tp_name_prefix + '.Channel.Type.StreamTube.DRAFT')

    call_async(q, tube_iface, 'AcceptStreamTube', 0, 0, '')

    event = q.expect('dbus-return', method='AcceptStreamTube')
    path2 = event.value[0]
    path2 = ''.join([chr(c) for c in path2])

    factory = EventProtocolClientFactory(q)
    reactor.connectUNIX(path2, factory)

    event = q.expect('stream-iq', iq_type='set', to='bob@localhost/Bob')
    iq = event.stanza
    si_nodes = xpath.queryForNodes('/iq/si', iq)
    assert si_nodes is not None
    assert len(si_nodes) == 1
    si = si_nodes[0]
    assert si['profile'] == NS_TUBES
    dbus_stream_id = si['id']

    feature = xpath.queryForNodes('/si/feature', si)[0]
    x = xpath.queryForNodes('/feature/x', feature)[0]
    assert x['type'] == 'form'
    field = xpath.queryForNodes('/x/field', x)[0]
    assert field['var'] == 'stream-method'
    assert field['type'] == 'list-multiple'
    value = xpath.queryForNodes('/field/option/value', field)[0]
    assert str(value) == NS_BYTESTREAMS
    value = xpath.queryForNodes('/field/option/value', field)[1]
    assert str(value) == NS_IBB

    result = IQ(stream, 'result')
    result['id'] = iq['id']
    result['from'] = iq['to']
    result['to'] = 'test@localhost/Resource'
    res_si = result.addElement((NS_SI, 'si'))
    res_feature = res_si.addElement((NS_FEATURE_NEG, 'feature'))
    res_x = res_feature.addElement((NS_X_DATA, 'x'))
    res_x['type'] = 'submit'
    res_field = res_x.addElement((None, 'field'))
    res_field['var'] = 'stream-method'
    res_value = res_field.addElement((None, 'value'))
    res_value.addContent(NS_BYTESTREAMS)
    res_value = res_field.addElement((None, 'value'))
    res_value.addContent(NS_IBB)

    stream.send(result)

    event = q.expect('stream-iq', iq_type='set', to='bob@localhost/Bob')
    iq = event.stanza
    query = xpath.queryForNodes('/iq/query', iq)[0]
    assert query.uri == NS_BYTESTREAMS
    sid = query['sid']
    streamhost = xpath.queryForNodes('/iq/query/streamhost', iq)[0]
    assert streamhost

    iq = IQ(stream, 'set')
    iq['to'] = 'test@localhost/Resource'
    iq['from'] = 'bob@localhost/Bob'
    open = iq.addElement((NS_IBB, 'open'))
    open['sid'] = sid
    open['block-size'] = '4096'
    stream.send(iq)

    q.expect('stream-iq', iq_type='result')

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


<commit_before>"""`uarray` provides functions for generating multimethods that dispatch to
multiple different backends

This should be imported, rather than `_uarray` so that an installed version could
be used instead, if available. This means that users can call
`uarray.set_backend` directly instead of going through SciPy.

"""

# Prefer an installed version of uarray, if available
try:
    import uarray as _uarray
except ImportError:
    _has_uarray = False
else:
    from scipy._lib._pep440 import Version

    _has_uarray = Version(_uarray.__version__) >= Version("0.5")
    del _uarray

if _has_uarray:
    from uarray import *
    from uarray import _Function
else:
    from ._uarray import *
    from ._uarray import _Function

del _has_uarray
<commit_msg>MAINT: Don't export Version from _lib.uarray<commit_after>"""`uarray` provides functions for generating multimethods that dispatch to
multiple different backends

This should be imported, rather than `_uarray` so that an installed version could
be used instead, if available. This means that users can call
`uarray.set_backend` directly instead of going through SciPy.

"""

# Prefer an installed version of uarray, if available
try:
    import uarray as _uarray
except ImportError:
    _has_uarray = False
else:
    from scipy._lib._pep440 import Version as _Version

    _has_uarray = _Version(_uarray.__version__) >= _Version("0.5")
    del _uarray
    del _Version

if _has_uarray:
    from uarray import *
    from uarray import _Function
else:
    from ._uarray import *
    from ._uarray import _Function

del _has_uarray
<|endoftext|>


<commit_before>import numpy as np
import openpnm as op
from skimage.morphology import ball, disk

class CubicTemplateTest:
    def setup_class(self):
        pass

    def teardown_class(self):
        pass

    def test_2D_template(self):
        net = op.network.CubicTemplate(template=disk(10), spacing=1)
        assert net.Np == 317
        assert net.Nt == 592

    def test_3D_template(self):
        net = op.network.CubicTemplate(template=ball(5), spacing=1)
        assert net.Np == 515
        assert net.Nt == 1302

    def test_labels(self):
        template = np.array(
            [[1, 1, 1, 1, 1],
             [1, 1, 0, 1, 1],
             [1, 1, 0, 0, 1],
             [1, 0, 0, 0, 1],
             [1, 1, 0, 1, 1]]
        )
        net = op.network.CubicTemplate(template=template)
        # Test "surface" label
        Ps_surf_desired = np.array([0, 1, 2, 3, 4, 5, 8, 9, 11, 12, 13, 14, 15, 16, 17])
        Ps_surf = net.pores("surface")
        np.testing.assert_allclose(Ps_surf, Ps_surf_desired)
        # Test "internal_surface" label
        Ps_int_surf_desired = np.array([6, 7, 10])
        Ps_int_surf = net.pores("internal_surface")
        np.testing.assert_allclose(Ps_int_surf, Ps_int_surf_desired)

if __name__ == '__main__':

    t = CubicTemplateTest()
    t.setup_class()
    self = t
    for item in t.__dir__():
        if item.startswith('test'):
            print('running test: '+item)
            t.__getattribute__(item)()
<commit_msg>Up code coverage<commit_after>import numpy as np
import openpnm as op
from skimage.morphology import ball, disk

class CubicTemplateTest:
    def setup_class(self):
        pass

    def teardown_class(self):
        pass

    def test_2D_template(self):
        net = op.network.CubicTemplate(template=disk(10), spacing=1)
        assert net.Np == 317
        assert net.Nt == 592

    def test_3D_template(self):
        net = op.network.CubicTemplate(template=ball(5), spacing=1)
        assert net.Np == 515
        assert net.Nt == 1302

    def test_labels(self):
        template = np.array(
            [[1, 1, 1, 1, 1],
             [1, 1, 0, 1, 1],
             [1, 1, 0, 0, 1],
             [1, 0, 0, 0, 1],
             [1, 1, 0, 1, 1]]
        )
        net = op.network.CubicTemplate(template=template, shape=[5, 5])
        # Test "surface" label
        Ps_surf_desired = np.array([0, 1, 2, 3, 4, 5, 8, 9, 11, 12, 13, 14, 15, 16, 17])
        Ps_surf = net.pores("surface")
        np.testing.assert_allclose(Ps_surf, Ps_surf_desired)
        # Test "internal_surface" label
        Ps_int_surf_desired = np.array([6, 7, 10])
        Ps_int_surf = net.pores("internal_surface")
        np.testing.assert_allclose(Ps_int_surf, Ps_int_surf_desired)

if __name__ == '__main__':

    t = CubicTemplateTest()
    t.setup_class()
    self = t
    for item in t.__dir__():
        if item.startswith('test'):
            print('running test: '+item)
            t.__getattribute__(item)()
<|endoftext|>


<commit_before>from .celestialmechanics import *
from .celestialmechanics_class import *
<commit_msg>import orbitalparams in init<commit_after>from .celestialmechanics import *
from .celestialmechanics_class import *
from .orbitalparams import *
<|endoftext|>


<commit_before>import logging
import os
from logging.handlers import TimedRotatingFileHandler

from . import conf

GET_FILES_TO_DELETE = "getFilesToDelete"
DO_ROLLOVER = "doRollover"

NO_FILE_BASED_LOGGING = os.environ.get("KOLIBRI_NO_FILE_BASED_LOGGING", False)

class KolibriTimedRotatingFileHandler(TimedRotatingFileHandler):
    """
    A custom TimedRotatingFileHandler that overrides two methods, getFilesToDelete
    and doRollover, to rename the rotation files from KOLIBRI_HOME/logs/kolibri.txt.YYYY-MM-DD
    to KOLIBRI_HOME/logs/archive/KOLIBRI-YYYY-MM-DD.txt.
    The original code is here: https://github.com/python/cpython/blob/2.7/Lib/logging/handlers.py#L162
    """

    def __init__(self, *args, **kwargs):
        super(KolibriTimedRotatingFileHandler, self).__init__(*args, **kwargs)
        dirname, basename = os.path.split(self.baseFilename)
        archive_dir = os.path.join(dirname, "archive")

        # Define attributes for this custom handler class
        self.dirname = dirname
        self.basename = basename
        self.archive_dir = archive_dir

    def getFilesToDelete(self):
        """
        Overriding the original getFilesToDelete method because the names of
        rotation files have been changed in doRollover method.
        """
        # If the archive directory does not exist, it means that there are no
        # rotation files
        if not os.path.exists(self.archive_dir):
            return []

        filenames = os.listdir(self.archive_dir)
        prefix = self.basename.split(".")[0] + "-"

        # Find all the rotation files in the KOLIBRI_HOME/logs/archive directory
        result = self._rotation_files(filenames, prefix, GET_FILES_TO_DELETE)
        result.sort()

        if len(result) < self.backupCount:
            result = []
        else:
            result = result[: len(result) - self.backupCount]
        return result

    def doRollover(self):
        """
        Overriding the original doRollover method so that the rotation files will
        be renamed from KOLIBRI_HOME/logs/kolibri.txt.YYYY-MM-DD to
        KOLIBRI_HOME/logs/archive/KOLIBRI-YYYY-MM-DD.txt.
        """
        super(KolibriTimedRotatingFileHandler, self).doRollover()
        filenames = os.listdir(self.dirname)
        prefix = self.basename + "."

        # Find all the rotation files in the KOLIBRI_HOME/logs directory and rename
        # them.
        if not os.path.exists(self.archive_dir):
            os.mkdir(self.archive_dir)
        self._rotation_files(filenames, prefix)

    def _rotation_files(self, filenames, prefix, func=DO_ROLLOVER):
        result = []
        plen = len(prefix)

        for filename in filenames:
            if filename[:plen] != prefix:
                continue

            rollover_time = filename[plen:].split(".")[0]
            if not self.extMatch.match(rollover_time):
                continue

            if func == GET_FILES_TO_DELETE:
                # Get the set of rotation files if the method is called from getFilesToDelete().
                result.append(os.path.join(self.archive_dir, filename))
            else:
                # Rename the rotation files if the method is called from doRollover().
                logname, ext = self.basename.split(".")
                new_name = logname + "-" + rollover_time + "." + ext
                destination_filename = os.path.join(self.archive_dir, new_name)
                source_filename = os.path.join(self.dirname, filename)
                os.rename(source_filename, destination_filename)

        return result

class FalseFilter(logging.Filter):
    """
    A filter that ignores everything, useful to create log config
    entries and inserting the actual filter later (when configuration is
    known)
    """

    def filter(self, record):
        return False

class RequireDebugTrue(logging.Filter):
    """A copy from Django to avoid loading Django's settings stack"""

    def filter(self, record):
        return conf.OPTIONS["Server"]["DEBUG"]

def get_default_logging_config(LOG_ROOT, debug=False, debug_database=False):
    """
    A minimal logging config for just kolibri without any Django
    specific handlers or anything from kolibri.utils.conf.

    This is used in early logging stations, before and during
    configuration.
    """

    DEFAULT_HANDLERS = (
        ["console"] if NO_FILE_BASED_LOGGING else ["file", "console", "file_debug"]
    )

    # This is the general level
    DEFAULT_LEVEL = "INFO" if not debug else "DEBUG"
    DATABASE_LEVEL = "INFO" if not debug_database else "DEBUG"

    return {
        "version": 1,
        "disable_existing_loggers": False,
        "filters": {"require_debug_true": {"()": FalseFilter}},  # Replaced later
        "formatters": {
            "verbose": {
                "format": "%(levelname)s %(asctime)s %(name)s %(process)d %(thread)d %(message)s"
            },
            "simple": {"format": "%(levelname)s %(message)s"},
            "simple_date": {"format": "%(levelname)s %(asctime)s %(name)s %(message)s"},
            "color": {
                "()": "colorlog.ColoredFormatter",
                "format": "%(log_color)s%(levelname)-8s %(message)s",
                "log_colors": {
                    "DEBUG": "bold_black",
                    "INFO": "white",
                    "WARNING": "yellow",
                    "ERROR": "red",
                    "CRITICAL": "bold_red",
                },
            },
        },
        "handlers": {
            "console": {
                "level": DEFAULT_LEVEL,
                "class": "logging.StreamHandler",
                "formatter": "color",
            },
            "file": {
                "level": "INFO",
                "filters": [],
                "class": "kolibri.utils.logger.KolibriTimedRotatingFileHandler",
                "filename": os.path.join(LOG_ROOT, "kolibri.txt"),
                "formatter": "simple_date",
                "when": "midnight",
                "backupCount": 30,
            },
            "file_debug": {
                "level": "DEBUG",
                "filters": ["require_debug_true"],
                "class": "logging.FileHandler",
                "filename": os.path.join(LOG_ROOT, "debug.txt"),
                "formatter": "simple_date",
            },
        },
        "loggers": {
            "kolibri": {
                "handlers": DEFAULT_HANDLERS,
                "level": DEFAULT_LEVEL,
                "propagate": False,
            },
            # For now, we do not fetch debugging output from this
            # We should introduce custom debug log levels or log
            # targets, i.e. --debug-level=high
            "kolibri.core.tasks.worker": {
                "handlers": DEFAULT_HANDLERS,
                "level": "INFO",
                "propagate": False,
            },
            "morango": {
                "handlers": DEFAULT_HANDLERS,
                "level": DEFAULT_LEVEL,
                "propagate": False,
            },
            "django": {
                "handlers": DEFAULT_HANDLERS,
                "level": DEFAULT_LEVEL,
                "propagate": False,
            },
            "django.db.backends": {
                "handlers": DEFAULT_HANDLERS,
                "level": DATABASE_LEVEL,
                "propagate": False,
            },
            "django.request": {
                "handlers": DEFAULT_HANDLERS,
                "level": DEFAULT_LEVEL,
                "propagate": False,
            },
        },
    }

def get_base_logging_config(LOG_ROOT, debug=False, debug_database=False):
    """
    Returns configured instance of the logger. Why? Because
    kolibri.utils.conf and kolibri.utils.options need logging, too and
    have to call get_default_logging_config.
    """
    config = get_default_logging_config(
        LOG_ROOT, debug=debug, debug_database=debug_database
    )
    config["filters"]["require_debug_true"] = {"()": RequireDebugTrue}

    return config

def get_logging_config(LOG_ROOT, debug=False, debug_database=False):
    """
    Returns a Django-specific set logging config. Namely, because one of
    the logging handlers and filters, ``mail_admins`` and
    ``require_debug_false`` both require the Django stack to be active.
    """
    config = get_base_logging_config(
        LOG_ROOT, debug=debug, debug_database=debug_database
    )

    config["filters"]["require_debug_false"] = {
        "()": "django.utils.log.RequireDebugFalse"
    }
    config["handlers"].update(
        {
            "mail_admins": {
                "level": "ERROR",
                "class": "django.utils.log.AdminEmailHandler",
                "filters": ["require_debug_false"],
            }
        }
    )
    # Add the mail_admins handler
    config["loggers"]["kolibri"]["handlers"].append("mail_admins")
    config["loggers"]["django"]["handlers"].append("mail_admins")
    config["loggers"]["django.request"]["handlers"].append("mail_admins")
    return config
<commit_msg>Suppress django template debug messages as too noisy.<commit_after>import logging
import os
from logging.handlers import TimedRotatingFileHandler

from . import conf

GET_FILES_TO_DELETE = "getFilesToDelete"
DO_ROLLOVER = "doRollover"

NO_FILE_BASED_LOGGING = os.environ.get("KOLIBRI_NO_FILE_BASED_LOGGING", False)

class KolibriTimedRotatingFileHandler(TimedRotatingFileHandler):
    """
    A custom TimedRotatingFileHandler that overrides two methods, getFilesToDelete
    and doRollover, to rename the rotation files from KOLIBRI_HOME/logs/kolibri.txt.YYYY-MM-DD
    to KOLIBRI_HOME/logs/archive/KOLIBRI-YYYY-MM-DD.txt.
    The original code is here: https://github.com/python/cpython/blob/2.7/Lib/logging/handlers.py#L162
    """

    def __init__(self, *args, **kwargs):
        super(KolibriTimedRotatingFileHandler, self).__init__(*args, **kwargs)
        dirname, basename = os.path.split(self.baseFilename)
        archive_dir = os.path.join(dirname, "archive")

        # Define attributes for this custom handler class
        self.dirname = dirname
        self.basename = basename
        self.archive_dir = archive_dir

    def getFilesToDelete(self):
        """
        Overriding the original getFilesToDelete method because the names of
        rotation files have been changed in doRollover method.
        """
        # If the archive directory does not exist, it means that there are no
        # rotation files
        if not os.path.exists(self.archive_dir):
            return []

        filenames = os.listdir(self.archive_dir)
        prefix = self.basename.split(".")[0] + "-"

        # Find all the rotation files in the KOLIBRI_HOME/logs/archive directory
        result = self._rotation_files(filenames, prefix, GET_FILES_TO_DELETE)
        result.sort()

        if len(result) < self.backupCount:
            result = []
        else:
            result = result[: len(result) - self.backupCount]
        return result

    def doRollover(self):
        """
        Overriding the original doRollover method so that the rotation files will
        be renamed from KOLIBRI_HOME/logs/kolibri.txt.YYYY-MM-DD to
        KOLIBRI_HOME/logs/archive/KOLIBRI-YYYY-MM-DD.txt.
        """
        super(KolibriTimedRotatingFileHandler, self).doRollover()
        filenames = os.listdir(self.dirname)
        prefix = self.basename + "."

        # Find all the rotation files in the KOLIBRI_HOME/logs directory and rename
        # them.
        if not os.path.exists(self.archive_dir):
            os.mkdir(self.archive_dir)
        self._rotation_files(filenames, prefix)

    def _rotation_files(self, filenames, prefix, func=DO_ROLLOVER):
        result = []
        plen = len(prefix)

        for filename in filenames:
            if filename[:plen] != prefix:
                continue

            rollover_time = filename[plen:].split(".")[0]
            if not self.extMatch.match(rollover_time):
                continue

            if func == GET_FILES_TO_DELETE:
                # Get the set of rotation files if the method is called from getFilesToDelete().
                result.append(os.path.join(self.archive_dir, filename))
            else:
                # Rename the rotation files if the method is called from doRollover().
                logname, ext = self.basename.split(".")
                new_name = logname + "-" + rollover_time + "." + ext
                destination_filename = os.path.join(self.archive_dir, new_name)
                source_filename = os.path.join(self.dirname, filename)
                os.rename(source_filename, destination_filename)

        return result

class FalseFilter(logging.Filter):
    """
    A filter that ignores everything, useful to create log config
    entries and inserting the actual filter later (when configuration is
    known)
    """

    def filter(self, record):
        return False

class RequireDebugTrue(logging.Filter):
    """A copy from Django to avoid loading Django's settings stack"""

    def filter(self, record):
        return conf.OPTIONS["Server"]["DEBUG"]

def get_default_logging_config(LOG_ROOT, debug=False, debug_database=False):
    """
    A minimal logging config for just kolibri without any Django
    specific handlers or anything from kolibri.utils.conf.

    This is used in early logging stations, before and during
    configuration.
    """

    DEFAULT_HANDLERS = (
        ["console"] if NO_FILE_BASED_LOGGING else ["file", "console", "file_debug"]
    )

    # This is the general level
    DEFAULT_LEVEL = "INFO" if not debug else "DEBUG"
    DATABASE_LEVEL = "INFO" if not debug_database else "DEBUG"

    return {
        "version": 1,
        "disable_existing_loggers": False,
        "filters": {"require_debug_true": {"()": FalseFilter}},  # Replaced later
        "formatters": {
            "verbose": {
                "format": "%(levelname)s %(asctime)s %(name)s %(process)d %(thread)d %(message)s"
            },
            "simple": {"format": "%(levelname)s %(message)s"},
            "simple_date": {"format": "%(levelname)s %(asctime)s %(name)s %(message)s"},
            "color": {
                "()": "colorlog.ColoredFormatter",
                "format": "%(log_color)s%(levelname)-8s %(message)s",
                "log_colors": {
                    "DEBUG": "bold_black",
                    "INFO": "white",
                    "WARNING": "yellow",
                    "ERROR": "red",
                    "CRITICAL": "bold_red",
                },
            },
        },
        "handlers": {
            "console": {
                "level": DEFAULT_LEVEL,
                "class": "logging.StreamHandler",
                "formatter": "color",
            },
            "file": {
                "level": "INFO",
                "filters": [],
                "class": "kolibri.utils.logger.KolibriTimedRotatingFileHandler",
                "filename": os.path.join(LOG_ROOT, "kolibri.txt"),
                "formatter": "simple_date",
                "when": "midnight",
                "backupCount": 30,
            },
            "file_debug": {
                "level": "DEBUG",
                "filters": ["require_debug_true"],
                "class": "logging.FileHandler",
                "filename": os.path.join(LOG_ROOT, "debug.txt"),
                "formatter": "simple_date",
            },
        },
        "loggers": {
            "kolibri": {
                "handlers": DEFAULT_HANDLERS,
                "level": DEFAULT_LEVEL,
                "propagate": False,
            },
            # For now, we do not fetch debugging output from this
            # We should introduce custom debug log levels or log
            # targets, i.e. --debug-level=high
            "kolibri.core.tasks.worker": {
                "handlers": DEFAULT_HANDLERS,
                "level": "INFO",
                "propagate": False,
            },
            "morango": {
                "handlers": DEFAULT_HANDLERS,
                "level": DEFAULT_LEVEL,
                "propagate": False,
            },
            "django": {
                "handlers": DEFAULT_HANDLERS,
                "level": DEFAULT_LEVEL,
                "propagate": False,
            },
            "django.db.backends": {
                "handlers": DEFAULT_HANDLERS,
                "level": DATABASE_LEVEL,
                "propagate": False,
            },
            "django.request": {
                "handlers": DEFAULT_HANDLERS,
                "level": DEFAULT_LEVEL,
                "propagate": False,
            },
            "django.template": {
                "handlers": DEFAULT_HANDLERS,
                # Django template debug is very noisy, only log INFO and above.
                "level": "INFO",
                "propagate": False,
            },
        },
    }

def get_base_logging_config(LOG_ROOT, debug=False, debug_database=False):
    """
    Returns configured instance of the logger. Why? Because
    kolibri.utils.conf and kolibri.utils.options need logging, too and
    have to call get_default_logging_config.
    """
    config = get_default_logging_config(
        LOG_ROOT, debug=debug, debug_database=debug_database
    )
    config["filters"]["require_debug_true"] = {"()": RequireDebugTrue}

    return config

def get_logging_config(LOG_ROOT, debug=False, debug_database=False):
    """
    Returns a Django-specific set logging config. Namely, because one of
    the logging handlers and filters, ``mail_admins`` and
    ``require_debug_false`` both require the Django stack to be active.
    """
    config = get_base_logging_config(
        LOG_ROOT, debug=debug, debug_database=debug_database
    )

    config["filters"]["require_debug_false"] = {
        "()": "django.utils.log.RequireDebugFalse"
    }
    config["handlers"].update(
        {
            "mail_admins": {
                "level": "ERROR",
                "class": "django.utils.log.AdminEmailHandler",
                "filters": ["require_debug_false"],
            }
        }
    )
    # Add the mail_admins handler
    config["loggers"]["kolibri"]["handlers"].append("mail_admins")
    config["loggers"]["django"]["handlers"].append("mail_admins")
    config["loggers"]["django.request"]["handlers"].append("mail_admins")
    return config
<|endoftext|>