Skip to content

Commit

Permalink
Merge pull request #582 from idaholab/580-syntaxnode-object-has-no-at…
Browse files Browse the repository at this point in the history
…tribute-_grab_beginning_comment

Fixed SyntaxNode AttributeError.
  • Loading branch information
MicahGale authored Oct 30, 2024
2 parents 2850c97 + e0f324f commit c0bbeba
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 22 deletions.
3 changes: 2 additions & 1 deletion doc/source/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ MontePy Changelog
0.5 releases
============

#Next version#
#Next Version#
--------------

**Bug Fixes**

* Fixed ``AttributeError`` that occured when a data block ``IMP`` was preceded by a comment (:issue:`580`).
* Fixed bug where tally inputs in a file prevented the file from being pickled or copied (:issue:`463`).

0.5.0
Expand Down
7 changes: 6 additions & 1 deletion montepy/data_inputs/cell_modifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,12 @@ def format_for_mcnp_input(self, mcnp_version, has_following=False):
# print in either block
if (self.in_cell_block != print_in_data_block) and self._is_worth_printing:
self._update_values()
return self.wrap_string_for_mcnp(self._format_tree(), mcnp_version, True)
return self.wrap_string_for_mcnp(
self._format_tree(),
mcnp_version,
True,
suppress_blank_end=not self.in_cell_block,
)
return []

@property
Expand Down
66 changes: 53 additions & 13 deletions montepy/data_inputs/importance.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@
from montepy.utilities import *
import numbers

#
# ********************* Developer Notes ********************************************
#
# How Importance handles syntax trees is complicated.
# One object holds information for N particle types.
# This can be associated with between 1 and N syntax trees (imp:n,p v. imp:n imp:p)
#
# Variables
#
# * _tree : the syntax tree from parsing. Only used on initial parsing
# * _real_tree : holds unique trees for every particle type. This is used in data block formatting.
# * _particle_importances : a dictionary of ParameterNodes that maps a particle to it's ParameterNode
# * _part_combos : a list of ParticleNode that show which particles were combined on the original input


class Importance(CellModifierInput):
"""
Expand Down Expand Up @@ -368,22 +382,48 @@ def __delete_common_trailing(self, part):
for combo_set in self._part_combos:
if part in combo_set:
to_delete |= combo_set
for part in to_delete:
self._particle_importances[part]["data"]._delete_trailing_comment()
if self._in_cell_block:
for part in to_delete:
self._particle_importances[part]["data"]._delete_trailing_comment()
else:
for part in to_delete:
self._real_tree[part]._delete_trailing_comment()

def _grab_beginning_comment(self, new_padding):
def _grab_beginning_comment(self, new_padding, last_obj=None):
last_tree = None
last_padding = None
for part, tree in self._particle_importances.items():
if last_padding is not None and last_tree is not None:
last_tree._grab_beginning_comment(last_padding)
self.__delete_common_trailing(part)
last_padding = tree.get_trailing_comment()
last_tree = tree
if new_padding:
next(iter(self._particle_importances.values()))[
"start_pad"
]._grab_beginning_comment(new_padding)
if self._in_cell_block:
if not isinstance(last_obj, Importance):
for part, tree in self._particle_importances.items():
if last_padding is not None and last_tree is not None:
last_tree._grab_beginning_comment(last_padding)
self.__delete_common_trailing(part)
last_padding = tree.get_trailing_comment()
last_tree = tree
if new_padding:
next(iter(self._particle_importances.values()))[
"start_pad"
]._grab_beginning_comment(new_padding)
else:
# if not inside a block of importances
if not isinstance(last_obj, Importance):
for part, tree in self._real_tree.items():
if tree.get_trailing_comment() == last_padding:
continue
if last_padding is not None and last_tree is not None:
last_tree._grab_beginning_comment(last_padding)
self.__delete_common_trailing(part)
last_padding = tree.get_trailing_comment()
last_tree = tree
if new_padding:
next(iter(self._real_tree.values()))[
"start_pad"
]._grab_beginning_comment(new_padding)
# otherwise keep it as is inside the block
else:
list(self._real_tree.values())[-1]["start_pad"]._grab_beginning_comment(
new_padding
)


def _generate_default_data_tree(particle):
Expand Down
29 changes: 29 additions & 0 deletions montepy/input_parser/syntax_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,19 @@ def _delete_trailing_comment(self):
if isinstance(tail, SyntaxNodeBase):
tail._delete_trailing_comment()

def _grab_beginning_comment(self, extra_padding):
"""
Consumes the provided comment, and moves it to the beginning of this node.
:param extra_padding: the padding comment to add to the beginning of this padding.
:type extra_padding: list
"""
if len(self.nodes) == 0 or extra_padding is None:
return
head = self.nodes[0]
if isinstance(head, SyntaxNodeBase):
head._grab_beginning_comment(extra_padding)

def check_for_graveyard_comments(self, has_following_input=False):
"""
Checks if there is a graveyard comment that is preventing information from being part of the tree, and handles
Expand Down Expand Up @@ -260,6 +273,19 @@ def get_trailing_comment(self):
if node:
return node.get_trailing_comment()

