Skip to content

Commit a4d66cc

Browse files
JSON: Selectively suppress unknown key warnings (#1700)
* Add functionality to selectively suppress key warnings For unknown keys. { "dont_warn_unused_keys": [ "key1", "key3" ], "key1": 5, "key2": { "dont_warn_unused_keys": [ "key1" ], "key1": 5, "key2": 6 }, "key3": { "dont_warn_unused_keys": [ "key1" ], "key1": 5, "key2": 6 } } Will yield the warning: [Series] The following parts of the global JSON config remains unused: { "key2": { "dont_warn_unused_keys": [ "key1" ], "key1": 5, "key2": 6 }, "key3": { "key2": 6 } } TODO: Better errors when parsing, documentation * init(): Treat the original JSON val as const * Documentation * Bugfix * More precise error messages
1 parent d5b42ed commit a4d66cc

File tree

3 files changed

+133
-2
lines changed

3 files changed

+133
-2
lines changed

docs/source/details/backendconfig.rst

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,42 @@ For JSON and ADIOS2, all datasets are resizable, independent of this option.
101101

102102
The key ``rank_table`` allows specifying the creation of a **rank table**, used for tracking :ref:`chunk provenance especially in streaming setups <rank_table>`, refer to the streaming documentation for details.
103103

104+
A warning is printed if the JSON/TOML configuration contains keys that are not understood (and hence ignored) by the openPMD-api.
105+
Such warnings can be suppressed by listing key names under ``"dont_warn_unused_keys"``.
106+
107+
Example:
108+
109+
.. code-block:: json
110+
111+
{
112+
"adio2": {
113+
"dataset": {
114+
"put dataset options": "here"
115+
}
116+
},
117+
"hdf5": {
118+
"an unknown": "key",
119+
"another unknown": "key",
120+
"a third unknown": "key",
121+
"dont_warn_unused_keys": ["an unknown", "another unknown"]
122+
}
123+
}
124+
125+
The openPMD-api will warn about the unknown key ``"adio2"`` (in order to give feedback about the apparent misspelling of ``"adios2"`` to users); there will similarly be a warning for the unknown HDF5 key ``"a third unknown"``. Warnings about the other two unknown keys have been suppressed. The printed warning will hence be about these unknown parts of the JSON configuration:
126+
127+
.. code-block:: json
128+
129+
{
130+
"adio2": {
131+
"dataset": {
132+
"put dataset options": "here"
133+
}
134+
},
135+
"hdf5": {
136+
"a third unknown": "key"
137+
}
138+
}
139+
104140
Configuration Structure per Backend
105141
-----------------------------------
106142

include/openPMD/auxiliary/JSON_internal.hpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
#include "openPMD/config.hpp"
2525

26+
#include <deque>
2627
#include <nlohmann/json.hpp>
2728
#include <toml.hpp>
2829

@@ -150,6 +151,11 @@ namespace json
150151
*
151152
*/
152153
nlohmann::json *m_positionInShadow;
154+
/**
155+
* @brief (Redundantly) track the current path within the JSON value.
156+
* Used (currently) only for more precise error messages.
157+
*/
158+
std::deque<std::string> m_positionForErrorMessages;
153159
bool m_trace = true;
154160

155161
void invertShadow(
@@ -160,8 +166,20 @@ namespace json
160166
std::shared_ptr<nlohmann::json> shadow,
161167
nlohmann::json *positionInOriginal,
162168
nlohmann::json *positionInShadow,
169+
std::deque<std::string> positionForErrorMessages,
163170
SupportedLanguages originallySpecifiedAs,
164171
bool trace);
172+
173+
void init();
174+
/*
175+
* Called upon each traced access of a location in the JSON value, along
176+
* with the matching subtree of the shadow.
177+
* This implements the `dont_warn_unused_keys` functionality.
178+
*/
179+
static void init(
180+
nlohmann::json const &original,
181+
nlohmann::json &shadow,
182+
std::deque<std::string> &positionForErrorMessages);
165183
};
166184

