Repository: idaholab/MontePy

Issue:
Surfaces can't be unset from is_reflecting
**Describe the bug**

This seems to be closely tied to #698. When you parse a surface, set `is_reflecting=False` and then export it, the output is not updated. 

**To Reproduce**


``` python
In [1]: import montepy

In [2]: surf = montepy.surfaces.Surface("*1 P 0.0")

In [3]: surf.is_reflecting = False

In [4]: surf.is_reflecting
Out[4]: False

In [5]: surf.format_for_mcnp_input((6,2,0))
Out[5]: ['*1 P 0.0']
```

**Version**

 - Version 1.0.0a3



Discussion:

Patch:
diff --git a/doc/source/changelog.rst b/doc/source/changelog.rst
index cb72a5e1..e14f48a3 100644
--- a/doc/source/changelog.rst
+++ b/doc/source/changelog.rst
@@ -37,6 +37,7 @@ MontePy Changelog
 * Fixed bug where setting a lattice would print as ``LAT=None``. Also switched ``CellModifier`` to print in the cell block by default (:issue:`699`). 
 * Fixed bug that wouldn't allow cloning most surfaces (:issue:`704`).
 * Fixed bug that crashed when some cells were not assigned to any universes (:issue:`705`).
+* Fixed bug where setting ``surf.is_reflecting`` to ``False`` did not always get exported properly (:issue:`709`).
  
 **Breaking Changes**
 
diff --git a/montepy/input_parser/syntax_node.py b/montepy/input_parser/syntax_node.py
index 80f13679..3e26cfab 100644
--- a/montepy/input_parser/syntax_node.py
+++ b/montepy/input_parser/syntax_node.py
@@ -1328,9 +1328,14 @@ class ValueNode(SyntaxNodeBase):
         else:
             pad_str = ""
             extra_pad_str = ""
-        buffer = "{temp:<{value_length}}{padding}".format(
-            temp=temp, padding=pad_str, **self._formatter
-        )
+        if not self.never_pad:
+            buffer = "{temp:<{value_length}}{padding}".format(
+                temp=temp, padding=pad_str, **self._formatter
+            )
+        else:
+            buffer = "{temp}{padding}".format(
+                temp=temp, padding=pad_str, **self._formatter
+            )
         """
         If:
             1. expanded
diff --git a/montepy/mcnp_object.py b/montepy/mcnp_object.py
index eb9cfc20..71d190fe 100644
--- a/montepy/mcnp_object.py
+++ b/montepy/mcnp_object.py
@@ -161,11 +161,16 @@ class MCNP_Object(ABC, metaclass=_ExceptionContextAdder):
             )
 
     @staticmethod
-    def _generate_default_node(value_type: type, default, padding: str = " "):
+    def _generate_default_node(
+        value_type: type, default: str, padding: str = " ", never_pad: bool = False
+    ):
         """Generates a "default" or blank ValueNode.
 
         None is generally a safe default value to provide.
 
+        .. versionchanged:: 1.0.0
+            Added ``never_pad`` argument.
+
         Parameters
         ----------
         value_type : Class
@@ -176,6 +181,8 @@ class MCNP_Object(ABC, metaclass=_ExceptionContextAdder):
         padding : str, None
             the string to provide to the PaddingNode. If None no
             PaddingNode will be added.
+        never_pad: bool
+            Whether to never add trailing padding. True means extra padding is suppressed.
 
         Returns
         -------
@@ -187,8 +194,8 @@ class MCNP_Object(ABC, metaclass=_ExceptionContextAdder):
         else:
             padding_node = None
         if default is None or isinstance(default, montepy.input_parser.mcnp_input.Jump):
-            return ValueNode(default, value_type, padding_node)
-        return ValueNode(str(default), value_type, padding_node)
+            return ValueNode(default, value_type, padding_node, never_pad)
+        return ValueNode(str(default), value_type, padding_node, never_pad)
 
     @property
     def parameters(self) -> dict[str, str]:
diff --git a/montepy/surfaces/surface.py b/montepy/surfaces/surface.py
index 8df9621d..2660f80a 100644
--- a/montepy/surfaces/surface.py
+++ b/montepy/surfaces/surface.py
@@ -64,7 +64,7 @@ class Surface(Numbered_MCNP_Object):
                 elif "+" in self._number.token:
                     self._is_white_boundary = True
                     self._number._token = self._number.token.replace("+", "")
-                    self._modifier = self._generate_default_node(str, "+", None)
+                    self._modifier = self._generate_default_node(str, "+", None, True)
                     self._tree["surface_num"].nodes["modifier"] = self._modifier
             try:
                 assert self._number.value > 0
@@ -289,6 +289,8 @@ class Surface(Numbered_MCNP_Object):
             modifier.value = "*"
         elif self.is_white_boundary:
             modifier.value = "+"
+        else:
+            modifier.value = ""
         if self.transform is not None:
             self._old_transform_number.value = self.transform.number
             self._old_transform_number.is_negative = False


Test patch:
diff --git a/tests/test_surfaces.py b/tests/test_surfaces.py
index d2ca57d3..52f96207 100644
--- a/tests/test_surfaces.py
+++ b/tests/test_surfaces.py
@@ -1,5 +1,7 @@
 # Copyright 2024-2025, Battelle Energy Alliance, LLC All Rights Reserved.
