Skip to content

Commit 9ad9290

Browse files
committed
Merge branch 'logger'
2 parents 3837991 + 5b18120 commit 9ad9290

File tree

5 files changed

+158
-24
lines changed

5 files changed

+158
-24
lines changed

setup.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def platform_detection(install_binaries=True):
5555

5656
# Set some variables (PKGBUILD inspired)
5757
DATA_FILES = platform_detection()
58-
VERSION = "0.3.2"
58+
VERSION = "0.4.0"
5959
URL = "https://github.com/StuntsPT/Structure_threader"
6060

6161

@@ -65,7 +65,8 @@ def platform_detection(install_binaries=True):
6565
packages=["structure_threader",
6666
"structure_threader.evanno",
6767
"structure_threader.plotter",
68-
"structure_threader.sanity_checks"],
68+
"structure_threader.sanity_checks",
69+
"structure_threader.colorer"],
6970
install_requires=["plotly",
7071
"colorlover",
7172
"numpy",

structure_threader/colorer/__init__.py

Whitespace-only changes.
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#!/usr/bin/env python
2+
# encoding: utf-8
3+
4+
# Code taken from http://stackoverflow.com/a/1336640/3091595.
5+
# Thanks to @sorin for providing this coloring method!
6+
7+
import logging
8+
# now we patch Python code to add color support to logging.StreamHandler
9+
def add_coloring_to_emit_windows(fn):
10+
# add methods we need to the class
11+
def _out_handle(self):
12+
import ctypes
13+
return ctypes.windll.kernel32.GetStdHandle(self.STD_OUTPUT_HANDLE)
14+
out_handle = property(_out_handle)
15+
16+
def _set_color(self, code):
17+
import ctypes
18+
# Constants from the Windows API
19+
self.STD_OUTPUT_HANDLE = -11
20+
hdl = ctypes.windll.kernel32.GetStdHandle(self.STD_OUTPUT_HANDLE)
21+
ctypes.windll.kernel32.SetConsoleTextAttribute(hdl, code)
22+
23+
setattr(logging.StreamHandler, '_set_color', _set_color)
24+
25+
def new(*args):
26+
FOREGROUND_BLUE = 0x0001 # text color contains blue.
27+
FOREGROUND_GREEN = 0x0002 # text color contains green.
28+
FOREGROUND_RED = 0x0004 # text color contains red.
29+
FOREGROUND_INTENSITY = 0x0008 # text color is intensified.
30+
FOREGROUND_WHITE = FOREGROUND_BLUE|FOREGROUND_GREEN |FOREGROUND_RED
31+
# winbase.h
32+
STD_INPUT_HANDLE = -10
33+
STD_OUTPUT_HANDLE = -11
34+
STD_ERROR_HANDLE = -12
35+
36+
# wincon.h
37+
FOREGROUND_BLACK = 0x0000
38+
FOREGROUND_BLUE = 0x0001
39+
FOREGROUND_GREEN = 0x0002
40+
FOREGROUND_CYAN = 0x0003
41+
FOREGROUND_RED = 0x0004
42+
FOREGROUND_MAGENTA = 0x0005
43+
FOREGROUND_YELLOW = 0x0006
44+
FOREGROUND_GREY = 0x0007
45+
FOREGROUND_INTENSITY = 0x0008 # foreground color is intensified.
46+
47+
BACKGROUND_BLACK = 0x0000
48+
BACKGROUND_BLUE = 0x0010
49+
BACKGROUND_GREEN = 0x0020
50+
BACKGROUND_CYAN = 0x0030
51+
BACKGROUND_RED = 0x0040
52+
BACKGROUND_MAGENTA = 0x0050
53+
BACKGROUND_YELLOW = 0x0060
54+
BACKGROUND_GREY = 0x0070
55+
BACKGROUND_INTENSITY = 0x0080 # background color is intensified.
56+
57+
levelno = args[1].levelno
58+
if(levelno>=50):
59+
color = BACKGROUND_YELLOW | FOREGROUND_RED | FOREGROUND_INTENSITY | BACKGROUND_INTENSITY
60+
elif(levelno>=40):
61+
color = FOREGROUND_RED | FOREGROUND_INTENSITY
62+
elif(levelno>=30):
63+
color = FOREGROUND_YELLOW | FOREGROUND_INTENSITY
64+
elif(levelno>=20):
65+
color = FOREGROUND_GREEN
66+
elif(levelno>=10):
67+
color = FOREGROUND_MAGENTA
68+
else:
69+
color = FOREGROUND_WHITE
70+
args[0]._set_color(color)
71+
72+
ret = fn(*args)
73+
args[0]._set_color( FOREGROUND_WHITE )
74+
#print "after"
75+
return ret
76+
return new
77+
78+
def add_coloring_to_emit_ansi(fn):
79+
# add methods we need to the class
80+
def new(*args):
81+
levelno = args[1].levelno
82+
if(levelno>=50):
83+
color = '\x1b[31m' # red
84+
elif(levelno>=40):
85+
color = '\x1b[31m' # red
86+
elif(levelno>=30):
87+
color = '\x1b[33m' # yellow
88+
elif(levelno>=20):
89+
color = '\x1b[32m' # green
90+
elif(levelno>=10):
91+
color = '\x1b[35m' # pink
92+
else:
93+
color = '\x1b[0m' # normal
94+
args[1].msg = color + args[1].msg + '\x1b[0m' # normal
95+
#print "after"
96+
return fn(*args)
97+
return new
98+
99+
import platform
100+
if platform.system()=='Windows':
101+
# Windows does not support ANSI escapes and we are using API calls to set the console color
102+
logging.StreamHandler.emit = add_coloring_to_emit_windows(logging.StreamHandler.emit)
103+
else:
104+
# all non-Windows platforms are supporting ANSI escapes so we use them
105+
logging.StreamHandler.emit = add_coloring_to_emit_ansi(logging.StreamHandler.emit)
106+
#log = logging.getLogger()
107+
#log.addFilter(log_filter())
108+
#//hdlr = logging.StreamHandler()
109+
#//hdlr.setFormatter(formatter())

structure_threader/sanity_checks/sanity.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,15 @@
1616
# along with structure_threader. If not, see <http://www.gnu.org/licenses/>.
1717

1818
import os
19-
import numpy as np
2019
import logging
2120

2221
from collections import Counter
2322

23+
import numpy as np
24+
25+
# Set default log level and format
26+
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
27+
2428

2529
class AuxSanity(object):
2630

@@ -43,8 +47,8 @@ def ind_mismatch(self, exp_array, kvals):
4347
if exp_array.shape[0] != kobj.qvals.shape[0]:
4448
mismatch.append("{}: {} individuas (expected from "
4549
"popfile: {})".format(kobj.file_path,
46-
kobj.qvals.shape[0],
47-
exp_array.shape[0]))
50+
kobj.qvals.shape[0],
51+
exp_array.shape[0]))
4852

