adjusting indents

should be always 4 spaces
This commit is contained in:
Martin Diehl 2020-02-21 23:25:22 +01:00
parent c2ae657f5b
commit 1dddfa040e
2 changed files with 434 additions and 437 deletions

View File

@ -1,359 +1,355 @@
import numpy as np import numpy as np
class Color(): class Color():
"""Color representation in and conversion between different color-spaces.""" """Color representation in and conversion between different color-spaces."""
__slots__ = [ __slots__ = [
'model', 'model',
'color', 'color',
'__dict__', '__dict__',
] ]
# ------------------------------------------------------------------ def __init__(self,
def __init__(self, model = 'RGB',
model = 'RGB', color = np.zeros(3,'d')):
color = np.zeros(3,'d')): """
""" Create a Color object.
Create a Color object.
Parameters Parameters
---------- ----------
model : string model : string
color model color model
color : numpy.ndarray color : numpy.ndarray
vector representing the color according to the selected model vector representing the color according to the selected model
""" """
self.__transforms__ = \ self.__transforms__ = \
{'HSV': {'index': 0, 'next': self._HSV2HSL}, {'HSV': {'index': 0, 'next': self._HSV2HSL},
'HSL': {'index': 1, 'next': self._HSL2RGB, 'prev': self._HSL2HSV}, 'HSL': {'index': 1, 'next': self._HSL2RGB, 'prev': self._HSL2HSV},
'RGB': {'index': 2, 'next': self._RGB2XYZ, 'prev': self._RGB2HSL}, 'RGB': {'index': 2, 'next': self._RGB2XYZ, 'prev': self._RGB2HSL},
'XYZ': {'index': 3, 'next': self._XYZ2CIELAB, 'prev': self._XYZ2RGB}, 'XYZ': {'index': 3, 'next': self._XYZ2CIELAB, 'prev': self._XYZ2RGB},
'CIELAB': {'index': 4, 'next': self._CIELAB2MSH, 'prev': self._CIELAB2XYZ}, 'CIELAB': {'index': 4, 'next': self._CIELAB2MSH, 'prev': self._CIELAB2XYZ},
'MSH': {'index': 5, 'prev': self._MSH2CIELAB}, 'MSH': {'index': 5, 'prev': self._MSH2CIELAB},
} }
model = model.upper() model = model.upper()
if model not in list(self.__transforms__.keys()): model = 'RGB' if model not in list(self.__transforms__.keys()): model = 'RGB'
if model == 'RGB' and max(color) > 1.0: # are we RGB255 ? if model == 'RGB' and max(color) > 1.0: # are we RGB255 ?
for i in range(3): for i in range(3):
color[i] /= 255.0 # rescale to RGB color[i] /= 255.0 # rescale to RGB
if model == 'HSL': # are we HSL ? if model == 'HSL': # are we HSL ?
if abs(color[0]) > 1.0: color[0] /= 360.0 # with angular hue? if abs(color[0]) > 1.0: color[0] /= 360.0 # with angular hue?
while color[0] >= 1.0: color[0] -= 1.0 # rewind to proper range while color[0] >= 1.0: color[0] -= 1.0 # rewind to proper range
while color[0] < 0.0: color[0] += 1.0 # rewind to proper range while color[0] < 0.0: color[0] += 1.0 # rewind to proper range
self.model = model self.model = model
self.color = np.array(color,'d') self.color = np.array(color,'d')
# ------------------------------------------------------------------ def __repr__(self):
def __repr__(self): """Color model and values."""
"""Color model and values.""" return 'Model: %s Color: %s'%(self.model,str(self.color))
return 'Model: %s Color: %s'%(self.model,str(self.color))
# ------------------------------------------------------------------ def __str__(self):
def __str__(self): """Color model and values."""
"""Color model and values.""" return self.__repr__()
return self.__repr__()
# ------------------------------------------------------------------ def convert_to(self,toModel = 'RGB'):
def convertTo(self,toModel = 'RGB'): """
""" Change the color model permanently.
Change the color model permanently.
Parameters Parameters
---------- ----------
toModel : string toModel : string
color model color model
""" """
toModel = toModel.upper() toModel = toModel.upper()
if toModel not in list(self.__transforms__.keys()): return if toModel not in list(self.__transforms__.keys()): return
sourcePos = self.__transforms__[self.model]['index'] sourcePos = self.__transforms__[self.model]['index']
targetPos = self.__transforms__[toModel]['index'] targetPos = self.__transforms__[toModel]['index']
while sourcePos < targetPos: while sourcePos < targetPos:
self.__transforms__[self.model]['next']() self.__transforms__[self.model]['next']()
sourcePos += 1 sourcePos += 1
while sourcePos > targetPos: while sourcePos > targetPos:
self.__transforms__[self.model]['prev']() self.__transforms__[self.model]['prev']()
sourcePos -= 1 sourcePos -= 1
return self return self
# ------------------------------------------------------------------ def express_as(self,asModel = 'RGB'):
def expressAs(self,asModel = 'RGB'): """
""" Return the color in a different model.
Return the color in a different model.
Parameters Parameters
---------- ----------
asModel : string asModel : string
color model color model
""" """
return self.__class__(self.model,self.color).convertTo(asModel) return self.__class__(self.model,self.color).convert_to(asModel)
def _HSV2HSL(self): def _HSV2HSL(self):
""" """
Convert H(ue) S(aturation) V(alue or brightness) to H(ue) S(aturation) L(uminance). Convert H(ue) S(aturation) V(alue or brightness) to H(ue) S(aturation) L(uminance).
All values are in the range [0,1] All values are in the range [0,1]
http://codeitdown.com/hsl-hsb-hsv-color http://codeitdown.com/hsl-hsb-hsv-color
""" """
if self.model != 'HSV': return if self.model != 'HSV': return
converted = Color('HSL',np.array([ converted = Color('HSL',np.array([
self.color[0], self.color[0],
1. if self.color[2] == 0.0 or (self.color[1] == 0.0 and self.color[2] == 1.0) \ 1. if self.color[2] == 0.0 or (self.color[1] == 0.0 and self.color[2] == 1.0) \
else self.color[1]*self.color[2]/(1.-abs(self.color[2]*(2.-self.color[1])-1.)), else self.color[1]*self.color[2]/(1.-abs(self.color[2]*(2.-self.color[1])-1.)),
0.5*self.color[2]*(2.-self.color[1]), 0.5*self.color[2]*(2.-self.color[1]),
])) ]))
self.model = converted.model self.model = converted.model
self.color = converted.color self.color = converted.color
def _HSL2HSV(self): def _HSL2HSV(self):
""" """
Convert H(ue) S(aturation) L(uminance) to H(ue) S(aturation) V(alue or brightness). Convert H(ue) S(aturation) L(uminance) to H(ue) S(aturation) V(alue or brightness).
All values are in the range [0,1] All values are in the range [0,1]
http://codeitdown.com/hsl-hsb-hsv-color http://codeitdown.com/hsl-hsb-hsv-color
""" """
if self.model != 'HSL': return if self.model != 'HSL': return
h = self.color[0] h = self.color[0]
b = self.color[2]+0.5*(self.color[1]*(1.-abs(2*self.color[2]-1))) b = self.color[2]+0.5*(self.color[1]*(1.-abs(2*self.color[2]-1)))
s = 1.0 if b == 0.0 else 2.*(b-self.color[2])/b s = 1.0 if b == 0.0 else 2.*(b-self.color[2])/b
converted = Color('HSV',np.array([h,s,b])) converted = Color('HSV',np.array([h,s,b]))
self.model = converted.model self.model = converted.model
self.color = converted.color self.color = converted.color
def _HSL2RGB(self): def _HSL2RGB(self):
""" """
Convert H(ue) S(aturation) L(uminance) to R(red) G(reen) B(lue). Convert H(ue) S(aturation) L(uminance) to R(red) G(reen) B(lue).
All values are in the range [0,1] All values are in the range [0,1]
from http://en.wikipedia.org/wiki/HSL_and_HSV from http://en.wikipedia.org/wiki/HSL_and_HSV
""" """
if self.model != 'HSL': return if self.model != 'HSL': return
sextant = self.color[0]*6.0 sextant = self.color[0]*6.0
c = (1.0 - abs(2.0 * self.color[2] - 1.0))*self.color[1] c = (1.0 - abs(2.0 * self.color[2] - 1.0))*self.color[1]
x = c*(1.0 - abs(sextant%2 - 1.0)) x = c*(1.0 - abs(sextant%2 - 1.0))
m = self.color[2] - 0.5*c m = self.color[2] - 0.5*c
converted = Color('RGB',np.array([ converted = Color('RGB',np.array([
[c+m, x+m, m], [c+m, x+m, m],
[x+m, c+m, m], [x+m, c+m, m],
[m, c+m, x+m], [m, c+m, x+m],
[m, x+m, c+m], [m, x+m, c+m],
[x+m, m, c+m], [x+m, m, c+m],
[c+m, m, x+m], [c+m, m, x+m],
][int(sextant)],'d')) ][int(sextant)],'d'))
self.model = converted.model self.model = converted.model
self.color = converted.color self.color = converted.color
def _RGB2HSL(self): def _RGB2HSL(self):
""" """
Convert R(ed) G(reen) B(lue) to H(ue) S(aturation) L(uminance). Convert R(ed) G(reen) B(lue) to H(ue) S(aturation) L(uminance).
All values are in the range [0,1] All values are in the range [0,1]
from http://130.113.54.154/~monger/hsl-rgb.html from http://130.113.54.154/~monger/hsl-rgb.html
""" """
if self.model != 'RGB': return if self.model != 'RGB': return
HSL = np.zeros(3,'d') HSL = np.zeros(3,'d')
maxcolor = self.color.max() maxcolor = self.color.max()
mincolor = self.color.min() mincolor = self.color.min()
HSL[2] = (maxcolor + mincolor)/2.0 HSL[2] = (maxcolor + mincolor)/2.0
if(mincolor == maxcolor): if(mincolor == maxcolor):
HSL[0] = 0.0 HSL[0] = 0.0
HSL[1] = 0.0 HSL[1] = 0.0
else:
if (HSL[2]<0.5):
HSL[1] = (maxcolor - mincolor)/(maxcolor + mincolor)
else: else:
HSL[1] = (maxcolor - mincolor)/(2.0 - maxcolor - mincolor) if (HSL[2]<0.5):
if (maxcolor == self.color[0]): HSL[1] = (maxcolor - mincolor)/(maxcolor + mincolor)
HSL[0] = 0.0 + (self.color[1] - self.color[2])/(maxcolor - mincolor) else:
elif (maxcolor == self.color[1]): HSL[1] = (maxcolor - mincolor)/(2.0 - maxcolor - mincolor)
HSL[0] = 2.0 + (self.color[2] - self.color[0])/(maxcolor - mincolor) if (maxcolor == self.color[0]):
elif (maxcolor == self.color[2]): HSL[0] = 0.0 + (self.color[1] - self.color[2])/(maxcolor - mincolor)
HSL[0] = 4.0 + (self.color[0] - self.color[1])/(maxcolor - mincolor) elif (maxcolor == self.color[1]):
HSL[0] = HSL[0]*60.0 # scaling to 360 might be dangerous for small values HSL[0] = 2.0 + (self.color[2] - self.color[0])/(maxcolor - mincolor)
if (HSL[0] < 0.0): elif (maxcolor == self.color[2]):
HSL[0] = HSL[0] + 360.0 HSL[0] = 4.0 + (self.color[0] - self.color[1])/(maxcolor - mincolor)
for i in range(2): HSL[0] = HSL[0]*60.0 # scaling to 360 might be dangerous for small values
HSL[i+1] = min(HSL[i+1],1.0) if (HSL[0] < 0.0):
HSL[i+1] = max(HSL[i+1],0.0) HSL[0] = HSL[0] + 360.0
for i in range(2):
HSL[i+1] = min(HSL[i+1],1.0)
HSL[i+1] = max(HSL[i+1],0.0)
converted = Color('HSL', HSL) converted = Color('HSL', HSL)
self.model = converted.model self.model = converted.model
self.color = converted.color self.color = converted.color
def _RGB2XYZ(self): def _RGB2XYZ(self):
""" """
Convert R(ed) G(reen) B(lue) to CIE XYZ. Convert R(ed) G(reen) B(lue) to CIE XYZ.
All values are in the range [0,1] All values are in the range [0,1]
from http://www.cs.rit.edu/~ncs/color/t_convert.html from http://www.cs.rit.edu/~ncs/color/t_convert.html
""" """
if self.model != 'RGB': return if self.model != 'RGB': return
XYZ = np.zeros(3,'d') XYZ = np.zeros(3,'d')
RGB_lin = np.zeros(3,'d') RGB_lin = np.zeros(3,'d')
convert = np.array([[0.412453,0.357580,0.180423], convert = np.array([[0.412453,0.357580,0.180423],
[0.212671,0.715160,0.072169], [0.212671,0.715160,0.072169],
[0.019334,0.119193,0.950227]]) [0.019334,0.119193,0.950227]])
for i in range(3): for i in range(3):
if (self.color[i] > 0.04045): RGB_lin[i] = ((self.color[i]+0.0555)/1.0555)**2.4 if (self.color[i] > 0.04045): RGB_lin[i] = ((self.color[i]+0.0555)/1.0555)**2.4
else: RGB_lin[i] = self.color[i] /12.92 else: RGB_lin[i] = self.color[i] /12.92
XYZ = np.dot(convert,RGB_lin) XYZ = np.dot(convert,RGB_lin)
for i in range(3): for i in range(3):
XYZ[i] = max(XYZ[i],0.0) XYZ[i] = max(XYZ[i],0.0)
converted = Color('XYZ', XYZ) converted = Color('XYZ', XYZ)
self.model = converted.model self.model = converted.model
self.color = converted.color self.color = converted.color
def _XYZ2RGB(self): def _XYZ2RGB(self):
""" """
Convert CIE XYZ to R(ed) G(reen) B(lue). Convert CIE XYZ to R(ed) G(reen) B(lue).
All values are in the range [0,1] All values are in the range [0,1]
from http://www.cs.rit.edu/~ncs/color/t_convert.html from http://www.cs.rit.edu/~ncs/color/t_convert.html
""" """
if self.model != 'XYZ': if self.model != 'XYZ':
return return
convert = np.array([[ 3.240479,-1.537150,-0.498535], convert = np.array([[ 3.240479,-1.537150,-0.498535],
[-0.969256, 1.875992, 0.041556], [-0.969256, 1.875992, 0.041556],
[ 0.055648,-0.204043, 1.057311]]) [ 0.055648,-0.204043, 1.057311]])
RGB_lin = np.dot(convert,self.color) RGB_lin = np.dot(convert,self.color)
RGB = np.zeros(3,'d') RGB = np.zeros(3,'d')
for i in range(3): for i in range(3):
if (RGB_lin[i] > 0.0031308): RGB[i] = ((RGB_lin[i])**(1.0/2.4))*1.0555-0.0555 if (RGB_lin[i] > 0.0031308): RGB[i] = ((RGB_lin[i])**(1.0/2.4))*1.0555-0.0555
else: RGB[i] = RGB_lin[i] *12.92 else: RGB[i] = RGB_lin[i] *12.92
for i in range(3): for i in range(3):
RGB[i] = min(RGB[i],1.0) RGB[i] = min(RGB[i],1.0)
RGB[i] = max(RGB[i],0.0) RGB[i] = max(RGB[i],0.0)
maxVal = max(RGB) # clipping colors according to the display gamut maxVal = max(RGB) # clipping colors according to the display gamut
if (maxVal > 1.0): RGB /= maxVal if (maxVal > 1.0): RGB /= maxVal
converted = Color('RGB', RGB) converted = Color('RGB', RGB)
self.model = converted.model self.model = converted.model
self.color = converted.color self.color = converted.color
def _CIELAB2XYZ(self): def _CIELAB2XYZ(self):
""" """
Convert CIE Lab to CIE XYZ. Convert CIE Lab to CIE XYZ.
All values are in the range [0,1] All values are in the range [0,1]
from http://www.easyrgb.com/index.php?X=MATH&H=07#text7 from http://www.easyrgb.com/index.php?X=MATH&H=07#text7
""" """
if self.model != 'CIELAB': return if self.model != 'CIELAB': return
ref_white = np.array([.95047, 1.00000, 1.08883],'d') # Observer = 2, Illuminant = D65 ref_white = np.array([.95047, 1.00000, 1.08883],'d') # Observer = 2, Illuminant = D65
XYZ = np.zeros(3,'d') XYZ = np.zeros(3,'d')
XYZ[1] = (self.color[0] + 16.0 ) / 116.0 XYZ[1] = (self.color[0] + 16.0 ) / 116.0
XYZ[0] = XYZ[1] + self.color[1]/ 500.0 XYZ[0] = XYZ[1] + self.color[1]/ 500.0
XYZ[2] = XYZ[1] - self.color[2]/ 200.0 XYZ[2] = XYZ[1] - self.color[2]/ 200.0
for i in range(len(XYZ)): for i in range(len(XYZ)):
if (XYZ[i] > 6./29. ): XYZ[i] = XYZ[i]**3. if (XYZ[i] > 6./29. ): XYZ[i] = XYZ[i]**3.
else: XYZ[i] = 108./841. * (XYZ[i] - 4./29.) else: XYZ[i] = 108./841. * (XYZ[i] - 4./29.)
converted = Color('XYZ', XYZ*ref_white) converted = Color('XYZ', XYZ*ref_white)
self.model = converted.model self.model = converted.model
self.color = converted.color self.color = converted.color
def _XYZ2CIELAB(self):
"""
Convert CIE XYZ to CIE Lab.
All values are in the range [0,1]
from http://en.wikipedia.org/wiki/Lab_color_space,
http://www.cs.rit.edu/~ncs/color/t_convert.html
"""
if self.model != 'XYZ': return
ref_white = np.array([.95047, 1.00000, 1.08883],'d') # Observer = 2, Illuminant = D65
XYZ = self.color/ref_white
for i in range(len(XYZ)):
if (XYZ[i] > 216./24389 ): XYZ[i] = XYZ[i]**(1.0/3.0)
else: XYZ[i] = (841./108. * XYZ[i]) + 16.0/116.0
converted = Color('CIELAB', np.array([ 116.0 * XYZ[1] - 16.0,
500.0 * (XYZ[0] - XYZ[1]),
200.0 * (XYZ[1] - XYZ[2]) ]))
self.model = converted.model
self.color = converted.color
def _CIELAB2MSH(self): def _XYZ2CIELAB(self):
""" """
Convert CIE Lab to Msh colorspace. Convert CIE XYZ to CIE Lab.
from http://www.cs.unm.edu/~kmorel/documents/ColorMaps/DivergingColorMapWorkshop.xls All values are in the range [0,1]
""" from http://en.wikipedia.org/wiki/Lab_color_space,
if self.model != 'CIELAB': return http://www.cs.rit.edu/~ncs/color/t_convert.html
"""
if self.model != 'XYZ': return
Msh = np.zeros(3,'d') ref_white = np.array([.95047, 1.00000, 1.08883],'d') # Observer = 2, Illuminant = D65
Msh[0] = np.sqrt(np.dot(self.color,self.color)) XYZ = self.color/ref_white
if (Msh[0] > 0.001):
Msh[1] = np.arccos(self.color[0]/Msh[0])
if (self.color[1] != 0.0):
Msh[2] = np.arctan2(self.color[2],self.color[1])
converted = Color('MSH', Msh) for i in range(len(XYZ)):
self.model = converted.model if (XYZ[i] > 216./24389 ): XYZ[i] = XYZ[i]**(1.0/3.0)
self.color = converted.color else: XYZ[i] = (841./108. * XYZ[i]) + 16.0/116.0
converted = Color('CIELAB', np.array([ 116.0 * XYZ[1] - 16.0,
500.0 * (XYZ[0] - XYZ[1]),
200.0 * (XYZ[1] - XYZ[2]) ]))
self.model = converted.model
self.color = converted.color
def _MSH2CIELAB(self): def _CIELAB2MSH(self):
""" """
Convert Msh colorspace to CIE Lab. Convert CIE Lab to Msh colorspace.
with s,h in radians from http://www.cs.unm.edu/~kmorel/documents/ColorMaps/DivergingColorMapWorkshop.xls
from http://www.cs.unm.edu/~kmorel/documents/ColorMaps/DivergingColorMapWorkshop.xls """
""" if self.model != 'CIELAB': return
if self.model != 'MSH': return
Lab = np.zeros(3,'d') Msh = np.zeros(3,'d')
Lab[0] = self.color[0] * np.cos(self.color[1]) Msh[0] = np.sqrt(np.dot(self.color,self.color))
Lab[1] = self.color[0] * np.sin(self.color[1]) * np.cos(self.color[2]) if (Msh[0] > 0.001):
Lab[2] = self.color[0] * np.sin(self.color[1]) * np.sin(self.color[2]) Msh[1] = np.arccos(self.color[0]/Msh[0])
if (self.color[1] != 0.0):
Msh[2] = np.arctan2(self.color[2],self.color[1])
converted = Color('CIELAB', Lab) converted = Color('MSH', Msh)
self.model = converted.model self.model = converted.model
self.color = converted.color self.color = converted.color
def _MSH2CIELAB(self):
"""
Convert Msh colorspace to CIE Lab.
with s,h in radians
from http://www.cs.unm.edu/~kmorel/documents/ColorMaps/DivergingColorMapWorkshop.xls
"""
if self.model != 'MSH': return
Lab = np.zeros(3,'d')
Lab[0] = self.color[0] * np.cos(self.color[1])
Lab[1] = self.color[0] * np.sin(self.color[1]) * np.cos(self.color[2])
Lab[2] = self.color[0] * np.sin(self.color[1]) * np.sin(self.color[2])
converted = Color('CIELAB', Lab)
self.model = converted.model
self.color = converted.color
class Colormap(): class Colormap():
@ -498,13 +494,13 @@ class Colormap():
def interpolate_linear(lo, hi, frac): def interpolate_linear(lo, hi, frac):
"""Linear interpolation between lo and hi color at given fraction; output in model of lo color.""" """Linear interpolation between lo and hi color at given fraction; output in model of lo color."""
interpolation = (1.0 - frac) * np.array(lo.color[:]) \ interpolation = (1.0 - frac) * np.array(lo.color[:]) \
+ frac * np.array(hi.expressAs(lo.model).color[:]) + frac * np.array(hi.express_as(lo.model).color[:])
return Color(lo.model,interpolation) return Color(lo.model,interpolation)
if self.interpolate == 'perceptualuniform': if self.interpolate == 'perceptualuniform':
return interpolate_Msh(self.left.expressAs('MSH').color, return interpolate_Msh(self.left.express_as('MSH').color,
self.right.expressAs('MSH').color,fraction) self.right.express_as('MSH').color,fraction)
elif self.interpolate == 'linear': elif self.interpolate == 'linear':
return interpolate_linear(self.left, return interpolate_linear(self.left,
self.right,fraction) self.right,fraction)
@ -528,7 +524,7 @@ class Colormap():
""" """
format = format.lower() # consistent comparison basis format = format.lower() # consistent comparison basis
frac = 0.5*(np.array(crop) + 1.0) # rescale crop range to fractions frac = 0.5*(np.array(crop) + 1.0) # rescale crop range to fractions
colors = [self.color(float(i)/(steps-1)*(frac[1]-frac[0])+frac[0]).expressAs(model).color for i in range(steps)] colors = [self.color(float(i)/(steps-1)*(frac[1]-frac[0])+frac[0]).express_as(model).color for i in range(steps)]
if format == 'paraview': if format == 'paraview':
colormap = ['[\n {{\n "ColorSpace": "RGB", "Name": "{}", "DefaultMap": true,\n "RGBPoints" : ['.format(name)] \ colormap = ['[\n {{\n "ColorSpace": "RGB", "Name": "{}", "DefaultMap": true,\n "RGBPoints" : ['.format(name)] \
+ [' {:4d},{:8.6f},{:8.6f},{:8.6f},'.format(i,color[0],color[1],color[2],) \ + [' {:4d},{:8.6f},{:8.6f},{:8.6f},'.format(i,color[0],color[1],color[2],) \

View File

@ -38,192 +38,193 @@ class bcolors:
self.CROSSOUT = '' self.CROSSOUT = ''
# -----------------------------
def srepr(arg,glue = '\n'): def srepr(arg,glue = '\n'):
""" """
Join arguments as individual lines. Join arguments as individual lines.
Parameters Parameters
---------- ----------
arg : iterable arg : iterable
Items to join. Items to join.
glue : str, optional glue : str, optional
Defaults to \n. Defaults to \n.
"""
if (not hasattr(arg, "strip") and
(hasattr(arg, "__getitem__") or
hasattr(arg, "__iter__"))):
return glue.join(str(x) for x in arg)
return arg if isinstance(arg,str) else repr(arg)
"""
if (not hasattr(arg, "strip") and
(hasattr(arg, "__getitem__") or
hasattr(arg, "__iter__"))):
return glue.join(str(x) for x in arg)
return arg if isinstance(arg,str) else repr(arg)
# -----------------------------
def croak(what, newline = True): def croak(what, newline = True):
""" """
Write formated to stderr. Write formated to stderr.
Parameters Parameters
---------- ----------
what : str or iterable what : str or iterable
Content to be displayed Content to be displayed
newline : bool, optional newline : bool, optional
Separate items of what by newline. Defaults to True. Separate items of what by newline. Defaults to True.
"""
if not what:
sys.stderr.write(srepr(what,glue = '\n') + ('\n' if newline else ''))
sys.stderr.flush()
"""
if what is not None:
sys.stderr.write(srepr(what,glue = '\n') + ('\n' if newline else ''))
sys.stderr.flush()
# -----------------------------
def report(who = None, def report(who = None,
what = None): what = None):
""" """
Reports script and file name. Reports script and file name.
DEPRECATED DEPRECATED
""" """
croak( (emph(who)+': ' if who is not None else '') + (what if what is not None else '') + '\n' ) croak( (emph(who)+': ' if who is not None else '') + (what if what is not None else '') + '\n' )
# -----------------------------
def emph(what): def emph(what):
"""Formats string with emphasis.""" """Formats string with emphasis."""
return bcolors.BOLD+srepr(what)+bcolors.ENDC return bcolors.BOLD+srepr(what)+bcolors.ENDC
# -----------------------------
def deemph(what): def deemph(what):
"""Formats string with deemphasis.""" """Formats string with deemphasis."""
return bcolors.DIM+srepr(what)+bcolors.ENDC return bcolors.DIM+srepr(what)+bcolors.ENDC
# -----------------------------
def delete(what): def delete(what):
"""Formats string as deleted.""" """Formats string as deleted."""
return bcolors.DIM+srepr(what)+bcolors.ENDC return bcolors.DIM+srepr(what)+bcolors.ENDC
# -----------------------------
def strikeout(what): def strikeout(what):
"""Formats string as strikeout.""" """Formats string as strikeout."""
return bcolors.CROSSOUT+srepr(what)+bcolors.ENDC return bcolors.CROSSOUT+srepr(what)+bcolors.ENDC
# -----------------------------
def execute(cmd, def execute(cmd,
streamIn = None, streamIn = None,
wd = './', wd = './',
env = None): env = None):
"""
Execute command.
Parameters
----------
cmd : str
Command to be executed.
streanIn :, optional
Input (via pipe) for executed process.
wd : str, optional
Working directory of process. Defaults to ./ .
env :
Environment
"""
initialPath = os.getcwd()
os.chdir(wd)
myEnv = os.environ if env is None else env
process = subprocess.Popen(shlex.split(cmd),
stdout = subprocess.PIPE,
stderr = subprocess.PIPE,
stdin = subprocess.PIPE,
env = myEnv)
out,error = [i for i in (process.communicate() if streamIn is None
else process.communicate(streamIn.read().encode('utf-8')))]
out = out.decode('utf-8').replace('\x08','')
error = error.decode('utf-8').replace('\x08','')
os.chdir(initialPath)
if process.returncode != 0: raise RuntimeError('{} failed with returncode {}'.format(cmd,process.returncode))
return out,error
# -----------------------------
class extendableOption(Option):
"""
Used for definition of new option parser action 'extend', which enables to take multiple option arguments.
Adopted from online tutorial http://docs.python.org/library/optparse.html
DEPRECATED
"""
ACTIONS = Option.ACTIONS + ("extend",)
STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)
ALWAYS_TYPED_ACTIONS = Option.ALWAYS_TYPED_ACTIONS + ("extend",)
def take_action(self, action, dest, opt, value, values, parser):
if action == "extend":
lvalue = value.split(",")
values.ensure_value(dest, []).extend(lvalue)
else:
Option.take_action(self, action, dest, opt, value, values, parser)
# from https://gist.github.com/aubricus/f91fb55dc6ba5557fbab06119420dd6a
def progressBar(iteration, total, prefix='', bar_length=50):
"""
Call in a loop to create terminal progress bar.
Parameters
----------
iteration : int
Current iteration.
total : int
Total iterations.
prefix : str, optional
Prefix string.
bar_length : int, optional
Character length of bar. Defaults to 50.
"""
fraction = iteration / float(total)
if not hasattr(progressBar, "last_fraction"): # first call to function
progressBar.start_time = time.time()
progressBar.last_fraction = -1.0
remaining_time = ' n/a'
else:
if fraction <= progressBar.last_fraction or iteration == 0: # reset: called within a new loop
progressBar.start_time = time.time()
progressBar.last_fraction = -1.0
remaining_time = ' n/a'
else:
progressBar.last_fraction = fraction
remainder = (total - iteration) * (time.time()-progressBar.start_time)/iteration
remaining_time = '{: 3d}:'.format(int( remainder//3600)) + \
'{:02d}:'.format(int((remainder//60)%60)) + \
'{:02d}' .format(int( remainder %60))
filled_length = int(round(bar_length * fraction))
bar = '' * filled_length + '' * (bar_length - filled_length)
sys.stderr.write('\r{} {} {}'.format(prefix, bar, remaining_time)),
if iteration == total: sys.stderr.write('\n')
sys.stderr.flush()
class return_message():
"""Object with formatted return message."""
def __init__(self,message):
""" """
Sets return message. Execute command.
Parameters Parameters
---------- ----------
message : str or list of str cmd : str
message for output to screen Command to be executed.
streanIn :, optional
Input (via pipe) for executed process.
wd : str, optional
Working directory of process. Defaults to ./ .
env :
Environment
""" """
self.message = message initialPath = os.getcwd()
os.chdir(wd)
myEnv = os.environ if env is None else env
process = subprocess.Popen(shlex.split(cmd),
stdout = subprocess.PIPE,
stderr = subprocess.PIPE,
stdin = subprocess.PIPE,
env = myEnv)
out,error = [i for i in (process.communicate() if streamIn is None
else process.communicate(streamIn.read().encode('utf-8')))]
out = out.decode('utf-8').replace('\x08','')
error = error.decode('utf-8').replace('\x08','')
os.chdir(initialPath)
if process.returncode != 0:
raise RuntimeError('{} failed with returncode {}'.format(cmd,process.returncode))
return out,error
def __repr__(self):
"""Return message suitable for interactive shells.""" class extendableOption(Option):
return srepr(self.message) """
Used for definition of new option parser action 'extend', which enables to take multiple option arguments.
Adopted from online tutorial http://docs.python.org/library/optparse.html
DEPRECATED
"""
ACTIONS = Option.ACTIONS + ("extend",)
STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)
ALWAYS_TYPED_ACTIONS = Option.ALWAYS_TYPED_ACTIONS + ("extend",)
def take_action(self, action, dest, opt, value, values, parser):
if action == "extend":
lvalue = value.split(",")
values.ensure_value(dest, []).extend(lvalue)
else:
Option.take_action(self, action, dest, opt, value, values, parser)
def progressBar(iteration, total, prefix='', bar_length=50):
"""
Call in a loop to create terminal progress bar.
From https://gist.github.com/aubricus/f91fb55dc6ba5557fbab06119420dd6a
Parameters
----------
iteration : int
Current iteration.
total : int
Total iterations.
prefix : str, optional
Prefix string.
bar_length : int, optional
Character length of bar. Defaults to 50.
"""
fraction = iteration / float(total)
if not hasattr(progressBar, "last_fraction"): # first call to function
progressBar.start_time = time.time()
progressBar.last_fraction = -1.0
remaining_time = ' n/a'
else:
if fraction <= progressBar.last_fraction or iteration == 0: # reset: called within a new loop
progressBar.start_time = time.time()
progressBar.last_fraction = -1.0
remaining_time = ' n/a'
else:
progressBar.last_fraction = fraction
remainder = (total - iteration) * (time.time()-progressBar.start_time)/iteration
remaining_time = '{: 3d}:'.format(int( remainder//3600)) + \
'{:02d}:'.format(int((remainder//60)%60)) + \
'{:02d}' .format(int( remainder %60))
filled_length = int(round(bar_length * fraction))
bar = '' * filled_length + '' * (bar_length - filled_length)
sys.stderr.write('\r{} {} {}'.format(prefix, bar, remaining_time)),
if iteration == total:
sys.stderr.write('\n')
sys.stderr.flush()
class return_message():
"""Object with formatted return message."""
def __init__(self,message):
"""
Sets return message.
Parameters
----------
message : str or list of str
message for output to screen
"""
self.message = message
def __repr__(self):
"""Return message suitable for interactive shells."""
return srepr(self.message)
class ThreadPool: class ThreadPool: