@davidlamb ,
I don't use the Python library, but here's a good and quick way to tell what to send.
Open up the developer tools in your browser (F12 in Chrome or Firefox). Then go to the network tab. Create a question and look at the XHR request that Canvas makes. In Chrome, it's under the headers tab, then scroll down to Form Data. Then duplicate what Canvas is sending.

Here's what Canvas sent when I created your question. Note that it had a lot of other crud in there, I isolated just the relevant portions.
question[question_name]: Question 10
question[question_type]: numerical_question
question[points_possible]: 10
question[question_text]: <p>Select the appropriate answer</p>
question[answers][0][answer_exact]: 42
question[answers][0][answer_error_margin]: 4
question[answers][0][answer_weight]: 100
question[answers][0][numerical_answer_type]: exact_answer
When I look at what Canvas sends vs what you send, I see that the answer_text is not used for a numerical answer question. It typically ignores things that aren't relevant, so including it may not hurt anything, but it's not used. Also, you have a weight of 1 instead of 100.
I don't know if those matter, but if you have exactly what Canvas is sending and it still doesn't work, then it might have to do with the structure rather than the data you're sending.