Skip to content

Commit 69c563a

Browse files
committed
Unify networkparser, structs, and rulemod error handling
1 parent 014fe1d commit 69c563a

5 files changed

Lines changed: 122 additions & 13 deletions

File tree

bionetgen/modelapi/rulemod.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
from bionetgen.core.exc import BNGParseError
2+
3+
14
class RuleMod:
25
"""
36
Rule modifiers class for storage and printing.
@@ -42,4 +45,6 @@ def type(self, val):
4245
if val in self.valid_mod_names or val is None:
4346
self._type = val
4447
else:
45-
print(f"Rule modifier type {val} is not a valid type")
48+
raise BNGParseError(
49+
message=f": Rule modifier type {val} is not a valid type"
50+
)

bionetgen/modelapi/structs.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def line_label(self, val) -> None:
6969
try:
7070
ll = int(val)
7171
self._line_label = "{} ".format(ll)
72-
except:
72+
except (TypeError, ValueError):
7373
self._line_label = "{}: ".format(val)
7474

7575
def print_line(self) -> str:
@@ -423,7 +423,12 @@ def set_rate_constants(self, rate_cts):
423423
self.rate_constants = [rate_cts[0], rate_cts[1]]
424424
self.bidirectional = True
425425
else:
426-
print("1 or 2 rate constants allowed")
426+
raise BNGParseError(
427+
message=(
428+
f": Rule {self.name} requires 1 or 2 rate constants, "
429+
f"got {len(rate_cts)}"
430+
)
431+
)
427432

428433
def gen_string(self):
429434
if self.bidirectional:

bionetgen/network/networkparser.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import re, os
2+
from bionetgen.core.exc import BNGParseError
3+
from bionetgen.core.utils.logging import BNGLogger
24
from bionetgen.main import BioNetGen
35
from bionetgen.network.blocks import (
46
NetworkGroupBlock,
@@ -16,6 +18,7 @@
1618
app.setup()
1719
conf = app.config["bionetgen"]
1820
def_bng_path = conf["bngpath"]
21+
logger = BNGLogger()
1922

2023

2124
class BNGNetworkParser:
@@ -92,16 +95,25 @@ def parse_network(self, network_obj) -> None:
9295
spec_block = NetworkSpeciesBlock()
9396
for iline in range(sblock[0] + 1, sblock[1]):
9497
m = re.match("([^#]*)(#.*)?", self.network_lines[iline])
95-
if m.group(1).strip() != "":
96-
splt = m.group(1).split()
98+
if m is None:
99+
continue
100+
line_text = m.group(1) or ""
101+
if line_text.strip() != "":
102+
splt = line_text.split()
103+
if len(splt) < 3:
104+
msg = (
105+
f"Malformed species line at {self.path}:{iline + 1}; "
106+
"expected '<id> <species> <count>', "
107+
f"got {line_text.strip()!r}"
108+
)
109+
logger.error(
110+
msg,
111+
loc=f"{__file__} : BNGNetworkParser.parse_network()",
112+
)
113+
raise BNGParseError(self.path, message=f": {msg}")
97114
sid = splt[0]
98115
name = splt[1]
99-
try:
100-
count = splt[2]
101-
except:
102-
import IPython
103-
104-
IPython.embed()
116+
count = splt[2]
105117
spec_block.add_species(sid, name, count)
106118
network_obj.add_block(spec_block)
107119
# add reactions
@@ -137,4 +149,3 @@ def parse_network(self, network_obj) -> None:
137149
comment = m.group(2)
138150
grps_block.add_group(rid, name, members, comment=comment)
139151
network_obj.add_block(grps_block)
140-
# import IPython,sys;IPython.embed();sys.exit()

bionetgen/network/structs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def line_label(self, val) -> None:
6969
try:
7070
ll = int(val)
7171
self._line_label = "{} ".format(ll)
72-
except:
72+
except (TypeError, ValueError):
7373
self._line_label = "{}: ".format(val)
7474

7575
def print_line(self) -> str:
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
from unittest.mock import patch
2+
3+
import pytest
4+
5+
from bionetgen.core.exc import BNGParseError
6+
from bionetgen.modelapi.rulemod import RuleMod
7+
from bionetgen.modelapi.structs import Parameter, Rule
8+
from bionetgen.network.structs import NetworkObj
9+
10+
11+
class FakePattern:
12+
def __init__(self, text):
13+
self._text = text
14+
15+
def __str__(self):
16+
return self._text
17+
18+
19+
NET_MALFORMED_SPECIES = """\
20+
# NET file
21+
begin species
22+
1 A(b)
23+
end species
24+
"""
25+
26+
27+
def test_networkparser_malformed_species_line_raises_parse_error(tmp_path):
28+
net_file = tmp_path / "bad_species.net"
29+
net_file.write_text(NET_MALFORMED_SPECIES)
30+
from bionetgen.network import networkparser as networkparser_module
31+
from bionetgen.network.network import Network
32+
33+
with patch.object(networkparser_module, "logger") as mock_logger:
34+
with pytest.raises(BNGParseError, match="Malformed species line"):
35+
Network(str(net_file))
36+
37+
mock_logger.error.assert_called_once()
38+
error_args, error_kwargs = mock_logger.error.call_args
39+
assert "Malformed species line" in error_args[0]
40+
assert "expected '<id> <species> <count>'" in error_args[0]
41+
assert "bad_species.net:3" in error_args[0]
42+
assert "BNGNetworkParser.parse_network()" in error_kwargs["loc"]
43+
44+
45+
def test_model_struct_line_label_none_uses_string_fallback():
46+
parameter = Parameter("k1", "1")
47+
parameter.line_label = None
48+
assert parameter.line_label == "None: "
49+
50+
51+
def test_network_struct_line_label_none_uses_string_fallback():
52+
obj = NetworkObj()
53+
obj.line_label = None
54+
assert obj.line_label == "None: "
55+
56+
57+
def test_rule_set_rate_constants_invalid_length_raises_parse_error():
58+
rule = Rule(
59+
name="r",
60+
reactants=[FakePattern("A()")],
61+
products=[FakePattern("B()")],
62+
rate_constants=("k1",),
63+
)
64+
with pytest.raises(BNGParseError, match="1 or 2 rate constants"):
65+
rule.set_rate_constants(("k1", "k2", "k3"))
66+
assert rule.bidirectional is False
67+
assert rule.rate_constants == ["k1"]
68+
69+
70+
def test_rule_init_without_rate_constants_raises_parse_error():
71+
with pytest.raises(BNGParseError, match="1 or 2 rate constants"):
72+
Rule(
73+
name="r",
74+
reactants=[FakePattern("A()")],
75+
products=[FakePattern("B()")],
76+
)
77+
78+
79+
def test_rulemod_invalid_init_raises_parse_error():
80+
with pytest.raises(BNGParseError, match="Rule modifier type InvalidMod"):
81+
RuleMod(mod_type="InvalidMod")
82+
83+
84+
def test_rulemod_invalid_setter_raises_parse_error():
85+
rule_mod = RuleMod()
86+
with pytest.raises(BNGParseError, match="Rule modifier type BadType"):
87+
rule_mod.type = "BadType"
88+
assert rule_mod.type is None

0 commit comments

Comments
 (0)