167185
template <typename Key>
@@ -178,11 +196,14 @@ namespace json
178196
newPositionInShadow = &m_positionInShadow->operator[](key);
179197
}
180198
bool traceFurther = newPositionInOriginal->is_object();
199+
auto new_path = m_positionForErrorMessages;
200+
new_path.push_back(std::forward<Key>(key));
181201
return TracingJSON(
182202
m_originalJSON,
183203
m_shadow,
184204
newPositionInOriginal,
185205
newPositionInShadow,
206+
std::move(new_path),
186207
originallySpecifiedAs,
187208
traceFurther);
188209
}

src/auxiliary/JSON.cpp

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ TracingJSON::TracingJSON(
5353
, m_shadow(std::make_shared<nlohmann::json>())
5454
, m_positionInOriginal(&*m_originalJSON)
5555
, m_positionInShadow(&*m_shadow)
56-
{}
56+
{
57+
init();
58+
}
5759

5860
TracingJSON::TracingJSON(ParsedConfig parsedConfig)
5961
: TracingJSON{
@@ -150,15 +152,87 @@ TracingJSON::TracingJSON(
150152
std::shared_ptr<nlohmann::json> shadow,
151153
nlohmann::json *positionInOriginal,
152154
nlohmann::json *positionInShadow,
155+
std::deque<std::string> positionForErrorMessages,
153156
SupportedLanguages originallySpecifiedAs_in,
154157
bool trace)
155158
: originallySpecifiedAs(originallySpecifiedAs_in)
156159
, m_originalJSON(std::move(originalJSON))
157160
, m_shadow(std::move(shadow))
158161
, m_positionInOriginal(positionInOriginal)
159162
, m_positionInShadow(positionInShadow)
163+
, m_positionForErrorMessages(std::move(positionForErrorMessages))
160164
, m_trace(trace)
161-
{}
165+
{
166+
init();
167+
}
168+
169+
void TracingJSON::init()
170+
{
171+
if (m_originalJSON)
172+
{
173+
init(
174+
*m_positionInOriginal,
175+
*m_positionInShadow,
176+
m_positionForErrorMessages);
177+
}
178+
}
179+
180+
void TracingJSON::init(
181+
nlohmann::json const &original,
182+
nlohmann::json &shadow,
183+
std::deque<std::string> &positionForErrorMessages)
184+
{
185+
if (original.is_object() && original.contains("dont_warn_unused_keys"))
186+
{
187+
auto suppress_warnings_for_these_json =
188+
original.at("dont_warn_unused_keys");
189+
auto suppress_warnings_for_these = [&]() {
190+
try
191+
{
192+
return suppress_warnings_for_these_json
193+
.get<std::vector<std::string>>();
194+
}
195+
catch (nlohmann::json::type_error const &e)
196+
{
197+
std::vector<std::string> errorPath;
198+
errorPath.reserve(positionForErrorMessages.size() + 1);
199+
for (auto const &val : positionForErrorMessages)
200+
{
201+
errorPath.push_back(val);
202+
}
203+
errorPath.emplace_back("dont_warn_unused_keys");
204+
throw error::BackendConfigSchema(
205+
errorPath,
206+
"Key `dont_warn_unused_keys` must be a list of strings, "
207+
"original error was: " +
208+
std::string(e.what()));
209+
}
210+
}();
211+
for (auto const &key : suppress_warnings_for_these)
212+
{
213+
// For each suppressed key, we now emulate an access to that
214+
// key. This entails calling init() recursively since that
215+
// function is called upon each access to a traced key.
216+
auto it = original.find(key);
217+
if (it == original.end())
218+
{
219+
continue;
220+
}
221+
positionForErrorMessages.push_back(key);
222+
try
223+
{
224+
init(*it, shadow[key], positionForErrorMessages);
225+
}
226+
catch (...)
227+
{
228+
positionForErrorMessages.pop_back();
229+
throw;
230+
}
231+
positionForErrorMessages.pop_back();
232+
}
233+
shadow["dont_warn_unused_keys"] = nlohmann::json();
234+
}
235+
}
162236

163237
namespace
164238
{

0 commit comments

Comments
 (0)