I ran your code, and I cannot reproduce your problem. The line
tag( [c4d.ID_CA_CONSTRAINT_TAG_PARENT] = True is not really wrong but makes not too much sense as you are calling there
C4DAtom.__call__, the line should be
tag[c4d.ID_CA_CONSTRAINT_TAG_PARENT] = True.
I also added undo steps to your script, but it was working without them for me too. Maybe I am misunderstanding what you mean with 'When doing it manually, I get no offset on the objects, they all stay in place as intended.', but for me there is no 'offset'.
I ran the code on
2023.1.0 to the same effect, find my code below. If the problem does persist for you, I will have to ask you to explain what you would consider wrong with the result.
"""Constraints the two currently selected objects with a parent-child constraint.
doc: c4d.documents.BaseDocument # The active document
op: typing.Optional[c4d.BaseObject] # The active object, None if unselected
def main() -> None:
# Get the object selection in order and bail when not exactly two objects are selected.
selection: list[c4d.BaseObject] = doc.GetActiveObjects(
c4d.GETACTIVEOBJECTFLAGS_SELECTIONORDER | c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
if len(selection) != 2:
raise RuntimeError("Please select exactly two objects.")
# Unpack the selection into a parent and child variable, rename the two objects, and add undos
# for the operation.
parent, child = selection
# Create the tag.
tag: c4d.BaseTag = child.MakeTag(c4d.Tcaconstraint)
if tag is None:
raise MemoryError("Could not allocate tag.")
# Add an undo for the tag being added (must be done after the operation) and add another undo
# for the tag being modified (not really necessary here, but good form).
# Constraint #child to #parent.
tag[c4d.ID_CA_CONSTRAINT_TAG_PARENT] = True
tag = parent
if __name__ == '__main__':