4953
return mismatch
5054

structure_threader/structure_threader.py

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import subprocess
2323
import itertools
2424
import argparse
25+
import logging
2526

2627
from multiprocessing import Pool
2728
from random import randrange
@@ -30,24 +31,32 @@
3031
try:
3132
import plotter.structplot as sp
3233
import sanity_checks.sanity as sanity
34+
import colorer.colorer as colorer
3335
except ImportError:
3436
import structure_threader.plotter.structplot as sp
3537
import structure_threader.sanity_checks.sanity as sanity
38+
import structure_threader.colorer.colorer as colorer
3639

3740
# Where are we?
3841
CWD = os.getcwd()
3942

43+
# Set default log level and format
44+
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
45+
4046

4147
def gracious_exit(*args):
42-
"""Graciously exit the program."""
43-
print("\rExiting graciously, murdering child processes and cleaning output"
44-
" directory.", end="")
48+
"""
49+
Graciously exit the program.
50+
"""
51+
logging.critical("\rExiting graciously, murdering child processes and "
52+
"cleaning output directory.")
4553
os.chdir(CWD)
4654
sys.exit(0)
4755

4856

4957
def runprogram(wrapped_prog, iterations, arg):
50-
"""Run each wrapped program job. Return the worker status.
58+
"""
59+
Run each wrapped program job. Return the worker status.
5160
This attribute will be populated with the worker exit code and output file
5261
and returned. The first element is the exit code itself (0 if normal exit
5362
and -1 in case of errors). The second element contains the output file
@@ -108,7 +117,7 @@ def runprogram(wrapped_prog, iterations, arg):
108117
if arg.external_prog.endswith(".py") is False:
109118
cli = cli[1:]
110119

