@@ -734,15 +734,50 @@ def realign_remark(remark):
734734 )
735735
736736
737- HAS_REAL_CONTEXTVARS = True
737+ def _is_threading_local_monkey_patched ():
738+ # type: () -> bool
739+ try :
740+ from gevent .monkey import is_object_patched # type: ignore
741+
742+ if is_object_patched ("_threading" , "local" ):
743+ return True
744+ except ImportError :
745+ pass
746+
747+ try :
748+ from eventlet .patcher import is_monkey_patched # type: ignore
749+
750+ if is_monkey_patched ("thread" ):
751+ return True
752+ except ImportError :
753+ pass
754+
755+ return False
756+
738757
739- try :
740- from contextvars import ContextVar # type: ignore
758+ IS_THREADING_LOCAL_MONKEY_PATCHED = _is_threading_local_monkey_patched ()
759+ del _is_threading_local_monkey_patched
741760
742- if not PY2 and sys .version_info < (3 , 7 ):
743- import aiocontextvars # type: ignore # noqa
744- except ImportError :
745- HAS_REAL_CONTEXTVARS = False
761+
762+ def _get_contextvars ():
763+ # () -> (bool, Type)
764+ """
765+ Try to import contextvars and use it if it's deemed safe. We should not use
766+ contextvars if gevent or eventlet have patched thread locals, as
767+ contextvars are unaffected by that patch.
768+
769+ https://github.com/gevent/gevent/issues/1407
770+ """
771+ if not IS_THREADING_LOCAL_MONKEY_PATCHED :
772+ try :
773+ from contextvars import ContextVar # type: ignore
774+
775+ if not PY2 and sys .version_info < (3 , 7 ):
776+ import aiocontextvars # type: ignore # noqa
777+
778+ return True , ContextVar
779+ except ImportError :
780+ pass
746781
747782 from threading import local
748783
@@ -759,6 +794,12 @@ def get(self, default):
759794 def set (self , value ):
760795 setattr (self ._local , "value" , value )
761796
797+ return False , ContextVar
798+
799+
800+ HAS_REAL_CONTEXTVARS , ContextVar = _get_contextvars ()
801+ del _get_contextvars
802+
762803
763804def transaction_from_function (func ):
764805 # type: (Callable[..., Any]) -> Optional[str]
0 commit comments