Thank you @zipit and @m_magalhaes for your replies! @zipit your response put me on the right track. The issue was that I was trying to do all of the conversions using C4D's left-handed coordinate matrices, and it was auto-fixing my "malformed" matrices.
I ended up porting the Three.js Matrix4 and Euler classes from JS to python and using them in my script.
So, the final code (leaving out the ported methods) looked something like:
mg = self.op.GetMg()
parent_mg = self.op.GetUpMg()
c4d_to_three = c4d.Matrix(
off=c4d.Vector(0),
v1=c4d.Vector(1, 0, 0),
v2=c4d.Vector(0, 1, 0),
v3=c4d.Vector(0, 0, -1)
)
# Convert to new coordinate space
# http://www.techart3d.com/2016/02/convert-left-handed-to-right-handed-coordinates/
mg_three_coords = c4d_to_three * mg * c4d_to_three
parent_mg_three_coords = c4d_to_three * parent_mg * c4d_to_three
mg_mat4 = Matrix4(mg_three_coords)
parent_mg_mat4 = Matrix4(parent_mg_three_coords)
inv_parent_mg_mat4 = parent_mg_mat4.Clone()
inv_parent_mg_mat4 = inv_parent_mg_mat4.Inverse()
node_local = inv_parent_mg_mat4.Clone()
node_local = node_local.MultiplyMatrices(inv_parent_mg_mat4, mg_mat4)
position, scale, rotation = node_local.Decompose()
if position != c4d.Vector(0):
self.props["position"] = position
if scale != c4d.Vector(1):
self.props["scale"] = scale
if rotation != c4d.Vector(0):
self.props["rotation"] = rotation