Originally those were assertions that were kept even in release builds,
which meant that calling math.angle() on non-normalized vectors aborted
the whole Python interpreted. Not great. But then the assertions were
made debug-only, which means invalid usage from Python (where the
bindings are usually only built as Release) now silently gives back a
wrong result, which is perhaps even worse.
Because the Python overhead is already massive due to all string lookup
and such, doing one more check in the implementations isn't really going
to slow down anything. Thus I'm mirroring all (debug-only) Magnum
assertions on the Python side, turning them into exceptions. With proper
messages as well, because those are extremely useful.
Use only py::error_already_set as that's the least heavy of them. Also
changed all occurences of "throw" to "raise" so next time I'm doing a
prune of all C++ exceptions for good, those are easy to find.
This is so ugly it's beautiful. The translation needed a metaclass to
work properly, but the undoubtedly worst/best is making those exposed
nicely in the docs.
The order should be (and now is):
1. magnum's own conversion constructors (double from integer and such)
2. stuff like implicit color3 -> color4, if applicable
3. buffer protocol constructors
4. general "init from a tuple" constructors last, because they're the
slowest
The clash of static constructors and members / properties is ...
unfortunate. This is resolved using a minor hack, but I think that's
warranted if it preserves C++/Python API compatibility. The
translation() static constructor and property is not done yet, tho.