I'd like to intensify the problem, though: you're in a thread and you want to call a Python API function safely. Period.
Are there semantic requirements to the Python API in this context, with respect to the state of global things?
No more than self-consistency, I expect, same as for a proper call now run from a thread.
E.g. when I run the simple string "import sys;print sys.modules", would I need to get the same output that I get elsewhere? If yes, is it possible to characterize "elsewhere" any better?
I don't know what "elsewhere" means at all. Let's make some assumptions first: Python either has already been initialized successfully, or does initialize successfully as a result of whatever prologue dance is required before you're allowed to "run the simple string". "sys" resolves to the builtin sys. You "run the simple string" at time T1, and it returns at time T2. Nobody finalizes Python "by surprise", or kills it, during this either. Then I expect the strongest that can be said is that the output you get corresponds to the actual state of sys.modules at some time T, with T1 <= T <= T2 (and because you're executing Python code, there's nothing to stop the interpreter from letting some other thread(s) run before and after each of the interpreted string statements, and they can do anything to sys.modules). I don't expect we can say anything stronger than that today either.