From 739dd4a011365a14b440580ddfd0a02ebe58a8f3 Mon Sep 17 00:00:00 2001 From: mit-da <102551711+mit-da@users.noreply.github.com> Date: Wed, 14 Jun 2023 15:32:53 -0400 Subject: [PATCH 1/5] Add retry on EINTR. Try and fix issue #242 by adding a retry on EINTR and a sleep before attempting to do so. --- Lib/ldap/ldapobject.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Lib/ldap/ldapobject.py b/Lib/ldap/ldapobject.py index 7a9c17f6..341a14ac 100644 --- a/Lib/ldap/ldapobject.py +++ b/Lib/ldap/ldapobject.py @@ -47,6 +47,24 @@ class NO_UNIQUE_ENTRY(ldap.NO_SUCH_OBJECT): """ +def _retry_on_interrupted_ldap_call(func, *args, **kwargs): + """Call func, retrying if it raises an LDAPError with errno == EINTR. + """ + + attempts = 0 + while True: + attempts += 1 + try: + return func(*args, **kwargs) + except LDAPError as e: + if attempts > 1: + raise e + if e.args[0]['errno'] == EINTR: + time.sleep(0.1) + continue + raise e + + class SimpleLDAPObject: """ This basic class wraps all methods of the underlying C API object. @@ -125,7 +143,7 @@ def _ldap_call(self,func,*args,**kwargs): diagnostic_message_success = None try: try: - result = func(*args,**kwargs) + result = _retry_on_interrupted_ldap_call(*args,**kwargs) if __debug__ and self._trace_level>=2: if func.__name__!="unbind_ext": diagnostic_message_success = self._l.get_option(ldap.OPT_DIAGNOSTIC_MESSAGE) From dab133110182b25170e801eda214364f29a1da24 Mon Sep 17 00:00:00 2001 From: mit-da <102551711+mit-da@users.noreply.github.com> Date: Thu, 13 Jul 2023 18:40:24 +0000 Subject: [PATCH 2/5] Add missing import --- Lib/ldap/ldapobject.py | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/Lib/ldap/ldapobject.py b/Lib/ldap/ldapobject.py index 341a14ac..98441073 100644 --- a/Lib/ldap/ldapobject.py +++ b/Lib/ldap/ldapobject.py @@ -28,24 +28,7 @@ from ldap import LDAPError - -class LDAPBytesWarning(BytesWarning): - """Python 2 bytes mode warning""" - - def __init__(self, *args, **kwargs): - warnings.warn( - "LDAPBytesWarning is deprecated and will be removed in the future", - DeprecationWarning, - ) - super().__init__(*args, **kwargs) - - -class NO_UNIQUE_ENTRY(ldap.NO_SUCH_OBJECT): - """ - Exception raised if a LDAP search returned more than entry entry - although assumed to return a unique single search result. - """ - +from errno import EINTR def _retry_on_interrupted_ldap_call(func, *args, **kwargs): """Call func, retrying if it raises an LDAPError with errno == EINTR. @@ -65,6 +48,24 @@ def _retry_on_interrupted_ldap_call(func, *args, **kwargs): raise e +class LDAPBytesWarning(BytesWarning): + """Python 2 bytes mode warning""" + + def __init__(self, *args, **kwargs): + warnings.warn( + "LDAPBytesWarning is deprecated and will be removed in the future", + DeprecationWarning, + ) + super().__init__(*args, **kwargs) + + +class NO_UNIQUE_ENTRY(ldap.NO_SUCH_OBJECT): + """ + Exception raised if a LDAP search returned more than entry entry + although assumed to return a unique single search result. + """ + + class SimpleLDAPObject: """ This basic class wraps all methods of the underlying C API object. From bf9b41638b96c3f3b120a2111548ad3c666fca80 Mon Sep 17 00:00:00 2001 From: mit-da <102551711+mit-da@users.noreply.github.com> Date: Thu, 13 Jul 2023 18:42:42 +0000 Subject: [PATCH 3/5] Add the function as a param. --- Lib/ldap/ldapobject.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/ldap/ldapobject.py b/Lib/ldap/ldapobject.py index 98441073..fe2404a0 100644 --- a/Lib/ldap/ldapobject.py +++ b/Lib/ldap/ldapobject.py @@ -144,7 +144,7 @@ def _ldap_call(self,func,*args,**kwargs): diagnostic_message_success = None try: try: - result = _retry_on_interrupted_ldap_call(*args,**kwargs) + result = _retry_on_interrupted_ldap_call(func,*args,**kwargs) if __debug__ and self._trace_level>=2: if func.__name__!="unbind_ext": diagnostic_message_success = self._l.get_option(ldap.OPT_DIAGNOSTIC_MESSAGE) From 60b5376493660bd139e700629be7452df91c85d3 Mon Sep 17 00:00:00 2001 From: mit-da <102551711+mit-da@users.noreply.github.com> Date: Thu, 13 Jul 2023 19:35:01 +0000 Subject: [PATCH 4/5] Add error handling checks for index out of range similar to original function to pass tests. --- Lib/ldap/ldapobject.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Lib/ldap/ldapobject.py b/Lib/ldap/ldapobject.py index fe2404a0..4ffd73cb 100644 --- a/Lib/ldap/ldapobject.py +++ b/Lib/ldap/ldapobject.py @@ -31,7 +31,8 @@ from errno import EINTR def _retry_on_interrupted_ldap_call(func, *args, **kwargs): - """Call func, retrying if it raises an LDAPError with errno == EINTR. + """ + Call func, retrying if it raises an LDAPError with errno == EINTR. """ attempts = 0 @@ -42,9 +43,13 @@ def _retry_on_interrupted_ldap_call(func, *args, **kwargs): except LDAPError as e: if attempts > 1: raise e - if e.args[0]['errno'] == EINTR: - time.sleep(0.1) - continue + try: + if 'info' not in e.args[0] and 'errno' in e.args[0]: + if e.args[0]['errno'] == EINTR: + time.sleep(0.1) + continue + except IndexError: + pass raise e From 9b2b534a392a1db868dece1a1bb75f0ed5bc2709 Mon Sep 17 00:00:00 2001 From: mit-da <102551711+mit-da@users.noreply.github.com> Date: Thu, 13 Jul 2023 20:06:44 +0000 Subject: [PATCH 5/5] Minor swap --- Lib/ldap/ldapobject.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Lib/ldap/ldapobject.py b/Lib/ldap/ldapobject.py index 4ffd73cb..b6f5efb0 100644 --- a/Lib/ldap/ldapobject.py +++ b/Lib/ldap/ldapobject.py @@ -44,7 +44,7 @@ def _retry_on_interrupted_ldap_call(func, *args, **kwargs): if attempts > 1: raise e try: - if 'info' not in e.args[0] and 'errno' in e.args[0]: + if 'errno' in e.args[0]: if e.args[0]['errno'] == EINTR: time.sleep(0.1) continue @@ -52,7 +52,6 @@ def _retry_on_interrupted_ldap_call(func, *args, **kwargs): pass raise e - class LDAPBytesWarning(BytesWarning): """Python 2 bytes mode warning"""