From 5f634acf83151af58e0dd9f54c6492684e3c825d Mon Sep 17 00:00:00 2001 From: William Zhou Date: Wed, 21 Apr 2021 12:20:53 -0700 Subject: [PATCH 1/4] PYTHON-2234: When mongocryptd spawn fails, the driver does not indicate what it tried to spawn (#591) (cherry picked from commit aaba51d927618e7ac2be7c208a014f9d66cb2c40) --- pymongo/daemon.py | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/pymongo/daemon.py b/pymongo/daemon.py index f066a02c23..8f18233a39 100644 --- a/pymongo/daemon.py +++ b/pymongo/daemon.py @@ -24,6 +24,8 @@ import sys import time +from pymongo.errors import PyMongoError + # The maximum amount of time to wait for the intermediate subprocess. _WAIT_TIMEOUT = 10 _THIS_FILE = os.path.realpath(__file__) @@ -75,12 +77,16 @@ def _silence_resource_warning(popen): def _spawn_daemon(args): """Spawn a daemon process (Windows).""" - with open(os.devnull, 'r+b') as devnull: - popen = subprocess.Popen( - args, - creationflags=_DETACHED_PROCESS, - stdin=devnull, stderr=devnull, stdout=devnull) - _silence_resource_warning(popen) + try: + with open(os.devnull, 'r+b') as devnull: + popen = subprocess.Popen( + args, + creationflags=_DETACHED_PROCESS, + stdin=devnull, stderr=devnull, stdout=devnull) + _silence_resource_warning(popen) + except FileNotFoundError as exc: + raise PyMongoError( + f'Failed to start {args[0]}: is it on your $PATH?\nOriginal exception: {exc}') else: # On Unix we spawn the daemon process with a double Popen. # 1) The first Popen runs this file as a Python script using the current @@ -95,12 +101,15 @@ def _spawn_daemon(args): # we spawn the mongocryptd daemon process. def _spawn(args): """Spawn the process and silence stdout/stderr.""" - with open(os.devnull, 'r+b') as devnull: - return subprocess.Popen( - args, - close_fds=True, - stdin=devnull, stderr=devnull, stdout=devnull) - + try: + with open(os.devnull, 'r+b') as devnull: + return subprocess.Popen( + args, + close_fds=True, + stdin=devnull, stderr=devnull, stdout=devnull) + except FileNotFoundError as exc: + raise PyMongoError( + f'Failed to start {args[0]}: is it on your $PATH?\nOriginal exception: {exc}') def _spawn_daemon_double_popen(args): """Spawn a daemon process using a double subprocess.Popen.""" From 0eee2049ab25029454e984f099f816a8a7b025ee Mon Sep 17 00:00:00 2001 From: Prashant Mital Date: Wed, 21 Apr 2021 12:36:13 -0700 Subject: [PATCH 2/4] make string formatting py2-friendly --- pymongo/daemon.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pymongo/daemon.py b/pymongo/daemon.py index 8f18233a39..fe0f3f9841 100644 --- a/pymongo/daemon.py +++ b/pymongo/daemon.py @@ -85,8 +85,8 @@ def _spawn_daemon(args): stdin=devnull, stderr=devnull, stdout=devnull) _silence_resource_warning(popen) except FileNotFoundError as exc: - raise PyMongoError( - f'Failed to start {args[0]}: is it on your $PATH?\nOriginal exception: {exc}') + raise PyMongoError('Failed to start %s: is it on your $PATH?\n' + 'Original exception: %s' % (args[0], exc)) else: # On Unix we spawn the daemon process with a double Popen. # 1) The first Popen runs this file as a Python script using the current @@ -108,8 +108,8 @@ def _spawn(args): close_fds=True, stdin=devnull, stderr=devnull, stdout=devnull) except FileNotFoundError as exc: - raise PyMongoError( - f'Failed to start {args[0]}: is it on your $PATH?\nOriginal exception: {exc}') + raise PyMongoError('Failed to start %s: is it on your $PATH?\n' + 'Original exception: %s' % (args[0], exc)) def _spawn_daemon_double_popen(args): """Spawn a daemon process using a double subprocess.Popen.""" From 5659be127cbf589e73431b0d5ae960fb24f77e55 Mon Sep 17 00:00:00 2001 From: Prashant Mital Date: Wed, 21 Apr 2021 15:24:06 -0700 Subject: [PATCH 3/4] fixes --- pymongo/daemon.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/pymongo/daemon.py b/pymongo/daemon.py index fe0f3f9841..6966d4febc 100644 --- a/pymongo/daemon.py +++ b/pymongo/daemon.py @@ -23,13 +23,14 @@ import subprocess import sys import time +import warnings -from pymongo.errors import PyMongoError # The maximum amount of time to wait for the intermediate subprocess. _WAIT_TIMEOUT = 10 _THIS_FILE = os.path.realpath(__file__) + if sys.version_info[0] < 3: def _popen_wait(popen, timeout): """Implement wait timeout support for Python 2.""" @@ -68,7 +69,9 @@ def _silence_resource_warning(popen): # "ResourceWarning: subprocess XXX is still running". # See https://bugs.python.org/issue38890 and # https://bugs.python.org/issue26741. - popen.returncode = 0 + # popen is None when mongocryptd spawning fails + if popen is not None: + popen.returncode = 0 if sys.platform == 'win32': @@ -85,8 +88,9 @@ def _spawn_daemon(args): stdin=devnull, stderr=devnull, stdout=devnull) _silence_resource_warning(popen) except FileNotFoundError as exc: - raise PyMongoError('Failed to start %s: is it on your $PATH?\n' - 'Original exception: %s' % (args[0], exc)) + warnings.warn('Failed to start %s: is it on your $PATH?\n' + f'Original exception: %s' % (args[0], exc), + RuntimeWarning, stacklevel=2) else: # On Unix we spawn the daemon process with a double Popen. # 1) The first Popen runs this file as a Python script using the current @@ -108,8 +112,9 @@ def _spawn(args): close_fds=True, stdin=devnull, stderr=devnull, stdout=devnull) except FileNotFoundError as exc: - raise PyMongoError('Failed to start %s: is it on your $PATH?\n' - 'Original exception: %s' % (args[0], exc)) + warnings.warn('Failed to start %s: is it on your $PATH?\n' + f'Original exception: %s' % (args[0], exc), + RuntimeWarning, stacklevel=2) def _spawn_daemon_double_popen(args): """Spawn a daemon process using a double subprocess.Popen.""" From 257cc274cf1df631093d657b9d4efd97575144fb Mon Sep 17 00:00:00 2001 From: Prashant Mital Date: Wed, 21 Apr 2021 15:25:45 -0700 Subject: [PATCH 4/4] fix typo --- pymongo/daemon.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pymongo/daemon.py b/pymongo/daemon.py index 6966d4febc..82502b30de 100644 --- a/pymongo/daemon.py +++ b/pymongo/daemon.py @@ -89,7 +89,7 @@ def _spawn_daemon(args): _silence_resource_warning(popen) except FileNotFoundError as exc: warnings.warn('Failed to start %s: is it on your $PATH?\n' - f'Original exception: %s' % (args[0], exc), + 'Original exception: %s' % (args[0], exc), RuntimeWarning, stacklevel=2) else: # On Unix we spawn the daemon process with a double Popen. @@ -113,7 +113,7 @@ def _spawn(args): stdin=devnull, stderr=devnull, stdout=devnull) except FileNotFoundError as exc: warnings.warn('Failed to start %s: is it on your $PATH?\n' - f'Original exception: %s' % (args[0], exc), + 'Original exception: %s' % (args[0], exc), RuntimeWarning, stacklevel=2) def _spawn_daemon_double_popen(args):