From cb081195e8912105f1df0d0072608dd5456f247c Mon Sep 17 00:00:00 2001 From: KulaginVladimir Date: Sun, 4 Feb 2024 12:23:29 +0300 Subject: [PATCH 1/5] Traps and DerivedQuantities are subclasses of list --- festim/concentration/mobile.py | 2 +- festim/concentration/traps/traps.py | 52 ++++++---- .../derived_quantities/derived_quantities.py | 44 ++++++--- festim/exports/exports.py | 24 ++++- festim/generic_simulation.py | 19 ++-- festim/h_transport_problem.py | 10 +- festim/materials/materials.py | 21 +++- .../test_postprocessing_integration.py | 43 ++++---- test/system/test_misc.py | 26 +++++ test/system/test_system.py | 37 ++++--- .../test_derived_quantities.py | 99 ++++++++++++------- test/unit/test_exports/test_exports.py | 22 +++++ test/unit/test_materials.py | 20 ++++ test/unit/test_mobile.py | 2 +- test/unit/test_traps/test_traps.py | 22 ++--- 15 files changed, 304 insertions(+), 139 deletions(-) create mode 100644 test/unit/test_exports/test_exports.py diff --git a/festim/concentration/mobile.py b/festim/concentration/mobile.py index 0af4900ee..995a47c2e 100644 --- a/festim/concentration/mobile.py +++ b/festim/concentration/mobile.py @@ -109,7 +109,7 @@ def create_diffusion_form( # add the trapping terms F_trapping = 0 if traps is not None: - for trap in traps.traps: + for trap in traps: for i, mat in enumerate(trap.materials): if type(trap.k_0) is list: k_0 = trap.k_0[i] diff --git a/festim/concentration/traps/traps.py b/festim/concentration/traps/traps.py index da03b6b52..8ad7d33af 100644 --- a/festim/concentration/traps/traps.py +++ b/festim/concentration/traps/traps.py @@ -1,52 +1,62 @@ import festim import fenics as f +import warnings -class Traps: - def __init__(self, traps=[]) -> None: - self.traps = traps +class Traps(list): + """ + A list of festim.Trap objects + """ + + def __init__(self, *args): + # checks that input is list + try: + super().__init__(*args) + except: + raise TypeError("festim.Traps must be a list") + + # checks that list elements are festim.Export + if len(self) != 0: + if not all(isinstance(t, festim.Trap) for t in self): + raise TypeError("festim.Traps must be a list of festim.Trap") + self.F = None self.extrinsic_formulations = [] self.sub_expressions = [] # add ids if unspecified - for i, trap in enumerate(self.traps, 1): + for i, trap in enumerate(self, 1): if trap.id is None: trap.id = i @property def traps(self): - return self._traps - - @traps.setter - def traps(self, value): - if isinstance(value, list): - if not all(isinstance(t, festim.Trap) for t in value): - raise TypeError("traps must be a list of festim.Trap") - self._traps = value - else: - raise TypeError("traps must be a list") + warnings.warn( + "The traps attribute will be deprecated in a future release, please use festim.Traps[:] instead", + DeprecationWarning, + ) + return self def make_traps_materials(self, materials): - for trap in self.traps: + for trap in self: trap.make_materials(materials) def create_forms(self, mobile, materials, T, dx, dt=None): self.F = 0 - for trap in self.traps: + for trap in self: trap.create_form(mobile, materials, T, dx, dt=dt) self.F += trap.F self.sub_expressions += trap.sub_expressions def get_trap(self, id): - for trap in self.traps: + for trap in self: if trap.id == id: return trap raise ValueError("Couldn't find trap {}".format(id)) def initialise_extrinsic_traps(self, V): """Add functions to ExtrinsicTrapBase objects for density form""" - for trap in self.traps: + for trap in self: if isinstance(trap, festim.ExtrinsicTrapBase): trap.density = [f.Function(V)] trap.density_test_function = f.TestFunction(V) @@ -63,14 +73,14 @@ def define_variational_problem_extrinsic_traps(self, dx, dt, T): """ self.extrinsic_formulations = [] expressions_extrinsic = [] - for trap in self.traps: + for trap in self: if isinstance(trap, festim.ExtrinsicTrapBase): trap.create_form_density(dx, dt, T) self.extrinsic_formulations.append(trap.form_density) self.sub_expressions.extend(expressions_extrinsic) def solve_extrinsic_traps(self): - for trap in self.traps: + for trap in self: if isinstance(trap, festim.ExtrinsicTrapBase): du_t = f.TrialFunction(trap.density[0].function_space()) J_t = f.derivative(trap.form_density, trap.density[0], du_t) @@ -91,6 +101,6 @@ def solve_extrinsic_traps(self): solver.solve() def update_extrinsic_traps_density(self): - for trap in self.traps: + for trap in self: if isinstance(trap, festim.ExtrinsicTrapBase): trap.density_previous_solution.assign(trap.density[0]) diff --git a/festim/exports/derived_quantities/derived_quantities.py b/festim/exports/derived_quantities/derived_quantities.py index b93c401c5..04e8d0a8b 100644 --- a/festim/exports/derived_quantities/derived_quantities.py +++ b/festim/exports/derived_quantities/derived_quantities.py @@ -7,13 +7,14 @@ import os import numpy as np from typing import Union +import warnings -class DerivedQuantities: +class DerivedQuantities(list): """ + A list of festim.DerivedQuantity objects + Args: - derived_quantities (list, optional): list of F.DerivedQuantity - object. Defaults to None. filename (str, optional): the filename (must end with .csv). If None, the data will not be exported. Defaults to None. nb_iterations_between_compute (int, optional): number of @@ -26,22 +27,39 @@ class DerivedQuantities: def __init__( self, - derived_quantities: list = None, + *args, filename: str = None, nb_iterations_between_compute: int = 1, nb_iterations_between_exports: int = None, ) -> None: + # checks that input is list + try: + super().__init__(*args) + except: + raise TypeError("festim.DerivedQuantities must be a list") + + # checks that list elements are festim.Export + if len(self) != 0: + if not all(isinstance(t, DerivedQuantity) for t in self): + raise TypeError( + "festim.DerivedQuantities must be a list of festim.DerivedQuantity" + ) + self.filename = filename self.nb_iterations_between_compute = nb_iterations_between_compute self.nb_iterations_between_exports = nb_iterations_between_exports - self.derived_quantities = derived_quantities - if derived_quantities is None: - self.derived_quantities = [] - self.data = [self.make_header()] self.t = [] + @property + def derived_quantities(self): + warnings.warn( + "The derived_quantities attribute will be deprecated in a future release, please use festim.DerivedQuantities[:] instead", + DeprecationWarning, + ) + return self + @property def filename(self): return self._filename @@ -57,13 +75,13 @@ def filename(self, value): def make_header(self): header = ["t(s)"] - for quantity in self.derived_quantities: + for quantity in self: header.append(quantity.title) return header def assign_measures_to_quantities(self, dx, ds): self.volume_markers = dx.subdomain_data() - for quantity in self.derived_quantities: + for quantity in self: quantity.dx = dx quantity.ds = ds quantity.n = f.FacetNormal(dx.subdomain_data().mesh()) @@ -75,7 +93,7 @@ def assign_properties_to_quantities(self, materials): Args: materials (festim.Materials): the materials """ - for quantity in self.derived_quantities: + for quantity in self: quantity.D = materials.D quantity.S = materials.S quantity.thermal_cond = materials.thermal_cond @@ -84,7 +102,7 @@ def assign_properties_to_quantities(self, materials): def compute(self, t): # TODO need to support for soret flag in surface flux row = [t] - for quantity in self.derived_quantities: + for quantity in self: if isinstance(quantity, (MaximumVolume, MinimumVolume)): value = quantity.compute(self.volume_markers) else: @@ -180,7 +198,7 @@ def filter( quantities = [] # iterate through derived_quantities - for quantity in self.derived_quantities: + for quantity in self: # initialise flags to False match_surface, match_volume, match_field, match_instance = ( False, diff --git a/festim/exports/exports.py b/festim/exports/exports.py index b11b797ed..ec90f7915 100644 --- a/festim/exports/exports.py +++ b/festim/exports/exports.py @@ -1,5 +1,6 @@ import festim import fenics as f +import warnings class Exports(list): @@ -8,12 +9,33 @@ class Exports(list): """ def __init__(self, *args): - super().__init__(*args) + # checks that input is list + try: + super().__init__(*args) + except: + raise TypeError("festim.Exports must be a list") + + # checks that list elements are festim.Export + if len(self) != 0: + if not all( + isinstance(t, festim.Export) or isinstance(t, festim.DerivedQuantities) + for t in self + ): + raise TypeError("festim.Exports must be a list of festim.Export") + self.t = None self.V_DG1 = None self.final_time = None self.nb_iterations = 0 + @property + def exports(self): + warnings.warn( + "The exports attribute will be deprecated in a future release, please use festim.Exports[:] instead", + DeprecationWarning, + ) + return self + def write(self, label_to_function, dx): """writes to file diff --git a/festim/generic_simulation.py b/festim/generic_simulation.py index 78fea6539..f1547b34b 100644 --- a/festim/generic_simulation.py +++ b/festim/generic_simulation.py @@ -115,10 +115,13 @@ def traps(self): def traps(self, value): if value is None: self._traps = festim.Traps([]) - elif isinstance(value, list): - self._traps = festim.Traps(value) elif isinstance(value, festim.Traps): self._traps = value + elif isinstance(value, list): + if not all(isinstance(t, festim.Trap) for t in value): + raise TypeError("traps must be a list of festim.Trap") + else: + self._traps = festim.Traps(value) elif isinstance(value, festim.Trap): self._traps = festim.Traps([value]) else: @@ -171,7 +174,7 @@ def attribute_source_terms(self): # reinitialise sources for concentrations and temperature self.mobile.sources = [] self.T.sources = [] - for t in self.traps.traps: + for t in self.traps: t.sources = [] # make field_to_object dict @@ -182,7 +185,7 @@ def attribute_source_terms(self): "mobile": self.mobile, "T": self.T, } - for i, trap in enumerate(self.traps.traps, 1): + for i, trap in enumerate(self.traps, 1): field_to_object[i] = trap field_to_object[str(i)] = trap @@ -204,8 +207,8 @@ def attribute_boundary_conditions(self): valid_fields = ( ["T", 0, "0"] # temperature and mobile concentration - + [str(i + 1) for i, _ in enumerate(self.traps.traps)] - + [i + 1 for i, _ in enumerate(self.traps.traps)] + + [str(i + 1) for i, _ in enumerate(self.traps)] + + [i + 1 for i, _ in enumerate(self.traps)] ) # collect all DirichletBCs @@ -429,10 +432,10 @@ def update_post_processing_solutions(self): "T": self.T.T, "retention": sum( [self.mobile.post_processing_solution] - + [trap.post_processing_solution for trap in self.traps.traps] + + [trap.post_processing_solution for trap in self.traps] ), } - for trap in self.traps.traps: + for trap in self.traps: label_to_function[trap.id] = trap.post_processing_solution label_to_function[str(trap.id)] = trap.post_processing_solution diff --git a/festim/h_transport_problem.py b/festim/h_transport_problem.py index 24eba30ba..eea9c7722 100644 --- a/festim/h_transport_problem.py +++ b/festim/h_transport_problem.py @@ -88,7 +88,7 @@ def define_function_space(self, mesh): element_solute, order_solute = "CG", 1 # function space for H concentrations - nb_traps = len(self.traps.traps) + nb_traps = len(self.traps) if nb_traps == 0: V = FunctionSpace(mesh.mesh, element_solute, order_solute) else: @@ -120,7 +120,7 @@ def initialise_concentrations(self): self.mobile.previous_solution = self.u_n self.mobile.test_function = self.v else: - for i, concentration in enumerate([self.mobile, *self.traps.traps]): + for i, concentration in enumerate([self.mobile, *self.traps]): concentration.solution = self.u.sub(i) # concentration.solution = list(split(self.u))[i] concentration.previous_solution = self.u_n.sub(i) @@ -132,7 +132,7 @@ def initialise_concentrations(self): "0": 0, 0: 0, } - for i, trap in enumerate(self.traps.traps, 1): + for i, trap in enumerate(self.traps, 1): field_to_component[trap.id] = i field_to_component[str(trap.id)] = i # TODO refactore this, attach the initial conditions to the objects directly @@ -168,7 +168,7 @@ def initialise_concentrations(self): # this is needed to correctly create the formulation # TODO: write a test for this? if self.V.num_sub_spaces() != 0: - for i, concentration in enumerate([self.mobile, *self.traps.traps]): + for i, concentration in enumerate([self.mobile, *self.traps]): concentration.previous_solution = list(split(self.u_n))[i] concentration.solution = list(split(self.u))[i] @@ -299,7 +299,7 @@ def update_post_processing_solutions(self, exports): else: res = list(self.u.split()) - for i, trap in enumerate(self.traps.traps, 1): + for i, trap in enumerate(self.traps, 1): trap.post_processing_solution = res[i] if self.settings.chemical_pot: diff --git a/festim/materials/materials.py b/festim/materials/materials.py index 9d900b5b7..4924b7e80 100644 --- a/festim/materials/materials.py +++ b/festim/materials/materials.py @@ -5,6 +5,7 @@ import festim import fenics as f from typing import Union +import warnings class Materials(list): @@ -13,7 +14,17 @@ class Materials(list): """ def __init__(self, *args): - super().__init__(*args) + # checks that input is list + try: + super().__init__(*args) + except: + raise TypeError("festim.Materials must be a list") + + # checks that list elements are festim.Material + if len(self) != 0: + if not all(isinstance(t, festim.Material) for t in self): + raise TypeError("festim.Materials must be a list of festim.Material") + self.D = None self.S = None self.thermal_cond = None @@ -21,6 +32,14 @@ def __init__(self, *args): self.density = None self.Q = None + @property + def materials(self): + warnings.warn( + "The materials attribute will be deprecated in a future release, please use festim.Materials[:] instead", + DeprecationWarning, + ) + return self + def check_borders(self, size): """Checks that the borders of the materials match diff --git a/test/simulation/test_postprocessing_integration.py b/test/simulation/test_postprocessing_integration.py index 4e87588bf..b5f1deb27 100644 --- a/test/simulation/test_postprocessing_integration.py +++ b/test/simulation/test_postprocessing_integration.py @@ -42,12 +42,13 @@ def my_sim(self): return my_sim def test_derived_quantities_size(self, my_sim): - derived_quantities = festim.DerivedQuantities() - derived_quantities.derived_quantities = [ - festim.SurfaceFlux("solute", 1), - festim.AverageVolume("T", 1), - festim.TotalVolume("1", 1), - ] + derived_quantities = festim.DerivedQuantities( + [ + festim.SurfaceFlux("solute", 1), + festim.AverageVolume("T", 1), + festim.TotalVolume("1", 1), + ] + ) derived_quantities.assign_measures_to_quantities(my_sim.mesh.dx, my_sim.mesh.ds) derived_quantities.assign_properties_to_quantities(my_sim.materials) @@ -85,13 +86,14 @@ def test_pure_diffusion(self, my_sim): ), ) - derived_quantities = festim.DerivedQuantities() - derived_quantities.derived_quantities = [ - festim.AverageVolume("solute", 2), - festim.AverageVolume("T", 2), - festim.AverageVolume("retention", 2), - festim.MinimumVolume("retention", 1), - ] + derived_quantities = festim.DerivedQuantities( + [ + festim.AverageVolume("solute", 2), + festim.AverageVolume("T", 2), + festim.AverageVolume("retention", 2), + festim.MinimumVolume("retention", 1), + ] + ) derived_quantities.assign_measures_to_quantities(my_sim.mesh.dx, my_sim.mesh.ds) my_sim.exports = [derived_quantities] @@ -132,13 +134,14 @@ def test_fluxes(self, my_sim): f.interpolate(u_expr, my_sim.h_transport_problem.V.sub(0).collapse()), ) - derived_quantities = festim.DerivedQuantities() - derived_quantities.derived_quantities = [ - festim.SurfaceFlux("solute", 1), - festim.SurfaceFlux("solute", 2), - festim.SurfaceFlux("T", 1), - festim.SurfaceFlux("T", 2), - ] + derived_quantities = festim.DerivedQuantities( + [ + festim.SurfaceFlux("solute", 1), + festim.SurfaceFlux("solute", 2), + festim.SurfaceFlux("T", 1), + festim.SurfaceFlux("T", 2), + ] + ) derived_quantities.assign_measures_to_quantities(my_sim.mesh.dx, my_sim.mesh.ds) derived_quantities.assign_properties_to_quantities(my_sim.materials) diff --git a/test/system/test_misc.py b/test/system/test_misc.py index 1dbc3fdbb..ce18cb60f 100644 --- a/test/system/test_misc.py +++ b/test/system/test_misc.py @@ -312,3 +312,29 @@ def test_materials_setter(): test_materials = F.Materials([]) my_model.materials = test_materials assert my_model.materials is test_materials + + +def test_depr_warns(): + """ + A temporary test to check DeprecationWarnings + """ + + my_mat = F.Material(id=1, E_D=1, D_0=1) + my_mats = F.Materials([my_mat]) + my_derived_quantities = F.DerivedQuantities([F.SurfaceFlux(0, 2)]) + my_exports = F.Exports([F.Export(field=0)] + my_derived_quantities) + my_traps = F.Traps( + [F.Trap(k_0=1, E_k=1, p_0=1, E_p=1, density=1, materials=my_mat)] + ) + + with pytest.deprecated_call(): + my_mats.materials[0] + + with pytest.deprecated_call(): + my_exports.exports[0] + + with pytest.deprecated_call(): + my_derived_quantities.derived_quantities[0] + + with pytest.deprecated_call(): + my_traps.traps[0] diff --git a/test/system/test_system.py b/test/system/test_system.py index 391c730a2..41576d03a 100644 --- a/test/system/test_system.py +++ b/test/system/test_system.py @@ -52,8 +52,8 @@ def test_run_temperature_stationary(tmpdir): ) my_derived_quantities = festim.DerivedQuantities( + [festim.TotalVolume("solute", 1)], filename="{}/derived_quantities.csv".format(str(Path(d))), - derived_quantities=[festim.TotalVolume("solute", 1)], ) my_exports = [ @@ -250,7 +250,7 @@ def run(h): ) error_v = compute_error( v, - computed=my_sim.traps.traps[0].post_processing_solution, + computed=my_sim.traps[0].post_processing_solution, t=my_sim.t, norm="error_max", ) @@ -372,7 +372,7 @@ def run(h): ) computed_v = fenics.project( - my_sim.traps.traps[0].post_processing_solution, my_sim.V_DG1 + my_sim.traps[0].post_processing_solution, my_sim.V_DG1 ) error_u = compute_error(u, computed=computed_u, t=my_sim.t, norm="error_max") @@ -436,8 +436,7 @@ def test_run_chemical_pot_mass_balance(tmpdir): total_solute = festim.TotalVolume("solute", 1) total_retention = festim.TotalVolume("retention", 1) - derived_quantities = festim.DerivedQuantities() - derived_quantities.derived_quantities = [total_solute, total_retention] + derived_quantities = festim.DerivedQuantities([total_solute, total_retention]) my_exports = festim.Exports( [ festim.XDMFExport( @@ -651,7 +650,7 @@ def run(h): ) error_v = compute_error( v, - computed=my_sim.traps.traps[0].post_processing_solution, + computed=my_sim.traps[0].post_processing_solution, t=my_sim.t, norm="error_max", ) @@ -704,8 +703,7 @@ def test_chemical_pot_T_solve_stationary(tmpdir): final_time=100, ) my_dt = festim.Stepsize(10, stepsize_change_ratio=1.2, dt_min=1e-8) - my_derived_quantities = festim.DerivedQuantities() - my_derived_quantities.derived_quantities = [festim.TotalSurface("solute", 2)] + my_derived_quantities = festim.DerivedQuantities([festim.TotalSurface("solute", 2)]) my_exports = festim.Exports( [ festim.XDMFExport( @@ -749,12 +747,13 @@ def test_export_particle_flux_with_chemical_pot(tmpdir): chemical_pot=True, transient=False, ) - my_derived_quantities = festim.DerivedQuantities() - my_derived_quantities.derived_quantities = [ - festim.SurfaceFlux("solute", 1), - festim.SurfaceFlux("T", 1), - festim.TotalVolume("retention", 1), - ] + my_derived_quantities = festim.DerivedQuantities( + [ + festim.SurfaceFlux("solute", 1), + festim.SurfaceFlux("T", 1), + festim.TotalVolume("retention", 1), + ] + ) my_exports = festim.Exports( [ festim.XDMFExport( @@ -936,11 +935,11 @@ def init_sim(nb_it_compute): my_dt = festim.Stepsize(4) my_derived_quantities = festim.DerivedQuantities( - nb_iterations_between_compute=nb_it_compute + [ + festim.TotalVolume("retention", 1), + ], + nb_iterations_between_compute=nb_it_compute, ) - my_derived_quantities.derived_quantities = [ - festim.TotalVolume("retention", 1), - ] my_exports = festim.Exports([my_derived_quantities]) my_sim = festim.Simulation( @@ -1170,7 +1169,7 @@ def test_MMS_decay_with_trap(): ) error_max_v = compute_error( v, - computed=my_sim.traps.traps[0].post_processing_solution, + computed=my_sim.traps[0].post_processing_solution, t=my_sim.t, norm="error_max", ) diff --git a/test/unit/test_exports/test_derived_quantities/test_derived_quantities.py b/test/unit/test_exports/test_derived_quantities/test_derived_quantities.py index c61a7f103..97036a5cb 100644 --- a/test/unit/test_exports/test_derived_quantities/test_derived_quantities.py +++ b/test/unit/test_exports/test_derived_quantities/test_derived_quantities.py @@ -15,7 +15,7 @@ class TestMakeHeader: - my_derv_quant = DerivedQuantities() + my_derv_quant = None surface_flux_1 = SurfaceFlux("solute", 2) surface_flux_2 = SurfaceFlux("T", 3) average_vol_1 = AverageVolume("solute", 3) @@ -26,14 +26,22 @@ class TestMakeHeader: min_vol_1 = MinimumVolume("retention", 2) max_vol_1 = MaximumVolume("T", 2) + @property + def my_derv_quant(self): + return self._my_derv_quant + + @my_derv_quant.setter + def my_derv_quant(self, value): + self._my_derv_quant = DerivedQuantities(value) + def test_simple(self): - self.my_derv_quant.derived_quantities = [self.surface_flux_1] + self.my_derv_quant = [self.surface_flux_1] header = self.my_derv_quant.make_header() expected_header = ["t(s)", self.surface_flux_1.title] assert header == expected_header def test_two_quantities(self): - self.my_derv_quant.derived_quantities = [ + self.my_derv_quant = [ self.surface_flux_1, self.tot_surf_1, ] @@ -42,7 +50,7 @@ def test_two_quantities(self): assert header == expected_header def test_all_quantities(self): - self.my_derv_quant.derived_quantities = [ + self.my_derv_quant = [ self.surface_flux_1, self.average_vol_1, self.tot_surf_1, @@ -78,15 +86,15 @@ class TestAssignMeasuresToQuantities: my_quantities.assign_measures_to_quantities(dx, ds) def test_quantities_have_dx(self): - for quantity in self.my_quantities.derived_quantities: + for quantity in self.my_quantities: assert quantity.dx == self.dx def test_quantities_have_ds(self): - for quantity in self.my_quantities.derived_quantities: + for quantity in self.my_quantities: assert quantity.ds == self.ds def test_quantities_have_n(self): - for quantity in self.my_quantities.derived_quantities: + for quantity in self.my_quantities: assert quantity.n == self.n @@ -94,7 +102,7 @@ class TestAssignPropertiesToQuantities: mesh = f.UnitIntervalMesh(10) V = f.FunctionSpace(mesh, "P", 1) my_quantities = DerivedQuantities( - derived_quantities=[ + [ SurfaceFlux("solute", 2), SurfaceFlux("T", 3), AverageVolume("solute", 3), @@ -110,24 +118,24 @@ class TestAssignPropertiesToQuantities: my_quantities.assign_properties_to_quantities(my_mats) def test_quantities_have_D(self): - for quantity in self.my_quantities.derived_quantities: + for quantity in self.my_quantities: assert quantity.D == self.my_mats.D def test_quantities_have_S(self): - for quantity in self.my_quantities.derived_quantities: + for quantity in self.my_quantities: assert quantity.S == self.my_mats.S def test_quantities_have_Q(self): - for quantity in self.my_quantities.derived_quantities: + for quantity in self.my_quantities: assert quantity.Q == self.my_mats.Q def test_quantities_have_thermal_cond(self): - for quantity in self.my_quantities.derived_quantities: + for quantity in self.my_quantities: assert quantity.thermal_cond == self.my_mats.thermal_cond class TestCompute: - my_derv_quant = DerivedQuantities() + my_derv_quant = None surface_flux_1 = SurfaceFlux("solute", 2) surface_flux_2 = SurfaceFlux("T", 3) average_vol_1 = AverageVolume("solute", 1) @@ -165,37 +173,40 @@ class TestCompute: my_mats.H = f.interpolate(f.Constant(2), V) my_mats.thermal_cond = f.interpolate(f.Constant(2), V) + @property + def my_derv_quant(self): + return self._my_derv_quant + + @my_derv_quant.setter + def my_derv_quant(self, value): + self._my_derv_quant = DerivedQuantities(value) + def test_simple(self): - self.my_derv_quant.derived_quantities = [self.surface_flux_1] - for quantity in self.my_derv_quant.derived_quantities: + self.my_derv_quant = [self.surface_flux_1] + for quantity in self.my_derv_quant: quantity.function = self.label_to_function[quantity.field] self.my_derv_quant.assign_properties_to_quantities(self.my_mats) self.my_derv_quant.assign_measures_to_quantities(self.dx, self.ds) t = 2 - expected_data = [t] + [ - quantity.compute() for quantity in self.my_derv_quant.derived_quantities - ] + expected_data = [t] + [quantity.compute() for quantity in self.my_derv_quant] self.my_derv_quant.data = [] self.my_derv_quant.compute(t) - assert self.my_derv_quant.data[0] == expected_data def test_two_quantities(self): - self.my_derv_quant.derived_quantities = [ + self.my_derv_quant = [ self.surface_flux_1, self.average_vol_1, ] - for quantity in self.my_derv_quant.derived_quantities: + for quantity in self.my_derv_quant: quantity.function = self.label_to_function[quantity.field] self.my_derv_quant.assign_properties_to_quantities(self.my_mats) self.my_derv_quant.assign_measures_to_quantities(self.dx, self.ds) t = 2 - expected_data = [t] + [ - quantity.compute() for quantity in self.my_derv_quant.derived_quantities - ] + expected_data = [t] + [quantity.compute() for quantity in self.my_derv_quant] self.my_derv_quant.data = [] self.my_derv_quant.compute(t) @@ -203,7 +214,7 @@ def test_two_quantities(self): assert self.my_derv_quant.data[0] == expected_data def test_all_quantities(self): - self.my_derv_quant.derived_quantities = [ + self.my_derv_quant = [ self.surface_flux_1, self.average_vol_1, self.tot_surf_1, @@ -211,14 +222,14 @@ def test_all_quantities(self): self.min_vol_1, self.max_vol_1, ] - for quantity in self.my_derv_quant.derived_quantities: + for quantity in self.my_derv_quant: quantity.function = self.label_to_function[quantity.field] self.my_derv_quant.assign_properties_to_quantities(self.my_mats) self.my_derv_quant.assign_measures_to_quantities(self.dx, self.ds) t = 2 expected_data = [t] - for quantity in self.my_derv_quant.derived_quantities: + for quantity in self.my_derv_quant: if isinstance(quantity, (MaximumVolume, MinimumVolume)): expected_data.append(quantity.compute(self.vol_markers)) else: @@ -269,10 +280,9 @@ class TestFilter: """Tests the filter method of DerivedQUantities""" def test_simple(self): - derived_quantities = DerivedQuantities() flux1 = SurfaceFlux(field="solute", surface=1) flux2 = SurfaceFlux(field="T", surface=2) - derived_quantities.derived_quantities = [flux1, flux2] + derived_quantities = DerivedQuantities([flux1, flux2]) assert derived_quantities.filter(surfaces=[1, 2]) == [flux1, flux2] assert derived_quantities.filter(surfaces=[1]) == flux1 @@ -281,14 +291,13 @@ def test_simple(self): assert derived_quantities.filter(fields=["solute"], surfaces=[1, 2]) == flux1 def test_with_volumes(self): - derived_quantities = DerivedQuantities() flux1 = SurfaceFlux(field="solute", surface=1) flux2 = SurfaceFlux(field="T", surface=2) total1 = TotalVolume(field="1", volume=3) total2 = TotalVolume(field="retention", volume=1) - derived_quantities.derived_quantities = [flux1, flux2, total1, total2] + derived_quantities = DerivedQuantities([flux1, flux2, total1, total2]) - assert derived_quantities.filter() == derived_quantities.derived_quantities + assert derived_quantities.filter() == derived_quantities assert derived_quantities.filter(surfaces=[1, 2], volumes=[3]) == [] assert ( derived_quantities.filter(volumes=[1, 3], fields=["retention", "solute"]) @@ -296,22 +305,20 @@ def test_with_volumes(self): ) def test_with_single_args(self): - derived_quantities = DerivedQuantities() flux1 = SurfaceFlux(field="solute", surface=1) flux2 = SurfaceFlux(field="T", surface=2) total1 = TotalVolume(field="1", volume=3) - derived_quantities.derived_quantities = [flux1, flux2, total1] + derived_quantities = DerivedQuantities([flux1, flux2, total1]) assert derived_quantities.filter(surfaces=1) == flux1 assert derived_quantities.filter(fields="T") == flux2 assert derived_quantities.filter(volumes=3) == total1 def test_several_quantities_one_surface(self): - derived_quantities = DerivedQuantities() surf1 = SurfaceFlux(field="solute", surface=1) surf2 = TotalSurface(field="solute", surface=1) - derived_quantities.derived_quantities = [surf1, surf2] + derived_quantities = DerivedQuantities([surf1, surf2]) assert derived_quantities.filter(surfaces=1, instances=SurfaceFlux) == surf1 assert derived_quantities.filter(surfaces=1, instances=TotalSurface) == surf2 @@ -330,3 +337,23 @@ def test_filename_ends_with_csv(): """Checks that an error is raised when filename doesn't end with .csv""" with pytest.raises(ValueError, match="filename must end with .csv"): DerivedQuantities(filename="coucou") + + +def test_set_derived_quantitites_wrong_type(): + """Checks an error is raised when festim.DerivedQuantities is set with the wrong type""" + flux1 = SurfaceFlux(field="solute", surface=1) + + combinations = [flux1, "coucou", 1, True] + + for dq_combination in combinations: + with pytest.raises( + TypeError, + match="festim.DerivedQuantities must be a list", + ): + DerivedQuantities(dq_combination) + + with pytest.raises( + TypeError, + match="festim.DerivedQuantities must be a list of festim.DerivedQuantity", + ): + DerivedQuantities([flux1, 2]) diff --git a/test/unit/test_exports/test_exports.py b/test/unit/test_exports/test_exports.py new file mode 100644 index 000000000..af1d674c6 --- /dev/null +++ b/test/unit/test_exports/test_exports.py @@ -0,0 +1,22 @@ +import festim +import pytest + + +def test_set_traps_wrong_type(): + """Checks an error is raised when festim.Exports is set with the wrong type""" + export = festim.Export(field=0) + + combinations = [export, "coucou", 1, True] + + for export_combination in combinations: + with pytest.raises( + TypeError, + match="festim.Exports must be a list", + ): + festim.Exports(export_combination) + + with pytest.raises( + TypeError, + match="festim.Exports must be a list of festim.Export", + ): + festim.Exports([export, 2]) diff --git a/test/unit/test_materials.py b/test/unit/test_materials.py index 3df541511..779a44160 100644 --- a/test/unit/test_materials.py +++ b/test/unit/test_materials.py @@ -307,3 +307,23 @@ def test_equality_identity_two_empty_materials(): my_materials1 = F.Materials([]) my_materials2 = F.Materials([]) assert (my_materials1 == my_materials2) and (my_materials1 is not my_materials2) + + +def test_set_materials_wrong_type(): + """Checks an error is raised when festim.Materials is set with the wrong type""" + my_mat = F.Material(1, 1, 0) + + combinations = [my_mat, "coucou", 1, True] + + for mat_combination in combinations: + with pytest.raises( + TypeError, + match="festim.Materials must be a list", + ): + F.Materials(mat_combination) + + with pytest.raises( + TypeError, + match="festim.Materials must be a list of festim.Material", + ): + F.Materials([my_mat, 2]) diff --git a/test/unit/test_mobile.py b/test/unit/test_mobile.py index 97c5e161a..c6415842b 100644 --- a/test/unit/test_mobile.py +++ b/test/unit/test_mobile.py @@ -160,7 +160,7 @@ def test_with_traps_transient(self): expected_form = ((c_0 - c_0_n) / self.dt.value) * v * self.my_mesh.dx(1) expected_form += f.dot(D * f.grad(c_0), f.grad(v)) * self.my_mesh.dx(1) form_trapping_expected = 0 - for trap in my_traps.traps: + for trap in my_traps: form_trapping_expected += ( ( -trap.k_0 diff --git a/test/unit/test_traps/test_traps.py b/test/unit/test_traps/test_traps.py index 325a5ae1b..8ff4ca1f0 100644 --- a/test/unit/test_traps/test_traps.py +++ b/test/unit/test_traps/test_traps.py @@ -4,8 +4,6 @@ def test_set_traps(): - my_traps = festim.Traps() - my_mat = festim.Material(1, 1, 0) trap1 = festim.Trap(1, 1, 1, 1, [my_mat], density=1) trap2 = festim.Trap(2, 2, 2, 2, [my_mat], density=1) @@ -13,13 +11,11 @@ def test_set_traps(): combinations = [[trap1], [trap1, trap2]] for trap_combination in combinations: - my_traps.traps = trap_combination + festim.Traps(trap_combination) def test_set_traps_wrong_type(): - """Checks an error is raised when traps is set with the wrong type""" - my_traps = festim.Traps() - + """Checks an error is raised when festim.Traps is set with the wrong type""" my_mat = festim.Material(1, 1, 0) trap1 = festim.Trap(1, 1, 1, 1, [my_mat], density=1) @@ -28,15 +24,15 @@ def test_set_traps_wrong_type(): for trap_combination in combinations: with pytest.raises( TypeError, - match="traps must be a list", + match="festim.Traps must be a list", ): - my_traps.traps = trap_combination + festim.Traps(trap_combination) with pytest.raises( TypeError, - match="traps must be a list of festim.Trap", + match="festim.Traps must be a list of festim.Trap", ): - my_traps.traps = [trap1, 2] + festim.Traps([trap1, 2]) def add_functions(trap, V, id=1): @@ -74,7 +70,7 @@ def test_one_trap_steady_state(self): my_traps.create_forms(self.my_mobile, self.my_mats, self.my_temp, self.dx) - for trap in my_traps.traps: + for trap in my_traps: assert trap.F is not None def test_one_trap_transient(self): @@ -84,7 +80,7 @@ def test_one_trap_transient(self): self.my_mobile, self.my_mats, self.my_temp, self.dx, dt=self.dt ) - for trap in my_traps.traps: + for trap in my_traps: assert trap.F is not None def test_two_traps_transient(self): @@ -94,7 +90,7 @@ def test_two_traps_transient(self): self.my_mobile, self.my_mats, self.my_temp, self.dx, dt=self.dt ) - for trap in my_traps.traps: + for trap in my_traps: assert trap.F is not None From b2090018f89aa80fad4d2c4fbda73ee68f620dd2 Mon Sep 17 00:00:00 2001 From: KulaginVladimir Date: Sun, 4 Feb 2024 12:49:26 +0300 Subject: [PATCH 2/5] upd traps.setter --- festim/generic_simulation.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/festim/generic_simulation.py b/festim/generic_simulation.py index f1547b34b..e89b620ad 100644 --- a/festim/generic_simulation.py +++ b/festim/generic_simulation.py @@ -118,10 +118,7 @@ def traps(self, value): elif isinstance(value, festim.Traps): self._traps = value elif isinstance(value, list): - if not all(isinstance(t, festim.Trap) for t in value): - raise TypeError("traps must be a list of festim.Trap") - else: - self._traps = festim.Traps(value) + self._traps = festim.Traps(value) elif isinstance(value, festim.Trap): self._traps = festim.Traps([value]) else: From fb9d5c3a2d94c3f6234d105bcedd6812526118e3 Mon Sep 17 00:00:00 2001 From: KulaginVladimir Date: Mon, 5 Feb 2024 21:19:17 +0300 Subject: [PATCH 3/5] upd properties and attributes of classes --- festim/concentration/traps/traps.py | 45 ++++- .../derived_quantities/derived_quantities.py | 51 ++++-- festim/exports/exports.py | 58 ++++-- festim/materials/materials.py | 45 ++++- .../test_initialisation.py | 2 +- test/h_transport_problem/test_solving.py | 8 +- test/system/test_misc.py | 102 ++++++++++- .../test_derived_quantities.py | 168 ++++++++++-------- test/unit/test_exports/test_exports.py | 43 ++++- test/unit/test_materials.py | 35 ++++ test/unit/test_traps/test_traps.py | 77 +++++--- 11 files changed, 484 insertions(+), 150 deletions(-) diff --git a/festim/concentration/traps/traps.py b/festim/concentration/traps/traps.py index 8ad7d33af..4feae1c70 100644 --- a/festim/concentration/traps/traps.py +++ b/festim/concentration/traps/traps.py @@ -10,15 +10,9 @@ class Traps(list): def __init__(self, *args): # checks that input is list - try: - super().__init__(*args) - except: + if not isinstance(*args, list): raise TypeError("festim.Traps must be a list") - - # checks that list elements are festim.Export - if len(self) != 0: - if not all(isinstance(t, festim.Trap) for t in self): - raise TypeError("festim.Traps must be a list of festim.Trap") + super().__init__(self._validate_trap(item) for item in args[0]) self.F = None self.extrinsic_formulations = [] @@ -32,11 +26,44 @@ def __init__(self, *args): @property def traps(self): warnings.warn( - "The traps attribute will be deprecated in a future release, please use festim.Traps[:] instead", + "The traps attribute will be deprecated in a future release, please use festim.Traps as a list instead", DeprecationWarning, ) return self + @traps.setter + def traps(self, value): + warnings.warn( + "The traps attribute will be deprecated in a future release, please use festim.Traps as a list instead", + DeprecationWarning, + ) + if isinstance(value, list): + if not all(isinstance(t, festim.Trap) for t in value): + raise TypeError("traps must be a list of festim.Trap") + super().__init__(value) + else: + raise TypeError("traps must be a list") + + def __setitem__(self, index, item): + super().__setitem__(index, self._validate_trap(item)) + + def insert(self, index, item): + super().insert(index, self._validate_trap(item)) + + def append(self, item): + super().append(self._validate_trap(item)) + + def extend(self, other): + if isinstance(other, type(self)): + super().extend(other) + else: + super().extend(self._validate_trap(item) for item in other) + + def _validate_trap(self, value): + if isinstance(value, festim.Trap): + return value + raise TypeError("festim.Traps must be a list of festim.Trap") + def make_traps_materials(self, materials): for trap in self: trap.make_materials(materials) diff --git a/festim/exports/derived_quantities/derived_quantities.py b/festim/exports/derived_quantities/derived_quantities.py index 04e8d0a8b..5a4cfe594 100644 --- a/festim/exports/derived_quantities/derived_quantities.py +++ b/festim/exports/derived_quantities/derived_quantities.py @@ -33,17 +33,9 @@ def __init__( nb_iterations_between_exports: int = None, ) -> None: # checks that input is list - try: - super().__init__(*args) - except: + if not isinstance(*args, list): raise TypeError("festim.DerivedQuantities must be a list") - - # checks that list elements are festim.Export - if len(self) != 0: - if not all(isinstance(t, DerivedQuantity) for t in self): - raise TypeError( - "festim.DerivedQuantities must be a list of festim.DerivedQuantity" - ) + super().__init__(self._validate_derived_quantity(item) for item in args[0]) self.filename = filename self.nb_iterations_between_compute = nb_iterations_between_compute @@ -55,11 +47,48 @@ def __init__( @property def derived_quantities(self): warnings.warn( - "The derived_quantities attribute will be deprecated in a future release, please use festim.DerivedQuantities[:] instead", + "The derived_quantities attribute will be deprecated in a future release, please use festim.DerivedQuantities as a list instead", DeprecationWarning, ) return self + @derived_quantities.setter + def derived_quantities(self, value): + warnings.warn( + "The derived_quantities attribute will be deprecated in a future release, please use festim.DerivedQuantities as a list instead", + DeprecationWarning, + ) + if isinstance(value, list): + if not all(isinstance(t, DerivedQuantity) for t in value): + raise TypeError( + "derived_quantities must be a list of festim.DerivedQuantity" + ) + super().__init__(value) + else: + raise TypeError("derived_quantities must be a list") + + def __setitem__(self, index, item): + super().__setitem__(index, self._validate_derived_quantity(item)) + + def insert(self, index, item): + super().insert(index, self._validate_derived_quantity(item)) + + def append(self, item): + super().append(self._validate_derived_quantity(item)) + + def extend(self, other): + if isinstance(other, type(self)): + super().extend(other) + else: + super().extend(self._validate_derived_quantity(item) for item in other) + + def _validate_derived_quantity(self, value): + if isinstance(value, DerivedQuantity): + return value + raise TypeError( + "festim.DerivedQuantities must be a list of festim.DerivedQuantity" + ) + @property def filename(self): return self._filename diff --git a/festim/exports/exports.py b/festim/exports/exports.py index ec90f7915..84a23ef4d 100644 --- a/festim/exports/exports.py +++ b/festim/exports/exports.py @@ -10,18 +10,9 @@ class Exports(list): def __init__(self, *args): # checks that input is list - try: - super().__init__(*args) - except: + if not isinstance(*args, list): raise TypeError("festim.Exports must be a list") - - # checks that list elements are festim.Export - if len(self) != 0: - if not all( - isinstance(t, festim.Export) or isinstance(t, festim.DerivedQuantities) - for t in self - ): - raise TypeError("festim.Exports must be a list of festim.Export") + super().__init__(self._validate_export(item) for item in args[0]) self.t = None self.V_DG1 = None @@ -31,11 +22,52 @@ def __init__(self, *args): @property def exports(self): warnings.warn( - "The exports attribute will be deprecated in a future release, please use festim.Exports[:] instead", + "The exports attribute will be deprecated in a future release, please use festim.Exports as a list instead", DeprecationWarning, ) return self + @exports.setter + def exports(self, value): + warnings.warn( + "The exports attribute will be deprecated in a future release, please use festim.Exports as a list instead", + DeprecationWarning, + ) + if isinstance(value, list): + if not all( + ( + isinstance(t, festim.Export) + or isinstance(t, festim.DerivedQuantities) + ) + for t in value + ): + raise TypeError("exports must be a list of festim.Export") + super().__init__(value) + else: + raise TypeError("exports must be a list") + + def __setitem__(self, index, item): + super().__setitem__(index, self._validate_export(item)) + + def insert(self, index, item): + super().insert(index, self._validate_export(item)) + + def append(self, item): + super().append(self._validate_export(item)) + + def extend(self, other): + if isinstance(other, type(self)): + super().extend(other) + else: + super().extend(self._validate_export(item) for item in other) + + def _validate_export(self, value): + if isinstance(value, festim.Export) or isinstance( + value, festim.DerivedQuantities + ): + return value + raise TypeError("festim.Exports must be a list of festim.Export") + def write(self, label_to_function, dx): """writes to file @@ -48,7 +80,7 @@ def write(self, label_to_function, dx): # compute derived quantities if export.is_compute(self.nb_iterations): # check if function has to be projected - for quantity in export.derived_quantities: + for quantity in export: if isinstance( quantity, (festim.MaximumVolume, festim.MinimumVolume) ): diff --git a/festim/materials/materials.py b/festim/materials/materials.py index 4924b7e80..be5b6c16b 100644 --- a/festim/materials/materials.py +++ b/festim/materials/materials.py @@ -15,15 +15,9 @@ class Materials(list): def __init__(self, *args): # checks that input is list - try: - super().__init__(*args) - except: + if not isinstance(*args, list): raise TypeError("festim.Materials must be a list") - - # checks that list elements are festim.Material - if len(self) != 0: - if not all(isinstance(t, festim.Material) for t in self): - raise TypeError("festim.Materials must be a list of festim.Material") + super().__init__(self._validate_material(item) for item in args[0]) self.D = None self.S = None @@ -35,11 +29,44 @@ def __init__(self, *args): @property def materials(self): warnings.warn( - "The materials attribute will be deprecated in a future release, please use festim.Materials[:] instead", + "The materials attribute will be deprecated in a future release, please use festim.Materials as a list instead", DeprecationWarning, ) return self + @materials.setter + def materials(self, value): + warnings.warn( + "The materials attribute will be deprecated in a future release, please use festim.Materials as a list instead", + DeprecationWarning, + ) + if isinstance(value, list): + if not all(isinstance(t, festim.Material) for t in value): + raise TypeError("materials must be a list of festim.Material") + super().__init__(value) + else: + raise TypeError("materials must be a list") + + def __setitem__(self, index, item): + super().__setitem__(index, self._validate_material(item)) + + def insert(self, index, item): + super().insert(index, self._validate_material(item)) + + def append(self, item): + super().append(self._validate_material(item)) + + def extend(self, other): + if isinstance(other, type(self)): + super().extend(other) + else: + super().extend(self._validate_material(item) for item in other) + + def _validate_material(self, value): + if isinstance(value, festim.Material): + return value + raise TypeError("festim.Materials must be a list of festim.Material") + def check_borders(self, size): """Checks that the borders of the materials match diff --git a/test/h_transport_problem/test_initialisation.py b/test/h_transport_problem/test_initialisation.py index 274196416..e0cfa77c0 100644 --- a/test/h_transport_problem/test_initialisation.py +++ b/test/h_transport_problem/test_initialisation.py @@ -49,7 +49,7 @@ def test_initialisation_from_xdmf(tmpdir): ) my_problem.V = V - my_mats = festim.Materials() + my_mats = festim.Materials([]) my_mats.S = None my_problem.initialise_concentrations() w = my_problem.u_n diff --git a/test/h_transport_problem/test_solving.py b/test/h_transport_problem/test_solving.py index 9144a113c..8aa7d5dae 100644 --- a/test/h_transport_problem/test_solving.py +++ b/test/h_transport_problem/test_solving.py @@ -24,7 +24,7 @@ def test_default_dt_min_value(): final_time=500, ) my_problem = festim.HTransportProblem( - festim.Mobile(), festim.Traps(), festim.Temperature(200), my_settings, [] + festim.Mobile(), festim.Traps([]), festim.Temperature(200), my_settings, [] ) my_problem.u = f.Function(V) my_problem.u_n = f.Function(V) @@ -47,7 +47,7 @@ def test_solve_once_jacobian_is_none(): absolute_tolerance=1e-10, relative_tolerance=1e-10, maximum_iterations=50 ) my_problem = festim.HTransportProblem( - festim.Mobile(), festim.Traps(), festim.Temperature(200), my_settings, [] + festim.Mobile(), festim.Traps([]), festim.Temperature(200), my_settings, [] ) my_problem.u = f.Function(V) my_problem.u_n = f.Function(V) @@ -74,7 +74,7 @@ def test_solve_once_returns_false(): absolute_tolerance=1e-20, relative_tolerance=1e-20, maximum_iterations=1 ) my_problem = festim.HTransportProblem( - festim.Mobile(), festim.Traps(), festim.Temperature(200), my_settings, [] + festim.Mobile(), festim.Traps([]), festim.Temperature(200), my_settings, [] ) my_problem.u = f.Function(V) my_problem.u_n = f.Function(V) @@ -104,7 +104,7 @@ def test_solve_once_linear_solver_mumps(): linear_solver="mumps", ) my_problem = festim.HTransportProblem( - festim.Mobile(), festim.Traps(), festim.Temperature(200), my_settings, [] + festim.Mobile(), festim.Traps([]), festim.Temperature(200), my_settings, [] ) my_problem.u = f.Function(V) my_problem.u_n = f.Function(V) diff --git a/test/system/test_misc.py b/test/system/test_misc.py index ce18cb60f..aff0b2b98 100644 --- a/test/system/test_misc.py +++ b/test/system/test_misc.py @@ -314,18 +314,17 @@ def test_materials_setter(): assert my_model.materials is test_materials -def test_depr_warns(): +def test_property_depr_warns(): """ - A temporary test to check DeprecationWarnings + A temporary test to check DeprecationWarnings in @property """ my_mat = F.Material(id=1, E_D=1, D_0=1) my_mats = F.Materials([my_mat]) my_derived_quantities = F.DerivedQuantities([F.SurfaceFlux(0, 2)]) my_exports = F.Exports([F.Export(field=0)] + my_derived_quantities) - my_traps = F.Traps( - [F.Trap(k_0=1, E_k=1, p_0=1, E_p=1, density=1, materials=my_mat)] - ) + my_trap = F.Trap(k_0=1, E_k=1, p_0=1, E_p=1, density=1, materials=my_mat) + my_traps = F.Traps([my_trap]) with pytest.deprecated_call(): my_mats.materials[0] @@ -338,3 +337,96 @@ def test_depr_warns(): with pytest.deprecated_call(): my_traps.traps[0] + + +def test_property_setter_depr_warns(): + """ + A temporary test to check DeprecationWarnings in @property.setter + """ + + my_mat = F.Material(id=1, E_D=1, D_0=1) + my_derived_quantity = F.SurfaceFlux(0, 2) + my_export = F.Export(field=0) + my_trap = F.Trap(k_0=1, E_k=1, p_0=1, E_p=1, density=1, materials=my_mat) + + my_exports = F.Exports([]) + my_mats = F.Materials([]) + my_traps = F.Traps([]) + my_derived_quantities = F.DerivedQuantities([]) + + with pytest.deprecated_call(): + my_traps.traps = [my_trap] + + with pytest.deprecated_call(): + my_derived_quantities.derived_quantities = [my_derived_quantity] + + with pytest.deprecated_call(): + my_exports.exports = [my_export] + + with pytest.deprecated_call(): + my_mats.materials = [my_mat] + + +def test_set_attr_wrong_type(): + """ + Checks an error is raised in @property.setter when the attribute + is set with the wrong type + """ + + my_mat = F.Material(id=1, E_D=1, D_0=1) + my_derived_quantity = F.SurfaceFlux(0, 2) + my_export = F.Export(field=0) + my_trap = F.Trap(k_0=1, E_k=1, p_0=1, E_p=1, density=1, materials=my_mat) + + my_exports = F.Exports([]) + my_mats = F.Materials([]) + my_traps = F.Traps([]) + my_derived_quantities = F.DerivedQuantities([]) + + with pytest.raises( + TypeError, + match="traps must be a list", + ): + my_traps.traps = my_trap + + with pytest.raises( + TypeError, + match="traps must be a list of festim.Trap", + ): + my_traps.traps = [my_trap, 1] + + with pytest.raises( + TypeError, + match="derived_quantities must be a list", + ): + my_derived_quantities.derived_quantities = my_derived_quantity + + with pytest.raises( + TypeError, + match="derived_quantities must be a list of festim.DerivedQuantity", + ): + my_derived_quantities.derived_quantities = [my_derived_quantity, 1] + + with pytest.raises( + TypeError, + match="exports must be a list", + ): + my_exports.exports = my_export + + with pytest.raises( + TypeError, + match="exports must be a list of festim.Export", + ): + my_exports.exports = [my_export, 1] + + with pytest.raises( + TypeError, + match="materials must be a list", + ): + my_mats.materials = my_mat + + with pytest.raises( + TypeError, + match="materials must be a list of festim.Material", + ): + my_mats.materials = [my_mat, 1] diff --git a/test/unit/test_exports/test_derived_quantities/test_derived_quantities.py b/test/unit/test_exports/test_derived_quantities/test_derived_quantities.py index 97036a5cb..53ac6f06d 100644 --- a/test/unit/test_exports/test_derived_quantities/test_derived_quantities.py +++ b/test/unit/test_exports/test_derived_quantities/test_derived_quantities.py @@ -15,7 +15,6 @@ class TestMakeHeader: - my_derv_quant = None surface_flux_1 = SurfaceFlux("solute", 2) surface_flux_2 = SurfaceFlux("T", 3) average_vol_1 = AverageVolume("solute", 3) @@ -26,39 +25,35 @@ class TestMakeHeader: min_vol_1 = MinimumVolume("retention", 2) max_vol_1 = MaximumVolume("T", 2) - @property - def my_derv_quant(self): - return self._my_derv_quant - - @my_derv_quant.setter - def my_derv_quant(self, value): - self._my_derv_quant = DerivedQuantities(value) - def test_simple(self): - self.my_derv_quant = [self.surface_flux_1] - header = self.my_derv_quant.make_header() + my_derv_quant = DerivedQuantities([self.surface_flux_1]) + header = my_derv_quant.make_header() expected_header = ["t(s)", self.surface_flux_1.title] assert header == expected_header def test_two_quantities(self): - self.my_derv_quant = [ - self.surface_flux_1, - self.tot_surf_1, - ] - header = self.my_derv_quant.make_header() + my_derv_quant = DerivedQuantities( + [ + self.surface_flux_1, + self.tot_surf_1, + ] + ) + header = my_derv_quant.make_header() expected_header = ["t(s)", self.surface_flux_1.title, self.tot_surf_1.title] assert header == expected_header def test_all_quantities(self): - self.my_derv_quant = [ - self.surface_flux_1, - self.average_vol_1, - self.tot_surf_1, - self.tot_vol_1, - self.min_vol_1, - self.max_vol_1, - ] - header = self.my_derv_quant.make_header() + my_derv_quant = DerivedQuantities( + [ + self.surface_flux_1, + self.average_vol_1, + self.tot_surf_1, + self.tot_vol_1, + self.min_vol_1, + self.max_vol_1, + ] + ) + header = my_derv_quant.make_header() expected_header = ["t(s)"] + [ self.surface_flux_1.title, self.average_vol_1.title, @@ -108,7 +103,7 @@ class TestAssignPropertiesToQuantities: AverageVolume("solute", 3), ] ) - my_mats = Materials() + my_mats = Materials([]) my_mats.D = f.Function(V) my_mats.S = f.Function(V) my_mats.Q = f.Function(V) @@ -135,7 +130,6 @@ def test_quantities_have_thermal_cond(self): class TestCompute: - my_derv_quant = None surface_flux_1 = SurfaceFlux("solute", 2) surface_flux_2 = SurfaceFlux("T", 3) average_vol_1 = AverageVolume("solute", 1) @@ -167,78 +161,74 @@ class TestCompute: n = f.FacetNormal(mesh) T = f.interpolate(f.Constant(2), V) - my_mats = Materials() + my_mats = Materials([]) my_mats.D = f.interpolate(f.Constant(2), V) my_mats.S = f.interpolate(f.Constant(2), V) my_mats.H = f.interpolate(f.Constant(2), V) my_mats.thermal_cond = f.interpolate(f.Constant(2), V) - @property - def my_derv_quant(self): - return self._my_derv_quant - - @my_derv_quant.setter - def my_derv_quant(self, value): - self._my_derv_quant = DerivedQuantities(value) - def test_simple(self): - self.my_derv_quant = [self.surface_flux_1] - for quantity in self.my_derv_quant: + my_derv_quant = DerivedQuantities([self.surface_flux_1]) + for quantity in my_derv_quant: quantity.function = self.label_to_function[quantity.field] - self.my_derv_quant.assign_properties_to_quantities(self.my_mats) - self.my_derv_quant.assign_measures_to_quantities(self.dx, self.ds) + my_derv_quant.assign_properties_to_quantities(self.my_mats) + my_derv_quant.assign_measures_to_quantities(self.dx, self.ds) t = 2 - expected_data = [t] + [quantity.compute() for quantity in self.my_derv_quant] + expected_data = [t] + [quantity.compute() for quantity in my_derv_quant] - self.my_derv_quant.data = [] - self.my_derv_quant.compute(t) - assert self.my_derv_quant.data[0] == expected_data + my_derv_quant.data = [] + my_derv_quant.compute(t) + assert my_derv_quant.data[0] == expected_data def test_two_quantities(self): - self.my_derv_quant = [ - self.surface_flux_1, - self.average_vol_1, - ] - for quantity in self.my_derv_quant: + my_derv_quant = DerivedQuantities( + [ + self.surface_flux_1, + self.average_vol_1, + ] + ) + for quantity in my_derv_quant: quantity.function = self.label_to_function[quantity.field] - self.my_derv_quant.assign_properties_to_quantities(self.my_mats) - self.my_derv_quant.assign_measures_to_quantities(self.dx, self.ds) + my_derv_quant.assign_properties_to_quantities(self.my_mats) + my_derv_quant.assign_measures_to_quantities(self.dx, self.ds) t = 2 - expected_data = [t] + [quantity.compute() for quantity in self.my_derv_quant] + expected_data = [t] + [quantity.compute() for quantity in my_derv_quant] - self.my_derv_quant.data = [] - self.my_derv_quant.compute(t) + my_derv_quant.data = [] + my_derv_quant.compute(t) - assert self.my_derv_quant.data[0] == expected_data + assert my_derv_quant.data[0] == expected_data def test_all_quantities(self): - self.my_derv_quant = [ - self.surface_flux_1, - self.average_vol_1, - self.tot_surf_1, - self.tot_vol_1, - self.min_vol_1, - self.max_vol_1, - ] - for quantity in self.my_derv_quant: + my_derv_quant = DerivedQuantities( + [ + self.surface_flux_1, + self.average_vol_1, + self.tot_surf_1, + self.tot_vol_1, + self.min_vol_1, + self.max_vol_1, + ] + ) + for quantity in my_derv_quant: quantity.function = self.label_to_function[quantity.field] - self.my_derv_quant.assign_properties_to_quantities(self.my_mats) - self.my_derv_quant.assign_measures_to_quantities(self.dx, self.ds) + my_derv_quant.assign_properties_to_quantities(self.my_mats) + my_derv_quant.assign_measures_to_quantities(self.dx, self.ds) t = 2 expected_data = [t] - for quantity in self.my_derv_quant: + for quantity in my_derv_quant: if isinstance(quantity, (MaximumVolume, MinimumVolume)): expected_data.append(quantity.compute(self.vol_markers)) else: expected_data.append(quantity.compute()) - self.my_derv_quant.data = [] - self.my_derv_quant.compute(t) + my_derv_quant.data = [] + my_derv_quant.compute(t) - assert self.my_derv_quant.data[0] == expected_data + assert my_derv_quant.data[0] == expected_data class TestWrite: @@ -249,7 +239,7 @@ def folder(self, tmpdir): @pytest.fixture def my_derived_quantities(self): filename = "my_file.csv" - my_derv_quant = DerivedQuantities(filename=filename) + my_derv_quant = DerivedQuantities([], filename=filename) my_derv_quant.data = [ ["a", "b", "c"], [1, 2, 3], @@ -330,13 +320,13 @@ def test_several_quantities_one_surface(self): def test_wrong_type_filename(): """Checks that an error is raised when filename is not a string""" with pytest.raises(TypeError, match="filename must be a string"): - DerivedQuantities(filename=2) + DerivedQuantities([], filename=2) def test_filename_ends_with_csv(): """Checks that an error is raised when filename doesn't end with .csv""" with pytest.raises(ValueError, match="filename must end with .csv"): - DerivedQuantities(filename="coucou") + DerivedQuantities([], filename="coucou") def test_set_derived_quantitites_wrong_type(): @@ -357,3 +347,35 @@ def test_set_derived_quantitites_wrong_type(): match="festim.DerivedQuantities must be a list of festim.DerivedQuantity", ): DerivedQuantities([flux1, 2]) + + +def test_assign_derived_quantitites_wrong_type(): + """Checks an error is raised when the wrong type is assigned to festim.DerivedQuantities""" + my_derived_quantities = DerivedQuantities([]) + combinations = ["coucou", 1, True] + error_pattern = "festim.DerivedQuantities must be a list of festim.DerivedQuantity" + + for dq_combination in combinations: + with pytest.raises( + TypeError, + match=error_pattern, + ): + my_derived_quantities.append(dq_combination) + + with pytest.raises( + TypeError, + match=error_pattern, + ): + my_derived_quantities.extend([dq_combination]) + + with pytest.raises( + TypeError, + match=error_pattern, + ): + my_derived_quantities[0] = dq_combination + + with pytest.raises( + TypeError, + match=error_pattern, + ): + my_derived_quantities.insert(0, dq_combination) diff --git a/test/unit/test_exports/test_exports.py b/test/unit/test_exports/test_exports.py index af1d674c6..9fcba7180 100644 --- a/test/unit/test_exports/test_exports.py +++ b/test/unit/test_exports/test_exports.py @@ -2,11 +2,11 @@ import pytest -def test_set_traps_wrong_type(): +def test_set_exports_wrong_type(): """Checks an error is raised when festim.Exports is set with the wrong type""" - export = festim.Export(field=0) + my_export = festim.Export(field=0) - combinations = [export, "coucou", 1, True] + combinations = [my_export, "coucou", 1, True] for export_combination in combinations: with pytest.raises( @@ -19,4 +19,39 @@ def test_set_traps_wrong_type(): TypeError, match="festim.Exports must be a list of festim.Export", ): - festim.Exports([export, 2]) + festim.Exports([my_export, 2]) + + +def test_assign_exports_wrong_type(): + """Checks an error is raised when the wrong type is assigned to festim.Exports""" + my_export = festim.Export(field=0) + my_exports = festim.Exports([my_export]) + + combinations = ["coucou", 1, True] + + error_pattern = "festim.Exports must be a list of festim.Export" + + for export_combination in combinations: + with pytest.raises( + TypeError, + match=error_pattern, + ): + my_exports.append(export_combination) + + with pytest.raises( + TypeError, + match=error_pattern, + ): + my_exports.extend([export_combination]) + + with pytest.raises( + TypeError, + match=error_pattern, + ): + my_exports[0] = export_combination + + with pytest.raises( + TypeError, + match=error_pattern, + ): + my_exports.insert(0, export_combination) diff --git a/test/unit/test_materials.py b/test/unit/test_materials.py index 779a44160..7cbcd4e3e 100644 --- a/test/unit/test_materials.py +++ b/test/unit/test_materials.py @@ -327,3 +327,38 @@ def test_set_materials_wrong_type(): match="festim.Materials must be a list of festim.Material", ): F.Materials([my_mat, 2]) + + +def test_assign_materials_wrong_type(): + """Checks an error is raised when the wrong type is assigned to festim.Materials""" + my_mat = F.Material(1, 1, 0) + my_materials = F.Materials([my_mat]) + + combinations = ["coucou", 1, True] + + error_pattern = "festim.Materials must be a list of festim.Material" + + for mat_combination in combinations: + with pytest.raises( + TypeError, + match=error_pattern, + ): + my_materials.append(mat_combination) + + with pytest.raises( + TypeError, + match=error_pattern, + ): + my_materials.extend([mat_combination]) + + with pytest.raises( + TypeError, + match=error_pattern, + ): + my_materials[0] = mat_combination + + with pytest.raises( + TypeError, + match=error_pattern, + ): + my_materials.insert(0, mat_combination) diff --git a/test/unit/test_traps/test_traps.py b/test/unit/test_traps/test_traps.py index 8ff4ca1f0..1ce5255dd 100644 --- a/test/unit/test_traps/test_traps.py +++ b/test/unit/test_traps/test_traps.py @@ -14,27 +14,6 @@ def test_set_traps(): festim.Traps(trap_combination) -def test_set_traps_wrong_type(): - """Checks an error is raised when festim.Traps is set with the wrong type""" - my_mat = festim.Material(1, 1, 0) - trap1 = festim.Trap(1, 1, 1, 1, [my_mat], density=1) - - combinations = [trap1, "coucou", 1, True] - - for trap_combination in combinations: - with pytest.raises( - TypeError, - match="festim.Traps must be a list", - ): - festim.Traps(trap_combination) - - with pytest.raises( - TypeError, - match="festim.Traps must be a list of festim.Trap", - ): - festim.Traps([trap1, 2]) - - def add_functions(trap, V, id=1): trap.solution = f.Function(V, name="c_t_{}".format(id)) trap.previous_solution = f.Function(V, name="c_t_n_{}".format(id)) @@ -124,3 +103,59 @@ def test_error_is_raised_when_not_found(self): id = -2 with pytest.raises(ValueError, match="Couldn't find trap {}".format(id)): self.my_traps.get_trap(id=id) + + +def test_set_traps_wrong_type(): + """Checks an error is raised when festim.Traps is set with the wrong type""" + my_mat = festim.Material(1, 1, 0) + trap1 = festim.Trap(1, 1, 1, 1, [my_mat], density=1) + + combinations = [trap1, "coucou", 1, True] + + for trap_combination in combinations: + with pytest.raises( + TypeError, + match="festim.Traps must be a list", + ): + festim.Traps(trap_combination) + + with pytest.raises( + TypeError, + match="festim.Traps must be a list of festim.Trap", + ): + festim.Traps([trap1, 2]) + + +def test_assign_traps_wrong_type(): + """Checks an error is raised when the wrong type is assigned to festim.Traps""" + my_mat = festim.Material(1, 1, 0) + trap1 = festim.Trap(1, 1, 1, 1, [my_mat], density=1) + my_traps = festim.Traps([trap1]) + + combinations = ["coucou", 1, True] + error_pattern = "festim.Traps must be a list of festim.Trap" + + for trap_combination in combinations: + with pytest.raises( + TypeError, + match=error_pattern, + ): + my_traps.append(trap_combination) + + with pytest.raises( + TypeError, + match=error_pattern, + ): + my_traps.extend([trap_combination]) + + with pytest.raises( + TypeError, + match=error_pattern, + ): + my_traps[0] = trap_combination + + with pytest.raises( + TypeError, + match=error_pattern, + ): + my_traps.insert(0, trap_combination) From 0d2e3d6e3cb98267adeb21913385b6e675298872 Mon Sep 17 00:00:00 2001 From: KulaginVladimir Date: Mon, 5 Feb 2024 21:57:07 +0300 Subject: [PATCH 4/5] tests for methods --- .../test_derived_quantities.py | 21 ++++++++++++++++++ test/unit/test_exports/test_exports.py | 22 +++++++++++++++++++ test/unit/test_materials.py | 22 +++++++++++++++++++ test/unit/test_traps/test_traps.py | 22 +++++++++++++++++++ 4 files changed, 87 insertions(+) diff --git a/test/unit/test_exports/test_derived_quantities/test_derived_quantities.py b/test/unit/test_exports/test_derived_quantities/test_derived_quantities.py index 53ac6f06d..9e0025524 100644 --- a/test/unit/test_exports/test_derived_quantities/test_derived_quantities.py +++ b/test/unit/test_exports/test_derived_quantities/test_derived_quantities.py @@ -329,6 +329,27 @@ def test_filename_ends_with_csv(): DerivedQuantities([], filename="coucou") +def test_derived_quantities_methods(): + flux1 = SurfaceFlux(field="solute", surface=1) + flux2 = SurfaceFlux(field="solute", surface=2) + my_dqs = DerivedQuantities([flux1]) + + my_dqs.append(flux2) + assert my_dqs == [flux1, flux2] + + my_dqs.insert(0, flux2) + assert my_dqs == [flux2, flux1, flux2] + + my_dqs[0] = flux1 + assert my_dqs == [flux1, flux1, flux2] + + my_dqs.extend([flux1]) + assert my_dqs == [flux1, flux1, flux2, flux1] + + my_dqs.extend(DerivedQuantities([flux2])) + assert my_dqs == DerivedQuantities([flux1, flux1, flux2, flux1, flux2]) + + def test_set_derived_quantitites_wrong_type(): """Checks an error is raised when festim.DerivedQuantities is set with the wrong type""" flux1 = SurfaceFlux(field="solute", surface=1) diff --git a/test/unit/test_exports/test_exports.py b/test/unit/test_exports/test_exports.py index 9fcba7180..ac6d74566 100644 --- a/test/unit/test_exports/test_exports.py +++ b/test/unit/test_exports/test_exports.py @@ -2,6 +2,28 @@ import pytest +def test_exports_methods(): + my_exp1 = festim.Export(field=0) + my_exp2 = festim.Export(field="T") + + my_exports = festim.Exports([my_exp1]) + + my_exports.append(my_exp2) + assert my_exports == [my_exp1, my_exp2] + + my_exports.insert(0, my_exp2) + assert my_exports == [my_exp2, my_exp1, my_exp2] + + my_exports[0] = my_exp1 + assert my_exports == [my_exp1, my_exp1, my_exp2] + + my_exports.extend([my_exp1]) + assert my_exports == [my_exp1, my_exp1, my_exp2, my_exp1] + + my_exports.extend(festim.Exports([my_exp2])) + assert my_exports == festim.Exports([my_exp1, my_exp1, my_exp2, my_exp1, my_exp2]) + + def test_set_exports_wrong_type(): """Checks an error is raised when festim.Exports is set with the wrong type""" my_export = festim.Export(field=0) diff --git a/test/unit/test_materials.py b/test/unit/test_materials.py index 7cbcd4e3e..883eb1710 100644 --- a/test/unit/test_materials.py +++ b/test/unit/test_materials.py @@ -309,6 +309,28 @@ def test_equality_identity_two_empty_materials(): assert (my_materials1 == my_materials2) and (my_materials1 is not my_materials2) +def test_materials_methods(): + my_mat1 = F.Material(1, 1, 0) + my_mat2 = F.Material(2, 1, 0) + + my_materials = F.Materials([my_mat1]) + + my_materials.append(my_mat2) + assert my_materials == [my_mat1, my_mat2] + + my_materials.insert(0, my_mat2) + assert my_materials == [my_mat2, my_mat1, my_mat2] + + my_materials[0] = my_mat1 + assert my_materials == [my_mat1, my_mat1, my_mat2] + + my_materials.extend([my_mat1]) + assert my_materials == [my_mat1, my_mat1, my_mat2, my_mat1] + + my_materials.extend(F.Materials([my_mat2])) + assert my_materials == F.Materials([my_mat1, my_mat1, my_mat2, my_mat1, my_mat2]) + + def test_set_materials_wrong_type(): """Checks an error is raised when festim.Materials is set with the wrong type""" my_mat = F.Material(1, 1, 0) diff --git a/test/unit/test_traps/test_traps.py b/test/unit/test_traps/test_traps.py index 1ce5255dd..973eff232 100644 --- a/test/unit/test_traps/test_traps.py +++ b/test/unit/test_traps/test_traps.py @@ -105,6 +105,28 @@ def test_error_is_raised_when_not_found(self): self.my_traps.get_trap(id=id) +def test_traps_methods(): + my_mat = festim.Material(1, 1, 0) + my_trap1 = festim.Trap(1, 1, 1, 1, [my_mat], density=1) + my_trap2 = festim.Trap(2, 1, 1, 1, [my_mat], density=1) + my_traps = festim.Traps([my_trap1]) + + my_traps.append(my_trap2) + assert my_traps == [my_trap1, my_trap2] + + my_traps.insert(0, my_trap2) + assert my_traps == [my_trap2, my_trap1, my_trap2] + + my_traps[0] = my_trap1 + assert my_traps == [my_trap1, my_trap1, my_trap2] + + my_traps.extend([my_trap1]) + assert my_traps == [my_trap1, my_trap1, my_trap2, my_trap1] + + my_traps.extend(festim.Traps([my_trap2])) + assert my_traps == festim.Traps([my_trap1, my_trap1, my_trap2, my_trap1, my_trap2]) + + def test_set_traps_wrong_type(): """Checks an error is raised when festim.Traps is set with the wrong type""" my_mat = festim.Material(1, 1, 0) From 0d68ce50ee5087d24d0b13908ba19b2e4e9af21c Mon Sep 17 00:00:00 2001 From: KulaginVladimir Date: Tue, 6 Feb 2024 11:13:24 +0300 Subject: [PATCH 5/5] upd tests --- test/system/test_misc.py | 118 ------------------ .../test_derived_quantities.py | 75 +++++++++-- test/unit/test_exports/test_exports.py | 76 +++++++++-- test/unit/test_materials.py | 82 +++++++++--- test/unit/test_traps/test_traps.py | 89 ++++++++++--- 5 files changed, 271 insertions(+), 169 deletions(-) diff --git a/test/system/test_misc.py b/test/system/test_misc.py index aff0b2b98..1dbc3fdbb 100644 --- a/test/system/test_misc.py +++ b/test/system/test_misc.py @@ -312,121 +312,3 @@ def test_materials_setter(): test_materials = F.Materials([]) my_model.materials = test_materials assert my_model.materials is test_materials - - -def test_property_depr_warns(): - """ - A temporary test to check DeprecationWarnings in @property - """ - - my_mat = F.Material(id=1, E_D=1, D_0=1) - my_mats = F.Materials([my_mat]) - my_derived_quantities = F.DerivedQuantities([F.SurfaceFlux(0, 2)]) - my_exports = F.Exports([F.Export(field=0)] + my_derived_quantities) - my_trap = F.Trap(k_0=1, E_k=1, p_0=1, E_p=1, density=1, materials=my_mat) - my_traps = F.Traps([my_trap]) - - with pytest.deprecated_call(): - my_mats.materials[0] - - with pytest.deprecated_call(): - my_exports.exports[0] - - with pytest.deprecated_call(): - my_derived_quantities.derived_quantities[0] - - with pytest.deprecated_call(): - my_traps.traps[0] - - -def test_property_setter_depr_warns(): - """ - A temporary test to check DeprecationWarnings in @property.setter - """ - - my_mat = F.Material(id=1, E_D=1, D_0=1) - my_derived_quantity = F.SurfaceFlux(0, 2) - my_export = F.Export(field=0) - my_trap = F.Trap(k_0=1, E_k=1, p_0=1, E_p=1, density=1, materials=my_mat) - - my_exports = F.Exports([]) - my_mats = F.Materials([]) - my_traps = F.Traps([]) - my_derived_quantities = F.DerivedQuantities([]) - - with pytest.deprecated_call(): - my_traps.traps = [my_trap] - - with pytest.deprecated_call(): - my_derived_quantities.derived_quantities = [my_derived_quantity] - - with pytest.deprecated_call(): - my_exports.exports = [my_export] - - with pytest.deprecated_call(): - my_mats.materials = [my_mat] - - -def test_set_attr_wrong_type(): - """ - Checks an error is raised in @property.setter when the attribute - is set with the wrong type - """ - - my_mat = F.Material(id=1, E_D=1, D_0=1) - my_derived_quantity = F.SurfaceFlux(0, 2) - my_export = F.Export(field=0) - my_trap = F.Trap(k_0=1, E_k=1, p_0=1, E_p=1, density=1, materials=my_mat) - - my_exports = F.Exports([]) - my_mats = F.Materials([]) - my_traps = F.Traps([]) - my_derived_quantities = F.DerivedQuantities([]) - - with pytest.raises( - TypeError, - match="traps must be a list", - ): - my_traps.traps = my_trap - - with pytest.raises( - TypeError, - match="traps must be a list of festim.Trap", - ): - my_traps.traps = [my_trap, 1] - - with pytest.raises( - TypeError, - match="derived_quantities must be a list", - ): - my_derived_quantities.derived_quantities = my_derived_quantity - - with pytest.raises( - TypeError, - match="derived_quantities must be a list of festim.DerivedQuantity", - ): - my_derived_quantities.derived_quantities = [my_derived_quantity, 1] - - with pytest.raises( - TypeError, - match="exports must be a list", - ): - my_exports.exports = my_export - - with pytest.raises( - TypeError, - match="exports must be a list of festim.Export", - ): - my_exports.exports = [my_export, 1] - - with pytest.raises( - TypeError, - match="materials must be a list", - ): - my_mats.materials = my_mat - - with pytest.raises( - TypeError, - match="materials must be a list of festim.Material", - ): - my_mats.materials = [my_mat, 1] diff --git a/test/unit/test_exports/test_derived_quantities/test_derived_quantities.py b/test/unit/test_exports/test_derived_quantities/test_derived_quantities.py index 9e0025524..f61cbb585 100644 --- a/test/unit/test_exports/test_derived_quantities/test_derived_quantities.py +++ b/test/unit/test_exports/test_derived_quantities/test_derived_quantities.py @@ -329,25 +329,35 @@ def test_filename_ends_with_csv(): DerivedQuantities([], filename="coucou") -def test_derived_quantities_methods(): +class TestDerivedQuantititesMethods: + """Checks that festim.DerivedQuantitites methods work properly""" + flux1 = SurfaceFlux(field="solute", surface=1) flux2 = SurfaceFlux(field="solute", surface=2) + my_dqs = DerivedQuantities([flux1]) - my_dqs.append(flux2) - assert my_dqs == [flux1, flux2] + def test_DQs_append(self): + self.my_dqs.append(self.flux2) + assert self.my_dqs == [self.flux1, self.flux2] - my_dqs.insert(0, flux2) - assert my_dqs == [flux2, flux1, flux2] + def test_DQs_insert(self): + self.my_dqs.insert(0, self.flux2) + assert self.my_dqs == [self.flux2, self.flux1, self.flux2] - my_dqs[0] = flux1 - assert my_dqs == [flux1, flux1, flux2] + def test_DQs_setitem(self): + self.my_dqs[0] = self.flux1 + assert self.my_dqs == [self.flux1, self.flux1, self.flux2] - my_dqs.extend([flux1]) - assert my_dqs == [flux1, flux1, flux2, flux1] + def test_DQs_extend_list_type(self): + self.my_dqs.extend([self.flux1]) + assert self.my_dqs == [self.flux1, self.flux1, self.flux2, self.flux1] - my_dqs.extend(DerivedQuantities([flux2])) - assert my_dqs == DerivedQuantities([flux1, flux1, flux2, flux1, flux2]) + def test_DQs_extend_self_type(self): + self.my_dqs.extend(DerivedQuantities([self.flux2])) + assert self.my_dqs == DerivedQuantities( + [self.flux1, self.flux1, self.flux2, self.flux1, self.flux2] + ) def test_set_derived_quantitites_wrong_type(): @@ -400,3 +410,46 @@ def test_assign_derived_quantitites_wrong_type(): match=error_pattern, ): my_derived_quantities.insert(0, dq_combination) + + +class TestDerivedQuantititesPropertyDeprWarn: + """ + A temporary test to check DeprecationWarnings in festim.DerivedQuantitites.exports + """ + + my_derived_quantity = SurfaceFlux(0, 2) + my_derived_quantities = DerivedQuantities([]) + + def test_property_depr_warns(self): + with pytest.deprecated_call(): + self.my_derived_quantities.derived_quantities + + def test_property_setter_depr_warns(self): + with pytest.deprecated_call(): + self.my_derived_quantities.derived_quantities = [self.my_derived_quantity] + + +class TestDerivedQuantititesPropertyRaiseError: + """ + A temporary test to check TypeErrors in festim.DerivedQuantitites.exports + """ + + my_derived_quantity = SurfaceFlux(0, 2) + my_derived_quantities = DerivedQuantities([]) + + def test_set_der_quants_wrong_type(self): + with pytest.raises( + TypeError, + match="derived_quantities must be a list", + ): + self.my_derived_quantities.derived_quantities = self.my_derived_quantity + + def test_set_der_quants_list_wrong_type(self): + with pytest.raises( + TypeError, + match="derived_quantities must be a list of festim.DerivedQuantity", + ): + self.my_derived_quantities.derived_quantities = [ + self.my_derived_quantity, + 1, + ] diff --git a/test/unit/test_exports/test_exports.py b/test/unit/test_exports/test_exports.py index ac6d74566..7df859d74 100644 --- a/test/unit/test_exports/test_exports.py +++ b/test/unit/test_exports/test_exports.py @@ -2,26 +2,40 @@ import pytest -def test_exports_methods(): +class TestExportsMethods: + """Checks that festim.Exports methods work properly""" + my_exp1 = festim.Export(field=0) my_exp2 = festim.Export(field="T") my_exports = festim.Exports([my_exp1]) - my_exports.append(my_exp2) - assert my_exports == [my_exp1, my_exp2] + def test_exports_append(self): + self.my_exports.append(self.my_exp2) + assert self.my_exports == [self.my_exp1, self.my_exp2] - my_exports.insert(0, my_exp2) - assert my_exports == [my_exp2, my_exp1, my_exp2] + def test_exports_insert(self): + self.my_exports.insert(0, self.my_exp2) + assert self.my_exports == [self.my_exp2, self.my_exp1, self.my_exp2] - my_exports[0] = my_exp1 - assert my_exports == [my_exp1, my_exp1, my_exp2] + def test_exports_setitem(self): + self.my_exports[0] = self.my_exp1 + assert self.my_exports == [self.my_exp1, self.my_exp1, self.my_exp2] - my_exports.extend([my_exp1]) - assert my_exports == [my_exp1, my_exp1, my_exp2, my_exp1] + def test_exports_extend_list_type(self): + self.my_exports.extend([self.my_exp1]) + assert self.my_exports == [ + self.my_exp1, + self.my_exp1, + self.my_exp2, + self.my_exp1, + ] - my_exports.extend(festim.Exports([my_exp2])) - assert my_exports == festim.Exports([my_exp1, my_exp1, my_exp2, my_exp1, my_exp2]) + def test_exports_extend_self_type(self): + self.my_exports.extend(festim.Exports([self.my_exp2])) + assert self.my_exports == festim.Exports( + [self.my_exp1, self.my_exp1, self.my_exp2, self.my_exp1, self.my_exp2] + ) def test_set_exports_wrong_type(): @@ -77,3 +91,43 @@ def test_assign_exports_wrong_type(): match=error_pattern, ): my_exports.insert(0, export_combination) + + +class TestExportsPropertyDeprWarn: + """ + A temporary test to check DeprecationWarnings in festim.Exports.exports + """ + + my_export = festim.Export(field=0) + my_exports = festim.Exports([]) + + def test_property_depr_warns(self): + with pytest.deprecated_call(): + self.my_exports.exports + + def test_property_setter_depr_warns(self): + with pytest.deprecated_call(): + self.my_exports.exports = [self.my_export] + + +class TestExportsPropertyRaiseError: + """ + A temporary test to check TypeErrors in festim.Exports.exports + """ + + my_export = festim.Export(field=0) + my_exports = festim.Exports([]) + + def test_set_exports_wrong_type(self): + with pytest.raises( + TypeError, + match="exports must be a list", + ): + self.my_exports.exports = self.my_export + + def test_set_exports_list_wrong_type(self): + with pytest.raises( + TypeError, + match="exports must be a list of festim.Export", + ): + self.my_exports.exports = [self.my_export, 1] diff --git a/test/unit/test_materials.py b/test/unit/test_materials.py index 883eb1710..9abe14c1a 100644 --- a/test/unit/test_materials.py +++ b/test/unit/test_materials.py @@ -309,26 +309,40 @@ def test_equality_identity_two_empty_materials(): assert (my_materials1 == my_materials2) and (my_materials1 is not my_materials2) -def test_materials_methods(): +class TestMaterialsMethods: + """Checks that F.Materials methods work properly""" + my_mat1 = F.Material(1, 1, 0) my_mat2 = F.Material(2, 1, 0) my_materials = F.Materials([my_mat1]) - my_materials.append(my_mat2) - assert my_materials == [my_mat1, my_mat2] - - my_materials.insert(0, my_mat2) - assert my_materials == [my_mat2, my_mat1, my_mat2] - - my_materials[0] = my_mat1 - assert my_materials == [my_mat1, my_mat1, my_mat2] - - my_materials.extend([my_mat1]) - assert my_materials == [my_mat1, my_mat1, my_mat2, my_mat1] + def test_mats_append(self): + self.my_materials.append(self.my_mat2) + assert self.my_materials == [self.my_mat1, self.my_mat2] + + def test_mats_insert(self): + self.my_materials.insert(0, self.my_mat2) + assert self.my_materials == [self.my_mat2, self.my_mat1, self.my_mat2] + + def test_mats_setitem(self): + self.my_materials[0] = self.my_mat1 + assert self.my_materials == [self.my_mat1, self.my_mat1, self.my_mat2] + + def test_mats_extend_list_type(self): + self.my_materials.extend([self.my_mat1]) + assert self.my_materials == [ + self.my_mat1, + self.my_mat1, + self.my_mat2, + self.my_mat1, + ] - my_materials.extend(F.Materials([my_mat2])) - assert my_materials == F.Materials([my_mat1, my_mat1, my_mat2, my_mat1, my_mat2]) + def test_mats_extend_self_type(self): + self.my_materials.extend(F.Materials([self.my_mat2])) + assert self.my_materials == F.Materials( + [self.my_mat1, self.my_mat1, self.my_mat2, self.my_mat1, self.my_mat2] + ) def test_set_materials_wrong_type(): @@ -384,3 +398,43 @@ def test_assign_materials_wrong_type(): match=error_pattern, ): my_materials.insert(0, mat_combination) + + +class TestMaterialsPropertyDeprWarn: + """ + A temporary test to check DeprecationWarnings in F.Materials.materials + """ + + my_mat = F.Material(id=1, E_D=1, D_0=1) + my_mats = F.Materials([]) + + def test_property_depr_warns(self): + with pytest.deprecated_call(): + self.my_mats.materials + + def test_property_setter_depr_warns(self): + with pytest.deprecated_call(): + self.my_mats.materials = [self.my_mat] + + +class TestMaterialsPropertyRaiseError: + """ + A temporary test to check TypeErrors in F.Materials.materials + """ + + my_mat = F.Material(id=1, E_D=1, D_0=1) + my_mats = F.Materials([]) + + def test_set_materials_wrong_type(self): + with pytest.raises( + TypeError, + match="materials must be a list", + ): + self.my_mats.materials = self.my_mat + + def test_set_materials_list_wrong_type(self): + with pytest.raises( + TypeError, + match="materials must be a list of festim.Material", + ): + self.my_mats.materials = [self.my_mat, 1] diff --git a/test/unit/test_traps/test_traps.py b/test/unit/test_traps/test_traps.py index 973eff232..267fd8f78 100644 --- a/test/unit/test_traps/test_traps.py +++ b/test/unit/test_traps/test_traps.py @@ -105,26 +105,41 @@ def test_error_is_raised_when_not_found(self): self.my_traps.get_trap(id=id) -def test_traps_methods(): +class TestTrapsMethods: + """Checks that festim.Traps methods work properly""" + my_mat = festim.Material(1, 1, 0) my_trap1 = festim.Trap(1, 1, 1, 1, [my_mat], density=1) my_trap2 = festim.Trap(2, 1, 1, 1, [my_mat], density=1) - my_traps = festim.Traps([my_trap1]) - - my_traps.append(my_trap2) - assert my_traps == [my_trap1, my_trap2] - - my_traps.insert(0, my_trap2) - assert my_traps == [my_trap2, my_trap1, my_trap2] - my_traps[0] = my_trap1 - assert my_traps == [my_trap1, my_trap1, my_trap2] - - my_traps.extend([my_trap1]) - assert my_traps == [my_trap1, my_trap1, my_trap2, my_trap1] + my_traps = festim.Traps([my_trap1]) - my_traps.extend(festim.Traps([my_trap2])) - assert my_traps == festim.Traps([my_trap1, my_trap1, my_trap2, my_trap1, my_trap2]) + def test_traps_append(self): + self.my_traps.append(self.my_trap2) + assert self.my_traps == [self.my_trap1, self.my_trap2] + + def test_traps_insert(self): + self.my_traps.insert(0, self.my_trap2) + assert self.my_traps == [self.my_trap2, self.my_trap1, self.my_trap2] + + def test_traps_setitem(self): + self.my_traps[0] = self.my_trap1 + assert self.my_traps == [self.my_trap1, self.my_trap1, self.my_trap2] + + def test_traps_extend_list_type(self): + self.my_traps.extend([self.my_trap1]) + assert self.my_traps == [ + self.my_trap1, + self.my_trap1, + self.my_trap2, + self.my_trap1, + ] + + def test_traps_extend_self_type(self): + self.my_traps.extend(festim.Traps([self.my_trap2])) + assert self.my_traps == festim.Traps( + [self.my_trap1, self.my_trap1, self.my_trap2, self.my_trap1, self.my_trap2] + ) def test_set_traps_wrong_type(): @@ -181,3 +196,47 @@ def test_assign_traps_wrong_type(): match=error_pattern, ): my_traps.insert(0, trap_combination) + + +class TestTrapsPropertyDeprWarn: + """ + A temporary test to check DeprecationWarnings in festim.Traps.traps + """ + + my_mat = festim.Material(1, 1, 1) + my_trap = festim.Trap(1, 1, 1, 1, [my_mat], 1) + + my_traps = festim.Traps([]) + + def test_property_depr_warns(self): + with pytest.deprecated_call(): + self.my_traps.traps + + def test_property_setter_depr_warns(self): + with pytest.deprecated_call(): + self.my_traps.traps = [self.my_trap] + + +class TestTrapsPropertyRaiseError: + """ + A temporary test to check TypeErrors in festim.Traps.traps + """ + + my_mat = festim.Material(1, 1, 1) + my_trap = festim.Trap(1, 1, 1, 1, [my_mat], 1) + + my_traps = festim.Traps([]) + + def test_set_traps_wrong_type(self): + with pytest.raises( + TypeError, + match="traps must be a list", + ): + self.my_traps.traps = self.my_trap + + def test_set_traps_list_wrong_type(self): + with pytest.raises( + TypeError, + match="traps must be a list of festim.Trap", + ): + self.my_traps.traps = [self.my_trap, 1]