Files
sqlalchemy/test/base/test_dependency.py
Federico Caselli 058c230cea Update black to v23.3.0 and flake8 to v6
This change could be added to .git-blame-ignore-revs

Change-Id: I7ba10052b26bc3c178d23fb50a1123d0aae965ca
2023-05-30 21:44:26 +02:00

370 lines
10 KiB
Python

from sqlalchemy import exc
from sqlalchemy.testing import assert_raises
from sqlalchemy.testing import eq_
from sqlalchemy.testing import fixtures
from sqlalchemy.testing.util import conforms_partial_ordering
from sqlalchemy.util import topological
class DependencySortTest(fixtures.TestBase):
def assert_sort(self, tuples, allitems=None):
if allitems is None:
allitems = self._nodes_from_tuples(tuples)
else:
allitems = self._nodes_from_tuples(tuples).union(allitems)
result = list(topological.sort(tuples, allitems))
assert conforms_partial_ordering(tuples, result)
def assert_sort_deterministic(self, tuples, allitems, expected):
result = list(topological.sort(tuples, allitems))
assert conforms_partial_ordering(tuples, result)
assert result == expected
def _nodes_from_tuples(self, tups):
s = set()
for tup in tups:
s.update(tup)
return s
def test_sort_one(self):
rootnode = "root"
node2 = "node2"
node3 = "node3"
node4 = "node4"
subnode1 = "subnode1"
subnode2 = "subnode2"
subnode3 = "subnode3"
subnode4 = "subnode4"
subsubnode1 = "subsubnode1"
tuples = [
(subnode3, subsubnode1),
(node2, subnode1),
(node2, subnode2),
(rootnode, node2),
(rootnode, node3),
(rootnode, node4),
(node4, subnode3),
(node4, subnode4),
]
self.assert_sort(tuples)
def test_sort_two(self):
node1 = "node1"
node2 = "node2"
node3 = "node3"
node4 = "node4"
node5 = "node5"
node6 = "node6"
node7 = "node7"
tuples = [
(node1, node2),
(node3, node4),
(node4, node5),
(node5, node6),
(node6, node2),
]
self.assert_sort(tuples, [node7])
def test_sort_three(self):
node1 = "keywords"
node2 = "itemkeyowrds"
node3 = "items"
node4 = "hoho"
tuples = [
(node1, node2),
(node4, node1),
(node1, node3),
(node3, node2),
]
self.assert_sort(tuples)
def test_sort_deterministic_one(self):
node1 = "node1"
node2 = "node2"
node3 = "node3"
node4 = "node4"
node5 = "node5"
node6 = "node6"
allitems = [node6, node5, node4, node3, node2, node1]
tuples = [(node6, node5), (node2, node1)]
expected = [node6, node4, node3, node2, node5, node1]
self.assert_sort_deterministic(tuples, allitems, expected)
def test_sort_deterministic_two(self):
node1 = 1
node2 = 2
node3 = 3
node4 = 4
node5 = 5
node6 = 6
allitems = [node6, node5, node4, node3, node2, node1]
tuples = [(node6, node5), (node4, node3), (node2, node1)]
expected = [node6, node4, node2, node5, node3, node1]
self.assert_sort_deterministic(tuples, allitems, expected)
def test_raise_on_cycle_one(self):
node1 = "node1"
node2 = "node2"
node3 = "node3"
node4 = "node4"
node5 = "node5"
tuples = [
(node4, node5),
(node5, node4),
(node1, node2),
(node2, node3),
(node3, node1),
(node4, node1),
]
allitems = self._nodes_from_tuples(tuples)
try:
list(topological.sort(tuples, allitems))
assert False
except exc.CircularDependencyError as err:
eq_(err.cycles, {"node1", "node3", "node2", "node5", "node4"})
eq_(
err.edges,
{
("node3", "node1"),
("node4", "node1"),
("node2", "node3"),
("node1", "node2"),
("node4", "node5"),
("node5", "node4"),
},
)
def test_raise_on_cycle_two(self):
# this condition was arising from ticket:362 and was not treated
# properly by topological sort
node1 = "node1"
node2 = "node2"
node3 = "node3"
node4 = "node4"
tuples = [
(node1, node2),
(node3, node1),
(node2, node4),
(node3, node2),
(node2, node3),
]
allitems = self._nodes_from_tuples(tuples)
try:
list(topological.sort(tuples, allitems))
assert False
except exc.CircularDependencyError as err:
eq_(err.cycles, {"node1", "node3", "node2"})
eq_(
err.edges,
{
("node3", "node1"),
("node2", "node3"),
("node3", "node2"),
("node1", "node2"),
("node2", "node4"),
},
)
def test_raise_on_cycle_three(self):
question, issue, providerservice, answer, provider = (
"Question",
"Issue",
"ProviderService",
"Answer",
"Provider",
)
tuples = [
(question, issue),
(providerservice, issue),
(provider, question),
(question, provider),
(providerservice, question),
(provider, providerservice),
(question, answer),
(issue, question),
]
allitems = self._nodes_from_tuples(tuples)
assert_raises(
exc.CircularDependencyError,
list,
topological.sort(tuples, allitems),
)
# TODO: test find_cycles
def test_large_sort(self):
tuples = [(i, i + 1) for i in range(0, 1500, 2)]
self.assert_sort(tuples)
def test_ticket_1380(self):
# ticket:1380 regression: would raise a KeyError
tuples = [(id(i), i) for i in range(3)]
self.assert_sort(tuples)
def test_find_cycle_one(self):
node1 = "node1"
node2 = "node2"
node3 = "node3"
node4 = "node4"
tuples = [
(node1, node2),
(node3, node1),
(node2, node4),
(node3, node2),
(node2, node3),
]
eq_(
topological.find_cycles(tuples, self._nodes_from_tuples(tuples)),
{node1, node2, node3},
)
def test_find_multiple_cycles_one(self):
node1 = "node1"
node2 = "node2"
node3 = "node3"
node4 = "node4"
node5 = "node5"
node6 = "node6"
node7 = "node7"
node8 = "node8"
node9 = "node9"
tuples = [ # cycle 1 cycle 2 cycle 3 cycle 4, but only if cycle
# 1 nodes are present
(node1, node2),
(node2, node4),
(node4, node1),
(node9, node9),
(node7, node5),
(node5, node7),
(node1, node6),
(node6, node8),
(node8, node4),
(node3, node1),
(node3, node2),
]
allnodes = {
node1,
node2,
node3,
node4,
node5,
node6,
node7,
node8,
node9,
}
eq_(
topological.find_cycles(tuples, allnodes),
{
"node8",
"node1",
"node2",
"node5",
"node4",
"node7",
"node6",
"node9",
},
)
def test_find_multiple_cycles_two(self):
node1 = "node1"
node2 = "node2"
node3 = "node3"
node4 = "node4"
node5 = "node5"
node6 = "node6"
tuples = [ # cycle 1 cycle 2
(node1, node2),
(node2, node4),
(node4, node1),
(node1, node6),
(node6, node2),
(node2, node4),
(node4, node1),
]
allnodes = {node1, node2, node3, node4, node5, node6}
# node6 only became present here once [ticket:2282] was addressed.
eq_(
topological.find_cycles(tuples, allnodes),
{"node1", "node2", "node4", "node6"},
)
def test_find_multiple_cycles_three(self):
node1 = "node1"
node2 = "node2"
node3 = "node3"
node4 = "node4"
node5 = "node5"
node6 = "node6"
tuples = [ # cycle 1 cycle 2 cycle3 cycle4
(node1, node2),
(node2, node1),
(node2, node3),
(node3, node2),
(node2, node4),
(node4, node2),
(node2, node5),
(node5, node6),
(node6, node2),
]
allnodes = {node1, node2, node3, node4, node5, node6}
eq_(topological.find_cycles(tuples, allnodes), allnodes)
def test_find_multiple_cycles_four(self):
tuples = [
("node6", "node2"),
("node15", "node19"),
("node19", "node2"),
("node4", "node10"),
("node15", "node13"),
("node17", "node11"),
("node1", "node19"),
("node15", "node8"),
("node6", "node20"),
("node14", "node11"),
("node6", "node14"),
("node11", "node2"),
("node10", "node20"),
("node1", "node11"),
("node20", "node19"),
("node4", "node20"),
("node15", "node20"),
("node9", "node19"),
("node11", "node10"),
("node11", "node19"),
("node13", "node6"),
("node3", "node15"),
("node9", "node11"),
("node4", "node17"),
("node2", "node20"),
("node19", "node10"),
("node8", "node4"),
("node11", "node3"),
("node6", "node1"),
]
allnodes = ["node%d" % i for i in range(1, 21)]
eq_(
topological.find_cycles(tuples, allnodes),
{
"node11",
"node10",
"node13",
"node15",
"node14",
"node17",
"node19",
"node20",
"node8",
"node1",
"node3",
"node2",
"node4",
"node6",
},
)