111-
print("Running: " + " ".join(cli))
120+
logging.info("Running: " + " ".join(cli))
112121
program = subprocess.Popen(cli,
113122
stdout=subprocess.PIPE,
114123
stderr=subprocess.PIPE)
@@ -130,8 +139,8 @@ def runprogram(wrapped_prog, iterations, arg):
130139

131140
logfile = open(os.path.join(arg.outpath, "K" + str(K) + "_rep" +
132141
str(rep_num) + ".stlog"), "w")
133-
print("Writing logfile for K" + str(K) + ", replicate " +
134-
str(rep_num) + ". Please wait...")
142+
logging.info("Writing logfile for K" + str(K) + ", replicate " +
143+
str(rep_num) + ". Please wait...")
135144
logfile.write(out)
136145
logfile.write(err)
137146
logfile.close()
@@ -140,7 +149,9 @@ def runprogram(wrapped_prog, iterations, arg):
140149

141150

142151
def structure_threader(Ks, replicates, threads, wrapped_prog, arg):
143-
"""Do the threading book-keeping to spawn jobs at the asked rate."""
152+
"""
153+
Do the threading book-keeping to spawn jobs at the asked rate.
154+
"""
144155

145156
if wrapped_prog != "structure":
146157
replicates = [1]
@@ -164,21 +175,24 @@ def structure_threader(Ks, replicates, threads, wrapped_prog, arg):
164175
# populated with the cli commands that generated the errors
165176
error_list = [x[1] for x in pool if x[0] == -1]
166177

167-
print("\n==============================\n")
178+
logging.info("\n==============================\n")
168179
if error_list:
169-
print("%s %s runs exited with errors. Check the log files of "
170-
"the following output files:" % (len(error_list), wrapped_prog))
180+
logging.critical("%s %s runs exited with errors. Check the log files of"
181+
" the following output files:",
182+
len(error_list), wrapped_prog)
171183
for out in error_list:
172-
print(out)
184+
logging.error(out)
173185
else:
174-
print("All %s jobs finished successfully." % len(pool))
186+
logging.info("All %s jobs finished successfully.", len(pool))
175187

176188
os.chdir(CWD)
177189

178190

179191
def structure_harvester(resultsdir, wrapped_prog):
180-
"""Run structureHarvester or fastChooseK to perform the Evanno test or the
181-
likelihood testing on the results."""
192+
"""
193+
Run structureHarvester or fastChooseK to perform the Evanno test or the
194+
likelihood testing on the results.
195+
"""
182196
outdir = os.path.join(resultsdir, "bestK")
183197
if not os.path.exists(outdir):
184198
os.mkdir(outdir)
@@ -201,8 +215,10 @@ def structure_harvester(resultsdir, wrapped_prog):
201215

202216

203217
def create_plts(resultsdir, wrapped_prog, Ks, bestk, arg):
204-
"""Create plots from result dir.
205-
:param resultsdir: path to results directory"""
218+
"""
219+
Create plots from result dir.
220+
:param resultsdir: path to results directory
221+
"""
206222

207223
plt_list = [x for x in Ks if x != 1] # Don't plot K=1
208224

@@ -468,9 +484,12 @@ def argument_parser(args):
468484

469485
return arguments
470486

487+
471488
def main():
472-
"""Main function, where variables are set and other functions get called
473-
from."""
489+
"""
490+
Main function, where variables are set and other functions get called
491+
from.
492+
"""
474493

475494
arg = argument_parser(sys.argv[1:])
476495

@@ -567,5 +586,6 @@ def main():
567586
sp.main(infiles, arg.format, arg.outpath, bestk, popfile=arg.popfile,
568587
indfile=arg.indfile, filter_k=bestk)
569588

589+
570590
if __name__ == "__main__":
571591
main()

0 commit comments

Comments
 (0)