/
helpers.py
131 lines (97 loc) · 3.69 KB
/
helpers.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
"""
fencepy.helpers
Shared/generic functions
"""
import os
import fnmatch
import platform
import psutil
import subprocess
import sys
from contextlib import contextmanager
def pseudo_merge_dict(dto, dfrom):
"""Recursively merge dict objects, overwriting any non-dict values"""
# a quick type check
if not (type(dto) == dict and type(dfrom) == dict):
raise ValueError('non-dict passed into _psuedo_merge_dict')
# do the work
for k, v in dfrom.items():
if k not in dto.keys():
dto[k] = v
# recurse on further dicts
elif type(dfrom[k]) == dict:
pseudo_merge_dict(dto[k], dfrom[k])
# everything else can just be overwritten
else:
dto[k] = dfrom[k]
def locate_subdirs(pattern, root):
"""Get a list of all subdirectories contained underneath a root"""
ret = []
for path, dirs, files in os.walk(os.path.abspath(root)):
for subdir in fnmatch.filter(dirs, pattern):
ret.append(os.path.join(path, subdir))
return ret
def getoutputoserror(cmd):
"""Similar behavior to commands.getstatusoutput for python 3 and windows support"""
p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
p.wait()
output = p.communicate()[0].decode()
if p.returncode:
raise OSError(p.returncode, '{0}: {1}'.format(cmd, output))
return output
def getpybindir():
"""Get the appropriate subdirectory for binaries depending on system"""
if platform.system() == 'Windows':
return 'Scripts'
return 'bin'
def findpybin(name, start):
"""For windows compatibility"""
# normalize to the root of the environment
rootpath = os.path.dirname(start) if os.path.isfile(start) else start
if os.path.basename(rootpath) in ('bin', 'Scripts'):
rootpath = os.path.dirname(rootpath)
# special case for Ubuntu (and other?) packaged python instances
if rootpath == '/usr':
binpath = os.path.join('/usr/local/bin', name)
if os.path.exists(binpath):
return binpath
# we're in a linux-based virtual environment
if 'bin' in os.listdir(rootpath):
binpath = os.path.join(rootpath, 'bin', name)
if os.path.exists(binpath):
return binpath
# we're in a windows virtual environment
elif 'Scripts' in os.listdir(rootpath):
binpath = os.path.join(rootpath, 'Scripts', '{0}.exe'.format(name))
if os.path.exists(binpath):
return binpath
raise IOError('could not find {0} relative to {1}'.format(name, start))
@contextmanager
def redirected(out=sys.stdout, err=sys.stderr):
"""Temporarily redirect stdout and/or stderr"""
saved = sys.stdout, sys.stderr
sys.stdout, sys.stderr = out, err
try:
yield
finally:
sys.stdout, sys.stderr = saved
def py2():
"""Check that we are running python 2.x"""
return sys.version.startswith('2')
def py3():
"""Check that we are running python 3.x"""
return sys.version.startswith('3')
def pyversionstr():
"""Return a x.y version string for the python version"""
return '.'.join([str(x) for x in sys.version_info[:2]])
def str2bool(value):
"""Convert various acceptable string values into a bool"""
if type(value) == str or (py2() and type(value) == unicode):
if value.lower() in ('true', 't', 'yes', 'y', '1'):
return True
elif value.lower() in ('false', 'f', 'no', 'n', '0'):
return False
raise ValueError('{0} is not an acceptable boolean value'.format(value))
def get_shell():
"""Get the name of the running shell according to psutil"""
return psutil.Process(psutil.Process(os.getpid()).ppid()).name()