Skip to content

Commit

Permalink
Drop dependency on psutil
Browse files Browse the repository at this point in the history
  • Loading branch information
tpambor committed Apr 8, 2020
1 parent 9ab481b commit 5f9a77b
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 21 deletions.
4 changes: 2 additions & 2 deletions pylink/jlock.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import psutil
from . import util

import errno
import tempfile
Expand Down Expand Up @@ -103,7 +103,7 @@ def acquire(self):

# In the case that the lockfile exists, but the pid does not
# correspond to a valid process, remove the file.
if not psutil.pid_exists(pid):
if not util.pid_exists(pid):
os.remove(self.path)

except ValueError as e:
Expand Down
63 changes: 63 additions & 0 deletions pylink/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

import platform
import sys
import os
import ctypes


def is_integer(val):
Expand Down Expand Up @@ -180,3 +182,64 @@ def calculate_parity(n):
y += n & 1
n = n >> 1
return y & 1


def pid_exists_win32(pid):
ERROR_ACCESS_DENIED = 0x5
ERROR_INVALID_PARAMETER = 0x57
PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
STILL_ACTIVE = 0x103

if pid == 0:
return True
elif pid == -1:
return False

hProcess = ctypes.windll.kernel32.OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, pid)
if not hProcess:
error = ctypes.windll.kernel32.GetLastError()
if error == ERROR_ACCESS_DENIED:
return True
elif error == ERROR_INVALID_PARAMETER:
return False
else:
raise ctypes.WinError()

exitCode = ctypes.c_int(0)
pExitCode = ctypes.pointer(exitCode)
if not ctypes.windll.kernel32.GetExitCodeProcess(hProcess, pExitCode):
error = ctypes.windll.kernel32.GetLastError()
if error == ERROR_ACCESS_DENIED:
ctypes.windll.kernel32.CloseHandle(hProcess)
return True
else:
raise ctypes.WinError()

if exitCode.value == STILL_ACTIVE:
ctypes.windll.kernel32.CloseHandle(hProcess)
return True

ctypes.windll.kernel32.CloseHandle(hProcess)
return False


def pid_exists_posix(pid):
if pid == 0:
return True
elif pid < 0:
return False

try:
os.kill(pid, 0)
except ProcessLookupError:
return False
except PermissionError:
return True
return True


def pid_exists(pid):
if sys.platform.startswith('win') or sys.platform.startswith('cygwin'):
return pid_exists_win32(pid)
else:
return pid_exists_posix(pid)
1 change: 0 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
behave == 1.2.5
coverage == 4.4.1
future
psutil >= 5.2.2
pycodestyle >= 2.3.1
six
sphinx == 1.4.8
Expand Down
8 changes: 0 additions & 8 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,6 @@

import sys

# Stub the 'psutil' module that is required by this package in order to enable
# the main module to be imported.
try:
import psutil
except ImportError:
sys.modules['psutil'] = {}

import pylink

import os
Expand Down Expand Up @@ -255,7 +248,6 @@ def long_description():

