]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Add function to deprecate parameter.
authorRene Gassmoeller <rene.gassmoeller@mailbox.org>
Sun, 11 Aug 2024 16:43:09 +0000 (10:43 -0600)
committerRene Gassmoeller <rene.gassmoeller@mailbox.org>
Wed, 21 Aug 2024 13:10:28 +0000 (15:10 +0200)
doc/news/changes/minor/20240811Gassmoeller [new file with mode: 0644]
include/deal.II/base/parameter_handler.h
source/base/parameter_handler.cc
tests/parameter_handler/parameter_handler_29.cc [new file with mode: 0644]
tests/parameter_handler/parameter_handler_29.output [new file with mode: 0644]

diff --git a/doc/news/changes/minor/20240811Gassmoeller b/doc/news/changes/minor/20240811Gassmoeller
new file mode 100644 (file)
index 0000000..e10f8ad
--- /dev/null
@@ -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.
+<br>
+(Rene Gassmoeller, 2024/08/11)
index 32f14ef0e9ad216f67418dccac941abe958012ee..20bfd4632b73f0056cb92dbae7bb881f334bd9bd 100644 (file)
@@ -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
    */
index 189910f9fe086a5a3c2f0818f62bbf412b0f2066..ee11dddd861e572833f64d99722947b1053afc44 100644 (file)
@@ -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<std::string>(
+           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<std::string>(
+      get_current_full_path(existing_entry_name) + path_separator + "value") ||
+      entries->get_optional<std::string>(
+        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<std::string>("documentation").empty())
                   out << "{\\it Description:} "
-                      << p.second.get<std::string>("documentation") << "\n\n"
+                      << p.second.get<std::string>("documentation")
+                      << ((p.second.get_optional<std::string>(
+                             "deprecation_status") &&
+                           p.second.get<std::string>("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<std::string>(path + path_separator +
+                                                 "deprecation_status") &&
+              entries->get<std::string>(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 (file)
index 0000000..a8d79bb
--- /dev/null
@@ -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 <deal.II/base/parameter_handler.h>
+
+#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 <unistd.h>
+
+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 (file)
index 0000000..6060059
--- /dev/null
@@ -0,0 +1,23 @@
+
+DEAL::ExcEncounteredDeprecatedEntries(deprecation_messages)
+    The following deprecated entries were encountered:
+
+
+--------------------------------------------------------
+An error occurred in file <parameter_handler.cc> in function
+    void dealii::ParameterHandler::scan_line(std::string, const string&, unsigned int, bool)
+Additional information: 
+    Line <2> of file <prm/parameter_handler_3.prm>: Entry <string list> is
+    deprecated.
+--------------------------------------------------------
+
+--------------------------------------------------------
+An error occurred in file <parameter_handler.cc> in function
+    void dealii::ParameterHandler::scan_line(std::string, const string&, unsigned int, bool)
+Additional information: 
+    Line <3> of file <prm/parameter_handler_3.prm>: Entry <int> is
+    deprecated.
+--------------------------------------------------------
+
+DEAL::a, b, c
+DEAL::3

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.