Problem with Boolean-difference modifier – or – How to model a cuboid with two cylindric holes Simplified: I want to generate a cuboid with cylinders as holes in Blender.

When I add with a difference-modifier, I come to pretty common problems/limitations. 


There are lots of tips or advice like about this theme:
-   Solidify the objects before booleaning them 
-   Recalculating normals
-   Close holes
I couldn’t fix the problem with this general advice. I know that these are the limitations of face-based modelling (with Blender) and not volume-based (other software) modelling. But there must be a work around for Blender?
I know a manual fix for this problem: 

By manually and step adding the faces (in the Edit Mode by selection one edge and pressing [enter])


Well at least it is nearly a solution…



But anyway, this isn't helpful for a scripted solution...
So what can I do?
Can someone tell me how to code this?



code Example of this Problem for Blender 2.80b (warning, this seems to be not backwards compatible with Blender 2.79):

#code for Blender 2.80
import bpy

def booleanModifierApplyAndDelete(fromObject, removeObject):
        ##Switch to 
        bpy.ops.object.select_all(action='DESELECT')
        bpy.context.view_layer.objects.active = bpy.data.objects[fromObject]
        bpy.data.objects[fromObject].select_set(state=True)

        ##addModifier Working
        bpy.ops.object.modifier_add(type='BOOLEAN')
        bpy.context.object.modifiers["Boolean"].operation = 'DIFFERENCE'
        bpy.context.object.modifiers["Boolean"].object = bpy.data.objects[removeObject]
        bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Boolean")
        bpy.data.objects.remove(bpy.data.objects[removeObject], do_unlink=True)   


#initial variables:

thickness = 2
width = 5
height = 2
overlap = 0.1


#delete all objects from previous Build
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(use_global=False)


##add mainCube
bpy.ops.mesh.primitive_cube_add(view_align=False, enter_editmode=False, location=(0,0,0))
bpy.context.active_object.name = 'mainCube'
bpy.context.object.dimensions = (thickness,width,height)



#top Rounding/hole
bpy.ops.mesh.primitive_cylinder_add(vertices=64, radius=1-overlap/2*2, depth=width+overlap*2, view_align=False, enter_editmode=False, location=(0, 0, 1), rotation=(1.5708, 0, 0))
bpy.context.active_object.name = 'topRounding'

booleanModifierApplyAndDelete('mainCube', 'topRounding')


#cylindrical hole
bpy.ops.mesh.primitive_cylinder_add(vertices=64, depth=height+overlap*2, view_align=False, enter_editmode=False, location=(0, 0, 0))
bpy.context.active_object.name = 'hole'

booleanModifierApplyAndDelete('mainCube', 'hole')
Because an intersection between two cylinders at 90 degrees is a 45 degree miter, this isn't too hard to model. Z up, Y along the lenght, X across


K with C to constrain and Z to cut through, make 2 45 degree cuts into  a half-cylinder as shown
E (right-click to cancel transform) followed by SX extrude the long edges outwards
Select all the faces, E extrude them downwards, followed by SZ0 about their median point to flatten them.
Select the central hole-faces on both sides, and CtrlE &gt; Bridge Edge Loops
Header select menu &gt; Select Sharp Edges, and add some by hand to complete the circumference of the top hole. Set the Bevel Weight of all the selected edges to 1.00

Assign a Bevel modifier by Weight, Segments 2, Profile 1.00. I usually switch off the clamps, and reduce the width until everything looks correct. Assign a Subdivision Surface modifier.