From: Rene Gassmoeller Date: Sun, 11 Aug 2024 16:43:09 +0000 (-0600) Subject: Add function to deprecate parameter. X-Git-Url: https://gitweb.dealii.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c9cc2947a35f634f2f0f32de04853697b52927c7;p=dealii.git Add function to deprecate parameter. --- diff --git a/doc/news/changes/minor/20240811Gassmoeller b/doc/news/changes/minor/20240811Gassmoeller new file mode 100644 index 0000000000..e10f8adcb2 --- /dev/null +++ b/doc/news/changes/minor/20240811Gassmoeller @@ -0,0 +1,7 @@ +New: Parameter entries in the ParameterHandler class can now be marked as +deprecated using the function 'mark_as_deprecated'. If deprecated parameters +are found in a parameter file an exception of type +'ExcEncounteredDeprecatedEntries' is thrown that can be caught in +the calling code, or if ignored will emit an error message. +
+(Rene Gassmoeller, 2024/08/11) diff --git a/include/deal.II/base/parameter_handler.h b/include/deal.II/base/parameter_handler.h index 32f14ef0e9..20bfd4632b 100644 --- a/include/deal.II/base/parameter_handler.h +++ b/include/deal.II/base/parameter_handler.h @@ -1127,6 +1127,25 @@ public: const std::string &documentation = "", const bool has_to_be_set = false); + /** + * Mark a previously declared parameter as deprecated. This will cause an + * exception of type ExcEncounteredDeprecatedEntries to be thrown if + * the parameter is used in the input file. + * + * The exception message will list the name of the parameter. + * + * @param entry The name of the parameter to mark as deprecated. + * @param deprecation_status An optional parameter that can be used to + * toggle the deprecation status of the parameter. If set to true, the + * parameter will be marked as deprecated. This is the default behavior. + * If set to false, the parameter will be marked as not deprecated. + * This is useful if a parameter is marked as deprecated by + * one function, but another function wants to keep using it. + */ + void + mark_as_deprecated(const std::string &entry, + const bool deprecation_status = true); + /** * Attach an action to the parameter with name @p entry in the current * section. The action needs to be a function-like object that takes the @@ -1659,6 +1678,25 @@ public: DeclException1(ExcEntryAlreadyExists, std::string, << "The following entry already exists: " << arg1 << '.'); + + /** + * Exception + */ + DeclException3(ExcEntryIsDeprecated, + int, + std::string, + std::string, + << "Line <" << arg1 << "> of file <" << arg2 << ">: " + << "Entry <" << arg3 << "> is deprecated."); + + /** + * Exception + */ + DeclException1(ExcEncounteredDeprecatedEntries, + std::string, + << "The following deprecated entries were encountered:\n\n" + << arg1); + /** * Exception */ @@ -1674,6 +1712,7 @@ public: ExcAlreadyAtTopLevel, "You can't leave a subsection if you are already at the top level " "of the subsection hierarchy."); + /** * Exception */ diff --git a/source/base/parameter_handler.cc b/source/base/parameter_handler.cc index 189910f9fe..ee11dddd86 100644 --- a/source/base/parameter_handler.cc +++ b/source/base/parameter_handler.cc @@ -449,6 +449,9 @@ ParameterHandler::parse_input(std::istream &input, unsigned int current_line_n = 0; unsigned int current_logical_line_n = 0; + // Keep a list of deprecation messages if we encounter deprecated entries. + std::string deprecation_messages; + // define an action that tries to scan a line. // // if that fails, i.e., if scan_line throws @@ -461,23 +464,30 @@ ParameterHandler::parse_input(std::istream &input, // unknown state. // // after unwinding the subsection stack, just re-throw the exception - auto scan_line_or_cleanup = [this, - &skip_undefined, - &saved_path](const std::string &line, - const std::string &filename, - const unsigned int line_number) { - try - { - scan_line(line, filename, line_number, skip_undefined); - } - catch (...) - { - while ((saved_path != subsection_path) && (subsection_path.size() > 0)) - leave_subsection(); + auto scan_line_or_cleanup = + [this, + &skip_undefined, + &saved_path, + &deprecation_messages](const std::string &line, + const std::string &filename, + const unsigned int line_number) { + try + { + scan_line(line, filename, line_number, skip_undefined); + } + catch (ExcEntryIsDeprecated &e) + { + deprecation_messages += e.what(); + } + catch (...) + { + while ((saved_path != subsection_path) && + (subsection_path.size() > 0)) + leave_subsection(); - throw; - } - }; + throw; + } + }; while (std::getline(input, input_line)) @@ -558,6 +568,11 @@ ParameterHandler::parse_input(std::istream &input, AssertThrow(false, ExcUnbalancedSubsections(filename, paths_message.str())); } + + // if we encountered deprecated entries, throw an exception + // that contains all the deprecation messages + AssertThrow(deprecation_messages.empty(), + ExcEncounteredDeprecatedEntries(deprecation_messages)); } @@ -980,9 +995,39 @@ ParameterHandler::declare_alias(const std::string &existing_entry_name, entries->put(get_current_full_path(alias_name) + path_separator + "alias", existing_entry_name); - entries->put(get_current_full_path(alias_name) + path_separator + + + if (alias_is_deprecated) + mark_as_deprecated(alias_name); + else + mark_as_deprecated(alias_name, false); +} + + + +void +ParameterHandler::mark_as_deprecated(const std::string &existing_entry_name, + const bool deprecation_status) +{ + // assert that the entry exists + Assert(entries->get_optional( + get_current_full_path(existing_entry_name)), + ExcMessage("You are trying to mark the entry <" + existing_entry_name + + "> as deprecated, but the entry does not exist.")); + + // then also make sure that what is being referred to is in + // fact a parameter or alias (not a subsection) + Assert( + entries->get_optional( + get_current_full_path(existing_entry_name) + path_separator + "value") || + entries->get_optional( + get_current_full_path(existing_entry_name) + path_separator + "alias"), + ExcMessage("You are trying to mark the entry <" + existing_entry_name + + "> as deprecated, but the entry does not seem to be a " + "parameter declaration or a parameter alias.")); + + entries->put(get_current_full_path(existing_entry_name) + path_separator + "deprecation_status", - (alias_is_deprecated ? "true" : "false")); + deprecation_status ? "true" : "false"); } @@ -1599,7 +1644,13 @@ ParameterHandler::recursively_print_parameters( if (!is_short && !p.second.get("documentation").empty()) out << "{\\it Description:} " - << p.second.get("documentation") << "\n\n" + << p.second.get("documentation") + << ((p.second.get_optional( + "deprecation_status") && + p.second.get("deprecation_status") == + "true") ? + " This parameter is deprecated.\n\n" : + "\n\n") << '\n'; if (!is_short) { @@ -2016,6 +2067,7 @@ ParameterHandler::scan_line(std::string line, // finally write the new value into the database entries->put(path + path_separator + "value", entry_value); + // record that the entry has been set manually auto map_iter = entries_set_status.find(path); if (map_iter != entries_set_status.end()) map_iter->second = @@ -2024,6 +2076,19 @@ ParameterHandler::scan_line(std::string line, AssertThrow(false, ExcMessage("Could not find parameter " + path + " in map entries_set_status.")); + + // Check if the entry (or the resolved alias) is deprecated, + // throw an exception if it is + if (entries->get_optional(path + path_separator + + "deprecation_status") && + entries->get(path + path_separator + + "deprecation_status") == "true") + { + AssertThrow(false, + ExcEntryIsDeprecated(current_line_n, + input_filename, + entry_name)); + } } else { diff --git a/tests/parameter_handler/parameter_handler_29.cc b/tests/parameter_handler/parameter_handler_29.cc new file mode 100644 index 0000000000..a8d79bb699 --- /dev/null +++ b/tests/parameter_handler/parameter_handler_29.cc @@ -0,0 +1,109 @@ +// ------------------------------------------------------------------------ +// +// SPDX-License-Identifier: LGPL-2.1-or-later +// Copyright (C) 2003 - 2023 by the deal.II authors +// +// This file is part of the deal.II library. +// +// Part of the source code is dual licensed under Apache-2.0 WITH +// LLVM-exception OR LGPL-2.1-or-later. Detailed license information +// governing the source code and code contributions can be found in +// LICENSE.md and CONTRIBUTING.md at the top level directory of deal.II. +// +// ------------------------------------------------------------------------ + + + +// test the output generated by +// ParameterHandler::print_parameters(LaTeX). like the _4a test, but +// deprecates the parameters. + +#include + +#include "../tests.h" + +// header for chdir is platform dependent; when the day comes that we support +// Windows in the test suite then conditionally include direction.h +#include + +int +main() +{ + initlog(); + + // We need a local path for the file to get consistent output messages. + const int chdir_return_code = chdir(SOURCE_DIR); + AssertThrow(chdir_return_code == 0, ExcInternalError()); + + ParameterHandler prm; + + try + { + prm.enter_subsection("Testing"); + { + prm.enter_subsection("Testing 2"); + { + prm.declare_entry("string list 2", + "a", + Patterns::List( + Patterns::Selection("a|b|c|d|e|f|g|h")), + "docs 1"); + prm.declare_entry("int 2", "1", Patterns::Integer()); + prm.declare_entry("double 2", + "3.1415926", + Patterns::Double(), + "docs 3"); + prm.mark_as_deprecated("string list 2"); + prm.mark_as_deprecated("int 2"); + prm.mark_as_deprecated("double 2"); + } + prm.leave_subsection(); + + prm.declare_entry("string list", + "a", + Patterns::List( + Patterns::Selection("a|b|c|d|e|f|g|h")), + "docs 1"); + prm.declare_entry("int", "1", Patterns::Integer()); + prm.declare_entry("double", "3.1415926", Patterns::Double(), "docs 3"); + prm.mark_as_deprecated("string list"); + prm.mark_as_deprecated("int"); + prm.mark_as_deprecated("double"); + } + prm.leave_subsection(); + + // read and then write + // parameters. take same input file + // as for parameter_handler_3, but + // use different output format + prm.parse_input("prm/parameter_handler_3.prm"); + prm.print_parameters(std::cout, ParameterHandler::LaTeX); + } + catch (const ParameterHandler::ExcEncounteredDeprecatedEntries &exc) + { + deallog << exc.get_exc_name() << std::endl; + exc.print_info(deallog.get_file_stream()); + + // Check that the deprecated entries are still accessible. + prm.enter_subsection("Testing"); + { + deallog << prm.get("string list") << std::endl; + deallog << prm.get("int") << std::endl; + } + prm.leave_subsection(); + } + catch (...) + { + deallog << std::endl + << std::endl + << "----------------------------------------------------" + << std::endl; + deallog << "Unknown exception!" << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + return 1; + }; + + return 0; +} diff --git a/tests/parameter_handler/parameter_handler_29.output b/tests/parameter_handler/parameter_handler_29.output new file mode 100644 index 0000000000..60600592b9 --- /dev/null +++ b/tests/parameter_handler/parameter_handler_29.output @@ -0,0 +1,23 @@ + +DEAL::ExcEncounteredDeprecatedEntries(deprecation_messages) + The following deprecated entries were encountered: + + +-------------------------------------------------------- +An error occurred in file in function + void dealii::ParameterHandler::scan_line(std::string, const string&, unsigned int, bool) +Additional information: + Line <2> of file : Entry is + deprecated. +-------------------------------------------------------- + +-------------------------------------------------------- +An error occurred in file in function + void dealii::ParameterHandler::scan_line(std::string, const string&, unsigned int, bool) +Additional information: + Line <3> of file : Entry is + deprecated. +-------------------------------------------------------- + +DEAL::a, b, c +DEAL::3