Python API conventions
Basic rules and good practices for both Python binding developers 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
Preprocessor definitions
Exposed to Python as plain boolean constants, and only those that actually are useful in a Python setting.
C++ | Python |
---|---|
CORRADE_BUILD_MULTITHREADED | corrade.BUILD_MULTITHREADED |
MAGNUM_TARGET_GLES | magnum.TARGET_GLES |
Namespaces / modules
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
Custom construction helpers for enums are converted to functions directly on the Python enum class.
Enum sets
Compared to C++, there’s just one enum type with a plural name, and it contains
both the values and binary operators. Additionally, there’s an explicit
NONE
value for an empty set.
C++ | Python |
---|---|
Trade::DataFlag::Mutable | trade.DataFlags.MUTABLE |
Trade::DataFlags{} | trade.DataFlags.NONE |
Constants
Apart from Math::Constants, which are exposed directly as members of the
magnum.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) |
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.
An exception to this rule is exposed preprocessor definitions — these are
not pulled in when doing from magnum import *
as this would likely
cause conflicts (in particular, BUILD_STATIC is defined by Corrade as
well). Instead, you have to access them like this:
import magnum if magnum.TARGET_GLES2: format = gl.TextureFormat.RGBA8 else: format = gl.TextureFormat.R8
Handling of alternate implementations
C++ APIs that have alternative implementations (such as
Platform::Sdl2Application vs. Platform::GlfwApplication, or
SceneGraph::MatrixTransformation3D vs.
SceneGraph::TranslationRotationScalingTransformation3D) either provide
typedef
s based on what header you include or require you to
typedef
them yourselves:
class MyApplication: Platform::Application {}; // depends on what you include typedef SceneGraph::Object<SceneGraph::MatrixTransformation3D> Object3D;
In Python, the alternate implementations are tucked in submodules (such as
platform.sdl2 vs. platform.glfw, or scenegraph.matrix vs.
scenegraph.trs), each submodule providing the same names (such as
Application or
Object3D)
and the designed way to use them is via from ... import
:
from magnum.platform.sdl2 import Application from magnum.scenegraph.trs import Scene3D, Object3D
Basic guarantees
- All types printable using Utility::Debug implement
__repr__()
on the Python side, producing the exact same output.