Browse Source

Add new "nonfatal error" handling for exporter

There are some cases where errors, while bad, are not the end of the
world. I'm thinking namely about compyling the age python. The age still
exports just fine, but the ancillary data is flawed. This new system
collects nonfatal errors until the export is done, then raises them all
at once.
pull/128/head
Adam Johnson 6 years ago
parent
commit
b2120aba10
Signed by: Hoikas
GPG Key ID: 0B6515D6FF6F271E
  1. 5
      korman/exporter/convert.py
  2. 9
      korman/exporter/explosions.py
  3. 31
      korman/exporter/logger.py
  4. 3
      korman/operators/op_export.py

5
korman/exporter/convert.py

@ -107,6 +107,11 @@ class Exporter:
self.report.progress_end() self.report.progress_end()
self.report.save() self.report.save()
# Step 5.2: If any nonfatal errors were encountered during the export, we will
# raise them here, now that everything is finished, to draw attention
# to whatever the problem might be.
self.report.raise_errors()
def _bake_static_lighting(self): def _bake_static_lighting(self):
lighting_method = self._op.lighting_method lighting_method = self._op.lighting_method
if lighting_method != "skip": if lighting_method != "skip":

9
korman/exporter/explosions.py

@ -13,6 +13,15 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Korman. If not, see <http://www.gnu.org/licenses/>. # along with Korman. If not, see <http://www.gnu.org/licenses/>.
class NonfatalExportError(Exception):
def __init__(self, *args, **kwargs):
assert args
if len(args) > 1:
super(Exception, self).__init__(args[0].format(*args[1:], **kwargs))
else:
super(Exception, self).__init__(args[0])
class ExportError(Exception): class ExportError(Exception):
def __init__(self, value="Undefined Export Error"): def __init__(self, value="Undefined Export Error"):
super(Exception, self).__init__(value) super(Exception, self).__init__(value)

31
korman/exporter/logger.py

@ -14,6 +14,7 @@
# along with Korman. If not, see <http://www.gnu.org/licenses/>. # along with Korman. If not, see <http://www.gnu.org/licenses/>.
from ..korlib import ConsoleToggler from ..korlib import ConsoleToggler
from .explosions import NonfatalExportError
from pathlib import Path from pathlib import Path
import threading import threading
import time import time
@ -24,6 +25,7 @@ _MAX_TIME_UNTIL_ELIPSES = 2.0
class _ExportLogger: class _ExportLogger:
def __init__(self, print_logs, age_path=None): def __init__(self, print_logs, age_path=None):
self._errors = []
self._porting = [] self._porting = []
self._warnings = [] self._warnings = []
self._age_path = Path(age_path) if age_path is not None else None self._age_path = Path(age_path) if age_path is not None else None
@ -42,10 +44,23 @@ class _ExportLogger:
def __exit__(self, type, value, traceback): def __exit__(self, type, value, traceback):
if value is not None: if value is not None:
ConsoleToggler().keep_console = True ConsoleToggler().keep_console = not isinstance(value, NonfatalExportError)
self._file.close() self._file.close()
return False return False
def error(self, *args, **kwargs):
assert args
indent = kwargs.get("indent", 0)
msg = "{}ERROR: {}".format(" " * indent, args[0])
if len(args) > 1:
msg = msg.format(*args[1:], **kwargs)
if self._file is not None:
self._file.writelines((msg, "\n"))
if self._print_logs:
print(msg)
cache = args[0] if len(args) == 1 else args[0].format(*args[1:])
self._errors.append(cache)
def msg(self, *args, **kwargs): def msg(self, *args, **kwargs):
assert args assert args
indent = kwargs.get("indent", 0) indent = kwargs.get("indent", 0)
@ -67,7 +82,8 @@ class _ExportLogger:
self._file.writelines((msg, "\n")) self._file.writelines((msg, "\n"))
if self._print_logs: if self._print_logs:
print(msg) print(msg)
self._porting.append(args[0]) cache = args[0] if len(args) == 1 else args[0].format(*args[1:])
self._porting.append(cache)
def progress_add_step(self, name): def progress_add_step(self, name):
@ -92,6 +108,14 @@ class _ExportLogger:
self.msg("Exporting '{}'", self._age_path.name) self.msg("Exporting '{}'", self._age_path.name)
self._time_start_overall = time.perf_counter() self._time_start_overall = time.perf_counter()
def raise_errors(self):
num_errors = len(self._errors)
if num_errors == 1:
raise NonfatalExportError(self._errors[0])
elif num_errors:
raise NonfatalExportError("""{} errors were encountered during export. Check the export log for more details:
{}""", num_errors, self._file.name)
def save(self): def save(self):
# TODO # TODO
pass pass
@ -106,7 +130,8 @@ class _ExportLogger:
self._file.writelines((msg, "\n")) self._file.writelines((msg, "\n"))
if self._print_logs: if self._print_logs:
print(msg) print(msg)
self._warnings.append(args[0]) cache = args[0] if len(args) == 1 else args[0].format(*args[1:])
self._warnings.append(cache)
class ExportProgressLogger(_ExportLogger): class ExportProgressLogger(_ExportLogger):

3
korman/operators/op_export.py

@ -177,6 +177,9 @@ class PlasmaAgeExportOperator(ExportOperator, bpy.types.Operator):
except exporter.ExportError as error: except exporter.ExportError as error:
self.report({"ERROR"}, str(error)) self.report({"ERROR"}, str(error))
return {"CANCELLED"} return {"CANCELLED"}
except exporter.NonfatalExportError as error:
self.report({"ERROR"}, str(error))
return {"FINISHED"}
else: else:
if self.profile_export: if self.profile_export:
stats_out = path.with_name("{}_profile.log".format(ageName)) stats_out = path.with_name("{}_profile.log".format(ageName))

Loading…
Cancel
Save