Safely pass string values to the CASA tools.

    item
      A value to be passed to a CASA tool.

    In Python 2, the bindings to CASA tasks expect to receive all string values
    as binary data (:class:`str`) and not Unicode. But :mod:`pwkit` often uses
    the ``from __future__ import unicode_literals`` statement to prepare for
    Python 3 compatibility, and other Python modules are getting better about
    using Unicode consistently, so more and more module code ends up using
    Unicode strings in cases where they might get exposed to CASA. Doing so
    will lead to errors.

    This helper function converts Unicode into UTF-8 encoded bytes for
    arguments that you might pass to a CASA tool. It will leave non-strings
    unchanged and recursively transform collections, so you can safely use it
    just about anywhere.

    I usually import this as just ``b`` and write ``tool.method(b(arg))``, in
    analogy with the ``b''`` byte string syntax. This leads to code such as::

      from pwkit.environments.casa.util import tools, sanitize_unicode as b

      tb = tools.table()
      path = u'data.ms'
      tb.open(path) # => raises exception
      tb.open(b(path)) # => works

def sanitize_unicode(item):
    """Safely pass string values to the CASA tools.

    item
      A value to be passed to a CASA tool.

    In Python 2, the bindings to CASA tasks expect to receive all string values
    as binary data (:class:`str`) and not Unicode. But :mod:`pwkit` often uses
    the ``from __future__ import unicode_literals`` statement to prepare for
    Python 3 compatibility, and other Python modules are getting better about
    using Unicode consistently, so more and more module code ends up using
    Unicode strings in cases where they might get exposed to CASA. Doing so
    will lead to errors.

    This helper function converts Unicode into UTF-8 encoded bytes for
    arguments that you might pass to a CASA tool. It will leave non-strings
    unchanged and recursively transform collections, so you can safely use it
    just about anywhere.

    I usually import this as just ``b`` and write ``tool.method(b(arg))``, in
    analogy with the ``b''`` byte string syntax. This leads to code such as::

      from pwkit.environments.casa.util import tools, sanitize_unicode as b

      tb = tools.table()
      path = u'data.ms'
      tb.open(path) # => raises exception
      tb.open(b(path)) # => works

    """
    if isinstance(item, text_type):
        return item.encode('utf8')
    if isinstance(item, dict):
        return dict((sanitize_unicode(k), sanitize_unicode(v)) for k, v in six.iteritems(item))
    if isinstance(item,(list, tuple)):
        return item.__class__(sanitize_unicode(x) for x in item)

    from ...io import Path
    if isinstance(item, Path):
        return str(item)

    return item