Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions bionetgen/modelapi/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,30 @@ def gen_string(self) -> str:
return "\n".join(block_lines)


class ProtocolBlock(ActionBlock):
"""
Protocol block object, subclass of ActionBlock.

Protocol lines live inside ``begin model``/``end model`` and must
retain their own begin/end block wrapper rather than being rendered
as top-level actions.
"""

def __init__(self) -> None:
super().__init__()
self.name = "protocol"

def add_item(self, item_tpl) -> None:
_, value = item_tpl
self.items.append(value)

def gen_string(self) -> str:
block_lines = ["\nbegin protocol"]
block_lines.extend(item.print_line() for item in self.items)
block_lines.append("end protocol\n")
return "\n".join(block_lines)


class EnergyPatternBlock(ModelBlock):
"""
Energy pattern block object, subclass of ModelBlock.
Expand Down
41 changes: 35 additions & 6 deletions bionetgen/modelapi/bngfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ def __init__(
self.BNGPATH = BNGPATH
self.bngexec = bngexec
self.parsed_actions = []
# Actions that live inside a ``begin protocol``/``end protocol``
# block, stored separately from top-level actions so BNGParser can
# round-trip them into a ProtocolBlock instead of folding them into
# the top-level ActionBlock.
self.parsed_protocol_actions = []

def generate_xml(self, xml_file, model_file=None) -> bool:
"""
Expand Down Expand Up @@ -155,12 +160,36 @@ def strip_actions(self, model_path, folder) -> str:
# to another line, so we can just remove the action lines
mstr = re.sub(r"\\\n", "", mstr)
mlines = mstr.split("\n")
stripped_lines = list(filter(lambda x: self._not_action(x), mlines))
# remove spaces, actions don't allow them
self.parsed_actions = [
x.replace(" ", "")
for x in filter(lambda x: not self._not_action(x), mlines)
]
# Walk the lines once, separating non-action content (kept in the
# stripped output for BNG2.pl) from action-shaped lines, and
# further splitting action-shaped lines based on whether they sit
# inside a ``begin protocol``/``end protocol`` block. Protocol
# actions are tracked separately so BNGParser can round-trip them
# into a ProtocolBlock instead of the top-level ActionBlock.
self.parsed_actions = []
self.parsed_protocol_actions = []
stripped_lines = []
in_protocol = False
for line in mlines:
if re.match(r"\s*(begin)\s+(protocol)\b", line):
in_protocol = True
stripped_lines.append(line)
continue
if re.match(r"\s*(end)\s+(protocol)\b", line):
in_protocol = False
stripped_lines.append(line)
continue
if self._not_action(line):
stripped_lines.append(line)
continue
# Hand the action line off to BNGParser intact — quoted
# spans (e.g. ``param=>"-v -gml 1000000"``) need to survive
# the whitespace-collapse pass, which `_normalize_action_text`
# does in a quote-aware way.
if in_protocol:
self.parsed_protocol_actions.append(line)
else:
self.parsed_actions.append(line)
# let's remove begin/end actions, rarely used but should be removed
remove_from = -1
remove_to = -1
Expand Down
Loading
Loading