# Path: s3transfer/compat.py
# MAXINT = None
# 
# Path: s3transfer/exceptions.py
# class RetriesExceededError(Exception):
# class S3UploadFailedError(Exception):
# class InvalidSubscriberMethodError(Exception):
# class TransferNotDoneError(Exception):
# class FatalError(CancelledError):
#     def __init__(self, last_exception, msg='Max Retries Exceeded'):
# 
# Path: s3transfer/utils.py
# class FunctionContainer:
#     """An object that contains a function and any args or kwargs to call it
# 
#     When called the provided function will be called with provided args
#     and kwargs.
#     """
# 
#     def __init__(self, func, *args, **kwargs):
#         self._func = func
#         self._args = args
#         self._kwargs = kwargs
# 
#     def __repr__(self):
#         return 'Function: {} with args {} and kwargs {}'.format(
#             self._func, self._args, self._kwargs
#         )
# 
#     def __call__(self):
#         return self._func(*self._args, **self._kwargs)
# 
# class TaskSemaphore:
#     def __init__(self, count):
#         """A semaphore for the purpose of limiting the number of tasks
# 
#         :param count: The size of semaphore
#         """
#         self._semaphore = threading.Semaphore(count)
# 
#     def acquire(self, tag, blocking=True):
#         """Acquire the semaphore
# 
#         :param tag: A tag identifying what is acquiring the semaphore. Note
#             that this is not really needed to directly use this class but is
#             needed for API compatibility with the SlidingWindowSemaphore
#             implementation.
#         :param block: If True, block until it can be acquired. If False,
#             do not block and raise an exception if cannot be acquired.
# 
#         :returns: A token (can be None) to use when releasing the semaphore
#         """
#         logger.debug("Acquiring %s", tag)
#         if not self._semaphore.acquire(blocking):
#             raise NoResourcesAvailable("Cannot acquire tag '%s'" % tag)
# 
#     def release(self, tag, acquire_token):
#         """Release the semaphore
# 
#         :param tag: A tag identifying what is releasing the semaphore
#         :param acquire_token:  The token returned from when the semaphore was
#             acquired. Note that this is not really needed to directly use this
#             class but is needed for API compatibility with the
#             SlidingWindowSemaphore implementation.
#         """
#         logger.debug(f"Releasing acquire {tag}/{acquire_token}")
#         self._semaphore.release()


import copy
import logging
import sys
import threading
from collections import namedtuple
from concurrent import futures
from s3transfer.compat import MAXINT
from s3transfer.exceptions import CancelledError, TransferNotDoneError
from s3transfer.utils import FunctionContainer, TaskSemaphore
    def __init__(
        self, max_size, max_num_threads, tag_semaphores=None, executor_cls=None
    ):
        """An executor implementation that has a maximum queued up tasks

        The executor will block if the number of tasks that have been
        submitted and is currently working on is past its maximum.

        :params max_size: The maximum number of inflight futures. An inflight
            future means that the task is either queued up or is currently
            being executed. A size of None or 0 means that the executor will
            have no bound in terms of the number of inflight futures.

        :params max_num_threads: The maximum number of threads the executor
            uses.

        :type tag_semaphores: dict
        :params tag_semaphores: A dictionary where the key is the name of the
            tag and the value is the semaphore to use when limiting the
            number of tasks the executor is processing at a time.

        :type executor_cls: BaseExecutor
        :param underlying_executor_cls: The executor class that
            get bounded by this executor. If None is provided, the
            concurrent.futures.ThreadPoolExecutor class is used.
        """
        self._max_num_threads = max_num_threads
        if executor_cls is None:
            executor_cls = self.EXECUTOR_CLS
        self._executor = executor_cls(max_workers=self._max_num_threads)

# Path: s3transfer/compat.py
# MAXINT = None
# 
# Path: s3transfer/exceptions.py
# class RetriesExceededError(Exception):
# class S3UploadFailedError(Exception):
# class InvalidSubscriberMethodError(Exception):
# class TransferNotDoneError(Exception):
# class FatalError(CancelledError):
#     def __init__(self, last_exception, msg='Max Retries Exceeded'):
# 
# Path: s3transfer/utils.py
# class FunctionContainer:
#     """An object that contains a function and any args or kwargs to call it
# 
#     When called the provided function will be called with provided args
#     and kwargs.
#     """
# 
#     def __init__(self, func, *args, **kwargs):
#         self._func = func
#         self._args = args
#         self._kwargs = kwargs
# 
#     def __repr__(self):
#         return 'Function: {} with args {} and kwargs {}'.format(
#             self._func, self._args, self._kwargs
#         )
# 
#     def __call__(self):
#         return self._func(*self._args, **self._kwargs)
# 
# class TaskSemaphore:
#     def __init__(self, count):
#         """A semaphore for the purpose of limiting the number of tasks
# 
#         :param count: The size of semaphore
#         """
#         self._semaphore = threading.Semaphore(count)
# 
#     def acquire(self, tag, blocking=True):
#         """Acquire the semaphore
# 
#         :param tag: A tag identifying what is acquiring the semaphore. Note
#             that this is not really needed to directly use this class but is
#             needed for API compatibility with the SlidingWindowSemaphore
#             implementation.
#         :param block: If True, block until it can be acquired. If False,
#             do not block and raise an exception if cannot be acquired.
# 
#         :returns: A token (can be None) to use when releasing the semaphore
#         """
#         logger.debug("Acquiring %s", tag)
#         if not self._semaphore.acquire(blocking):
#             raise NoResourcesAvailable("Cannot acquire tag '%s'" % tag)
# 
#     def release(self, tag, acquire_token):
#         """Release the semaphore
# 
#         :param tag: A tag identifying what is releasing the semaphore
#         :param acquire_token:  The token returned from when the semaphore was
#             acquired. Note that this is not really needed to directly use this
#             class but is needed for API compatibility with the
#             SlidingWindowSemaphore implementation.
#         """
#         logger.debug(f"Releasing acquire {tag}/{acquire_token}")
#         self._semaphore.release()


# Path: s3transfer/futures.py
import copy
import logging
import sys
import threading
from collections import namedtuple
from concurrent import futures
from s3transfer.compat import MAXINT
from s3transfer.exceptions import CancelledError, TransferNotDoneError
from s3transfer.utils import FunctionContainer, TaskSemaphore

    def __init__(
        self, max_size, max_num_threads, tag_semaphores=None, executor_cls=None
    ):
        """An executor implementation that has a maximum queued up tasks

        The executor will block if the number of tasks that have been
        submitted and is currently working on is past its maximum.

        :params max_size: The maximum number of inflight futures. An inflight
            future means that the task is either queued up or is currently
            being executed. A size of None or 0 means that the executor will
            have no bound in terms of the number of inflight futures.

        :params max_num_threads: The maximum number of threads the executor
            uses.

        :type tag_semaphores: dict
        :params tag_semaphores: A dictionary where the key is the name of the
            tag and the value is the semaphore to use when limiting the
            number of tasks the executor is processing at a time.

        :type executor_cls: BaseExecutor
        :param underlying_executor_cls: The executor class that
            get bounded by this executor. If None is provided, the
            concurrent.futures.ThreadPoolExecutor class is used.
        """
        self._max_num_threads = max_num_threads
        if executor_cls is None:
            executor_cls = self.EXECUTOR_CLS
        self._executor = executor_cls(max_workers=self._max_num_threads)

        self._semaphore = TaskSemaphore(max_size)