Skip to content

Commit 284ddc4

Browse files
committed
Drop dependency on psutil
1 parent 9ab481b commit 284ddc4

File tree

5 files changed

+72
-21
lines changed

5 files changed

+72
-21
lines changed

pylink/jlock.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
import psutil
15+
from . import util
1616

1717
import errno
1818
import tempfile
@@ -103,7 +103,7 @@ def acquire(self):
103103

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

109109
except ValueError as e:

pylink/util.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
import platform
1919
import sys
20+
import os
21+
import ctypes
2022

2123

2224
def is_integer(val):
@@ -180,3 +182,61 @@ def calculate_parity(n):
180182
y += n & 1
181183
n = n >> 1
182184
return y & 1
185+
186+
def pid_exists_win32(pid):
187+
ERROR_ACCESS_DENIED = 0x5
188+
ERROR_INVALID_PARAMETER = 0x57
189+
PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
190+
STILL_ACTIVE = 0x103
191+
192+
if pid == 0:
193+
return True
194+
elif pid == -1:
195+
return False
196+
197+
hProcess = ctypes.windll.kernel32.OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, pid)
198+
if not hProcess:
199+
error = ctypes.windll.kernel32.GetLastError()
200+
if error == ERROR_ACCESS_DENIED:
201+
return True
202+
elif error == ERROR_INVALID_PARAMETER:
203+
return False
204+
else:
205+
raise ctypes.WinError()
206+
207+
exitCode = ctypes.c_int(0)
208+
pExitCode = ctypes.pointer(exitCode)
209+
if not ctypes.windll.kernel32.GetExitCodeProcess(hProcess, pExitCode):
210+
error = ctypes.windll.kernel32.GetLastError()
211+
if error == ERROR_ACCESS_DENIED:
212+
ctypes.windll.kernel32.CloseHandle(hProcess)
213+
return True
214+
else:
215+
raise ctypes.WinError()
216+
217+
if exitCode.value == STILL_ACTIVE:
218+
ctypes.windll.kernel32.CloseHandle(hProcess)
219+
return True
220+
221+
ctypes.windll.kernel32.CloseHandle(hProcess)
222+
return False
223+
224+
def pid_exists_posix(pid):
225+
if pid == 0:
226+
return True
227+
elif pid < 0:
228+
return False
229+
230+
try:
231+
os.kill(pid, 0)
232+
except ProcessLookupError:
233+
return False
234+
except PermissionError:
235+
return True
236+
return True
237+
238+
def pid_exists(pid):
239+
if sys.platform.startswith('win') or sys.platform.startswith('cygwin'):
240+
return pid_exists_win32(pid)
241+
else:
242+
return pid_exists_posix(pid)

requirements.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
behave == 1.2.5
22
coverage == 4.4.1
33
future
4-
psutil >= 5.2.2
54
pycodestyle >= 2.3.1
65
six
76
sphinx == 1.4.8

setup.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,6 @@
1414

1515
import sys
1616

17-
# Stub the 'psutil' module that is required by this package in order to enable
18-
# the main module to be imported.
19-
try:
20-
import psutil
21-
except ImportError:
22-
sys.modules['psutil'] = {}
23-
2417
import pylink
2518

2619
import os
@@ -255,7 +248,6 @@ def long_description():
255248

256249
# Dependencies.
257250
install_requires=[
258-
'psutil >= 5.2.2',
259251
'future',
260252
'six'
261253
],

