"""
escape/unescape routines available for backends which need
alphanumeric usernames, services, or other values

Originally provided by the keyring module, these escape utility
routines have been removed from it in version 15.0.0, see
https://github.com/jaraco/keyring/blob/master/CHANGES.rst#1500
"""

import re
import string
import sys
import warnings

warnings.warn(
    "escape is deprecated and will be removed",
    DeprecationWarning,
)

# True if we are running on Python 3.
# taken from six.py
PY3 = sys.version_info[0] == 3

# allow use of unicode literals
if PY3:
    def u(s):
        return s
else:
    def u(s):
        return s.decode('utf-8')

_unichr = chr if PY3 else unichr  # noqa: F821

LEGAL_CHARS = (
    getattr(string, 'letters', None)  # Python 2
    or getattr(string, 'ascii_letters')  # Python 3
) + string.digits

ESCAPE_FMT = "_%02X"


def _escape_char(c):
    "Single char escape. Return the char, escaped if not already legal"
    if isinstance(c, int):
        c = _unichr(c)
    return c if c in LEGAL_CHARS else ESCAPE_FMT % ord(c)


def escape(value):
    """
    Escapes given string so the result consists of alphanumeric chars and
    underscore only.
    """
    return "".join(_escape_char(c) for c in value.encode('utf-8'))


def _unescape_code(regex_match):
    ordinal = int(regex_match.group('code'), 16)
    return bytes([ordinal]) if PY3 else chr(ordinal)


def unescape(value):
    """
    Inverse of escape.
    """
    pattern = ESCAPE_FMT.replace('%02X', '(?P<code>[0-9A-Fa-f]{2})')
    # the pattern must be bytes to operate on bytes
    pattern_bytes = pattern.encode('ascii')
    re_esc = re.compile(pattern_bytes)
    return re_esc.sub(_unescape_code, value.encode('ascii')).decode('utf-8')

"""
escape/unescape routines available for backends which need
alphanumeric usernames, services, or other values

Originally provided by the keyring module, these escape utility
routines have been removed from it in version 15.0.0, see
https://github.com/jaraco/keyring/blob/master/CHANGES.rst#1500
"""

import re
import string
import sys

# True if we are running on Python 3.
# taken from six.py
PY3 = sys.version_info[0] == 3

# allow use of unicode literals
if PY3:
    def u(s):
        return s
else:
    def u(s):
        return s.decode('utf-8')

_unichr = chr if PY3 else unichr  # noqa: F821

LEGAL_CHARS = (
    getattr(string, 'letters', None)  # Python 2
    or getattr(string, 'ascii_letters')  # Python 3
) + string.digits

ESCAPE_FMT = "_%02X"


def _escape_char(c):
    "Single char escape. Return the char, escaped if not already legal"
    if isinstance(c, int):
        c = _unichr(c)
    return c if c in LEGAL_CHARS else ESCAPE_FMT % ord(c)


def escape(value):
    """
    Escapes given string so the result consists of alphanumeric chars and
    underscore only.
    """
    return "".join(_escape_char(c) for c in value.encode('utf-8'))


def _unescape_code(regex_match):
    ordinal = int(regex_match.group('code'), 16)
    return bytes([ordinal]) if PY3 else chr(ordinal)


def unescape(value):
    """
    Inverse of escape.
    """
    pattern = ESCAPE_FMT.replace('%02X', '(?P<code>[0-9A-Fa-f]{2})')
    # the pattern must be bytes to operate on bytes
    pattern_bytes = pattern.encode('ascii')
    re_esc = re.compile(pattern_bytes)
    return re_esc.sub(_unescape_code, value.encode('ascii')).decode('utf-8')

Remove deprecation warning