Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop dependency on psutil #68

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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