# Dependencies.
install_requires=[
'psutil >= 5.2.2',
'future',
'six'
],
Expand Down
20 changes: 10 additions & 10 deletions tests/unit/test_jlock.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,15 @@ def test_jlock_init_and_delete(self):
@mock.patch('os.open')
@mock.patch('os.write')
@mock.patch('os.remove')
@mock.patch('pylink.jlock.psutil')
@mock.patch('pylink.jlock.util')
@mock.patch('pylink.jlock.open')
def test_jlock_acquire_exists(self, mock_open, mock_util, mock_rm, mock_wr, mock_op, mock_exists, mock_close):
"""Tests trying to acquire when the lock exists for an active process.
Args:
self (TestJLock): the ``TestJLock`` instance
mock_open (Mock): mocked built-in open method
mock_util (Mock): mocked ``psutil`` module
mock_util (Mock): mocked ``util`` module
mock_rm (Mock): mocked os remove method
mock_wr (Mock): mocked os write method
mock_op (Mock): mocked os open method
Expand Down Expand Up @@ -122,15 +122,15 @@ def test_jlock_acquire_exists(self, mock_open, mock_util, mock_rm, mock_wr, mock
@mock.patch('os.open')
@mock.patch('os.write')
@mock.patch('os.remove')
@mock.patch('pylink.jlock.psutil')
@mock.patch('pylink.jlock.util')
@mock.patch('pylink.jlock.open')
def test_jlock_acquire_os_error(self, mock_open, mock_util, mock_rm, mock_wr, mock_op, mock_exists, mock_close):
"""Tests trying to acquire the lock but generating an os-level error.
Args:
self (TestJLock): the ``TestJLock`` instance
mock_open (Mock): mocked built-in open method
mock_util (Mock): mocked ``psutil`` module
mock_util (Mock): mocked ``util`` module
mock_rm (Mock): mocked os remove method
mock_wr (Mock): mocked os write method
mock_op (Mock): mocked os open method
Expand Down Expand Up @@ -167,15 +167,15 @@ def test_jlock_acquire_os_error(self, mock_open, mock_util, mock_rm, mock_wr, mo
@mock.patch('os.open')
@mock.patch('os.write')
@mock.patch('os.remove')
@mock.patch('pylink.jlock.psutil')
@mock.patch('pylink.jlock.util')
@mock.patch('pylink.jlock.open')
def test_jlock_acquire_bad_file(self, mock_open, mock_util, mock_rm, mock_wr, mock_op, mock_exists, mock_close):
"""Tests acquiring the lockfile when the current lockfile is invallid.
Args:
self (TestJLock): the ``TestJLock`` instance
mock_open (Mock): mocked built-in open method
mock_util (Mock): mocked ``psutil`` module
mock_util (Mock): mocked ``util`` module
mock_rm (Mock): mocked os remove method
mock_wr (Mock): mocked os write method
mock_op (Mock): mocked os open method
Expand Down Expand Up @@ -216,15 +216,15 @@ def test_jlock_acquire_bad_file(self, mock_open, mock_util, mock_rm, mock_wr, mo
@mock.patch('os.open')
@mock.patch('os.write')
@mock.patch('os.remove')
@mock.patch('pylink.jlock.psutil')
@mock.patch('pylink.jlock.util')
@mock.patch('pylink.jlock.open')
def test_jlock_acquire_invalid_pid(self, mock_open, mock_util, mock_rm, mock_wr, mock_op, mock_exists, mock_close):
"""Tests acquiring the lockfile when the pid in the lockfile is invalid.
Args:
self (TestJLock): the ``TestJLock`` instance
mock_open (Mock): mocked built-in open method
mock_util (Mock): mocked ``psutil`` module
mock_util (Mock): mocked ``util`` module
mock_rm (Mock): mocked os remove method
mock_wr (Mock): mocked os write method
mock_op (Mock): mocked os open method
Expand Down Expand Up @@ -263,15 +263,15 @@ def test_jlock_acquire_invalid_pid(self, mock_open, mock_util, mock_rm, mock_wr,
@mock.patch('os.open')
@mock.patch('os.write')
@mock.patch('os.remove')
@mock.patch('pylink.jlock.psutil')
@mock.patch('pylink.jlock.util')
@mock.patch('pylink.jlock.open')
def test_jlock_acquire_old_pid(self, mock_open, mock_util, mock_rm, mock_wr, mock_op, mock_exists, mock_close):
"""Tests acquiring when the PID in the lockfile does not exist.
Args:
self (TestJLock): the ``TestJLock`` instance
mock_open (Mock): mocked built-in open method
mock_util (Mock): mocked ``psutil`` module
mock_util (Mock): mocked ``util`` module
mock_rm (Mock): mocked os remove method
mock_wr (Mock): mocked os write method
mock_op (Mock): mocked os open method
Expand Down

0 comments on commit 5f9a77b

Please sign in to comment.