warning_handling.h
1 /* Copyright (c) 2013-2023, EPFL/Blue Brain Project
2  *
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #pragma once
6 
7 #include <iostream>
8 #include <memory>
9 #include <set>
10 #include <sstream> // std::ostringstream
11 #include <string>
12 #include <utility>
13 #include <vector>
14 
15 #include <morphio/enums.h>
16 #include <morphio/types.h>
17 
18 
19 namespace morphio {
20 namespace details {
21 std::string errorLink(const std::string& uri,
22  long unsigned int lineNumber,
23  morphio::readers::ErrorLevel errorLevel);
24 } // namespace details
25 
26 
28  explicit WarningMessage(std::string uri_)
29  : uri(std::move(uri_)) {}
30  WarningMessage(const WarningMessage&) = default;
31  WarningMessage(WarningMessage&&) = delete;
32  WarningMessage& operator=(const WarningMessage&) = default;
33  WarningMessage& operator=(WarningMessage&&) = delete;
34  virtual std::string msg() const = 0;
35  virtual ~WarningMessage() = default;
36  virtual morphio::enums::Warning warning() const = 0;
37 
38  std::string uri;
39 };
40 
41 struct ZeroDiameter: public WarningMessage {
42  ZeroDiameter(std::string uri_, uint64_t lineNumber_)
43  : WarningMessage(std::move(uri_))
44  , lineNumber(lineNumber_) {}
45  morphio::enums::Warning warning() const final {
46  return Warning::ZERO_DIAMETER;
47  }
48  morphio::readers::ErrorLevel errorLevel = morphio::readers::ErrorLevel::WARNING;
49  std::string msg() const final {
50  static const char* description = "Warning: zero diameter in file";
51  return "\n" + details::errorLink(uri, lineNumber, errorLevel) + description;
52  }
53 
54  uint64_t lineNumber;
55 };
56 
58  DisconnectedNeurite(std::string uri_, uint64_t lineNumber_)
59  : WarningMessage(std::move(uri_))
60  , lineNumber(lineNumber_) {}
61  Warning warning() const final {
62  return Warning::DISCONNECTED_NEURITE;
63  }
64  morphio::readers::ErrorLevel errorLevel = morphio::readers::ErrorLevel::WARNING;
65  std::string msg() const final {
66  static const char* description =
67  "Warning: found a disconnected neurite.\n"
68  "Neurites are not supposed to have parentId: -1\n"
69  "(although this is normal if this neuron has no soma)";
70  return "\n" + details::errorLink(uri, lineNumber, errorLevel) + description;
71  }
72 
73  uint64_t lineNumber;
74 };
75 
76 struct NoSomaFound: public WarningMessage {
77  explicit NoSomaFound(std::string uri_)
78  : WarningMessage(std::move(uri_)) {}
79  Warning warning() const final {
80  return Warning::NO_SOMA_FOUND;
81  }
82  morphio::readers::ErrorLevel errorLevel = morphio::readers::ErrorLevel::WARNING;
83  std::string msg() const final {
84  static const char* description = "Warning: no soma found in file";
85  return "\n" + details::errorLink(uri, 0, errorLevel) + description;
86  }
87 };
88 
90  explicit SomaNonConform(std::string uri_, std::string description_)
91  : WarningMessage(std::move(uri_))
92  , description(std::move(description_)) {}
93  Warning warning() const final {
94  return Warning::SOMA_NON_CONFORM;
95  }
96  morphio::readers::ErrorLevel errorLevel = morphio::readers::ErrorLevel::WARNING;
97  std::string msg() const final {
98  return "\n" + details::errorLink(uri, 0, errorLevel) + description;
99  }
100  std::string description;
101 };
102 
104  explicit WrongRootPoint(std::string uri_, std::vector<unsigned int> lineNumbers_)
105  : WarningMessage(std::move(uri_))
106  , lineNumbers(std::move(lineNumbers_)) {}
107  Warning warning() const final {
108  return Warning::WRONG_ROOT_POINT;
109  }
110  morphio::readers::ErrorLevel errorLevel = morphio::readers::ErrorLevel::WARNING;
111  std::string msg() const final {
112  std::ostringstream oss;
113  oss << "Warning: with a 3 points soma, neurites must be connected to the first soma point:";
114  for (const auto& lineNumber : lineNumbers) {
115  oss << "\n" + details::errorLink(uri, lineNumber, errorLevel);
116  }
117  return oss.str();
118  }
119  std::vector<unsigned int> lineNumbers;
120 };
121 
123  explicit AppendingEmptySection(std::string uri_, uint32_t sectionId_)
124  : WarningMessage(std::move(uri_))
125  , sectionId(sectionId_) {}
126  Warning warning() const final {
127  return Warning::APPENDING_EMPTY_SECTION;
128  }
129  morphio::readers::ErrorLevel errorLevel = morphio::readers::ErrorLevel::WARNING;
130  std::string msg() const final {
131  static const char* description = "Warning: appending empty section with id: ";
132  return "\n" + details::errorLink(uri, 0, errorLevel) + description +
133  std::to_string(sectionId);
134  }
135  uint32_t sectionId;
136 };
137 
139  explicit WrongDuplicate(std::string uri_,
140  std::shared_ptr<morphio::mut::Section> current_,
141  std::shared_ptr<morphio::mut::Section> parent_)
142  : WarningMessage(std::move(uri_))
143  , current(std::move(current_))
144  , parent(std::move(parent_)) {}
145  std::string msg() const final;
146 
147  Warning warning() const final {
148  return Warning::WRONG_DUPLICATE;
149  }
150  morphio::readers::ErrorLevel errorLevel = morphio::readers::ErrorLevel::WARNING;
151  std::shared_ptr<morphio::mut::Section> current;
152  std::shared_ptr<morphio::mut::Section> parent;
153 };
154 
155 struct OnlyChild: public WarningMessage {
156  explicit OnlyChild(std::string uri_, unsigned int parentId_, unsigned int childId_)
157  : WarningMessage(std::move(uri_))
158  , parentId(parentId_)
159  , childId(childId_) {}
160  Warning warning() const final {
161  return Warning::ONLY_CHILD;
162  }
163  morphio::readers::ErrorLevel errorLevel = morphio::readers::ErrorLevel::WARNING;
164  std::string msg() const final {
165  std::ostringstream oss;
166  oss << "Warning: section " << childId << " is the only child of "
167  << "section: " << std::to_string(parentId)
168  << "\nIt will be merged with the parent section";
169 
170  return "\n" + details::errorLink(uri, 0, errorLevel) + oss.str();
171  }
172  unsigned int parentId;
173  unsigned int childId;
174 };
175 
176 struct WriteNoSoma: public WarningMessage {
177  WriteNoSoma()
178  : WarningMessage(std::string()) {}
179  Warning warning() const final {
180  return Warning::WRITE_NO_SOMA;
181  }
182  morphio::readers::ErrorLevel errorLevel = morphio::readers::ErrorLevel::WARNING;
183  std::string msg() const final {
184  static const char* description = "Warning: writing file without a soma";
185  return "\n" + details::errorLink(uri, 0, errorLevel) + description;
186  }
187 };
188 
191  : WarningMessage(std::string()) {}
192  Warning warning() const final {
193  return Warning::WRITE_EMPTY_MORPHOLOGY;
194  }
195  morphio::readers::ErrorLevel errorLevel = morphio::readers::ErrorLevel::WARNING;
196  std::string msg() const final {
197  static const char* description =
198  "Warning: Skipping an attempt to write an empty morphology.";
199  return "\n" + details::errorLink(uri, 0, errorLevel) + description;
200  }
201 };
202 
205  : WarningMessage(std::string()) {}
206  Warning warning() const final {
207  return Warning::WRITE_UNDEFINED_SOMA;
208  }
209  morphio::readers::ErrorLevel errorLevel = morphio::readers::ErrorLevel::WARNING;
210  std::string msg() const final {
211  static const char* description = "Warning: writing soma set to SOMA_UNDEFINED";
212  return "\n" + details::errorLink(uri, 0, errorLevel) + description;
213  }
214 };
215 
218  : WarningMessage(std::string()) {}
219  Warning warning() const final {
220  return Warning::MITOCHONDRIA_WRITE_NOT_SUPPORTED;
221  }
222  morphio::readers::ErrorLevel errorLevel = morphio::readers::ErrorLevel::WARNING;
223  std::string msg() const final {
224  static const char* description =
225  "Warning: this cell has mitochondria, they cannot be saved in "
226  " ASC or SWC format. Please use H5 if you want to save them.";
227  return "\n" + details::errorLink(uri, 0, errorLevel) + description;
228  }
229 };
230 
233  : WarningMessage(std::string()) {}
234  Warning warning() const final {
235  return Warning::SOMA_NON_CONTOUR;
236  }
237  morphio::readers::ErrorLevel errorLevel = morphio::readers::ErrorLevel::WARNING;
238  std::string msg() const final {
239  static const char* description =
240  "Soma must be a contour for ASC and H5: see "
241  "https://github.com/BlueBrain/MorphIO/issues/457";
242  return "\n" + details::errorLink(uri, 0, errorLevel) + description;
243  }
244 };
245 
248  : WarningMessage(std::string()) {}
249  Warning warning() const final {
250  return Warning::SOMA_NON_CYLINDER_OR_POINT;
251  }
252  morphio::readers::ErrorLevel errorLevel = morphio::readers::ErrorLevel::WARNING;
253  std::string msg() const final {
254  static const char* description =
255  "Soma must be stacked cylinders or a point: see "
256  "https://github.com/BlueBrain/MorphIO/issues/457";
257  return "\n" + details::errorLink(uri, 0, errorLevel) + description;
258  }
259 };
260 
262 {
263  public:
264  WarningHandler() = default;
265  WarningHandler(WarningHandler&&) = default;
266  WarningHandler& operator=(const WarningHandler&) = default;
267  WarningHandler& operator=(WarningHandler&&) = default;
268  WarningHandler(WarningHandler&) = default;
269  virtual ~WarningHandler() = default;
270 
271  virtual void emit(std::shared_ptr<WarningMessage>) = 0;
272  void setIgnoredWarning(enums::Warning warning, bool ignore);
273  bool isIgnored(enums::Warning warning);
274 
275  // To maintain backwards compatibility, these exist, eventhough they aren't applicable to things
276  // like the `WarningHandlerCollector` since one can post-process the errors, and raise
277  // exceptions oneself.
278  virtual int getMaxWarningCount() const = 0;
279  virtual void setMaxWarningCount(int warningCount) = 0;
280  virtual bool getRaiseWarnings() const = 0;
281  virtual void setRaiseWarnings(bool raise) = 0;
282 
283  private:
284  std::set<enums::Warning> ignoredWarnings_;
285 };
286 
289 {
290  public:
291  int getMaxWarningCount() const final;
292  void setMaxWarningCount(int warningCount) final;
293  bool getRaiseWarnings() const final;
294  void setRaiseWarnings(bool raise) final;
295  void emit(std::shared_ptr<morphio::WarningMessage> wm) final;
296 
297  private:
298  uint32_t errorCount = 0;
299  int32_t maxWarningCount_ = 100;
300  bool raiseWarnings_ = false;
301 };
302 
305 {
306  public:
307  struct Emission {
308  Emission(bool wasMarkedIgnore_, std::shared_ptr<WarningMessage> warning_)
309  : wasMarkedIgnore(wasMarkedIgnore_)
310  , warning(std::move(warning_)) {}
311  bool wasMarkedIgnore = false;
312  std::shared_ptr<WarningMessage> warning;
313  };
314 
315  int getMaxWarningCount() const final;
316  void setMaxWarningCount(int warningCount) final;
317  bool getRaiseWarnings() const final;
318  void setRaiseWarnings(bool raise) final;
319  void emit(std::shared_ptr<WarningMessage> wm) final;
320  void reset();
321  std::vector<Emission> getAll() const;
322 
323  private:
324  std::vector<Emission> m;
325 };
326 
327 } // namespace morphio
morphio::OnlyChild
Definition: warning_handling.h:155
morphio::WarningHandlerCollector
This warning handler collects the warnings, which can be retrieved with getAll()
Definition: warning_handling.h:304
morphio::WriteUndefinedSoma
Definition: warning_handling.h:203
morphio::WarningHandlerPrinter
This warning handler prints warnings immediately to STDERR.
Definition: warning_handling.h:288
morphio::SomaNonCynlinderOrPoint
Definition: warning_handling.h:246
morphio::enums::Warning
Warning
Definition: enums.h:29
morphio::NoSomaFound
Definition: warning_handling.h:76
morphio::WarningHandlerCollector::Emission
Definition: warning_handling.h:307
morphio::WriteNoSoma
Definition: warning_handling.h:176
morphio::SomaNonConform
Definition: warning_handling.h:89
morphio::ZeroDiameter
Definition: warning_handling.h:41
morphio::SomaNonContour
Definition: warning_handling.h:231
morphio::WriteEmptyMorphology
Definition: warning_handling.h:189
morphio::MitochondriaWriteNotSupported
Definition: warning_handling.h:216
morphio::WarningMessage
Definition: warning_handling.h:27
morphio::WarningHandler
Definition: warning_handling.h:261
morphio::DisconnectedNeurite
Definition: warning_handling.h:57
morphio::AppendingEmptySection
Definition: warning_handling.h:122
morphio::WrongDuplicate
Definition: warning_handling.h:138
morphio::WrongRootPoint
Definition: warning_handling.h:103