# Path: internetarchive/auth.py
# class S3Auth(AuthBase):
#     """Attaches S3 Basic Authentication to the given Request object."""
#     def __init__(self, access_key=None, secret_key=None):
#         self.access_key = access_key
#         self.secret_key = secret_key
# 
#     def __call__(self, r):
#         if not self.access_key:
#             if self.secret_key:
#                 raise AuthenticationError('No access_key set!'
#                                           ' Have you run `ia configure`?')
#         if not self.secret_key:
#             if self.access_key:
#                 raise AuthenticationError('No secret_key set!'
#                                           ' Have you run `ia configure`?')
#             else:
#                 raise AuthenticationError('No access_key or secret_key set!'
#                                           ' Have you run `ia configure`?')
# 
#         auth_str = f'LOW {self.access_key}:{self.secret_key}'
#         r.headers['Authorization'] = auth_str
#         return r


import itertools
from logging import getLogger
from requests.exceptions import ReadTimeout
from internetarchive.auth import S3Auth
            if all(s in j['error'].lower() for s in ['invalid', 'secret']):
                if not j['error'].endswith('.'):
                    j['error'] += '.'
                raise ValueError(f"{j['error']} Try running 'ia configure' and retrying.")
            raise ValueError(j.get('error'))

    def _get_item_from_search_result(self, search_result):
        return self.session.get_item(search_result['identifier'])

    def iter_as_results(self):
        return SearchIterator(self, self._make_results_generator())

    def iter_as_items(self):
        _map = map(self._get_item_from_search_result, self._make_results_generator())
        return SearchIterator(self, _map)

    def __len__(self):
        return self.num_found


class SearchIterator:
    """This class is an iterator wrapper for search results.

    It provides access to the underlying Search, and supports
    len() (since that is known initially)."""

    def __init__(self, search, iterator):
        self.search = search
        self.iterator = iterator


# Path: internetarchive/auth.py
# class S3Auth(AuthBase):
#     """Attaches S3 Basic Authentication to the given Request object."""
#     def __init__(self, access_key=None, secret_key=None):
#         self.access_key = access_key
#         self.secret_key = secret_key
# 
#     def __call__(self, r):
#         if not self.access_key:
#             if self.secret_key:
#                 raise AuthenticationError('No access_key set!'
#                                           ' Have you run `ia configure`?')
#         if not self.secret_key:
#             if self.access_key:
#                 raise AuthenticationError('No secret_key set!'
#                                           ' Have you run `ia configure`?')
#             else:
#                 raise AuthenticationError('No access_key or secret_key set!'
#                                           ' Have you run `ia configure`?')
# 
#         auth_str = f'LOW {self.access_key}:{self.secret_key}'
#         r.headers['Authorization'] = auth_str
#         return r


# Path: internetarchive/search.py
import itertools
from logging import getLogger
from requests.exceptions import ReadTimeout
from internetarchive.auth import S3Auth

            if all(s in j['error'].lower() for s in ['invalid', 'secret']):
                if not j['error'].endswith('.'):
                    j['error'] += '.'
                raise ValueError(f"{j['error']} Try running 'ia configure' and retrying.")
            raise ValueError(j.get('error'))

    def _get_item_from_search_result(self, search_result):
        return self.session.get_item(search_result['identifier'])

    def iter_as_results(self):
        return SearchIterator(self, self._make_results_generator())

    def iter_as_items(self):
        _map = map(self._get_item_from_search_result, self._make_results_generator())
        return SearchIterator(self, _map)

    def __len__(self):
        return self.num_found


class SearchIterator:
    """This class is an iterator wrapper for search results.

    It provides access to the underlying Search, and supports
    len() (since that is known initially)."""

    def __init__(self, search, iterator):
        self.search = search
        self.iterator = iterator


    def __len__(self):