Accept Merge Request #125: (api -> master)

Merge Request: Test cascade deletion

Created By: @王琼钰
Accepted By: @王琼钰
URL: https://tjwater.coding.net/p/tjwatercloud/d/TJWaterServer/git/merge/125
This commit is contained in:
王琼钰
2023-02-04 16:27:04 +08:00
5 changed files with 356 additions and 6 deletions

View File

@@ -215,7 +215,7 @@ def unset_pump_energy_by_pattern(name: str, pattern: str) -> ChangeSet:
effic = str(row2['effic']) if row2 != None else None
cs.append(g_update_prefix | {'type': 'pump_energy', 'pump' : pump, 'price': price, 'pattern': None, 'effic': effic})
return ChangeSet()
return cs
def unset_pump_energy_by_curve(name: str, curve: str) -> ChangeSet:
@@ -230,4 +230,4 @@ def unset_pump_energy_by_curve(name: str, curve: str) -> ChangeSet:
pattern = str(row2['pattern']) if row2 != None else None
cs.append(g_update_prefix | {'type': 'pump_energy', 'pump' : pump, 'price': price, 'pattern': pattern, 'effic': None})
return ChangeSet()
return cs

View File

@@ -14,7 +14,9 @@ def get_source_schema(name: str) -> dict[str, dict[str, Any]]:
def get_source(name: str, node: str) -> dict[str, Any]:
s = read(name, f"select * from sources where node = '{node}'")
s = try_read(name, f"select * from sources where node = '{node}'")
if s == None:
return {}
d = {}
d['node'] = str(s['node'])
d['s_type'] = str(s['type'])

View File

@@ -175,9 +175,12 @@ def inp_out_pump(name: str) -> list[str]:
def unset_pump_by_curve(name: str, curve: str) -> ChangeSet:
cs = ChangeSet()
rows = read_all(name, f"select id from pumps where head = '{curve}'")
rows = read_all(name, f"select * from pumps where head = '{curve}'")
for row in rows:
cs.append(g_update_prefix | {'type': 'pump', 'id': row['id'], 'head': None})
if row['power'] != None:
cs.append(g_update_prefix | {'type': 'pump', 'id': row['id'], 'head': None})
else: # workaround to prevent pump deletion... and I don't want to remove constraint...
cs.append(g_update_prefix | {'type': 'pump', 'id': row['id'], 'head': None, 'power': 0.0})
return cs

View File

@@ -169,6 +169,6 @@ def unset_demand_by_pattern(name: str, pattern: str) -> ChangeSet:
ds = get_demand(name, row['id'])
for d in ds['demands']:
d['pattern'] = None
cs.append(g_update_prefix | {'type': 'demand', 'junction': row['junction'], 'demands': ds})
cs.append(g_update_prefix | {'type': 'demand', 'junction': row['id'], 'demands': ds['demands']})
return cs

View File

