Welcome to the exciting new Python-flavored future of Magnum! Have fun, but please note this functionality is heavily experimental at the moment. Most APIs are missing, documentation is very sparse and everything is still evolving. Use at your own risk.

Python API conventions

Basic rules and good practices for both Python binding develpoers and users.

API naming

  • mapping is made as clear as possible, the user should not need assistance to know what’s the corresponding name in Python
  • modules lowercase, words not separated with underscores (which means C++ namespaces have to be named clearly and tersely to make this possible)
  • class names CamelCase
  • function names snake_case
  • constants and enums UPPERCASE, again underscores omitted if it doesn’t hurt readability

Namespaces

C++ Python
Magnum::Math magnum.math
Magnum::SceneGraph magnum.scenegraph

Classes

C++ Python
Vector2i Vector2i
GL::Buffer gl.Buffer

Functions

C++ Python
Math::angle() math.angle()
Vector2::xAxis() Vector2.x_axis()
v.isZero() v.is_zero()
m.transformVector(a) m.transform_vector(a)

Enums

C++ Python
PixelFormat::RGB8Unorm PixelFormat.RGB8UNORM
MeshPrimitive::TriangleStrip MeshPrimitive.TRIANGLE_STRIP

Constants

Apart from Math::Constants, which are exposed directly as members of the math submodule to mimic Python’s math, most of the constants used throughout the C++ API are related to templates. Those are, where applicable, converted to Python builtins such as len().

C++ Python
Constants::pi() math.pi
Math::Vector::Size len(vec)

Initialization tags

Since overloading based on argument types is not a common thing to do in Python (and it adds extra overhead in pybind11), all initialization tags are converted to static constructors instead:

Matrix4 a{Math::IdentityInit, 5.0f};
GL::Buffer b{NoCreate};

C++

a = Matrix4.identity_init(5.0)
b = gl.Buffer.no_create()

Python

There’s no equivalent for the Math::NoInit tag, as such optimization doesn’t make much sense when instances are copied back and forth between C++ and Python. Similarly, the NoCreate tag makes sense only in C++ which differentiates between stack-allocated and heap-allocated instances. In Python it’s enough to simply set an instance to None to achieve the same effect.

Name import conventions

Similarly to C++, where it’s encouraged to do something like

namespace YourProject {
    using namespace Magnum;
}

and then use Magnum C++ APIs unprefixed from inside that namespace, the recommended Python workflow is similar. Note that importing the root module does not import submodules, so you are expected to import those on an as-needed basis as well.

from magnum import *
from magnum import gl, platform

In particular, both the C++ and the Python API is designed in a way to prevent too generic or confusing names in the root namespace / module and also keeping it relatively clean and small, without too many symbols. On the other hand, the subnamespaces do have generic names. The GL::version() / gl.version() API is one example — it’s tucked in a subnamespace so the generic name isn’t a problem, but you wouldn’t find anything of similar genericity in the root namespace / module.

Basic guarantees

  • All types printable using Utility::Debug implement __repr__() on the Python side, producing the exact same output.