tests/unit/test_jlock.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,15 @@ def test_jlock_init_and_delete(self):
7474
@mock.patch('os.open')
7575
@mock.patch('os.write')
7676
@mock.patch('os.remove')
77-
@mock.patch('pylink.jlock.psutil')
77+
@mock.patch('pylink.jlock.util')
7878
@mock.patch('pylink.jlock.open')
7979
def test_jlock_acquire_exists(self, mock_open, mock_util, mock_rm, mock_wr, mock_op, mock_exists, mock_close):
8080
"""Tests trying to acquire when the lock exists for an active process.
8181
8282
Args:
8383
self (TestJLock): the ``TestJLock`` instance
8484
mock_open (Mock): mocked built-in open method
85-
mock_util (Mock): mocked ``psutil`` module
85+
mock_util (Mock): mocked ``util`` module
8686
mock_rm (Mock): mocked os remove method
8787
mock_wr (Mock): mocked os write method
8888
mock_op (Mock): mocked os open method
@@ -122,15 +122,15 @@ def test_jlock_acquire_exists(self, mock_open, mock_util, mock_rm, mock_wr, mock
122122
@mock.patch('os.open')
123123
@mock.patch('os.write')
124124
@mock.patch('os.remove')
125-
@mock.patch('pylink.jlock.psutil')
125+
@mock.patch('pylink.jlock.util')
126126
@mock.patch('pylink.jlock.open')
127127
def test_jlock_acquire_os_error(self, mock_open, mock_util, mock_rm, mock_wr, mock_op, mock_exists, mock_close):
128128
"""Tests trying to acquire the lock but generating an os-level error.
129129
130130
Args:
131131
self (TestJLock): the ``TestJLock`` instance
132132
mock_open (Mock): mocked built-in open method
133-
mock_util (Mock): mocked ``psutil`` module
133+
mock_util (Mock): mocked ``util`` module
134134
mock_rm (Mock): mocked os remove method
135135
mock_wr (Mock): mocked os write method
136136
mock_op (Mock): mocked os open method
@@ -167,15 +167,15 @@ def test_jlock_acquire_os_error(self, mock_open, mock_util, mock_rm, mock_wr, mo
167167
@mock.patch('os.open')
168168
@mock.patch('os.write')
169169
@mock.patch('os.remove')
170-
@mock.patch('pylink.jlock.psutil')
170+
@mock.patch('pylink.jlock.util')
171171
@mock.patch('pylink.jlock.open')
172172
def test_jlock_acquire_bad_file(self, mock_open, mock_util, mock_rm, mock_wr, mock_op, mock_exists, mock_close):
173173
"""Tests acquiring the lockfile when the current lockfile is invallid.
174174
175175
Args:
176176
self (TestJLock): the ``TestJLock`` instance
177177
mock_open (Mock): mocked built-in open method
178-
mock_util (Mock): mocked ``psutil`` module
178+
mock_util (Mock): mocked ``util`` module
179179
mock_rm (Mock): mocked os remove method
180180
mock_wr (Mock): mocked os write method
181181
mock_op (Mock): mocked os open method
@@ -216,15 +216,15 @@ def test_jlock_acquire_bad_file(self, mock_open, mock_util, mock_rm, mock_wr, mo
216216
@mock.patch('os.open')
217217
@mock.patch('os.write')
218218
@mock.patch('os.remove')
219-
@mock.patch('pylink.jlock.psutil')
219+
@mock.patch('pylink.jlock.util')
220220
@mock.patch('pylink.jlock.open')
221221
def test_jlock_acquire_invalid_pid(self, mock_open, mock_util, mock_rm, mock_wr, mock_op, mock_exists, mock_close):
222222
"""Tests acquiring the lockfile when the pid in the lockfile is invalid.
223223
224224
Args:
225225
self (TestJLock): the ``TestJLock`` instance
226226
mock_open (Mock): mocked built-in open method
227-
mock_util (Mock): mocked ``psutil`` module
227+
mock_util (Mock): mocked ``util`` module
228228
mock_rm (Mock): mocked os remove method
229229
mock_wr (Mock): mocked os write method
230230
mock_op (Mock): mocked os open method
@@ -263,15 +263,15 @@ def test_jlock_acquire_invalid_pid(self, mock_open, mock_util, mock_rm, mock_wr,
263263
@mock.patch('os.open')
264264
@mock.patch('os.write')
265265
@mock.patch('os.remove')
266-
@mock.patch('pylink.jlock.psutil')
266+
@mock.patch('pylink.jlock.util')
267267
@mock.patch('pylink.jlock.open')
268268
def test_jlock_acquire_old_pid(self, mock_open, mock_util, mock_rm, mock_wr, mock_op, mock_exists, mock_close):
269269
"""Tests acquiring when the PID in the lockfile does not exist.
270270
271271
Args:
272272
self (TestJLock): the ``TestJLock`` instance
273273
mock_open (Mock): mocked built-in open method
274-
mock_util (Mock): mocked ``psutil`` module
274+
mock_util (Mock): mocked ``util`` module
275275
mock_rm (Mock): mocked os remove method
276276
mock_wr (Mock): mocked os write method
277277
mock_op (Mock): mocked os open method

0 commit comments

Comments
 (0)