Colorlib design¶
New in version 1.6.
The purpose of this document is to describe the system that plumbum.colors implements. This system was designed to be flexible and to allow implementing new color backends. Hopefully this document will allow future work on colorlib to be as simple as possible.
Note
Enabling color
plumbum.colors tries to guess the color output settings of your system.
You can force the use of color globally by setting
colors.use_color=True See 256 Color Support for more options.
Generating colors¶
Styles are accessed through the colors object, which is an instance of a StyleFactory. The colors
object is actually an imitation module that wraps plumbum.colorlib.ansicolors with module-like access.
Thus, things like from plumbum.colors.bg import red work also. The library actually lives in plumbum.colorlib.
Style Factory¶
The colors object has the following available objects:
fgandbgThe foreground and background colors, reset to default with
colors.fg.resetor~colors.fgand likewise forbg. These areColorFactoryinstances.bold,dim,underline,italics,reverse,strikeout, andhiddenAll the ANSI modifiers are available, as well as their negations, such as
~colors.boldorcolors.bold.reset, etc. (These are generated automatically based on the Style attached to the factory.)resetThe global reset will restore all properties at once.
do_nothingDoes nothing at all, but otherwise acts like any
Styleobject. It is its own inverse. Useful forcliproperties.
The colors object can be used in a with statement, which resets all styles on leaving
the statement body. Although factories do support
some of the same methods as a Style, their primary purpose is to generate Styles. The colors object has a
use_color property that can be set to force the use of color. A stdout property is provided
to make changing the output of color statement easier. A colors.from_ansi(code) method allows
you to create a Style from any ansi sequence, even complex or combined ones.
Color Factories¶
The colors.fg and colors.bg are ColorFactory’s. In fact, the colors object itself acts exactly
like the colors.fg object, with the exception of the properties listed above.
Named foreground colors are available
directly as methods. The first 16 primary colors, black, red, green, yellow,
blue, magenta, cyan, etc, as well as reset, are available. All 256 color
names are available, but do not populate factory directly, so that auto-completion
gives reasonable results. You can also access colors using strings and do colors[string].
Capitalization, underscores, and spaces (for strings) will be ignored.
You can also access colors numerically with colors(n) or colors[n]
with the extended 256 color codes. The former will default to simple versions of
colors for the first 16 values. The later notation can also be used to slice.
Full hex codes can be used, too. If no match is found,
these will be the true 24 bit color value.
The fg and bg also can be put in with statements, and they
will restore the foreground and background color only, respectively.
colors.rgb(r,g,b) will create a color from an
input red, green, and blue values (integers from 0-255). colors.rgb(code) will allow
you to input an html style hex sequence. These work on fg and bg too. The repr of
styles is smart and will show you the closest color to the one you selected if you didn’t exactly
select a color through RGB.
Style manipulations¶
Safe color manipulations refer to changes that reset themselves at some point. Unsafe manipulations must be manually reset, and can leave your terminal color in an unreadable state if you forget to reset the color or encounter an exception. If you do get the color unset on a terminal, the following, typed into the command line, will restore it:
$ python3 -m plumbum.colors
This also supports command line access to unsafe color manipulations, such as
$ python3 -m plumbum.colors blue
$ python3 -m plumbum.colors bg red
$ python3 -m plumbum.colors fg 123
$ python3 -m plumbum.colors bg reset
$ python3 -m plumbum.colors underline
You can use any path or number available as a style.
Unsafe Manipulation¶
Styles have two unsafe operations: Concatenation (with + and a string) and calling .now() without
arguments (directly calling a style without arguments is also a shortcut for .now()). These two
operations do not restore normal color to the terminal by themselves. To protect their use,
you should always use a context manager around any unsafe operation.
An example of the usage of unsafe colors manipulations inside a context manager:
from plumbum import colors
with colors:
colors.fg.red.now()
print('This is in red')
colors.green.now()
print('This is green ' + colors.underline + 'and now also underlined!')
print('Underlined' + colors.underline.reset + ' and not underlined but still red')
print('This is completely restored, even if an exception is thrown!')
Output:
This is in red
This is in green and now also underlined!
Underlined and not underlined but still green.
This is completely restored, even if an exception is thrown!
We can use colors instead of colors.fg for foreground colors. If we had used colors.fg
as the context manager, then non-foreground properties, such as colors.underline or
colors.bg.yellow, would not have reset those properties. Each attribute,
as well as fg, bg, and colors all have inverses in the ANSI standard. They are
accessed with ~ or .reset, and can be used to manually make these operations
safer, but there is a better way.
Safe Manipulation¶
All other operations are safe; they restore the color automatically. The first, and hopefully
already obvious one, is using a Style rather than a colors or colors.fg object in a with statement.
This will set the color (using sys.stdout by default) to that color, and restore color on leaving.
The second method is to manually wrap a string. This can be done with color.wrap("string") or color["string"].
These produce strings that can be further manipulated or printed.
Finally, you can also print a color to stdout directly using color.print("string"). This
has the same syntax as the print function.
An example of safe manipulations:
colors.fg.yellow('This is yellow', end='')
print(' And this is normal again.')
with colors.red:
print('Red color!')
with colors.bold:
print("This is red and bold.")
print("Not bold, but still red.")
print("Not red color or bold.")
print((colors.magenta & colors.bold)["This is bold and colorful!"], "And this is not.")
Output:
This is yellow And this is normal again.
Red color!
This is red and bold.
Not bold, but still red.
Not red color or bold.
This is bold and colorful! And this is not.
Style Combinations¶
You can combine styles with & and they will create a new combined Style object. Colors will not be “summed”
or otherwise combined; the rightmost color will be used (this matches the expected effect of
applying the Styles individually to the strings). However, combined Styles are intelligent and
know how to reset just the properties that they contain. As you have seen in the example above,
the combined style (colors.magenta & colors.bold) can be used in any way a normal Style can.
Since wrapping is done with |, the Python order of operations causes styles to be combined first, then
wrapping is done last.
256 Color Support¶
While this library supports full 24 bit colors through escape sequences,
the library has special support for the “full” 256 colorset through numbers,
names or HEX html codes. Even if you use 24 bit color, the closest name is displayed
in the repr. You can access the colors as
as colors.fg.Light_Blue, colors.fg.lightblue, colors.fg[12], colors.fg('Light_Blue'),
colors.fg('LightBlue'), or colors.fg('#0000FF').
You can also iterate or slice the colors, colors.fg, or colors.bg objects. Slicing even
intelligently downgrades to the simple version of the codes if it is within the first 16 elements.
The supported colors are:
- ■
#000000Black - ■
#C00000Red - ■
#00C000Green - ■
#C0C000Yellow - ■
#0000C0Blue - ■
#C000C0Magenta - ■
#00C0C0Cyan - ■
#C0C0C0LightGray - ■
#808080DarkGray - ■
#FF0000LightRed - ■
#00FF00LightGreen - ■
#FFFF00LightYellow - ■
#0000FFLightBlue - ■
#FF00FFLightMagenta - ■
#00FFFFLightCyan - ■
#FFFFFFWhite - ■
#000000Grey0 - ■
#00005FNavyBlue - ■
#000087DarkBlue - ■
#0000AFBlue3 - ■
#0000D7Blue3A - ■
#0000FFBlue1 - ■
#005F00DarkGreen - ■
#005F5FDeepSkyBlue4 - ■
#005F87DeepSkyBlue4A - ■
#005FAFDeepSkyBlue4B - ■
#005FD7DodgerBlue3 - ■
#005FFFDodgerBlue2 - ■
#008700Green4 - ■
#00875FSpringGreen4 - ■
#008787Turquoise4 - ■
#0087AFDeepSkyBlue3 - ■
#0087D7DeepSkyBlue3A - ■
#0087FFDodgerBlue1 - ■
#00AF00Green3 - ■
#00AF5FSpringGreen3 - ■
#00AF87DarkCyan - ■
#00AFAFLightSeaGreen - ■
#00AFD7DeepSkyBlue2 - ■
#00AFFFDeepSkyBlue1 - ■
#00D700Green3A - ■
#00D75FSpringGreen3A - ■
#00D787SpringGreen2 - ■
#00D7AFCyan3 - ■
#00D7D7DarkTurquoise - ■
#00D7FFTurquoise2 - ■
#00FF00Green1 - ■
#00FF5FSpringGreen2A - ■
#00FF87SpringGreen1 - ■
#00FFAFMediumSpringGreen - ■
#00FFD7Cyan2 - ■
#00FFFFCyan1 - ■
#5F0000DarkRed - ■
#5F005FDeepPink4 - ■
#5F0087Purple4 - ■
#5F00AFPurple4A - ■
#5F00D7Purple3 - ■
#5F00FFBlueViolet - ■
#5F5F00Orange4 - ■
#5F5F5FGrey37 - ■
#5F5F87MediumPurple4 - ■
#5F5FAFSlateBlue3 - ■
#5F5FD7SlateBlue3A - ■
#5F5FFFRoyalBlue1 - ■
#5F8700Chartreuse4 - ■
#5F875FDarkSeaGreen4 - ■
#5F8787PaleTurquoise4 - ■
#5F87AFSteelBlue - ■
#5F87D7SteelBlue3 - ■
#5F87FFCornflowerBlue - ■
#5FAF00Chartreuse3 - ■
#5FAF5FDarkSeaGreen4A - ■
#5FAF87CadetBlue - ■
#5FAFAFCadetBlueA - ■
#5FAFD7SkyBlue3 - ■
#5FAFFFSteelBlue1 - ■
#5FD700Chartreuse3A - ■
#5FD75FPaleGreen3 - ■
#5FD787SeaGreen3 - ■
#5FD7AFAquamarine3 - ■
#5FD7D7MediumTurquoise - ■
#5FD7FFSteelBlue1A - ■
#5FFF00Chartreuse2A - ■
#5FFF5FSeaGreen2 - ■
#5FFF87SeaGreen1 - ■
#5FFFAFSeaGreen1A - ■
#5FFFD7Aquamarine1 - ■
#5FFFFFDarkSlateGray2 - ■
#870000DarkRedA - ■
#87005FDeepPink4A - ■
#870087DarkMagenta - ■
#8700AFDarkMagentaA - ■
#8700D7DarkViolet - ■
#8700FFPurple - ■
#875F00Orange4A - ■
#875F5FLightPink4 - ■
#875F87Plum4 - ■
#875FAFMediumPurple3 - ■
#875FD7MediumPurple3A - ■
#875FFFSlateBlue1 - ■
#878700Yellow4 - ■
#87875FWheat4 - ■
#878787Grey53 - ■
#8787AFLightSlateGrey - ■
#8787D7MediumPurple - ■
#8787FFLightSlateBlue - ■
#87AF00Yellow4A - ■
#87AF5FDarkOliveGreen3 - ■
#87AF87DarkSeaGreen - ■
#87AFAFLightSkyBlue3 - ■
#87AFD7LightSkyBlue3A - ■
#87AFFFSkyBlue2 - ■
#87D700Chartreuse2 - ■
#87D75FDarkOliveGreen3A - ■
#87D787PaleGreen3A - ■
#87D7AFDarkSeaGreen3 - ■
#87D7D7DarkSlateGray3 - ■
#87D7FFSkyBlue1 - ■
#87FF00Chartreuse1 - ■
#87FF5FLightGreenA - ■
#87FF87LightGreenB - ■
#87FFAFPaleGreen1 - ■
#87FFD7Aquamarine1A - ■
#87FFFFDarkSlateGray1 - ■
#AF0000Red3 - ■
#AF005FDeepPink4B - ■
#AF0087MediumVioletRed - ■
#AF00AFMagenta3 - ■
#AF00D7DarkVioletA - ■
#AF00FFPurpleA - ■
#AF5F00DarkOrange3 - ■
#AF5F5FIndianRed - ■
#AF5F87HotPink3 - ■
#AF5FAFMediumOrchid3 - ■
#AF5FD7MediumOrchid - ■
#AF5FFFMediumPurple2 - ■
#AF8700DarkGoldenrod - ■
#AF875FLightSalmon3 - ■
#AF8787RosyBrown - ■
#AF87AFGrey63 - ■
#AF87D7MediumPurple2A - ■
#AF87FFMediumPurple1 - ■
#AFAF00Gold3 - ■
#AFAF5FDarkKhaki - ■
#AFAF87NavajoWhite3 - ■
#AFAFAFGrey69 - ■
#AFAFD7LightSteelBlue3 - ■
#AFAFFFLightSteelBlue - ■
#AFD700Yellow3 - ■
#AFD75FDarkOliveGreen3B - ■
#AFD787DarkSeaGreen3A - ■
#AFD7AFDarkSeaGreen2 - ■
#AFD7D7LightCyan3 - ■
#AFD7FFLightSkyBlue1 - ■
#AFFF00GreenYellow - ■
#AFFF5FDarkOliveGreen2 - ■
#AFFF87PaleGreen1A - ■
#AFFFAFDarkSeaGreen2A - ■
#AFFFD7DarkSeaGreen1 - ■
#AFFFFFPaleTurquoise1 - ■
#D70000Red3A - ■
#D7005FDeepPink3 - ■
#D70087DeepPink3A - ■
#D700AFMagenta3A - ■
#D700D7Magenta3B - ■
#D700FFMagenta2 - ■
#D75F00DarkOrange3A - ■
#D75F5FIndianRedA - ■
#D75F87HotPink3A - ■
#D75FAFHotPink2 - ■
#D75FD7Orchid - ■
#D75FFFMediumOrchid1 - ■
#D78700Orange3 - ■
#D7875FLightSalmon3A - ■
#D78787LightPink3 - ■
#D787AFPink3 - ■
#D787D7Plum3 - ■
#D787FFViolet - ■
#D7AF00Gold3A - ■
#D7AF5FLightGoldenrod3 - ■
#D7AF87Tan - ■
#D7AFAFMistyRose3 - ■
#D7AFD7Thistle3 - ■
#D7AFFFPlum2 - ■
#D7D700Yellow3A - ■
#D7D75FKhaki3 - ■
#D7D787LightGoldenrod2 - ■
#D7D7AFLightYellow3 - ■
#D7D7D7Grey84 - ■
#D7D7FFLightSteelBlue1 - ■
#D7FF00Yellow2 - ■
#D7FF5FDarkOliveGreen1 - ■
#D7FF87DarkOliveGreen1A - ■
#D7FFAFDarkSeaGreen1A - ■
#D7FFD7Honeydew2 - ■
#D7FFFFLightCyan1 - ■
#FF0000Red1 - ■
#FF005FDeepPink2 - ■
#FF0087DeepPink1 - ■
#FF00AFDeepPink1A - ■
#FF00D7Magenta2A - ■
#FF00FFMagenta1 - ■
#FF5F00OrangeRed1 - ■
#FF5F5FIndianRed1 - ■
#FF5F87IndianRed1A - ■
#FF5FAFHotPink - ■
#FF5FD7HotPinkA - ■
#FF5FFFMediumOrchid1A - ■
#FF8700DarkOrange - ■
#FF875FSalmon1 - ■
#FF8787LightCoral - ■
#FF87AFPaleVioletRed1 - ■
#FF87D7Orchid2 - ■
#FF87FFOrchid1 - ■
#FFAF00Orange1 - ■
#FFAF5FSandyBrown - ■
#FFAF87LightSalmon1 - ■
#FFAFAFLightPink1 - ■
#FFAFD7Pink1 - ■
#FFAFFFPlum1 - ■
#FFD700Gold1 - ■
#FFD75FLightGoldenrod2A - ■
#FFD787LightGoldenrod2B - ■
#FFD7AFNavajoWhite1 - ■
#FFD7D7MistyRose1 - ■
#FFD7FFThistle1 - ■
#FFFF00Yellow1 - ■
#FFFF5FLightGoldenrod1 - ■
#FFFF87Khaki1 - ■
#FFFFAFWheat1 - ■
#FFFFD7Cornsilk1 - ■
#FFFFFFGrey100 - ■
#080808Grey3 - ■
#121212Grey7 - ■
#1C1C1CGrey11 - ■
#262626Grey15 - ■
#303030Grey19 - ■
#3A3A3AGrey23 - ■
#444444Grey27 - ■
#4E4E4EGrey30 - ■
#585858Grey35 - ■
#626262Grey39 - ■
#6C6C6CGrey42 - ■
#767676Grey46 - ■
#808080Grey50 - ■
#8A8A8AGrey54 - ■
#949494Grey58 - ■
#9E9E9EGrey62 - ■
#A8A8A8Grey66 - ■
#B2B2B2Grey70 - ■
#BCBCBCGrey74 - ■
#C6C6C6Grey78 - ■
#D0D0D0Grey82 - ■
#DADADAGrey85 - ■
#E4E4E4Grey89 - ■
#EEEEEEGrey93
If you want to enforce a specific representation, you can use .basic (8 color), .simple (16 color),
.full (256 color), or .true (24 bit color) on a Style, and the colors in that Style will conform to
the output representation and name of the best match color. The internal RGB colors
are remembered, so this is a non-destructive operation.
To limit the use of color to one of these styles, set colors.use_color to 1 for 8 colors, 2 for 16 colors,
3 for 256 colors, or 4 for true color. It will be guessed based on your system on initialisation.
The Classes¶
The library consists of three primary classes, the Color class, the Style class, and the StyleFactory class. The following
portion of this document is primarily dealing with the working of the system, and is meant to facilitate extensions or work on the system.
The Color class provides meaning to the concept of color, and can provide a variety of representations for any color. It
can be initialised from r,g,b values, or hex codes, 256 color names, or the simple color names via classmethods. If initialized
without arguments, it is the reset color. It also takes an fg True/False argument to indicate which color it is. You probably will
not be interacting with the Color class directly, and you probably will not need to subclass it, though new extensions to the
representations it can produce are welcome.
The Style class hold two colors and a dictionary of attributes. It is the workhorse of the system and is what is produced
by the colors factory. It holds Color as .color_class, which can be overridden by subclasses (again, this usually is not needed).
To create a color representation, you need to subclass Style and give it a working __str__ definition. ANSIStyle is derived
from Style in this way.
The factories, ColorFactory and StyleFactory, are factory classes that are meant to provide simple access to 1 style Style classes. To use,
you need to initialize an object of StyleFactory with your intended Style. For example, colors is created by:
colors = StyleFactory(ANSIStyle)
Subclassing Style¶
For example, if you wanted to create an HTMLStyle and HTMLcolors, you could do:
class HTMLStyle(Style):
attribute_names = dict(bold='b', li='li', code='code')
end = '<br/>\n'
def __str__(self):
result = ''
if self.bg and not self.bg.reset:
result += f'<span style="background-color: {self.bg.hex_code}">'
if self.fg and not self.fg.reset:
result += f'<font color="{self.fg.hex_code}">'
for attr in sorted(self.attributes):
if self.attributes[attr]:
result += '<' + self.attribute_names[attr] + '>'
for attr in reversed(sorted(self.attributes)):
if not self.attributes[attr]:
result += '</' + self.attribute_names[attr].split()[0] + '>'
if self.fg and self.fg.reset:
result += '</font>'
if self.bg and self.bg.reset:
result += '</span>'
return result
htmlcolors = StyleFactory(HTMLStyle)
This doesn’t support global resets, since that’s not how HTML works, but otherwise is a working implementation. This is an example of how easy it is to add support for other output formats.
An example of usage:
>>> htmlcolors.bold & htmlcolors.red | "This is colored text"
'<font color="#800000"><b>This is colored text</b></font>'
The above color table can be generated with:
for color in htmlcolors:
htmlcolors.li(
"■" | color,
color.fg.hex_code | htmlcolors.code,
color.fg.name_camelcase)
Note
HTMLStyle is implemented in the library, as well, with the
htmlcolors object available in plumbum.colorlib. It was used
to create the colored output in this document, with small changes
because colors.reset cannot be supported with HTML.