Move get_colors and get_color_theme to salt.utils.color.py

Moves the `get_colors` and `get_color_theme` out of `salt.utils.py`
and into a new file named `salt.utils.color.py`.

This PR moves the original functions, adds a deprecation warning to
the old function paths, and updates any references to the functions
in Salt code to the new location. This includes moving a test as well.
This commit is contained in:
rallytime 2017-08-29 17:33:01 -04:00
parent c6664291ce
commit 26f52bd2b8
12 changed files with 184 additions and 109 deletions

View file

@ -108,7 +108,7 @@ import pprint
import textwrap
# Import salt libs
import salt.utils
import salt.utils.color
import salt.utils.stringutils
import salt.output
from salt.utils.locales import sdecode
@ -158,7 +158,7 @@ def output(data, **kwargs): # pylint: disable=unused-argument
def _format_host(host, data):
host = sdecode(host)
colors = salt.utils.get_colors(
colors = salt.utils.color.get_colors(
__opts__.get('color'),
__opts__.get('color_theme'))
tabular = __opts__.get('state_tabular', False)

View file

@ -8,9 +8,9 @@ The ``salt-key`` command makes use of this outputter to format its output.
from __future__ import absolute_import
# Import salt libs
import salt.utils
import salt.output
from salt.utils.locales import sdecode
import salt.utils.color
def output(data, **kwargs): # pylint: disable=unused-argument
@ -18,7 +18,7 @@ def output(data, **kwargs): # pylint: disable=unused-argument
Read in the dict structure generated by the salt key API methods and
print the structure.
'''
color = salt.utils.get_colors(
color = salt.utils.color.get_colors(
__opts__.get('color'),
__opts__.get('color_theme'))
strip_colors = __opts__.get('strip_colors', True)

View file

@ -29,9 +29,9 @@ from numbers import Number
# Import salt libs
import salt.output
import salt.utils.color
import salt.utils.locales
import salt.utils.odict
from salt.utils import get_colors
from salt.ext.six import string_types
@ -41,7 +41,7 @@ class NestDisplay(object):
'''
def __init__(self):
self.__dict__.update(
get_colors(
salt.utils.color.get_colors(
__opts__.get('color'),
__opts__.get('color_theme')
)

View file

@ -15,7 +15,7 @@ Example output::
from __future__ import absolute_import
# Import salt libs
import salt.utils
import salt.utils.color
# Import 3rd-party libs
from salt.ext import six
@ -26,7 +26,7 @@ class NestDisplay(object):
Create generator for nested output
'''
def __init__(self):
self.colors = salt.utils.get_colors(
self.colors = salt.utils.color.get_colors(
__opts__.get(u'color'),
__opts__.get(u'color_theme'))

View file

@ -11,7 +11,7 @@ and should not be called directly.
from __future__ import absolute_import
# Import Salt libs
import salt.utils
import salt.utils.color
# Import 3rd-party libs
from salt.ext import six
@ -27,7 +27,7 @@ def output(data, **kwargs): # pylint: disable=unused-argument
'''
Format the data for printing stage information from the overstate system
'''
colors = salt.utils.get_colors(
colors = salt.utils.color.get_colors(
__opts__.get('color'),
__opts__.get('color_theme'))
ostr = ''

View file

@ -42,12 +42,10 @@ from functools import reduce # pylint: disable=redefined-builtin
# Import salt libs
import salt.output
import salt.utils.locales
from salt.ext.six import string_types
from salt.utils import get_colors
from salt.ext.six.moves import map # pylint: disable=redefined-builtin
from salt.ext.six.moves import zip # pylint: disable=redefined-builtin
from salt.ext.six.moves import map, zip # pylint: disable=redefined-builtin
import salt.utils.color
import salt.utils.locales
__virtualname__ = 'table'
@ -78,7 +76,7 @@ class TableDisplay(object):
width=50, # column max width
wrapfunc=None): # function wrapper
self.__dict__.update(
get_colors(
salt.utils.color.get_colors(
__opts__.get('color'),
__opts__.get('color_theme')
)

View file

@ -126,7 +126,6 @@ import salt.utils.dictupdate
import salt.utils.versions
import salt.version
from salt.utils.decorators.jinja import jinja_filter
from salt.textformat import TextFormat
from salt.exceptions import (
CommandExecutionError, SaltClientError,
CommandNotFoundError, SaltSystemExit,
@ -138,83 +137,6 @@ log = logging.getLogger(__name__)
_empty = object()
def get_color_theme(theme):
'''
Return the color theme to use
'''
# Keep the heavy lifting out of the module space
import yaml
if not os.path.isfile(theme):
log.warning('The named theme {0} if not available'.format(theme))
# Late import to avoid circular import.
import salt.utils.files
try:
with salt.utils.files.fopen(theme, 'rb') as fp_:
colors = yaml.safe_load(fp_.read())
ret = {}
for color in colors:
ret[color] = '\033[{0}m'.format(colors[color])
if not isinstance(colors, dict):
log.warning('The theme file {0} is not a dict'.format(theme))
return {}
return ret
except Exception:
log.warning('Failed to read the color theme {0}'.format(theme))
return {}
def get_colors(use=True, theme=None):
'''
Return the colors as an easy to use dict. Pass `False` to deactivate all
colors by setting them to empty strings. Pass a string containing only the
name of a single color to be used in place of all colors. Examples:
.. code-block:: python
colors = get_colors() # enable all colors
no_colors = get_colors(False) # disable all colors
red_colors = get_colors('RED') # set all colors to red
'''
colors = {
'BLACK': TextFormat('black'),
'DARK_GRAY': TextFormat('bold', 'black'),
'RED': TextFormat('red'),
'LIGHT_RED': TextFormat('bold', 'red'),
'GREEN': TextFormat('green'),
'LIGHT_GREEN': TextFormat('bold', 'green'),
'YELLOW': TextFormat('yellow'),
'LIGHT_YELLOW': TextFormat('bold', 'yellow'),
'BLUE': TextFormat('blue'),
'LIGHT_BLUE': TextFormat('bold', 'blue'),
'MAGENTA': TextFormat('magenta'),
'LIGHT_MAGENTA': TextFormat('bold', 'magenta'),
'CYAN': TextFormat('cyan'),
'LIGHT_CYAN': TextFormat('bold', 'cyan'),
'LIGHT_GRAY': TextFormat('white'),
'WHITE': TextFormat('bold', 'white'),
'DEFAULT_COLOR': TextFormat('default'),
'ENDC': TextFormat('reset'),
}
if theme:
colors.update(get_color_theme(theme))
if not use:
for color in colors:
colors[color] = ''
if isinstance(use, six.string_types):
# Try to set all of the colors to the passed color
if use in colors:
for color in colors:
# except for color reset
if color == 'ENDC':
continue
colors[color] = colors[use]
return colors
def get_context(template, line, num_lines=5, marker=None):
'''
Returns debugging context around a line in a given string
@ -3435,3 +3357,49 @@ def kwargs_warn_until(kwargs,
stacklevel=stacklevel,
_version_info_=_version_info_,
_dont_call_warnings=_dont_call_warnings)
def get_color_theme(theme):
'''
Return the color theme to use
.. deprecated:: Oxygen
'''
# Late import to avoid circular import.
import salt.utils.color
import salt.utils.versions
salt.utils.versions.warn_until(
'Neon',
'Use of \'salt.utils.get_color_theme\' detected. This function has '
'been moved to \'salt.utils.color.get_color_theme\' as of Salt '
'Oxygen. This warning will be removed in Salt Neon.'
)
return salt.utils.color.get_color_theme(theme)
def get_colors(use=True, theme=None):
'''
Return the colors as an easy to use dict. Pass `False` to deactivate all
colors by setting them to empty strings. Pass a string containing only the
name of a single color to be used in place of all colors. Examples:
.. code-block:: python
colors = get_colors() # enable all colors
no_colors = get_colors(False) # disable all colors
red_colors = get_colors('RED') # set all colors to red
.. deprecated:: Oxygen
'''
# Late import to avoid circular import.
import salt.utils.color
import salt.utils.versions
salt.utils.versions.warn_until(
'Neon',
'Use of \'salt.utils.get_colors\' detected. This function has '
'been moved to \'salt.utils.color.get_colors\' as of Salt '
'Oxygen. This warning will be removed in Salt Neon.'
)
return salt.utils.color.get_colors(use=use, theme=theme)

92
salt/utils/color.py Normal file
View file

@ -0,0 +1,92 @@
# -*- coding: utf-8 -*-
'''
Functions used for CLI color themes.
'''
# Import Python libs
from __future__ import absolute_import
import logging
import os
# Import Salt libs
from salt.ext import six
from salt.textformat import TextFormat
import salt.utils.files
log = logging.getLogger(__name__)
def get_color_theme(theme):
'''
Return the color theme to use
'''
# Keep the heavy lifting out of the module space
import yaml
if not os.path.isfile(theme):
log.warning('The named theme {0} if not available'.format(theme))
try:
with salt.utils.files.fopen(theme, 'rb') as fp_:
colors = yaml.safe_load(fp_.read())
ret = {}
for color in colors:
ret[color] = '\033[{0}m'.format(colors[color])
if not isinstance(colors, dict):
log.warning('The theme file {0} is not a dict'.format(theme))
return {}
return ret
except Exception:
log.warning('Failed to read the color theme {0}'.format(theme))
return {}
def get_colors(use=True, theme=None):
'''
Return the colors as an easy to use dict. Pass `False` to deactivate all
colors by setting them to empty strings. Pass a string containing only the
name of a single color to be used in place of all colors. Examples:
.. code-block:: python
colors = get_colors() # enable all colors
no_colors = get_colors(False) # disable all colors
red_colors = get_colors('RED') # set all colors to red
'''
colors = {
'BLACK': TextFormat('black'),
'DARK_GRAY': TextFormat('bold', 'black'),
'RED': TextFormat('red'),
'LIGHT_RED': TextFormat('bold', 'red'),
'GREEN': TextFormat('green'),
'LIGHT_GREEN': TextFormat('bold', 'green'),
'YELLOW': TextFormat('yellow'),
'LIGHT_YELLOW': TextFormat('bold', 'yellow'),
'BLUE': TextFormat('blue'),
'LIGHT_BLUE': TextFormat('bold', 'blue'),
'MAGENTA': TextFormat('magenta'),
'LIGHT_MAGENTA': TextFormat('bold', 'magenta'),
'CYAN': TextFormat('cyan'),
'LIGHT_CYAN': TextFormat('bold', 'cyan'),
'LIGHT_GRAY': TextFormat('white'),
'WHITE': TextFormat('bold', 'white'),
'DEFAULT_COLOR': TextFormat('default'),
'ENDC': TextFormat('reset'),
}
if theme:
colors.update(get_color_theme(theme))
if not use:
for color in colors:
colors[color] = ''
if isinstance(use, six.string_types):
# Try to set all of the colors to the passed color
if use in colors:
for color in colors:
# except for color reset
if color == 'ENDC':
continue
colors[color] = colors[use]
return colors

View file

@ -9,13 +9,13 @@ import pprint
import optparse
# Import Salt libs
import salt.utils
import salt.utils.color
# Import 3rd-party libs
import yaml
from salt.ext import six
colors = salt.utils.get_colors()
colors = salt.utils.color.get_colors()
def parse():

View file

@ -49,7 +49,8 @@ import salt.minion
import salt.runner
import salt.output
import salt.version
import salt.utils # Can be removed once get_colors and appendproctitle are moved
import salt.utils # Can be removed once appendproctitle is moved
import salt.utils.color
import salt.utils.files
import salt.utils.path
import salt.utils.platform
@ -188,7 +189,7 @@ class TestDaemon(object):
def __init__(self, parser):
self.parser = parser
self.colors = salt.utils.get_colors(self.parser.options.no_colors is False)
self.colors = salt.utils.color.get_colors (self.parser.options.no_colors is False)
if salt.utils.platform.is_windows():
# There's no shell color support on windows...
for key in self.colors:

View file

@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
'''
Unit tests for salt.utils.color.py
'''
# Import python libs
from __future__ import absolute_import
# Import Salt Testing libs
from tests.support.unit import TestCase
# Import Salt libs
import salt.utils.color
class ColorUtilsTestCase(TestCase):
def test_get_colors(self):
ret = salt.utils.color.get_colors()
self.assertEqual('\x1b[0;37m', str(ret['LIGHT_GRAY']))
ret = salt.utils.color.get_colors(use=False)
self.assertDictContainsSubset({'LIGHT_GRAY': ''}, ret)
ret = salt.utils.color.get_colors(use='LIGHT_GRAY')
# LIGHT_YELLOW now == LIGHT_GRAY
self.assertEqual(str(ret['LIGHT_YELLOW']), str(ret['LIGHT_GRAY']))

View file

@ -895,17 +895,6 @@ class UtilsTestCase(TestCase):
ret = salt.utils.repack_dictlist(LOREM_IPSUM)
self.assertDictEqual(ret, {})
def test_get_colors(self):
ret = salt.utils.get_colors()
self.assertEqual('\x1b[0;37m', str(ret['LIGHT_GRAY']))
ret = salt.utils.get_colors(use=False)
self.assertDictContainsSubset({'LIGHT_GRAY': ''}, ret)
ret = salt.utils.get_colors(use='LIGHT_GRAY')
# LIGHT_YELLOW now == LIGHT_GRAY
self.assertEqual(str(ret['LIGHT_YELLOW']), str(ret['LIGHT_GRAY']))
@skipIf(NO_MOCK, NO_MOCK_REASON)
def test_daemonize_if(self):
# pylint: disable=assignment-from-none