11from __future__ import print_function
2+
23import inspect
34import re
45import sys
56
7+ from distutils .sysconfig import get_python_lib
8+ from os .path import abspath , join
9+ from termcolor import colored
10+ from traceback import extract_tb , format_list , format_exception_only , format_exception
11+
12+
613class flushfile ():
714 """
815 Disable buffering for standard output and standard error.
916
1017 http://stackoverflow.com/a/231216
1118 """
19+
1220 def __init__ (self , f ):
1321 self .f = f
1422
@@ -18,9 +26,12 @@ def __getattr__(self, name):
1826 def write (self , x ):
1927 self .f .write (x )
2028 self .f .flush ()
29+
30+
2131sys .stderr = flushfile (sys .stderr )
2232sys .stdout = flushfile (sys .stdout )
2333
34+
2435def eprint (* args , ** kwargs ):
2536 """
2637 Print an error message to standard error, prefixing it with
@@ -32,6 +43,32 @@ def eprint(*args, **kwargs):
3243 print ("{}:{}: " .format (filename , lineno ), end = "" )
3344 print (* args , end = end , file = sys .stderr , sep = sep )
3445
46+
47+ def formatException (type , value , tb ):
48+ """
49+ Format traceback, darkening entries from global site-packages directories
50+ and user-specific site-packages directory.
51+
52+ https://stackoverflow.com/a/46071447/5156190
53+ """
54+
55+ # Absolute paths to site-packages
56+ packages = tuple (join (abspath (p ), "" ) for p in sys .path [1 :])
57+
58+ # Darken lines referring to files in site-packages
59+ lines = []
60+ for line in format_exception (type , value , tb ):
61+ matches = re .search (r"^ File \"([^\"]+)\", line \d+, in .+" , line )
62+ if matches and matches .group (1 ).startswith (packages ):
63+ lines += colored (line , attrs = ["dark" ])
64+ else :
65+ lines += line
66+ return "" .join (lines ).rstrip ()
67+
68+
69+ sys .excepthook = lambda type , value , tb : print (formatException (type , value , tb ), file = sys .stderr )
70+
71+
3572def get_char (prompt = None ):
3673 """
3774 Read a line of text from standard input and return the equivalent char;
@@ -49,6 +86,7 @@ def get_char(prompt=None):
4986 if prompt is None :
5087 print ("Retry: " , end = "" )
5188
89+
5290def get_float (prompt = None ):
5391 """
5492 Read a line of text from standard input and return the equivalent float
@@ -69,20 +107,21 @@ def get_float(prompt=None):
69107 if prompt is None :
70108 print ("Retry: " , end = "" )
71109
110+
72111def get_int (prompt = None ):
73112 """
74113 Read a line of text from standard input and return the equivalent int;
75114 if text does not represent an int, user is prompted to retry. If line
76115 can't be read, return None.
77116 """
78117 while True :
79- s = get_string (prompt );
118+ s = get_string (prompt )
80119 if s is None :
81120 return None
82121 if re .search (r"^[+-]?\d+$" , s ):
83122 try :
84123 i = int (s , 10 )
85- if type (i ) is int : # could become long in Python 2
124+ if type (i ) is int : # could become long in Python 2
86125 return i
87126 except ValueError :
88127 pass
@@ -91,6 +130,7 @@ def get_int(prompt=None):
91130 if prompt is None :
92131 print ("Retry: " , end = "" )
93132
133+
94134if sys .version_info .major != 3 :
95135 def get_long (prompt = None ):
96136 """
@@ -112,6 +152,7 @@ def get_long(prompt=None):
112152 if prompt is None :
113153 print ("Retry: " , end = "" )
114154
155+
115156def get_string (prompt = None ):
116157 """
117158 Read a line of text from standard input and return it as a string,
0 commit comments