Skip to content

Errors

Everything py2tosc raises on its own behalf inherits from Py2ToscError, so a caller that wants to treat any library failure alike can write one except.

Errors caused by passing a bad argument are deliberately left on the builtins. A ValueError for an unparseable colour or a TypeError for the wrong kind of message says exactly what it means already, and wrapping those would make ordinary Python harder to read without telling the caller anything new.

try:
    doc = py2tosc.load(path)
except py2tosc.FormatError as exc:
    print(f"{path}: not a layout ({exc})")

Py2ToscError

Bases: Exception

Base class for every error py2tosc defines.

Catching this catches anything the library treats as its own failure, without also catching the ValueError a caller gets for handing a function a bad argument.

Source code in src/py2tosc/errors.py
class Py2ToscError(Exception):
    """Base class for every error py2tosc defines.

    Catching this catches anything the library treats as its own failure,
    without also catching the `ValueError` a caller gets for handing a
    function a bad argument.
    """

FormatError

Bases: Py2ToscError, ValueError

Raised when input cannot be read as a TouchOSC layout.

Reading a layout can fail in three unrelated ways -- the bytes are not XML, a .tosc stream will not decompress, or the XML parses but is not a lexml root holding one node -- and each of those used to reach the caller as a different type from a different module. None of them was a py2tosc type, so no single except clause could express "that file is not a layout", which is the only distinction most callers want.

It also inherits ValueError, which is what load and loads have always documented themselves as raising. Code written against that contract keeps working, and code that wants the narrower type can ask for it.

Source code in src/py2tosc/errors.py
class FormatError(Py2ToscError, ValueError):
    """Raised when input cannot be read as a TouchOSC layout.

    Reading a layout can fail in three unrelated ways -- the bytes are not
    XML, a `.tosc` stream will not decompress, or the XML parses but is not a
    `lexml` root holding one node -- and each of those used to reach the
    caller as a different type from a different module. None of them was a
    py2tosc type, so no single `except` clause could express "that file is not
    a layout", which is the only distinction most callers want.

    It also inherits `ValueError`, which is what `load` and `loads` have always
    documented themselves as raising. Code written against that contract keeps
    working, and code that wants the narrower type can ask for it.
    """

ValidationError

Bases: Py2ToscError

Raised by save(validate=True) when a layout has errors.

Attributes:

Name Type Description
issues

Every finding, not only the errors, so a caller catching this can report the warnings too.

Source code in src/py2tosc/validate.py
class ValidationError(Py2ToscError):
    """Raised by `save(validate=True)` when a layout has errors.

    Attributes:
        issues: Every finding, not only the errors, so a caller catching this
            can report the warnings too.
    """

    def __init__(self, issues: list[Issue]):
        self.issues = issues
        errors = [i for i in issues if i.level == ERROR]
        super().__init__(
            f"{len(errors)} error(s) in the layout:\n"
            + "\n".join(f"  {i}" for i in errors)
        )