@@ -399,6 +399,65 @@ class TestApi:
self.leave(p)
def test_junction_del(self):
p = 'test_junction_del'
self.enter(p)
add_junction(p, ChangeSet({'id': 'j0', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}))
add_junction(p, ChangeSet({'id': 'j1', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}))
add_pipe(p, ChangeSet({'id': 'p0', 'node1': 'j0', 'node2': 'j1', 'length': 100.0, 'diameter': 10.0, 'roughness': 0.1, 'minor_loss': 0.5, 'status': PIPE_STATUS_OPEN }))
set_tag(p, ChangeSet({'t_type': TAG_TYPE_NODE, 'id': 'j0', 'tag': 'j0t' }))
set_demand(p, ChangeSet({'junction': 'j0', 'demands': [{'demand': 10.0, 'pattern': None, 'category': 'x'}, {'demand': 20.0, 'pattern': None, 'category': None}]}))
set_emitter(p, ChangeSet({'junction': 'j0', 'coefficient': 10.0}))
set_quality(p, ChangeSet({'node': 'j0', 'quality': 10.0}))
add_source(p, ChangeSet({'node': 'j0', 's_type': SOURCE_TYPE_CONCEN, 'strength': 10.0, 'pattern': None }))
add_label(p, ChangeSet({'x': 0.0, 'y': 0.0, 'label': 'x', 'node': 'j0'}))
assert is_junction(p, 'j0')
assert is_junction(p, 'j1')
assert is_pipe(p, 'p0')
assert get_tag(p, TAG_TYPE_NODE, 'j0')['tag'] == 'j0t'
assert get_demand(p, 'j0')['demands'] == [{'demand': 10.0, 'pattern': None, 'category': 'x'}, {'demand': 20.0, 'pattern': None, 'category': None}]
assert get_emitter(p, 'j0')['coefficient'] == 10.0
assert get_quality(p, 'j0')['quality'] == 10.0
assert get_source(p, 'j0')['s_type'] == SOURCE_TYPE_CONCEN
assert get_label(p, 0.0, 0.0)['node'] == 'j0'
delete_junction(p, ChangeSet({'id': 'j0'}))
assert is_junction(p, 'j0') == False
assert is_junction(p, 'j1')
assert is_pipe(p, 'p0') == False
assert get_tag(p, TAG_TYPE_NODE, 'j0')['tag'] == None
assert get_demand(p, 'j1')['demands'] == []
assert get_emitter(p, 'j0')['coefficient'] == None
assert get_quality(p, 'j0')['quality'] == None
assert get_source(p, 'j0') == {}
assert get_label(p, 0.0, 0.0)['node'] == None
execute_undo(p)
assert is_junction(p, 'j0')
assert is_junction(p, 'j1')
assert is_pipe(p, 'p0')
assert get_tag(p, TAG_TYPE_NODE, 'j0')['tag'] == 'j0t'
assert get_demand(p, 'j0')['demands'] == [{'demand': 10.0, 'pattern': None, 'category': 'x'}, {'demand': 20.0, 'pattern': None, 'category': None}]
assert get_emitter(p, 'j0')['coefficient'] == 10.0
assert get_quality(p, 'j0')['quality'] == 10.0
assert get_source(p, 'j0')['s_type'] == SOURCE_TYPE_CONCEN
assert get_label(p, 0.0, 0.0)['node'] == 'j0'
execute_redo(p)
assert is_junction(p, 'j0') == False
assert is_junction(p, 'j1')
assert is_pipe(p, 'p0') == False
assert get_tag(p, TAG_TYPE_NODE, 'j0')['tag'] == None
assert get_demand(p, 'j1')['demands'] == []
assert get_emitter(p, 'j0')['coefficient'] == None
assert get_quality(p, 'j0')['quality'] == None
assert get_source(p, 'j0') == {}
assert get_label(p, 0.0, 0.0)['node'] == None
self.leave(p)
# 3 reservoir
@@ -553,6 +612,35 @@ class TestApi:
self.leave(p)
def test_reservoir_del(self):
p = 'test_reservoir_del'
self.enter(p)
add_junction(p, ChangeSet({'id': 'j0', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}))
add_reservoir(p, ChangeSet({'id': 'r0', 'x': 0.0, 'y': 10.0, 'head': 20.0}))
add_pipe(p, ChangeSet({'id': 'p0', 'node1': 'j0', 'node2': 'r0', 'length': 100.0, 'diameter': 10.0, 'roughness': 0.1, 'minor_loss': 0.5, 'status': PIPE_STATUS_OPEN }))
assert is_junction(p, 'j0')
assert is_reservoir(p, 'r0')
assert is_pipe(p, 'p0')
delete_reservoir(p, ChangeSet({'id': 'r0'}))
assert is_junction(p, 'j0')
assert is_reservoir(p, 'r0') == False
assert is_pipe(p, 'p0') == False
execute_undo(p)
assert is_junction(p, 'j0')
assert is_reservoir(p, 'r0')
assert is_pipe(p, 'p0')
execute_redo(p)
assert is_junction(p, 'j0')
assert is_reservoir(p, 'r0') == False
assert is_pipe(p, 'p0') == False
self.leave(p)
# 4 tank
@@ -767,6 +855,40 @@ class TestApi:
self.leave(p)
def test_tank_del(self):
p = 'test_tank_del'
self.enter(p)
add_junction(p, ChangeSet({'id': 'j0', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}))
add_tank(p, ChangeSet({'id': 't0', 'x': 0.0, 'y': 10.0, 'elevation': 20.0, 'init_level': 1.0, 'min_level': 0.0, 'max_level': 2.0, 'diameter': 10.0, 'min_vol': 100.0, 'vol_curve': None, 'overflow': OVERFLOW_NO}))
add_pipe(p, ChangeSet({'id': 'p0', 'node1': 'j0', 'node2': 't0', 'length': 100.0, 'diameter': 10.0, 'roughness': 0.1, 'minor_loss': 0.5, 'status': PIPE_STATUS_OPEN }))
set_tank_reaction(p, ChangeSet({'tank': 't0', 'value': 10.0}))
assert is_junction(p, 'j0')
assert is_tank(p, 't0')
assert is_pipe(p, 'p0')
assert get_tank_reaction(p, 't0')['value'] == 10.0
delete_tank(p, ChangeSet({'id': 't0'}))
assert is_junction(p, 'j0')
assert is_tank(p, 't0') == False
assert is_pipe(p, 'p0') == False
assert get_tank_reaction(p, 't0')['value'] == None
execute_undo(p)
assert is_junction(p, 'j0')
assert is_tank(p, 't0')
assert is_pipe(p, 'p0')
assert get_tank_reaction(p, 't0')['value'] == 10.0
execute_redo(p)
assert is_junction(p, 'j0')
assert is_tank(p, 't0') == False
assert is_pipe(p, 'p0') == False
assert get_tank_reaction(p, 't0')['value'] == None
self.leave(p)
# 5 pipe
@@ -963,6 +1085,55 @@ class TestApi:
self.leave(p)
def test_pipe_del(self):
p = 'test_pipe_del'
self.enter(p)
add_junction(p, ChangeSet({'id': 'j0', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}))
add_junction(p, ChangeSet({'id': 'j1', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}))
add_pipe(p, ChangeSet({'id': 'p0', 'node1': 'j0', 'node2': 'j1', 'length': 100.0, 'diameter': 10.0, 'roughness': 0.1, 'minor_loss': 0.5, 'status': PIPE_STATUS_OPEN }))
set_tag(p, ChangeSet({'t_type': TAG_TYPE_LINK, 'id': 'p0', 'tag': 'p0t' }))
set_status(p, ChangeSet({'link': 'p0', 'status': LINK_STATUS_OPEN, 'setting': 10.0}))
set_pipe_reaction(p, ChangeSet({'pipe': 'p0', 'bulk': 10.0, 'wall': 20.0}))
set_vertex(p, ChangeSet({'link' : 'p0', 'coords': [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]}))
assert is_pipe(p, 'p0')
assert get_tag(p, TAG_TYPE_LINK, 'p0')['tag'] == 'p0t'
assert get_status(p, 'p0')['status'] == LINK_STATUS_OPEN
assert get_status(p, 'p0')['setting'] == 10.0
assert get_pipe_reaction(p, 'p0')['bulk'] == 10.0
assert get_pipe_reaction(p, 'p0')['wall'] == 20.0
assert get_vertex(p, 'p0')['coords'] == [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]
delete_pipe(p, ChangeSet({'id': 'p0'}))
assert is_pipe(p, 'p0') == False
assert get_tag(p, TAG_TYPE_LINK, 'p0')['tag'] == None
assert get_status(p, 'p0')['status'] == None
assert get_status(p, 'p0')['setting'] == None
assert get_pipe_reaction(p, 'p0')['bulk'] == None
assert get_pipe_reaction(p, 'p0')['wall'] == None
assert get_vertex(p, 'p0')['coords'] == []
execute_undo(p)
assert is_pipe(p, 'p0')
assert get_tag(p, TAG_TYPE_LINK, 'p0')['tag'] == 'p0t'
assert get_status(p, 'p0')['status'] == LINK_STATUS_OPEN
assert get_status(p, 'p0')['setting'] == 10.0
assert get_pipe_reaction(p, 'p0')['bulk'] == 10.0
assert get_pipe_reaction(p, 'p0')['wall'] == 20.0
assert get_vertex(p, 'p0')['coords'] == [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]
execute_redo(p)
assert is_pipe(p, 'p0') == False
assert get_tag(p, TAG_TYPE_LINK, 'p0')['tag'] == None
assert get_status(p, 'p0')['status'] == None
assert get_status(p, 'p0')['setting'] == None
assert get_pipe_reaction(p, 'p0')['bulk'] == None
assert get_pipe_reaction(p, 'p0')['wall'] == None
assert get_vertex(p, 'p0')['coords'] == []
self.leave(p)
# 6 pump
@@ -1125,6 +1296,51 @@ class TestApi:
self.leave(p)
def test_pump_del(self):
p = 'test_pump_del'
self.enter(p)
add_junction(p, ChangeSet({'id': 'j0', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}))
add_junction(p, ChangeSet({'id': 'j1', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}))
add_pump(p, ChangeSet({'id': 'p0', 'node1': 'j0', 'node2': 'j1', 'power': 0.0}))
set_tag(p, ChangeSet({'t_type': TAG_TYPE_LINK, 'id': 'p0', 'tag': 'p0t' }))
set_status(p, ChangeSet({'link': 'p0', 'status': LINK_STATUS_OPEN, 'setting': 10.0}))
set_pump_energy(p, ChangeSet({'pump' : 'p0', 'price': 1.0}))
set_vertex(p, ChangeSet({'link' : 'p0', 'coords': [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]}))
assert is_pump(p, 'p0')
assert get_tag(p, TAG_TYPE_LINK, 'p0')['tag'] == 'p0t'
assert get_status(p, 'p0')['status'] == LINK_STATUS_OPEN
assert get_status(p, 'p0')['setting'] == 10.0
assert get_pump_energy(p, 'p0')['price'] == 1.0
assert get_vertex(p, 'p0')['coords'] == [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]
delete_pump(p, ChangeSet({'id': 'p0'}))
assert is_pump(p, 'p0') == False
assert get_tag(p, TAG_TYPE_LINK, 'p0')['tag'] == None
assert get_status(p, 'p0')['status'] == None
assert get_status(p, 'p0')['setting'] == None
assert get_pump_energy(p, 'p0')['price'] == None
assert get_vertex(p, 'p0')['coords'] == []
execute_undo(p)
assert is_pump(p, 'p0')
assert get_tag(p, TAG_TYPE_LINK, 'p0')['tag'] == 'p0t'
assert get_status(p, 'p0')['status'] == LINK_STATUS_OPEN
assert get_status(p, 'p0')['setting'] == 10.0
assert get_pump_energy(p, 'p0')['price'] == 1.0
assert get_vertex(p, 'p0')['coords'] == [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]
execute_redo(p)
assert is_pump(p, 'p0') == False
assert get_tag(p, TAG_TYPE_LINK, 'p0')['tag'] == None
assert get_status(p, 'p0')['status'] == None
assert get_status(p, 'p0')['setting'] == None
assert get_pump_energy(p, 'p0')['price'] == None
assert get_vertex(p, 'p0')['coords'] == []
self.leave(p)
# 7 valve
@@ -1310,6 +1526,46 @@ class TestApi:
self.leave(p)
def test_valve_del(self):
p = 'test_valve_del'
self.enter(p)
add_junction(p, ChangeSet({'id': 'j0', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}))
add_junction(p, ChangeSet({'id': 'j1', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}))
add_valve(p, ChangeSet({'id': 'v0', 'node1': 'j0', 'node2': 'j1', 'diameter': 10.0, 'v_type': VALVES_TYPE_FCV, 'setting': 0.1, 'minor_loss': 0.5 }))
set_tag(p, ChangeSet({'t_type': TAG_TYPE_LINK, 'id': 'v0', 'tag': 'v0t' }))
set_status(p, ChangeSet({'link': 'v0', 'status': LINK_STATUS_OPEN, 'setting': 10.0}))
set_vertex(p, ChangeSet({'link' : 'v0', 'coords': [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]}))
assert is_valve(p, 'v0')
assert get_tag(p, TAG_TYPE_LINK, 'v0')['tag'] == 'v0t'
assert get_status(p, 'v0')['status'] == LINK_STATUS_OPEN
assert get_status(p, 'v0')['setting'] == 10.0
assert get_vertex(p, 'v0')['coords'] == [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]
delete_valve(p, ChangeSet({'id': 'v0'}))
assert is_valve(p, 'v0') == False
assert get_tag(p, TAG_TYPE_LINK, 'v0')['tag'] == None
assert get_status(p, 'v0')['status'] == None
assert get_status(p, 'v0')['setting'] == None
assert get_vertex(p, 'v0')['coords'] == []
execute_undo(p)
assert is_valve(p, 'v0')
assert get_tag(p, TAG_TYPE_LINK, 'v0')['tag'] == 'v0t'
assert get_status(p, 'v0')['status'] == LINK_STATUS_OPEN
assert get_status(p, 'v0')['setting'] == 10.0
assert get_vertex(p, 'v0')['coords'] == [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]
execute_redo(p)
assert is_valve(p, 'v0') == False
assert get_tag(p, TAG_TYPE_LINK, 'v0')['tag'] == None
assert get_status(p, 'v0')['status'] == None
assert get_status(p, 'v0')['setting'] == None
assert get_vertex(p, 'v0')['coords'] == []
self.leave(p)
# 8 tag
@@ -1702,6 +1958,55 @@ class TestApi:
self.leave(p)
def test_pattern_del(self):
p = 'test_pattern_del'
self.enter(p)
add_pattern(p, ChangeSet({'id' : 'p0', 'factors': [1.0, 2.0, 3.0]}))
add_junction(p, ChangeSet({'id': 'j0', 'x': 0.0, 'y': 10.0, 'elevation': 20.0, 'pattern': 'p0'}))
add_reservoir(p, ChangeSet({'id': 'r0', 'x': 0.0, 'y': 10.0, 'head': 20.0, 'pattern': 'p0'}))
add_pump(p, ChangeSet({'id': 'pump0', 'node1': 'j0', 'node2': 'r0', 'power': 0.0, 'pattern': 'p0'}))
set_demand(p, ChangeSet({'junction': 'j0', 'demands': [{'demand': 10.0, 'pattern': 'p0', 'category': 'x'}, {'demand': 20.0, 'pattern': 'p0', 'category': None}]}))
set_pump_energy(p, ChangeSet({'pump' : 'pump0', 'pattern': 'p0'}))
add_source(p, ChangeSet({'node': 'j0', 's_type': SOURCE_TYPE_CONCEN, 'strength': 10.0, 'pattern': 'p0' }))
assert is_pattern(p, 'p0')
assert get_junction(p, 'j0')['pattern'] == 'p0'
assert get_reservoir(p, 'r0')['pattern'] == 'p0'
assert get_pump(p, 'pump0')['pattern'] == 'p0'
assert get_demand(p, 'j0')['demands'] == [{'demand': 10.0, 'pattern': 'p0', 'category': 'x'}, {'demand': 20.0, 'pattern': 'p0', 'category': None}]
assert get_pump_energy(p, 'pump0')['pattern'] == 'p0'
assert get_source(p, 'j0')['pattern'] == 'p0'
delete_pattern(p, ChangeSet({'id': 'p0'}))
assert is_pattern(p, 'p0') == False
assert get_junction(p, 'j0')['pattern'] == None
assert get_reservoir(p, 'r0')['pattern'] == None
assert get_pump(p, 'pump0')['pattern'] == None
assert get_demand(p, 'j0')['demands'] == [{'demand': 10.0, 'pattern': None, 'category': 'x'}, {'demand': 20.0, 'pattern': None, 'category': None}]
assert get_pump_energy(p, 'pump0')['pattern'] == None
assert get_source(p, 'j0')['pattern'] == None
execute_undo(p)
assert is_pattern(p, 'p0')
assert get_junction(p, 'j0')['pattern'] == 'p0'
assert get_reservoir(p, 'r0')['pattern'] == 'p0'
assert get_pump(p, 'pump0')['pattern'] == 'p0'
assert get_demand(p, 'j0')['demands'] == [{'demand': 10.0, 'pattern': 'p0', 'category': 'x'}, {'demand': 20.0, 'pattern': 'p0', 'category': None}]
assert get_pump_energy(p, 'pump0')['pattern'] == 'p0'
assert get_source(p, 'j0')['pattern'] == 'p0'
execute_redo(p)
assert is_pattern(p, 'p0') == False
assert get_junction(p, 'j0')['pattern'] == None
assert get_reservoir(p, 'r0')['pattern'] == None
assert get_pump(p, 'pump0')['pattern'] == None
assert get_demand(p, 'j0')['demands'] == [{'demand': 10.0, 'pattern': None, 'category': 'x'}, {'demand': 20.0, 'pattern': None, 'category': None}]
assert get_pump_energy(p, 'pump0')['pattern'] == None
assert get_source(p, 'j0')['pattern'] == None
self.leave(p)
# 12 curve
@@ -1848,6 +2153,42 @@ class TestApi:
self.leave(p)
def test_curve_del(self):
p = 'test_curve_del'
self.enter(p)
add_curve(p, ChangeSet({'id' : 'c0', 'c_type' : CURVE_TYPE_PUMP, 'coords': [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]}))
add_tank(p, ChangeSet({'id': 't0', 'x': 0.0, 'y': 10.0, 'elevation': 20.0, 'init_level': 1.0, 'min_level': 0.0, 'max_level': 2.0, 'diameter': 10.0, 'min_vol': 100.0, 'vol_curve': 'c0', 'overflow': OVERFLOW_NO}))
add_junction(p, ChangeSet({'id': 'j0', 'x': 0.0, 'y': 10.0, 'elevation': 20.0, 'pattern': None}))
add_reservoir(p, ChangeSet({'id': 'r0', 'x': 0.0, 'y': 10.0, 'head': 20.0, 'pattern': None}))
add_pump(p, ChangeSet({'id': 'p0', 'node1': 'j0', 'node2': 'r0', 'head': 'c0'}))
set_pump_energy(p, ChangeSet({'pump' : 'p0', 'effic': 'c0'}))
assert is_curve(p, 'c0')
assert get_tank(p, 't0')['vol_curve'] == 'c0'
assert get_pump(p, 'p0')['head'] == 'c0'
assert get_pump_energy(p, 'p0')['effic'] == 'c0'
delete_curve(p, ChangeSet({'id': 'c0'}))
assert is_curve(p, 'c0') == False
assert get_tank(p, 't0')['vol_curve'] == None
assert get_pump(p, 'p0')['head'] == None
assert get_pump_energy(p, 'p0')['effic'] == None
execute_undo(p)
assert is_curve(p, 'c0')
assert get_tank(p, 't0')['vol_curve'] == 'c0'
assert get_pump(p, 'p0')['head'] == 'c0'
assert get_pump_energy(p, 'p0')['effic'] == 'c0'
execute_redo(p)
assert is_curve(p, 'c0') == False
assert get_tank(p, 't0')['vol_curve'] == None
assert get_pump(p, 'p0')['head'] == None
assert get_pump_energy(p, 'p0')['effic'] == None
self.leave(p)
# 13 control
@@ -2365,6 +2706,8 @@ class TestApi:
add_pattern(p, ChangeSet({'id' : 'p0', 'factors': [1.0, 2.0, 3.0]}))
add_pattern(p, ChangeSet({'id' : 'p1', 'factors': [1.0, 2.0, 3.0]}))
assert get_source(p, 'j0') == {}
add_source(p, ChangeSet({'node': 'j0', 's_type': SOURCE_TYPE_CONCEN, 'strength': 10.0, 'pattern': 'p0'}))
s = get_source(p, 'j0')
assert s['node'] == 'j0'
@@ -2395,6 +2738,8 @@ class TestApi:
delete_source(p, ChangeSet({'node': 'j0'}))
assert get_source(p, 'j0') == {}
self.leave(p)