Thanks for the context, but that actually seems to be describing the
situation from Python 3.2. Python 3.3 introduced module-level import
locking with improved deadlock detection that looks for actual cycles
and is supposed to fix the unnecessary ImportErrors described in
#8098, rendering the PyImport_ImportModuleNoBlock "fairy dust"
unnecessary -- in 3.3, I understand that PyImport_ImportModuleNoBlock
is now just a synonym for PyImport_ImportModule. But you're reporting
that you're still seeing issues with this in Python 3.3. Diving into
the code, I think I start to understand why. Take a look at this
function from Lib/importlib/_bootstrap.py:
def _lock_unlock_module(name):
"""Release the global import lock, and acquires then release the
module lock for a given module name.
This is used to ensure a module is completely initialized, in the
event it is being imported by another thread.
Should only be called with the import lock taken."""
lock = _get_module_lock(name)
_imp.release_lock()
try:
lock.acquire()
except _DeadlockError:
# Concurrent circular import, we'll accept a partially initialized
# module object.
pass
else:
lock.release()
Normally, it just acquires and releases the module lock to ensure that
the module has been completely initialized. If a deadlock is
detected, however, then it skips that step and instead of raising an
ImportError (which would seem to me to be the right thing to do here)
it allows the importing code to simply proceed with a module that may
not be fully imported yet. Since your error message concerned missing
module-level attributes within the _strptime module, that seems to be
what you're running into. The time.strptime function attempts to
import _strptime, which is already being imported by another thread;
for some unknown reason it detects a cyclical deadlock as a result of
this; it then white-washes the deadlock and tries to use the _strptime
module anyway, causing a different error to occur. The question then
is how you're managing to get an import cycle by using strptime.