def _grab_beginning_comment(self, extra_padding):
"""
Consumes the provided comment, and moves it to the beginning of this node.
:param extra_padding: the padding comment to add to the beginning of this padding.
:type extra_padding: list
"""
if len(self.nodes) == 0 or extra_padding is None:
return
head = next(iter(self.nodes.values()))
if isinstance(head, SyntaxNodeBase):
head._grab_beginning_comment(extra_padding)

def _get_trailing_node(self):
if len(self.nodes) == 0:
return
Expand Down Expand Up @@ -822,6 +848,9 @@ def __repr__(self):
ret += node.format()
return ret

def __eq__(self, other):
return str(self) == str(other)


class ValueNode(SyntaxNodeBase):
"""
Expand Down
12 changes: 10 additions & 2 deletions montepy/mcnp_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,9 @@ def leading_comments(self):
self._tree["start_pad"]._delete_trailing_comment()

@staticmethod
def wrap_string_for_mcnp(string, mcnp_version, is_first_line):
def wrap_string_for_mcnp(
string, mcnp_version, is_first_line, suppress_blank_end=True
):
"""
Wraps the list of the words to be a well formed MCNP input.
Expand All @@ -197,6 +199,9 @@ def wrap_string_for_mcnp(string, mcnp_version, is_first_line):
:param is_first_line: If true this will be the beginning of an MCNP input.
The first line will not be indented.
:type is_first_line: bool
:param suppress_blank_end: Whether or not to suppress any blank lines that would be added to the end.
Good for anywhere but cell modifiers in the cell block.
:type suppress_blank_end: bool
:returns: A list of strings that can be written to an input file, one item to a line.
:rtype: list
"""
Expand Down Expand Up @@ -228,6 +233,9 @@ def wrap_string_for_mcnp(string, mcnp_version, is_first_line):
LineExpansionWarning,
stacklevel=2,
)
# lazy final guard against extra lines
if suppress_blank_end:
buffer = [s for s in buffer if s.strip()]
ret += buffer
return ret

Expand Down Expand Up @@ -282,7 +290,7 @@ def trailing_comment(self):
def _delete_trailing_comment(self):
self._tree._delete_trailing_comment()

def _grab_beginning_comment(self, padding):
def _grab_beginning_comment(self, padding, last_obj=None):
if padding:
self._tree["start_pad"]._grab_beginning_comment(padding)

Expand Down
2 changes: 1 addition & 1 deletion montepy/mcnp_problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ def parse_input(self, check_input=False, replace=True):
if isinstance(obj, transform.Transform):
self._transforms.append(obj, False)
if trailing_comment is not None and last_obj is not None:
obj._grab_beginning_comment(trailing_comment)
obj._grab_beginning_comment(trailing_comment, last_obj)
last_obj._delete_trailing_comment()
trailing_comment = obj.trailing_comment
last_obj = obj
Expand Down
1 change: 1 addition & 0 deletions tests/inputs/test_importance.imcnp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ m3 1001.80c 2
MT3 lwtr.23t
C execution
ksrc 0 0 0
c other special comment for #580
imp:n,p 1 1 1 0 3
c special comment related to #520
imp:e 0 2r 1 r
Expand Down
8 changes: 4 additions & 4 deletions tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -511,9 +511,9 @@ def test_importance_format_unmutated(importance_problem):
imp = importance_problem.cells._importance
output = imp.format_for_mcnp_input((6, 2, 0))
print(output)
assert len(output) == 3
assert "imp:n,p 1 1 1 0 3" == output[0]
assert "imp:e 0 2r 1 r" == output[2]
assert len(output) == 4
assert "imp:n,p 1 1 1 0 3" == output[1]
assert "imp:e 0 2r 1 r" == output[3]


def test_importance_format_mutated(importance_problem):
Expand All @@ -523,7 +523,7 @@ def test_importance_format_mutated(importance_problem):
with pytest.warns(LineExpansionWarning):
output = imp.format_for_mcnp_input((6, 2, 0))
print(output)
assert len(output) == 4
assert len(output) == 6
assert "imp:n 0.5 1 1 0 3" in output
assert "c special comment related to #520" == output[2]

Expand Down

0 comments on commit c0bbeba

Please sign in to comment.