+import io
 from unittest import TestCase
+from pathlib import Path
 import pytest
 
 import montepy
@@ -129,26 +131,6 @@ class testSurfaces(TestCase):
         with self.assertRaises(montepy.errors.IllegalState):
             surf.validate()
 
-    def test_surface_is_reflecting_setter(self):
-        in_str = "1 PZ 0.0"
-        card = Input([in_str], BlockType.SURFACE)
-        surf = Surface(card)
-        surf.is_reflecting = True
-        self.assertTrue(surf.is_reflecting)
-        self.verify_export(surf)
-        with self.assertRaises(TypeError):
-            surf.is_reflecting = 1
-
-    def test_surface_is_white_bound_setter(self):
-        in_str = "1 PZ 0.0"
-        card = Input([in_str], BlockType.SURFACE)
-        surf = Surface(card)
-        surf.is_white_boundary = True
-        self.assertTrue(surf.is_white_boundary)
-        self.verify_export(surf)
-        with self.assertRaises(TypeError):
-            surf.is_white_boundary = 1
-
     def test_surface_constants_setter(self):
         in_str = "1 PZ 0.0"
         card = Input([in_str], BlockType.SURFACE)
@@ -315,24 +297,36 @@ class testSurfaces(TestCase):
         with self.assertRaises(ValueError):
             surf.coordinates = [3, 4, 5]
 
-    def verify_export(_, surf):
-        output = surf.format_for_mcnp_input((6, 3, 0))
-        print("Surface output", output)
-        new_surf = Surface("\n".join(output))
-        assert surf.number == new_surf.number, "Material number not preserved."
-        assert len(surf.surface_constants) == len(
-            new_surf.surface_constants
-        ), "number of surface constants not kept."
-        for old_const, new_const in zip(
-            surf.surface_constants, new_surf.surface_constants
-        ):
-            assert old_const == pytest.approx(new_const)
-        assert surf.is_reflecting == new_surf.is_reflecting
-        assert surf.is_white_boundary == new_surf.is_white_boundary
-        if surf.old_periodic_surface:
-            assert surf.old_periodic_surface == new_surf.old_periodic_surface
-        if surf.old_transform_number:
-            assert surf.old_transform_number == new_surf._old_transform_number
+
+def verify_export(surf):
+    output = surf.format_for_mcnp_input((6, 3, 0))
+    print("Surface output", output)
+    new_surf = Surface("\n".join(output))
+    verify_equiv_surf(surf, new_surf)
+
+
+def verify_equiv_surf(surf, new_surf):
+    assert surf.number == new_surf.number, "Material number not preserved."
+    assert len(surf.surface_constants) == len(
+        new_surf.surface_constants
+    ), "number of surface constants not kept."
+    for old_const, new_const in zip(surf.surface_constants, new_surf.surface_constants):
+        assert old_const == pytest.approx(new_const)
+    assert surf.is_reflecting == new_surf.is_reflecting
+    assert surf.is_white_boundary == new_surf.is_white_boundary
+    if surf.old_periodic_surface:
+        assert surf.old_periodic_surface == new_surf.old_periodic_surface
+    if surf.old_transform_number:
+        assert surf.old_transform_number == new_surf._old_transform_number
+
+
+def verify_prob_export(problem, surf):
+    with io.StringIO() as fh:
+        problem.write_problem(fh)
+        fh.seek(0)
+        new_problem = montepy.read_input(fh)
+    new_surf = new_problem.surfaces[surf.number]
+    verify_equiv_surf(surf, new_surf)
 
 
 @pytest.mark.parametrize(
@@ -345,3 +339,41 @@ def test_surface_clone(surf_str):
     new_surf = surf.clone()
     assert surf.surface_type == new_surf.surface_type
     assert surf.surface_constants == new_surf.surface_constants
+
+
+@pytest.fixture
+def simple_problem(scope="module"):
+    return montepy.read_input(Path("tests") / "inputs" / "test.imcnp")
+
+
+@pytest.fixture
+def cp_simple_problem(simple_problem):
+    return simple_problem.clone()
+
+
+@pytest.mark.parametrize(
+    "in_str, expected",
+    [("1 PZ 0.0", True), ("*1 PZ 0.0", False), ("    *1 PZ 0.0", False)],
+)
+def test_surface_is_reflecting_setter(cp_simple_problem, in_str, expected):
+    surf = Surface(in_str)
+    surf.is_reflecting = expected
+    assert surf.is_reflecting == expected
+    cp_simple_problem.surfaces.append(surf)
+    verify_prob_export(cp_simple_problem, surf)
+    with pytest.raises(TypeError):
+        surf.is_reflecting = 1
+
+
+@pytest.mark.parametrize(
+    "in_str, expected",
+    [("1 PZ 0.0", True), ("+1 PZ 0.0", False), ("    +1 PZ 0.0", False)],
+)
+def test_surface_is_white_bound_setter(cp_simple_problem, in_str, expected):
+    surf = Surface(in_str)
+    surf.is_white_boundary = expected
+    assert surf.is_white_boundary == expected
+    cp_simple_problem.surfaces.append(surf)
+    verify_prob_export(cp_simple_problem, surf)
+    with pytest.raises(TypeError):
+        surf.is_white_boundary = 1