From 72958e5f2c157738b1240d6092341015b28f4d3d Mon Sep 17 00:00:00 2001 From: "Travis J. Labossiere-Hickman" Date: Fri, 7 Feb 2025 11:11:34 -0700 Subject: [PATCH 01/18] New ParticleTypeWarning as parent class --- montepy/errors.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/montepy/errors.py b/montepy/errors.py index 75554649..abf39cac 100644 --- a/montepy/errors.py +++ b/montepy/errors.py @@ -153,10 +153,10 @@ def __init__(self, key, new_value): super().__init__(self.message) -class ParticleTypeNotInProblem(ValueError): +class ParticleTypeWarning(Warning): """ - Raised when data are set for a particle type not in - the problem's mode. + Base class for incongruencies between particle types + in problem mode, cell importances, and tallies """ def __init__(self, message): @@ -164,15 +164,22 @@ def __init__(self, message): super().__init__(message) -class ParticleTypeNotInCell(ValueError): +class ParticleTypeNotInProblem(ParticleTypeWarning): + """ + Raised when data, such as cell importance or tally type, + are set for a particle type not in the problem's mode. + """ + + pass + + +class ParticleTypeNotInCell(ParticleTypeWarning): """ Raised when data for importance data for a particle in the problem is not provided for a cell. """ - def __init__(self, message): - self.message = message - super().__init__(message) + pass class UnsupportedFeature(NotImplementedError): From 228272f7c4922603a2cf09c3feb9b429a0509ee2 Mon Sep 17 00:00:00 2001 From: "Travis J. Labossiere-Hickman" Date: Fri, 7 Feb 2025 11:18:55 -0700 Subject: [PATCH 02/18] Treat ParticleType exceptions as warnings --- montepy/cells.py | 2 -- montepy/data_inputs/importance.py | 13 ++++++++----- montepy/mcnp_problem.py | 4 ---- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/montepy/cells.py b/montepy/cells.py index 2be3e1bb..a6f77993 100644 --- a/montepy/cells.py +++ b/montepy/cells.py @@ -170,8 +170,6 @@ def handle_error(e): except ( BrokenObjectLinkError, MalformedInputError, - ParticleTypeNotInProblem, - ParticleTypeNotInCell, ) as e: handle_error(e) continue diff --git a/montepy/data_inputs/importance.py b/montepy/data_inputs/importance.py index 74bbcab0..72e654a4 100644 --- a/montepy/data_inputs/importance.py +++ b/montepy/data_inputs/importance.py @@ -2,6 +2,7 @@ import collections import copy import math +import warnings from montepy.data_inputs.cell_modifier import CellModifierInput, InitInput from montepy.errors import * from montepy.constants import DEFAULT_VERSION, rel_tol, abs_tol @@ -279,8 +280,9 @@ def _clear_data(self): def _check_particle_in_problem(self, particle_type): if self._problem: if particle_type not in self._problem.mode: - raise ParticleTypeNotInProblem( - f"Particle type: {particle_type} not included in problem mode." + warnings.warn( + f"Particle type: {particle_type} not included in problem mode.", + ParticleTypeNotInProblem ) def _collect_new_values(self): @@ -291,10 +293,12 @@ def _collect_new_values(self): try: tree = cell.importance._particle_importances[particle] except KeyError: - raise ParticleTypeNotInCell( + warnings.warn( f"Importance data not available for cell {cell.number} for particle: " - f"{particle}, though it is in the problem" + f"{particle}, though it is in the problem", + ParticleTypeNotInCell ) + # TODO: define default behavior. new_vals[particle].append(tree["data"][0]) if len(particle_pairings[particle]) == 0: particle_pairings[particle] = tree["classifier"].particles.particles @@ -483,7 +487,6 @@ def __create_particle_imp_doc(particle_type): :type importnace: float :returns: the importance for the particle type. If not set, defaults to 0. :rtype: float -:raises ParticleTypeNotInProblem: raised if this particle is accessed while not in the problem mode. """ diff --git a/montepy/mcnp_problem.py b/montepy/mcnp_problem.py index 247a199a..df0b6527 100644 --- a/montepy/mcnp_problem.py +++ b/montepy/mcnp_problem.py @@ -429,8 +429,6 @@ def handle_error(e): surface.update_pointers(self.surfaces, self._data_inputs) except ( BrokenObjectLinkError, - ParticleTypeNotInProblem, - ParticleTypeNotInCell, ) as e: handle_error(e) to_delete = [] @@ -441,8 +439,6 @@ def handle_error(e): except ( BrokenObjectLinkError, MalformedInputError, - ParticleTypeNotInProblem, - ParticleTypeNotInCell, ) as e: handle_error(e) continue From a159e8ce7dd3e5c6b3997b3dad5fff9a2a0cbd89 Mon Sep 17 00:00:00 2001 From: "Travis J. Labossiere-Hickman" Date: Fri, 7 Feb 2025 11:28:57 -0700 Subject: [PATCH 03/18] Convert test_importance.py from unittest to pytest Also, throughout, 'assertEqual' and 'assertAlmostEqual' were used interchangeably to test floating-point importances. I have changed them all to be 'assert x == y'. Alternatively, one could compare values with 'pytest.approx' --- tests/test_importance.py | 339 +++++++++++++++++++-------------------- 1 file changed, 168 insertions(+), 171 deletions(-) diff --git a/tests/test_importance.py b/tests/test_importance.py index e7b5f4ea..b8793a68 100644 --- a/tests/test_importance.py +++ b/tests/test_importance.py @@ -1,5 +1,4 @@ # Copyright 2024, Battelle Energy Alliance, LLC All Rights Reserved. -from unittest import TestCase import montepy from montepy.cell import Cell from montepy.particle import Particle @@ -7,178 +6,176 @@ from montepy.errors import * from montepy.input_parser import mcnp_input, block_type import os +import pytest -class TestImportance(TestCase): - def test_importance_init_cell(self): - # test_normal cell init - in_str = "1 0 -1 IMP:N,P=1" - card = mcnp_input.Input([in_str], block_type.BlockType.CELL) +def test_importance_init_cell(): + # test_normal cell init + in_str = "1 0 -1 IMP:N,P=1" + card = mcnp_input.Input([in_str], block_type.BlockType.CELL) + cell = Cell(card) + assert cell.importance.neutron == 1.0 + assert cell.importance.photon == 1.0 + assert cell.importance.alpha_particle == 0.0 + assert cell.importance.all is None + assert cell.importance.in_cell_block + # test non-number imp + in_str = "1 0 -1 IMP:N,P=h" + card = mcnp_input.Input([in_str], block_type.BlockType.CELL) + with pytest.raises(ValueError): cell = Cell(card) - self.assertEqual(cell.importance.neutron, 1.0) - self.assertEqual(cell.importance.photon, 1.0) - self.assertEqual(cell.importance.alpha_particle, 0.0) - self.assertIsNone(cell.importance.all) - self.assertTrue(cell.importance.in_cell_block) - # test non-number imp - in_str = "1 0 -1 IMP:N,P=h" - card = mcnp_input.Input([in_str], block_type.BlockType.CELL) - with self.assertRaises(ValueError): - cell = Cell(card) - # test negative imp - in_str = "1 0 -1 IMP:N,P=-2" - card = mcnp_input.Input([in_str], block_type.BlockType.CELL) - with self.assertRaises(ValueError): - cell = Cell(card) - - def test_importance_init_data(self): - in_str = "IMP:N,P 1 0" - card = mcnp_input.Input([in_str], block_type.BlockType.CELL) - imp = Importance(card) - self.assertEqual( - [val.value for val in imp._particle_importances[Particle.NEUTRON]["data"]], - [1.0, 0.0], - ) - self.assertEqual( - [val.value for val in imp._particle_importances[Particle.PHOTON]["data"]], - [1.0, 0.0], - ) - # test non-number imp - in_str = "IMP:N,P 1 h" - card = mcnp_input.Input([in_str], block_type.BlockType.CELL) - with self.assertRaises(ValueError): - imp = Importance(card) - # test negative - in_str = "IMP:N,P 1 -2" - card = mcnp_input.Input([in_str], block_type.BlockType.CELL) - with self.assertRaises(ValueError): - imp = Importance(card) - # test bad in_cell_block - in_str = "IMP:N,P 1 2" - card = mcnp_input.Input([in_str], block_type.BlockType.CELL) - with self.assertRaises(TypeError): - imp = Importance(card, in_cell_block=1) - # test bad key - in_str = "IMP:N,P 1 2" - card = mcnp_input.Input([in_str], block_type.BlockType.CELL) - with self.assertRaises(TypeError): - imp = Importance(card, key=1) - # test bad value - in_str = "IMP:N,P 1 2" - card = mcnp_input.Input([in_str], block_type.BlockType.CELL) - with self.assertRaises(TypeError): - imp = Importance(card, value=1) - - def test_importance_iter_getter_in(self): - in_str = "1 0 -1 IMP:N,P=1" - card = mcnp_input.Input([in_str], block_type.BlockType.CELL) - cell = Cell(card) - imp = cell.importance - particles = [ - montepy.particle.Particle.NEUTRON, - montepy.particle.Particle.PHOTON, - ] - for particle in imp: - self.assertIn(particle, particles) - self.assertAlmostEqual(imp[particle], 1.0) - for particle in particles: - self.assertIn(particle, imp) - with self.assertRaises(TypeError): - imp["hi"] - - def test_importance_all_setter(self): - in_str = "1 0 -1 IMP:N,P=1" - card = mcnp_input.Input([in_str], block_type.BlockType.CELL) - cell = Cell(card) - problem = montepy.mcnp_problem.MCNP_Problem("foo") - problem.mode.add(montepy.particle.Particle.NEUTRON) - problem.mode.add(montepy.particle.Particle.PHOTON) - imp = cell.importance - cell.link_to_problem(problem) - imp.all = 2.0 - self.assertAlmostEqual(imp.neutron, 2.0) - self.assertAlmostEqual(imp.photon, 2.0) - # try wrong type - with self.assertRaises(TypeError): - imp.all = "h" - # try negative type - with self.assertRaises(ValueError): - imp.all = -2.0 - - def test_importance_setter(self): - in_str = "1 0 -1 IMP:N,P=1" - card = mcnp_input.Input([in_str], block_type.BlockType.CELL) + # test negative imp + in_str = "1 0 -1 IMP:N,P=-2" + card = mcnp_input.Input([in_str], block_type.BlockType.CELL) + with pytest.raises(ValueError): cell = Cell(card) - cell.importance.neutron = 2.5 - self.assertEqual(cell.importance.neutron, 2.5) - problem = montepy.mcnp_problem.MCNP_Problem("foo") - cell.link_to_problem(problem) - # test problem mode enforcement - with self.assertRaises(ValueError): - cell.importance.photon = 1.0 - # test wrong type - with self.assertRaises(TypeError): - cell.importance.neutron = "h" - # test negative - with self.assertRaises(ValueError): - cell.importance.neutron = -0.5 - - cell.importance[Particle.NEUTRON] = 3 - self.assertEqual(cell.importance.neutron, 3.0) - with self.assertRaises(TypeError): - cell.importance[""] = 5 - with self.assertRaises(TypeError): - cell.importance[Particle.NEUTRON] = "" - with self.assertRaises(ValueError): - cell.importance[Particle.NEUTRON] = -1.0 - - def test_importance_deleter(self): - in_str = "1 0 -1 IMP:N,P=1" - card = mcnp_input.Input([in_str], block_type.BlockType.CELL) - cell = Cell(card) - del cell.importance.neutron - self.assertAlmostEqual(cell.importance.neutron, 0.0) - del cell.importance[Particle.PHOTON] - self.assertAlmostEqual(cell.importance.photon, 0.0) - with self.assertRaises(TypeError): - del cell.importance[""] - - def test_importance_merge(self): - in_str = "IMP:N,P 1 0" - card = mcnp_input.Input([in_str], block_type.BlockType.DATA) - imp1 = Importance(card) - in_str = "IMP:E 0 0" - card = mcnp_input.Input([in_str], block_type.BlockType.DATA) - imp2 = Importance(card) + + +def test_importance_init_data(): + in_str = "IMP:N,P 1 0" + card = mcnp_input.Input([in_str], block_type.BlockType.CELL) + imp = Importance(card) + assert [ + val.value for val in imp._particle_importances[Particle.NEUTRON]["data"] + ] == [1.0, 0.0] + assert [ + val.value for val in imp._particle_importances[Particle.PHOTON]["data"] + ] == [1.0, 0.0] + # test non-number imp + in_str = "IMP:N,P 1 h" + card = mcnp_input.Input([in_str], block_type.BlockType.CELL) + with pytest.raises(ValueError): + imp = Importance(card) + # test negative + in_str = "IMP:N,P 1 -2" + card = mcnp_input.Input([in_str], block_type.BlockType.CELL) + with pytest.raises(ValueError): + imp = Importance(card) + # test bad in_cell_block + in_str = "IMP:N,P 1 2" + card = mcnp_input.Input([in_str], block_type.BlockType.CELL) + with pytest.raises(TypeError): + imp = Importance(card, in_cell_block=1) + # test bad key + in_str = "IMP:N,P 1 2" + card = mcnp_input.Input([in_str], block_type.BlockType.CELL) + with pytest.raises(TypeError): + imp = Importance(card, key=1) + # test bad value + in_str = "IMP:N,P 1 2" + card = mcnp_input.Input([in_str], block_type.BlockType.CELL) + with pytest.raises(TypeError): + imp = Importance(card, value=1) + + +def test_importance_iter_getter_in(): + in_str = "1 0 -1 IMP:N,P=1" + card = mcnp_input.Input([in_str], block_type.BlockType.CELL) + cell = Cell(card) + imp = cell.importance + particles = [ + montepy.particle.Particle.NEUTRON, + montepy.particle.Particle.PHOTON, + ] + for particle in imp: + assert particle in particles + assert imp[particle] == 1.0 + for particle in particles: + assert particle in imp + with pytest.raises(TypeError): + imp["hi"] + + +def test_importance_all_setter(): + in_str = "1 0 -1 IMP:N,P=1" + card = mcnp_input.Input([in_str], block_type.BlockType.CELL) + cell = Cell(card) + problem = montepy.mcnp_problem.MCNP_Problem("foo") + problem.mode.add(montepy.particle.Particle.NEUTRON) + problem.mode.add(montepy.particle.Particle.PHOTON) + imp = cell.importance + cell.link_to_problem(problem) + imp.all = 2.0 + assert imp.neutron == 2.0 + assert imp.photon == 2.0 + # try wrong type + with pytest.raises(TypeError): + imp.all = "h" + # try negative type + with pytest.raises(ValueError): + imp.all = -2.0 + + +def test_importance_setter(): + in_str = "1 0 -1 IMP:N,P=1" + card = mcnp_input.Input([in_str], block_type.BlockType.CELL) + cell = Cell(card) + cell.importance.neutron = 2.5 + assert cell.importance.neutron == 2.5 + problem = montepy.mcnp_problem.MCNP_Problem("foo") + cell.link_to_problem(problem) + # test problem mode enforcement + with pytest.raises(ValueError): + cell.importance.photon = 1.0 + # test wrong type + with pytest.raises(TypeError): + cell.importance.neutron = "h" + # test negative + with pytest.raises(ValueError): + cell.importance.neutron = -0.5 + + cell.importance[Particle.NEUTRON] = 3 + assert cell.importance.neutron == 3.0 + with pytest.raises(TypeError): + cell.importance[""] = 5 + with pytest.raises(TypeError): + cell.importance[Particle.NEUTRON] = "" + with pytest.raises(ValueError): + cell.importance[Particle.NEUTRON] = -1.0 + + +def test_importance_deleter(): + in_str = "1 0 -1 IMP:N,P=1" + card = mcnp_input.Input([in_str], block_type.BlockType.CELL) + cell = Cell(card) + del cell.importance.neutron + assert cell.importance.neutron == 0.0 + del cell.importance[Particle.PHOTON] + assert cell.importance.photon == 0.0 + with pytest.raises(TypeError): + del cell.importance[""] + + +def test_importance_merge(): + in_str = "IMP:N,P 1 0" + card = mcnp_input.Input([in_str], block_type.BlockType.DATA) + imp1 = Importance(card) + in_str = "IMP:E 0 0" + card = mcnp_input.Input([in_str], block_type.BlockType.DATA) + imp2 = Importance(card) + imp1.merge(imp2) + assert [ + val.value for val in imp1._particle_importances[Particle.NEUTRON]["data"] + ] == [1.0, 0.0] + assert [ + val.value for val in imp1._particle_importances[Particle.ELECTRON]["data"] + ] == [0.0, 0.0] + # test bad type + with pytest.raises(TypeError): + imp1.merge("hi") + # test bad block type + in_str = "1 0 -1 IMP:N,P=1" + card = mcnp_input.Input([in_str], block_type.BlockType.CELL) + cell = Cell(card) + with pytest.raises(ValueError): + imp1.merge(cell.importance) + in_str = "IMP:P 0 0" + card = mcnp_input.Input([in_str], block_type.BlockType.CELL) + imp2 = Importance(card) + with pytest.raises(MalformedInputError): imp1.merge(imp2) - self.assertEqual( - [val.value for val in imp1._particle_importances[Particle.NEUTRON]["data"]], - [1.0, 0.0], - ) - self.assertEqual( - [ - val.value - for val in imp1._particle_importances[Particle.ELECTRON]["data"] - ], - [0.0, 0.0], - ) - # test bad type - with self.assertRaises(TypeError): - imp1.merge("hi") - # test bad block type - in_str = "1 0 -1 IMP:N,P=1" - card = mcnp_input.Input([in_str], block_type.BlockType.CELL) - cell = Cell(card) - with self.assertRaises(ValueError): - imp1.merge(cell.importance) - in_str = "IMP:P 0 0" - card = mcnp_input.Input([in_str], block_type.BlockType.CELL) - imp2 = Importance(card) - with self.assertRaises(MalformedInputError): - imp1.merge(imp2) - - def tests_redundant_importance(self): - with self.assertRaises(MalformedInputError): - montepy.read_input( - os.path.join("tests", "inputs", "test_imp_redundant.imcnp") - ) + + +def tests_redundant_importance(): + with pytest.raises(MalformedInputError): + montepy.read_input(os.path.join("tests", "inputs", "test_imp_redundant.imcnp")) From 63ab5eea6b3c681bdf8db9c850363da1a1f2b128 Mon Sep 17 00:00:00 2001 From: "Travis J. Labossiere-Hickman" Date: Fri, 7 Feb 2025 11:33:40 -0700 Subject: [PATCH 04/18] Unit test for warning, not error --- tests/test_importance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_importance.py b/tests/test_importance.py index b8793a68..6d6a5832 100644 --- a/tests/test_importance.py +++ b/tests/test_importance.py @@ -115,7 +115,7 @@ def test_importance_setter(): problem = montepy.mcnp_problem.MCNP_Problem("foo") cell.link_to_problem(problem) # test problem mode enforcement - with pytest.raises(ValueError): + with pytest.warns(ParticleTypeNotInProblem): cell.importance.photon = 1.0 # test wrong type with pytest.raises(TypeError): From 92f7917e982ccb4d6fe9f2a589d3a186cd22ea8a Mon Sep 17 00:00:00 2001 From: "Travis J. Labossiere-Hickman" Date: Fri, 7 Feb 2025 12:52:13 -0700 Subject: [PATCH 05/18] Format everything with Black. --- montepy/__init__.py | 2 +- montepy/data_inputs/importance.py | 4 ++-- montepy/mcnp_problem.py | 4 +--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/montepy/__init__.py b/montepy/__init__.py index 129a6d62..7f9d02a6 100644 --- a/montepy/__init__.py +++ b/montepy/__init__.py @@ -1,5 +1,5 @@ # Copyright 2024, Battelle Energy Alliance, LLC All Rights Reserved. -""" MontePy is a library for reading, editing, and writing MCNP input files. +"""MontePy is a library for reading, editing, and writing MCNP input files. This creates a semantic understanding of the MCNP input file. start by running montepy.read_input(). diff --git a/montepy/data_inputs/importance.py b/montepy/data_inputs/importance.py index 72e654a4..64ca4564 100644 --- a/montepy/data_inputs/importance.py +++ b/montepy/data_inputs/importance.py @@ -282,7 +282,7 @@ def _check_particle_in_problem(self, particle_type): if particle_type not in self._problem.mode: warnings.warn( f"Particle type: {particle_type} not included in problem mode.", - ParticleTypeNotInProblem + ParticleTypeNotInProblem, ) def _collect_new_values(self): @@ -296,7 +296,7 @@ def _collect_new_values(self): warnings.warn( f"Importance data not available for cell {cell.number} for particle: " f"{particle}, though it is in the problem", - ParticleTypeNotInCell + ParticleTypeNotInCell, ) # TODO: define default behavior. new_vals[particle].append(tree["data"][0]) diff --git a/montepy/mcnp_problem.py b/montepy/mcnp_problem.py index df0b6527..3a03aa6e 100644 --- a/montepy/mcnp_problem.py +++ b/montepy/mcnp_problem.py @@ -427,9 +427,7 @@ def handle_error(e): for surface in self._surfaces: try: surface.update_pointers(self.surfaces, self._data_inputs) - except ( - BrokenObjectLinkError, - ) as e: + except (BrokenObjectLinkError,) as e: handle_error(e) to_delete = [] for data_index, data_input in enumerate(self._data_inputs): From a18585ba4abb01ec82660877f47cf5bb68ace759 Mon Sep 17 00:00:00 2001 From: "Travis J. Labossiere-Hickman" Date: Fri, 7 Feb 2025 12:53:11 -0700 Subject: [PATCH 06/18] Update changelog --- doc/source/changelog.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/changelog.rst b/doc/source/changelog.rst index 28d9dc30..b92223c9 100644 --- a/doc/source/changelog.rst +++ b/doc/source/changelog.rst @@ -23,6 +23,7 @@ MontePy Changelog * Added ability to parse all MCNP objects from a string (:issue:`88`). * Added function: :func:`~montepy.mcnp_problem.MCNP_Problem.parse` to parse arbitrary MCNP object (:issue:`88`). * An error is now raised when typos in object attributes are used, e.g., ``cell.nubmer`` (:issue:`508`). +* Particle type exceptions are now warnings, not errors (:issue:`381`). **Bugs Fixed** From b343454771a176b9513d9e482ea39fcd1ed9483b Mon Sep 17 00:00:00 2001 From: "Travis J. Labossiere-Hickman" Date: Fri, 7 Feb 2025 14:06:53 -0700 Subject: [PATCH 07/18] Make default importance a NotImplementedError --- montepy/data_inputs/importance.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/montepy/data_inputs/importance.py b/montepy/data_inputs/importance.py index 64ca4564..635dbeba 100644 --- a/montepy/data_inputs/importance.py +++ b/montepy/data_inputs/importance.py @@ -293,12 +293,11 @@ def _collect_new_values(self): try: tree = cell.importance._particle_importances[particle] except KeyError: - warnings.warn( + raise NotImplementedError( f"Importance data not available for cell {cell.number} for particle: " - f"{particle}, though it is in the problem", - ParticleTypeNotInCell, + f"{particle}, though it is in the problem, and default importance logic " + "is not yet implemented in MontePy." ) - # TODO: define default behavior. new_vals[particle].append(tree["data"][0]) if len(particle_pairings[particle]) == 0: particle_pairings[particle] = tree["classifier"].particles.particles From e90c5a32858b8bba2609c0a76b480d3b453e628b Mon Sep 17 00:00:00 2001 From: "Travis J. Labossiere-Hickman" Date: Fri, 7 Feb 2025 16:01:18 -0700 Subject: [PATCH 08/18] Test the new NotImplementedError --- tests/test_importance.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/test_importance.py b/tests/test_importance.py index 6d6a5832..8a1ec310 100644 --- a/tests/test_importance.py +++ b/tests/test_importance.py @@ -6,6 +6,7 @@ from montepy.errors import * from montepy.input_parser import mcnp_input, block_type import os +import io import pytest @@ -176,6 +177,13 @@ def test_importance_merge(): imp1.merge(imp2) -def tests_redundant_importance(): +def test_redundant_importance(): with pytest.raises(MalformedInputError): montepy.read_input(os.path.join("tests", "inputs", "test_imp_redundant.imcnp")) + + +def test_not_imp(): + prob = montepy.read_input(os.path.join("tests", "inputs", "test_not_imp.imcnp")) + prob.print_in_data_block["imp"] = True + with pytest.raises(NotImplementedError): + prob.write_problem(io.StringIO()) From 9d476b9a345221f10baaa9f3cd408546e6a51852 Mon Sep 17 00:00:00 2001 From: "Travis J. Labossiere-Hickman" Date: Fri, 7 Feb 2025 16:07:52 -0700 Subject: [PATCH 09/18] oops forgot to commit the file --- tests/inputs/test_not_imp.imcnp | 48 +++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 tests/inputs/test_not_imp.imcnp diff --git a/tests/inputs/test_not_imp.imcnp b/tests/inputs/test_not_imp.imcnp new file mode 100644 index 00000000..62da55c0 --- /dev/null +++ b/tests/inputs/test_not_imp.imcnp @@ -0,0 +1,48 @@ +A test with a default importance (Not Implemented) +C cells +c +1 1 20 + -1000 $ dollar comment + U=350 trcl=5 + imp:n,p=1 $ imp:e should default to 1 +2 2 8 + -1005 + imp:n,p=1 $ imp:e should default to 1 +3 3 -1 + 1000 1005 -1010 + imp:n=3 $ imp:e and imp:p should default to 1 +99 0 + 1010 + imp:n=9 $ imp:e should default to 1 + imp:p=0 +5 0 + #99 + imp:n=0 $ imp:e should default to 0 + imp:p=0 +c foo end comment + +C surfaces +1000 SO 1 +1005 RCC 0 1.5 -0.5 0 0 1 0.25 +1010 SO 3 + +C data +C materials +C UO2 5 atpt enriched +m1 92235.80c 5 & +92238.80c 95 +C Iron +m2 26054.80c 5.85 + 26056.80c 91.75 + 26057.80c 2.12 + 26058.80c 0.28 +C water +m3 1001.80c 2 + 8016.80c 1 +MT3 lwtr.23t +C execution +ksrc 0 0 0 +kcode 100000 1.000 50 1050 +phys:p j 1 2j 1 +mode n p e + From 40fed3254f3a8731d083b4dc8703eb6e618b5d28 Mon Sep 17 00:00:00 2001 From: "Travis J. Labossiere-Hickman" Date: Fri, 7 Feb 2025 16:30:45 -0700 Subject: [PATCH 10/18] Give the test a more descriptive name. --- tests/test_importance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_importance.py b/tests/test_importance.py index 8a1ec310..fa4313e2 100644 --- a/tests/test_importance.py +++ b/tests/test_importance.py @@ -182,7 +182,7 @@ def test_redundant_importance(): montepy.read_input(os.path.join("tests", "inputs", "test_imp_redundant.imcnp")) -def test_not_imp(): +def test_default_importance_not_implemented(): prob = montepy.read_input(os.path.join("tests", "inputs", "test_not_imp.imcnp")) prob.print_in_data_block["imp"] = True with pytest.raises(NotImplementedError): From 3c6c18d7fc6cf923baf102d71e8a157991d2b0e9 Mon Sep 17 00:00:00 2001 From: "Micah D. Gale" Date: Fri, 7 Feb 2025 20:06:32 -0600 Subject: [PATCH 11/18] Added a long line comment to test #188 --- tests/inputs/test.imcnp | 2 +- tests/inputs/test_universe.imcnp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/inputs/test.imcnp b/tests/inputs/test.imcnp index 767df6b0..4029f809 100644 --- a/tests/inputs/test.imcnp +++ b/tests/inputs/test.imcnp @@ -41,7 +41,7 @@ C Iron m2 26054.80c 5.85 plib= 80p 26056.80c 91.75 - 26057.80c 2.12 + 26057.80c 2.12 $ very very very very very very very very very very very very very very long line that exceeds line limit 26058.80c 0.28 $ trailing comment shouldn't move #458. C water C foo diff --git a/tests/inputs/test_universe.imcnp b/tests/inputs/test_universe.imcnp index 59cf99d5..57eca507 100644 --- a/tests/inputs/test_universe.imcnp +++ b/tests/inputs/test_universe.imcnp @@ -24,6 +24,7 @@ c c foo end comment C surfaces +c this comment is a ver very very very very very very very very very long line in a comment that shouldn't raise a warning but maybe? 1000 SO 1 1005 RCC 0 1.5 -0.5 0 0 1 0.25 1010 SO 3 From eee87baa4f9ce0c32e4992eaa5116d2512149e6b Mon Sep 17 00:00:00 2001 From: "Micah D. Gale" Date: Fri, 7 Feb 2025 20:58:16 -0600 Subject: [PATCH 12/18] Made RE for finding C style comment --- montepy/__init__.py | 4 ++-- montepy/constants.py | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/montepy/__init__.py b/montepy/__init__.py index 129a6d62..921b44ae 100644 --- a/montepy/__init__.py +++ b/montepy/__init__.py @@ -1,5 +1,5 @@ -# Copyright 2024, Battelle Energy Alliance, LLC All Rights Reserved. -""" MontePy is a library for reading, editing, and writing MCNP input files. +# Copyright 2024-2025, Battelle Energy Alliance, LLC All Rights Reserved. +"""MontePy is a library for reading, editing, and writing MCNP input files. This creates a semantic understanding of the MCNP input file. start by running montepy.read_input(). diff --git a/montepy/constants.py b/montepy/constants.py index abe1091f..79d9ae17 100644 --- a/montepy/constants.py +++ b/montepy/constants.py @@ -1,4 +1,6 @@ -# Copyright 2024, Battelle Energy Alliance, LLC All Rights Reserved. +# Copyright 2024-2025, Battelle Energy Alliance, LLC All Rights Reserved. +import re + from montepy.errors import UnsupportedFeature """ @@ -25,6 +27,11 @@ Number of spaces in a new line before it's considered a continuation. """ +COMMENT_FINDER = re.compile(rf"\s{{0,{BLANK_SPACE_CONTINUE - 1}}}c", re.IGNORECASE) +""" +A regular expression for finding the start of a ``c`` style comment. +""" + LINE_LENGTH = { (5, 1, 60): 80, (6, 1, 0): 80, From 6327dba320679b9d1cf3421d076341919524612f Mon Sep 17 00:00:00 2001 From: "Micah D. Gale" Date: Fri, 7 Feb 2025 20:59:46 -0600 Subject: [PATCH 13/18] Added line overrun warning supression for comments. --- montepy/input_parser/input_syntax_reader.py | 28 ++++++++++++++------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/montepy/input_parser/input_syntax_reader.py b/montepy/input_parser/input_syntax_reader.py index 086ca917..f7b7de86 100644 --- a/montepy/input_parser/input_syntax_reader.py +++ b/montepy/input_parser/input_syntax_reader.py @@ -1,17 +1,21 @@ -# Copyright 2024, Battelle Energy Alliance, LLC All Rights Reserved. -from .block_type import BlockType +# Copyright 2024-2025, Battelle Energy Alliance, LLC All Rights Reserved. from collections import deque -from .. import errors import itertools import io +import re +import os +import warnings + + +from .block_type import BlockType +from .. import errors from montepy.constants import * from montepy.errors import * from montepy.input_parser.input_file import MCNP_InputFile from montepy.input_parser.mcnp_input import Input, Message, ReadInput, Title from montepy.input_parser.read_parser import ReadParser from montepy.utilities import is_comment -import os -import warnings + reading_queue = [] @@ -179,10 +183,16 @@ def flush_input(): old_line = line line = line[:line_length] if len(old_line) != len(line): - warnings.warn( - f"The line: {old_line} exceeded the allowed line length of: {line_length} for MCNP {mcnp_version}", - errors.LineOverRunWarning, - ) + if len(line.split("$")[0]) >= line_length and not COMMENT_FINDER.match( + line + ): + warnings.warn( + f"The line: {old_line} exceeded the allowed line length of: {line_length} for MCNP {mcnp_version}", + errors.LineOverRunWarning, + ) + # if extra length is a comment keep it long + else: + line = old_line if line.endswith(" &\n"): continue_input = True else: From d968f4b750c31214c1a41c3de04fa37edde94012 Mon Sep 17 00:00:00 2001 From: "Micah D. Gale" Date: Fri, 7 Feb 2025 21:00:29 -0600 Subject: [PATCH 14/18] Supressed line wrapping for comments. --- montepy/mcnp_object.py | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/montepy/mcnp_object.py b/montepy/mcnp_object.py index 54e15f63..dedb36d4 100644 --- a/montepy/mcnp_object.py +++ b/montepy/mcnp_object.py @@ -1,4 +1,4 @@ -# Copyright 2024, Battelle Energy Alliance, LLC All Rights Reserved. +# Copyright 2024-2025, Battelle Energy Alliance, LLC All Rights Reserved. from __future__ import annotations from abc import ABC, ABCMeta, abstractmethod import copy @@ -14,6 +14,7 @@ from montepy.errors import * from montepy.constants import ( BLANK_SPACE_CONTINUE, + COMMENT_FINDER, get_max_line_length, rel_tol, abs_tol, @@ -324,17 +325,26 @@ def wrap_string_for_mcnp( for line in strings: buffer = wrapper.wrap(line) if len(buffer) > 1: - warning = LineExpansionWarning( - f"The line exceeded the maximum length allowed by MCNP, and was split. The line was:\n{line}" - ) - warning.cause = "line" - warning.og_value = line - warning.new_value = buffer - warnings.warn( - warning, - LineExpansionWarning, - stacklevel=2, - ) + # don't warn for comments, nor line wrap + # this order assumes that comment overruns are rare + if COMMENT_FINDER.match(line): + buffer = [line] + elif "$" in line: + parts = line.split("$") + buffer = wrapper.wrap(parts[0]) + buffer[-1] = "$".join([buffer[-1]] + parts[1:]) + else: + warning = LineExpansionWarning( + f"The line exceeded the maximum length allowed by MCNP, and was split. The line was:\n{line}" + ) + warning.cause = "line" + warning.og_value = line + warning.new_value = buffer + warnings.warn( + warning, + LineExpansionWarning, + stacklevel=2, + ) # lazy final guard against extra lines if suppress_blank_end: buffer = [s for s in buffer if s.strip()] From 87155646eb5495e637e236564019e625c6464c5a Mon Sep 17 00:00:00 2001 From: "Micah D. Gale" Date: Fri, 7 Feb 2025 21:02:26 -0600 Subject: [PATCH 15/18] Added #188 to changelog. --- doc/source/changelog.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/changelog.rst b/doc/source/changelog.rst index 28d9dc30..f9c1b7e6 100644 --- a/doc/source/changelog.rst +++ b/doc/source/changelog.rst @@ -23,6 +23,7 @@ MontePy Changelog * Added ability to parse all MCNP objects from a string (:issue:`88`). * Added function: :func:`~montepy.mcnp_problem.MCNP_Problem.parse` to parse arbitrary MCNP object (:issue:`88`). * An error is now raised when typos in object attributes are used, e.g., ``cell.nubmer`` (:issue:`508`). +* Warnings are no longer raised for comments that exceed the maximum line lengths (:issue:`188`). **Bugs Fixed** From e52ed00a353556829178748e91494fd32f425b10 Mon Sep 17 00:00:00 2001 From: "Micah D. Gale" Date: Sat, 8 Feb 2025 11:29:32 -0600 Subject: [PATCH 16/18] Harmonized imports to meet dev standards. --- montepy/input_parser/input_syntax_reader.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/montepy/input_parser/input_syntax_reader.py b/montepy/input_parser/input_syntax_reader.py index f7b7de86..ab2c0995 100644 --- a/montepy/input_parser/input_syntax_reader.py +++ b/montepy/input_parser/input_syntax_reader.py @@ -6,11 +6,9 @@ import os import warnings - -from .block_type import BlockType -from .. import errors from montepy.constants import * from montepy.errors import * +from montepy.input_parser.block_type import BlockType from montepy.input_parser.input_file import MCNP_InputFile from montepy.input_parser.mcnp_input import Input, Message, ReadInput, Title from montepy.input_parser.read_parser import ReadParser @@ -178,7 +176,7 @@ def flush_input(): yield from flush_input() # die if it is a vertical syntax format if "#" in line[0:BLANK_SPACE_CONTINUE] and not line_is_comment: - raise errors.UnsupportedFeature("Vertical Input format is not allowed") + raise UnsupportedFeature("Vertical Input format is not allowed") # cut line down to allowed length old_line = line line = line[:line_length] @@ -188,7 +186,7 @@ def flush_input(): ): warnings.warn( f"The line: {old_line} exceeded the allowed line length of: {line_length} for MCNP {mcnp_version}", - errors.LineOverRunWarning, + LineOverRunWarning, ) # if extra length is a comment keep it long else: From bcc3e12d57c2b17294074b61822274064359900b Mon Sep 17 00:00:00 2001 From: "Micah D. Gale" Date: Sat, 8 Feb 2025 11:29:55 -0600 Subject: [PATCH 17/18] pinned black for the time being to 2025 releases. --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 534fc7f9..ebf8b482 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,7 +57,7 @@ doc = [ "sphinx_autodoc_typehints", "autodocsumm", ] -format = ["black>=23.3.0"] +format = ["black~=25.1"] build = [ "build", "setuptools>=64.0.0", From bf92f6b09828c820f68f511b5830d4c3cbc09e30 Mon Sep 17 00:00:00 2001 From: "Travis J. Labossiere-Hickman" Date: Sat, 8 Feb 2025 10:40:39 -0700 Subject: [PATCH 18/18] Update PR template to match pinned black version --- .github/pull_request_template.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 62231dfe..0564b1f6 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -12,6 +12,7 @@ Fixes # (issue number) - [ ] I have performed a self-review of my own code. - [ ] The code follows the standards outlined in the [development documentation](https://idaholab.github.io/MontePy/developing.html). +- [ ] I have formatted my code with `black` version 25. - [ ] I have added tests that prove my fix is effective or that my feature works (if applicable). ---