diff --git a/CHANGELOG.md b/CHANGELOG.md index 074e28af0..e09bd6ab8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). Attention: The newest changes should be on top --> ### Added +- ENH: Custom Exception errors and messages [#285](https://github.com/RocketPy-Team/RocketPy/issues/285) - ENH: Tank Fluids with Variable Density from Temperature and Pressure [#852](https://github.com/RocketPy-Team/RocketPy/pull/852) - ENH: Controller (AirBrakes) and Sensors Encoding [#849](https://github.com/RocketPy-Team/RocketPy/pull/849) - EHN: Addition of ensemble variable to ECMWF dictionaries [#842](https://github.com/RocketPy-Team/RocketPy/pull/842) diff --git a/rocketpy/rocket/rocket.py b/rocketpy/rocket/rocket.py index 1112a98f3..00a76c3a1 100644 --- a/rocketpy/rocket/rocket.py +++ b/rocketpy/rocket/rocket.py @@ -384,6 +384,35 @@ def __init__( # pylint: disable=too-many-statements self.prints = _RocketPrints(self) self.plots = _RocketPlots(self) + def _check_missing_components(self): + """Check if the rocket is missing any essential components and issue a warning. + + This method verifies whether the rocket has the following key components: + - motor + - parachute(s) + - aerodynamic surface(s) + + If any of these components are missing, a single warning message is issued + listing all missing components. This helps users quickly identify potential + issues before running simulations or analyses. + + Notes: + - The warning uses Python's built-in `warnings.warn` function. + """ + missing_components = [] + if isinstance(self.motor, EmptyMotor): + missing_components.append("motor") + if not self.parachutes: + missing_components.append("parachutes") + if not self.aerodynamic_surfaces or len(self.aerodynamic_surfaces) == 0: + missing_components.append("aerodynamic surfaces") + + if missing_components: + component_list = ", ".join(missing_components) + warnings.warn( + f"[WARNING] Rocket has no {component_list} defined.", UserWarning + ) + @property def nosecones(self): """A list containing all the nose cones currently added to the rocket.""" diff --git a/tests/unit/test_rocket.py b/tests/unit/test_rocket.py index 3c1e7168d..fe7fb6704 100644 --- a/tests/unit/test_rocket.py +++ b/tests/unit/test_rocket.py @@ -10,7 +10,9 @@ @patch("matplotlib.pyplot.show") -def test_elliptical_fins(mock_show, calisto_robust, calisto_trapezoidal_fins): # pylint: disable=unused-argument +def test_elliptical_fins( + mock_show, calisto_robust, calisto_trapezoidal_fins +): # pylint: disable=unused-argument test_rocket = calisto_robust calisto_robust.aerodynamic_surfaces.remove(calisto_trapezoidal_fins) test_rocket.add_elliptical_fins(4, span=0.100, root_chord=0.120, position=-1.168) @@ -370,6 +372,41 @@ def test_add_motor(calisto_motorless, cesaroni_m1670): assert center_of_mass_motorless is not center_of_mass_with_motor +def test_check_missing_all_components(calisto_motorless): + """Tests the _check_missing_components method for a Rocket with no components.""" + with pytest.warns(UserWarning) as record: + calisto_motorless._check_missing_components() + + assert len(record) == 1 + msg = str(record[0].message) + assert "motor" in msg + assert "parachutes" in msg + assert "aerodynamic surfaces" in msg + + +def test_check_missing_some_components(calisto): + """Tests the _check_missing_components method for a Rocket missing some components.""" + calisto.parachutes = [] + calisto.aerodynamic_surfaces = [] + + with pytest.warns(UserWarning) as record: + calisto._check_missing_components() + + assert len(record) == 1 + msg = str(record[0].message) + assert "parachutes" in msg + assert "aerodynamic surfaces" in msg + + +def test_check_missing_no_components_missing(calisto_robust): + """Tests the _check_missing_components method for a complete Rocket.""" + # Call directly — no warnings expected + with pytest.warns(None) as record: + calisto_robust._check_missing_components() + # If any warning occurs, pytest will fail automatically + assert len(record) == 0 + + def test_set_rail_button(calisto): rail_buttons = calisto.set_rail_buttons(0.2, -0.5, 30) # assert buttons_distance