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:
fg
andbg
The foreground and background colors, reset to default with
colors.fg.reset
or~colors.fg
and likewise forbg
. These areColorFactory
instances.bold
,dim
,underline
,italics
,reverse
,strikeout
, andhidden
All the ANSI modifiers are available, as well as their negations, such as
~colors.bold
orcolors.bold.reset
, etc. (These are generated automatically based on the Style attached to the factory.)reset
The global reset will restore all properties at once.
do_nothing
Does nothing at all, but otherwise acts like any
Style
object. It is its own inverse. Useful forcli
properties.
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:
- ■
#000000
Black - ■
#C00000
Red - ■
#00C000
Green - ■
#C0C000
Yellow - ■
#0000C0
Blue - ■
#C000C0
Magenta - ■
#00C0C0
Cyan - ■
#C0C0C0
LightGray - ■
#808080
DarkGray - ■
#FF0000
LightRed - ■
#00FF00
LightGreen - ■
#FFFF00
LightYellow - ■
#0000FF
LightBlue - ■
#FF00FF
LightMagenta - ■
#00FFFF
LightCyan - ■
#FFFFFF
White - ■
#000000
Grey0 - ■
#00005F
NavyBlue - ■
#000087
DarkBlue - ■
#0000AF
Blue3 - ■
#0000D7
Blue3A - ■
#0000FF
Blue1 - ■
#005F00
DarkGreen - ■
#005F5F
DeepSkyBlue4 - ■
#005F87
DeepSkyBlue4A - ■
#005FAF
DeepSkyBlue4B - ■
#005FD7
DodgerBlue3 - ■
#005FFF
DodgerBlue2 - ■
#008700
Green4 - ■
#00875F
SpringGreen4 - ■
#008787
Turquoise4 - ■
#0087AF
DeepSkyBlue3 - ■
#0087D7
DeepSkyBlue3A - ■
#0087FF
DodgerBlue1 - ■
#00AF00
Green3 - ■
#00AF5F
SpringGreen3 - ■
#00AF87
DarkCyan - ■
#00AFAF
LightSeaGreen - ■
#00AFD7
DeepSkyBlue2 - ■
#00AFFF
DeepSkyBlue1 - ■
#00D700
Green3A - ■
#00D75F
SpringGreen3A - ■
#00D787
SpringGreen2 - ■
#00D7AF
Cyan3 - ■
#00D7D7
DarkTurquoise - ■
#00D7FF
Turquoise2 - ■
#00FF00
Green1 - ■
#00FF5F
SpringGreen2A - ■
#00FF87
SpringGreen1 - ■
#00FFAF
MediumSpringGreen - ■
#00FFD7
Cyan2 - ■
#00FFFF
Cyan1 - ■
#5F0000
DarkRed - ■
#5F005F
DeepPink4 - ■
#5F0087
Purple4 - ■
#5F00AF
Purple4A - ■
#5F00D7
Purple3 - ■
#5F00FF
BlueViolet - ■
#5F5F00
Orange4 - ■
#5F5F5F
Grey37 - ■
#5F5F87
MediumPurple4 - ■
#5F5FAF
SlateBlue3 - ■
#5F5FD7
SlateBlue3A - ■
#5F5FFF
RoyalBlue1 - ■
#5F8700
Chartreuse4 - ■
#5F875F
DarkSeaGreen4 - ■
#5F8787
PaleTurquoise4 - ■
#5F87AF
SteelBlue - ■
#5F87D7
SteelBlue3 - ■
#5F87FF
CornflowerBlue - ■
#5FAF00
Chartreuse3 - ■
#5FAF5F
DarkSeaGreen4A - ■
#5FAF87
CadetBlue - ■
#5FAFAF
CadetBlueA - ■
#5FAFD7
SkyBlue3 - ■
#5FAFFF
SteelBlue1 - ■
#5FD700
Chartreuse3A - ■
#5FD75F
PaleGreen3 - ■
#5FD787
SeaGreen3 - ■
#5FD7AF
Aquamarine3 - ■
#5FD7D7
MediumTurquoise - ■
#5FD7FF
SteelBlue1A - ■
#5FFF00
Chartreuse2A - ■
#5FFF5F
SeaGreen2 - ■
#5FFF87
SeaGreen1 - ■
#5FFFAF
SeaGreen1A - ■
#5FFFD7
Aquamarine1 - ■
#5FFFFF
DarkSlateGray2 - ■
#870000
DarkRedA - ■
#87005F
DeepPink4A - ■
#870087
DarkMagenta - ■
#8700AF
DarkMagentaA - ■
#8700D7
DarkViolet - ■
#8700FF
Purple - ■
#875F00
Orange4A - ■
#875F5F
LightPink4 - ■
#875F87
Plum4 - ■
#875FAF
MediumPurple3 - ■
#875FD7
MediumPurple3A - ■
#875FFF
SlateBlue1 - ■
#878700
Yellow4 - ■
#87875F
Wheat4 - ■
#878787
Grey53 - ■
#8787AF
LightSlateGrey - ■
#8787D7
MediumPurple - ■
#8787FF
LightSlateBlue - ■
#87AF00
Yellow4A - ■
#87AF5F
DarkOliveGreen3 - ■
#87AF87
DarkSeaGreen - ■
#87AFAF
LightSkyBlue3 - ■
#87AFD7
LightSkyBlue3A - ■
#87AFFF
SkyBlue2 - ■
#87D700
Chartreuse2 - ■
#87D75F
DarkOliveGreen3A - ■
#87D787
PaleGreen3A - ■
#87D7AF
DarkSeaGreen3 - ■
#87D7D7
DarkSlateGray3 - ■
#87D7FF
SkyBlue1 - ■
#87FF00
Chartreuse1 - ■
#87FF5F
LightGreenA - ■
#87FF87
LightGreenB - ■
#87FFAF
PaleGreen1 - ■
#87FFD7
Aquamarine1A - ■
#87FFFF
DarkSlateGray1 - ■
#AF0000
Red3 - ■
#AF005F
DeepPink4B - ■
#AF0087
MediumVioletRed - ■
#AF00AF
Magenta3 - ■
#AF00D7
DarkVioletA - ■
#AF00FF
PurpleA - ■
#AF5F00
DarkOrange3 - ■
#AF5F5F
IndianRed - ■
#AF5F87
HotPink3 - ■
#AF5FAF
MediumOrchid3 - ■
#AF5FD7
MediumOrchid - ■
#AF5FFF
MediumPurple2 - ■
#AF8700
DarkGoldenrod - ■
#AF875F
LightSalmon3 - ■
#AF8787
RosyBrown - ■
#AF87AF
Grey63 - ■
#AF87D7
MediumPurple2A - ■
#AF87FF
MediumPurple1 - ■
#AFAF00
Gold3 - ■
#AFAF5F
DarkKhaki - ■
#AFAF87
NavajoWhite3 - ■
#AFAFAF
Grey69 - ■
#AFAFD7
LightSteelBlue3 - ■
#AFAFFF
LightSteelBlue - ■
#AFD700
Yellow3 - ■
#AFD75F
DarkOliveGreen3B - ■
#AFD787
DarkSeaGreen3A - ■
#AFD7AF
DarkSeaGreen2 - ■
#AFD7D7
LightCyan3 - ■
#AFD7FF
LightSkyBlue1 - ■
#AFFF00
GreenYellow - ■
#AFFF5F
DarkOliveGreen2 - ■
#AFFF87
PaleGreen1A - ■
#AFFFAF
DarkSeaGreen2A - ■
#AFFFD7
DarkSeaGreen1 - ■
#AFFFFF
PaleTurquoise1 - ■
#D70000
Red3A - ■
#D7005F
DeepPink3 - ■
#D70087
DeepPink3A - ■
#D700AF
Magenta3A - ■
#D700D7
Magenta3B - ■
#D700FF
Magenta2 - ■
#D75F00
DarkOrange3A - ■
#D75F5F
IndianRedA - ■
#D75F87
HotPink3A - ■
#D75FAF
HotPink2 - ■
#D75FD7
Orchid - ■
#D75FFF
MediumOrchid1 - ■
#D78700
Orange3 - ■
#D7875F
LightSalmon3A - ■
#D78787
LightPink3 - ■
#D787AF
Pink3 - ■
#D787D7
Plum3 - ■
#D787FF
Violet - ■
#D7AF00
Gold3A - ■
#D7AF5F
LightGoldenrod3 - ■
#D7AF87
Tan - ■
#D7AFAF
MistyRose3 - ■
#D7AFD7
Thistle3 - ■
#D7AFFF
Plum2 - ■
#D7D700
Yellow3A - ■
#D7D75F
Khaki3 - ■
#D7D787
LightGoldenrod2 - ■
#D7D7AF
LightYellow3 - ■
#D7D7D7
Grey84 - ■
#D7D7FF
LightSteelBlue1 - ■
#D7FF00
Yellow2 - ■
#D7FF5F
DarkOliveGreen1 - ■
#D7FF87
DarkOliveGreen1A - ■
#D7FFAF
DarkSeaGreen1A - ■
#D7FFD7
Honeydew2 - ■
#D7FFFF
LightCyan1 - ■
#FF0000
Red1 - ■
#FF005F
DeepPink2 - ■
#FF0087
DeepPink1 - ■
#FF00AF
DeepPink1A - ■
#FF00D7
Magenta2A - ■
#FF00FF
Magenta1 - ■
#FF5F00
OrangeRed1 - ■
#FF5F5F
IndianRed1 - ■
#FF5F87
IndianRed1A - ■
#FF5FAF
HotPink - ■
#FF5FD7
HotPinkA - ■
#FF5FFF
MediumOrchid1A - ■
#FF8700
DarkOrange - ■
#FF875F
Salmon1 - ■
#FF8787
LightCoral - ■
#FF87AF
PaleVioletRed1 - ■
#FF87D7
Orchid2 - ■
#FF87FF
Orchid1 - ■
#FFAF00
Orange1 - ■
#FFAF5F
SandyBrown - ■
#FFAF87
LightSalmon1 - ■
#FFAFAF
LightPink1 - ■
#FFAFD7
Pink1 - ■
#FFAFFF
Plum1 - ■
#FFD700
Gold1 - ■
#FFD75F
LightGoldenrod2A - ■
#FFD787
LightGoldenrod2B - ■
#FFD7AF
NavajoWhite1 - ■
#FFD7D7
MistyRose1 - ■
#FFD7FF
Thistle1 - ■
#FFFF00
Yellow1 - ■
#FFFF5F
LightGoldenrod1 - ■
#FFFF87
Khaki1 - ■
#FFFFAF
Wheat1 - ■
#FFFFD7
Cornsilk1 - ■
#FFFFFF
Grey100 - ■
#080808
Grey3 - ■
#121212
Grey7 - ■
#1C1C1C
Grey11 - ■
#262626
Grey15 - ■
#303030
Grey19 - ■
#3A3A3A
Grey23 - ■
#444444
Grey27 - ■
#4E4E4E
Grey30 - ■
#585858
Grey35 - ■
#626262
Grey39 - ■
#6C6C6C
Grey42 - ■
#767676
Grey46 - ■
#808080
Grey50 - ■
#8A8A8A
Grey54 - ■
#949494
Grey58 - ■
#9E9E9E
Grey62 - ■
#A8A8A8
Grey66 - ■
#B2B2B2
Grey70 - ■
#BCBCBC
Grey74 - ■
#C6C6C6
Grey78 - ■
#D0D0D0
Grey82 - ■
#DADADA
Grey85 - ■
#E4E4E4
Grey89 - ■
#EEEEEE
Grey93
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.