# Path: lib/util/str.py
# def bytes_to_str(data):
#     '''
#     Converts `data` to `str`.
# 
#     If data is a `bytes`, it is decoded into `str`.
#     If data is `str`, it is returned as-is.
#     '''
#     assert isinstance(data, (str, bytes)), \
#         'data must be str or bytes: %r' % (data)
#     if isinstance(data, str):
#         # already str, yay
#         return data
#     return data.decode()
# 
# def str_to_bytes(data):
#     '''
#     Converts `data` to `bytes`.
# 
#     If data is a `str`, it is encoded into `bytes`.
#     If data is `bytes`, it is returned as-is.
#     '''
#     assert isinstance(data, (str, bytes)), \
#         'data must be str or bytes: %r' % (data)
#     if isinstance(data, bytes):
#         # already bytes, yay
#         return data
#     return data.encode()
# 
# Path: lib/util/format.py
# def base64_encode(data):
#     '''
#     Encodes the given `data` in base-64. The result will either be a `str`,
#     or `bytes`, depending on the input type (same as input type).
#     '''
#     assert isinstance(data, (str, bytes)), \
#         'data must be str or bytes: %r' % (data)
# 
#     is_str = isinstance(data, str)
#     if is_str:
#         data = str_to_bytes(data)
# 
#     encoded = base64.b64encode(data)
# 
#     if is_str:
#         encoded = bytes_to_str(encoded)
# 
#     return encoded


import hashlib
import hmac
import logging
import os
from ..util.str import (
    bytes_to_str,
    str_to_bytes,
)
from ..util.format import (
    base64_encode,
)
    This is calculated by first generating the HMAC for each item in
    `content` separately, then concatenating them, and finally running another
    HMAC on the concatenated intermediate result. Finally, the result of that
    is base-64 encoded, so it is suitable for use in headers.
    '''
    assert isinstance(hmac_secret, (str, bytes)), \
        'hmac secret must be str or bytes: %r' % (hmac_secret)
    if len(content) == 0:
        raise ValueError('no data supplied')

    hmac_secret = str_to_bytes(hmac_secret)

    content_hmac_digests = map(
        lambda data: _calculate_hmac(
            hmac_secret, data=data, digestmod=digestmod,
        ), content,
    )

    if len(content) > 1:
        # compose individual hmac fragments into one and then hash it again
        concatenated_hmac_digests = b''.join(content_hmac_digests)
        hmac_digest_binary = _calculate_hmac(
            hmac_secret, data=concatenated_hmac_digests, digestmod=digestmod,
        )
    else:
        assert len(content) == 1, \
            '[internal] number of arguments is not 1: %r' % (content)
        hmac_digest_binary = next(content_hmac_digests)

    hmac_digest_bytes = base64_encode(hmac_digest_binary)

# Path: lib/util/str.py
# def bytes_to_str(data):
#     '''
#     Converts `data` to `str`.
# 
#     If data is a `bytes`, it is decoded into `str`.
#     If data is `str`, it is returned as-is.
#     '''
#     assert isinstance(data, (str, bytes)), \
#         'data must be str or bytes: %r' % (data)
#     if isinstance(data, str):
#         # already str, yay
#         return data
#     return data.decode()
# 
# def str_to_bytes(data):
#     '''
#     Converts `data` to `bytes`.
# 
#     If data is a `str`, it is encoded into `bytes`.
#     If data is `bytes`, it is returned as-is.
#     '''
#     assert isinstance(data, (str, bytes)), \
#         'data must be str or bytes: %r' % (data)
#     if isinstance(data, bytes):
#         # already bytes, yay
#         return data
#     return data.encode()
# 
# Path: lib/util/format.py
# def base64_encode(data):
#     '''
#     Encodes the given `data` in base-64. The result will either be a `str`,
#     or `bytes`, depending on the input type (same as input type).
#     '''
#     assert isinstance(data, (str, bytes)), \
#         'data must be str or bytes: %r' % (data)
# 
#     is_str = isinstance(data, str)
#     if is_str:
#         data = str_to_bytes(data)
# 
#     encoded = base64.b64encode(data)
# 
#     if is_str:
#         encoded = bytes_to_str(encoded)
# 
#     return encoded


# Path: lib/util/hmac.py
import hashlib
import hmac
import logging
import os
from ..util.str import (
    bytes_to_str,
    str_to_bytes,
)
from ..util.format import (
    base64_encode,
)

    This is calculated by first generating the HMAC for each item in
    `content` separately, then concatenating them, and finally running another
    HMAC on the concatenated intermediate result. Finally, the result of that
    is base-64 encoded, so it is suitable for use in headers.
    '''
    assert isinstance(hmac_secret, (str, bytes)), \
        'hmac secret must be str or bytes: %r' % (hmac_secret)
    if len(content) == 0:
        raise ValueError('no data supplied')

    hmac_secret = str_to_bytes(hmac_secret)

    content_hmac_digests = map(
        lambda data: _calculate_hmac(
            hmac_secret, data=data, digestmod=digestmod,
        ), content,
    )

    if len(content) > 1:
        # compose individual hmac fragments into one and then hash it again
        concatenated_hmac_digests = b''.join(content_hmac_digests)
        hmac_digest_binary = _calculate_hmac(
            hmac_secret, data=concatenated_hmac_digests, digestmod=digestmod,
        )
    else:
        assert len(content) == 1, \
            '[internal] number of arguments is not 1: %r' % (content)
        hmac_digest_binary = next(content_hmac_digests)

    hmac_digest_bytes = base64_encode(hmac_digest_binary)

    hmac_digest_str = bytes_to_str(hmac_digest_bytes)