diff options
Diffstat (limited to 'venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco')
8 files changed, 1337 insertions, 0 deletions
| diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/__init__.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/__init__.py diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/__pycache__/__init__.cpython-311.pycBinary files differ new file mode 100644 index 0000000..67aa412 --- /dev/null +++ b/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/__pycache__/__init__.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/__pycache__/context.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/__pycache__/context.cpython-311.pycBinary files differ new file mode 100644 index 0000000..0cb1a60 --- /dev/null +++ b/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/__pycache__/context.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/__pycache__/functools.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/__pycache__/functools.cpython-311.pycBinary files differ new file mode 100644 index 0000000..4682c17 --- /dev/null +++ b/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/__pycache__/functools.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/context.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/context.py new file mode 100644 index 0000000..87a4e3d --- /dev/null +++ b/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/context.py @@ -0,0 +1,213 @@ +import os +import subprocess +import contextlib +import functools +import tempfile +import shutil +import operator + + +@contextlib.contextmanager +def pushd(dir): +    orig = os.getcwd() +    os.chdir(dir) +    try: +        yield dir +    finally: +        os.chdir(orig) + + +@contextlib.contextmanager +def tarball_context(url, target_dir=None, runner=None, pushd=pushd): +    """ +    Get a tarball, extract it, change to that directory, yield, then +    clean up. +    `runner` is the function to invoke commands. +    `pushd` is a context manager for changing the directory. +    """ +    if target_dir is None: +        target_dir = os.path.basename(url).replace('.tar.gz', '').replace('.tgz', '') +    if runner is None: +        runner = functools.partial(subprocess.check_call, shell=True) +    # In the tar command, use --strip-components=1 to strip the first path and +    #  then +    #  use -C to cause the files to be extracted to {target_dir}. This ensures +    #  that we always know where the files were extracted. +    runner('mkdir {target_dir}'.format(**vars())) +    try: +        getter = 'wget {url} -O -' +        extract = 'tar x{compression} --strip-components=1 -C {target_dir}' +        cmd = ' | '.join((getter, extract)) +        runner(cmd.format(compression=infer_compression(url), **vars())) +        with pushd(target_dir): +            yield target_dir +    finally: +        runner('rm -Rf {target_dir}'.format(**vars())) + + +def infer_compression(url): +    """ +    Given a URL or filename, infer the compression code for tar. +    """ +    # cheat and just assume it's the last two characters +    compression_indicator = url[-2:] +    mapping = dict(gz='z', bz='j', xz='J') +    # Assume 'z' (gzip) if no match +    return mapping.get(compression_indicator, 'z') + + +@contextlib.contextmanager +def temp_dir(remover=shutil.rmtree): +    """ +    Create a temporary directory context. Pass a custom remover +    to override the removal behavior. +    """ +    temp_dir = tempfile.mkdtemp() +    try: +        yield temp_dir +    finally: +        remover(temp_dir) + + +@contextlib.contextmanager +def repo_context(url, branch=None, quiet=True, dest_ctx=temp_dir): +    """ +    Check out the repo indicated by url. + +    If dest_ctx is supplied, it should be a context manager +    to yield the target directory for the check out. +    """ +    exe = 'git' if 'git' in url else 'hg' +    with dest_ctx() as repo_dir: +        cmd = [exe, 'clone', url, repo_dir] +        if branch: +            cmd.extend(['--branch', branch]) +        devnull = open(os.path.devnull, 'w') +        stdout = devnull if quiet else None +        subprocess.check_call(cmd, stdout=stdout) +        yield repo_dir + + +@contextlib.contextmanager +def null(): +    yield + + +class ExceptionTrap: +    """ +    A context manager that will catch certain exceptions and provide an +    indication they occurred. + +    >>> with ExceptionTrap() as trap: +    ...     raise Exception() +    >>> bool(trap) +    True + +    >>> with ExceptionTrap() as trap: +    ...     pass +    >>> bool(trap) +    False + +    >>> with ExceptionTrap(ValueError) as trap: +    ...     raise ValueError("1 + 1 is not 3") +    >>> bool(trap) +    True + +    >>> with ExceptionTrap(ValueError) as trap: +    ...     raise Exception() +    Traceback (most recent call last): +    ... +    Exception + +    >>> bool(trap) +    False +    """ + +    exc_info = None, None, None + +    def __init__(self, exceptions=(Exception,)): +        self.exceptions = exceptions + +    def __enter__(self): +        return self + +    @property +    def type(self): +        return self.exc_info[0] + +    @property +    def value(self): +        return self.exc_info[1] + +    @property +    def tb(self): +        return self.exc_info[2] + +    def __exit__(self, *exc_info): +        type = exc_info[0] +        matches = type and issubclass(type, self.exceptions) +        if matches: +            self.exc_info = exc_info +        return matches + +    def __bool__(self): +        return bool(self.type) + +    def raises(self, func, *, _test=bool): +        """ +        Wrap func and replace the result with the truth +        value of the trap (True if an exception occurred). + +        First, give the decorator an alias to support Python 3.8 +        Syntax. + +        >>> raises = ExceptionTrap(ValueError).raises + +        Now decorate a function that always fails. + +        >>> @raises +        ... def fail(): +        ...     raise ValueError('failed') +        >>> fail() +        True +        """ + +        @functools.wraps(func) +        def wrapper(*args, **kwargs): +            with ExceptionTrap(self.exceptions) as trap: +                func(*args, **kwargs) +            return _test(trap) + +        return wrapper + +    def passes(self, func): +        """ +        Wrap func and replace the result with the truth +        value of the trap (True if no exception). + +        First, give the decorator an alias to support Python 3.8 +        Syntax. + +        >>> passes = ExceptionTrap(ValueError).passes + +        Now decorate a function that always fails. + +        >>> @passes +        ... def fail(): +        ...     raise ValueError('failed') + +        >>> fail() +        False +        """ +        return self.raises(func, _test=operator.not_) + + +class suppress(contextlib.suppress, contextlib.ContextDecorator): +    """ +    A version of contextlib.suppress with decorator support. + +    >>> @suppress(KeyError) +    ... def key_error(): +    ...     {}[''] +    >>> key_error() +    """ diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/functools.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/functools.py new file mode 100644 index 0000000..bbd8b29 --- /dev/null +++ b/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/functools.py @@ -0,0 +1,525 @@ +import functools +import time +import inspect +import collections +import types +import itertools + +import setuptools.extern.more_itertools + +from typing import Callable, TypeVar + + +CallableT = TypeVar("CallableT", bound=Callable[..., object]) + + +def compose(*funcs): +    """ +    Compose any number of unary functions into a single unary function. + +    >>> import textwrap +    >>> expected = str.strip(textwrap.dedent(compose.__doc__)) +    >>> strip_and_dedent = compose(str.strip, textwrap.dedent) +    >>> strip_and_dedent(compose.__doc__) == expected +    True + +    Compose also allows the innermost function to take arbitrary arguments. + +    >>> round_three = lambda x: round(x, ndigits=3) +    >>> f = compose(round_three, int.__truediv__) +    >>> [f(3*x, x+1) for x in range(1,10)] +    [1.5, 2.0, 2.25, 2.4, 2.5, 2.571, 2.625, 2.667, 2.7] +    """ + +    def compose_two(f1, f2): +        return lambda *args, **kwargs: f1(f2(*args, **kwargs)) + +    return functools.reduce(compose_two, funcs) + + +def method_caller(method_name, *args, **kwargs): +    """ +    Return a function that will call a named method on the +    target object with optional positional and keyword +    arguments. + +    >>> lower = method_caller('lower') +    >>> lower('MyString') +    'mystring' +    """ + +    def call_method(target): +        func = getattr(target, method_name) +        return func(*args, **kwargs) + +    return call_method + + +def once(func): +    """ +    Decorate func so it's only ever called the first time. + +    This decorator can ensure that an expensive or non-idempotent function +    will not be expensive on subsequent calls and is idempotent. + +    >>> add_three = once(lambda a: a+3) +    >>> add_three(3) +    6 +    >>> add_three(9) +    6 +    >>> add_three('12') +    6 + +    To reset the stored value, simply clear the property ``saved_result``. + +    >>> del add_three.saved_result +    >>> add_three(9) +    12 +    >>> add_three(8) +    12 + +    Or invoke 'reset()' on it. + +    >>> add_three.reset() +    >>> add_three(-3) +    0 +    >>> add_three(0) +    0 +    """ + +    @functools.wraps(func) +    def wrapper(*args, **kwargs): +        if not hasattr(wrapper, 'saved_result'): +            wrapper.saved_result = func(*args, **kwargs) +        return wrapper.saved_result + +    wrapper.reset = lambda: vars(wrapper).__delitem__('saved_result') +    return wrapper + + +def method_cache( +    method: CallableT, +    cache_wrapper: Callable[ +        [CallableT], CallableT +    ] = functools.lru_cache(),  # type: ignore[assignment] +) -> CallableT: +    """ +    Wrap lru_cache to support storing the cache data in the object instances. + +    Abstracts the common paradigm where the method explicitly saves an +    underscore-prefixed protected property on first call and returns that +    subsequently. + +    >>> class MyClass: +    ...     calls = 0 +    ... +    ...     @method_cache +    ...     def method(self, value): +    ...         self.calls += 1 +    ...         return value + +    >>> a = MyClass() +    >>> a.method(3) +    3 +    >>> for x in range(75): +    ...     res = a.method(x) +    >>> a.calls +    75 + +    Note that the apparent behavior will be exactly like that of lru_cache +    except that the cache is stored on each instance, so values in one +    instance will not flush values from another, and when an instance is +    deleted, so are the cached values for that instance. + +    >>> b = MyClass() +    >>> for x in range(35): +    ...     res = b.method(x) +    >>> b.calls +    35 +    >>> a.method(0) +    0 +    >>> a.calls +    75 + +    Note that if method had been decorated with ``functools.lru_cache()``, +    a.calls would have been 76 (due to the cached value of 0 having been +    flushed by the 'b' instance). + +    Clear the cache with ``.cache_clear()`` + +    >>> a.method.cache_clear() + +    Same for a method that hasn't yet been called. + +    >>> c = MyClass() +    >>> c.method.cache_clear() + +    Another cache wrapper may be supplied: + +    >>> cache = functools.lru_cache(maxsize=2) +    >>> MyClass.method2 = method_cache(lambda self: 3, cache_wrapper=cache) +    >>> a = MyClass() +    >>> a.method2() +    3 + +    Caution - do not subsequently wrap the method with another decorator, such +    as ``@property``, which changes the semantics of the function. + +    See also +    http://code.activestate.com/recipes/577452-a-memoize-decorator-for-instance-methods/ +    for another implementation and additional justification. +    """ + +    def wrapper(self: object, *args: object, **kwargs: object) -> object: +        # it's the first call, replace the method with a cached, bound method +        bound_method: CallableT = types.MethodType(  # type: ignore[assignment] +            method, self +        ) +        cached_method = cache_wrapper(bound_method) +        setattr(self, method.__name__, cached_method) +        return cached_method(*args, **kwargs) + +    # Support cache clear even before cache has been created. +    wrapper.cache_clear = lambda: None  # type: ignore[attr-defined] + +    return (  # type: ignore[return-value] +        _special_method_cache(method, cache_wrapper) or wrapper +    ) + + +def _special_method_cache(method, cache_wrapper): +    """ +    Because Python treats special methods differently, it's not +    possible to use instance attributes to implement the cached +    methods. + +    Instead, install the wrapper method under a different name +    and return a simple proxy to that wrapper. + +    https://github.com/jaraco/jaraco.functools/issues/5 +    """ +    name = method.__name__ +    special_names = '__getattr__', '__getitem__' +    if name not in special_names: +        return + +    wrapper_name = '__cached' + name + +    def proxy(self, *args, **kwargs): +        if wrapper_name not in vars(self): +            bound = types.MethodType(method, self) +            cache = cache_wrapper(bound) +            setattr(self, wrapper_name, cache) +        else: +            cache = getattr(self, wrapper_name) +        return cache(*args, **kwargs) + +    return proxy + + +def apply(transform): +    """ +    Decorate a function with a transform function that is +    invoked on results returned from the decorated function. + +    >>> @apply(reversed) +    ... def get_numbers(start): +    ...     "doc for get_numbers" +    ...     return range(start, start+3) +    >>> list(get_numbers(4)) +    [6, 5, 4] +    >>> get_numbers.__doc__ +    'doc for get_numbers' +    """ + +    def wrap(func): +        return functools.wraps(func)(compose(transform, func)) + +    return wrap + + +def result_invoke(action): +    r""" +    Decorate a function with an action function that is +    invoked on the results returned from the decorated +    function (for its side-effect), then return the original +    result. + +    >>> @result_invoke(print) +    ... def add_two(a, b): +    ...     return a + b +    >>> x = add_two(2, 3) +    5 +    >>> x +    5 +    """ + +    def wrap(func): +        @functools.wraps(func) +        def wrapper(*args, **kwargs): +            result = func(*args, **kwargs) +            action(result) +            return result + +        return wrapper + +    return wrap + + +def call_aside(f, *args, **kwargs): +    """ +    Call a function for its side effect after initialization. + +    >>> @call_aside +    ... def func(): print("called") +    called +    >>> func() +    called + +    Use functools.partial to pass parameters to the initial call + +    >>> @functools.partial(call_aside, name='bingo') +    ... def func(name): print("called with", name) +    called with bingo +    """ +    f(*args, **kwargs) +    return f + + +class Throttler: +    """ +    Rate-limit a function (or other callable) +    """ + +    def __init__(self, func, max_rate=float('Inf')): +        if isinstance(func, Throttler): +            func = func.func +        self.func = func +        self.max_rate = max_rate +        self.reset() + +    def reset(self): +        self.last_called = 0 + +    def __call__(self, *args, **kwargs): +        self._wait() +        return self.func(*args, **kwargs) + +    def _wait(self): +        "ensure at least 1/max_rate seconds from last call" +        elapsed = time.time() - self.last_called +        must_wait = 1 / self.max_rate - elapsed +        time.sleep(max(0, must_wait)) +        self.last_called = time.time() + +    def __get__(self, obj, type=None): +        return first_invoke(self._wait, functools.partial(self.func, obj)) + + +def first_invoke(func1, func2): +    """ +    Return a function that when invoked will invoke func1 without +    any parameters (for its side-effect) and then invoke func2 +    with whatever parameters were passed, returning its result. +    """ + +    def wrapper(*args, **kwargs): +        func1() +        return func2(*args, **kwargs) + +    return wrapper + + +def retry_call(func, cleanup=lambda: None, retries=0, trap=()): +    """ +    Given a callable func, trap the indicated exceptions +    for up to 'retries' times, invoking cleanup on the +    exception. On the final attempt, allow any exceptions +    to propagate. +    """ +    attempts = itertools.count() if retries == float('inf') else range(retries) +    for attempt in attempts: +        try: +            return func() +        except trap: +            cleanup() + +    return func() + + +def retry(*r_args, **r_kwargs): +    """ +    Decorator wrapper for retry_call. Accepts arguments to retry_call +    except func and then returns a decorator for the decorated function. + +    Ex: + +    >>> @retry(retries=3) +    ... def my_func(a, b): +    ...     "this is my funk" +    ...     print(a, b) +    >>> my_func.__doc__ +    'this is my funk' +    """ + +    def decorate(func): +        @functools.wraps(func) +        def wrapper(*f_args, **f_kwargs): +            bound = functools.partial(func, *f_args, **f_kwargs) +            return retry_call(bound, *r_args, **r_kwargs) + +        return wrapper + +    return decorate + + +def print_yielded(func): +    """ +    Convert a generator into a function that prints all yielded elements + +    >>> @print_yielded +    ... def x(): +    ...     yield 3; yield None +    >>> x() +    3 +    None +    """ +    print_all = functools.partial(map, print) +    print_results = compose(more_itertools.consume, print_all, func) +    return functools.wraps(func)(print_results) + + +def pass_none(func): +    """ +    Wrap func so it's not called if its first param is None + +    >>> print_text = pass_none(print) +    >>> print_text('text') +    text +    >>> print_text(None) +    """ + +    @functools.wraps(func) +    def wrapper(param, *args, **kwargs): +        if param is not None: +            return func(param, *args, **kwargs) + +    return wrapper + + +def assign_params(func, namespace): +    """ +    Assign parameters from namespace where func solicits. + +    >>> def func(x, y=3): +    ...     print(x, y) +    >>> assigned = assign_params(func, dict(x=2, z=4)) +    >>> assigned() +    2 3 + +    The usual errors are raised if a function doesn't receive +    its required parameters: + +    >>> assigned = assign_params(func, dict(y=3, z=4)) +    >>> assigned() +    Traceback (most recent call last): +    TypeError: func() ...argument... + +    It even works on methods: + +    >>> class Handler: +    ...     def meth(self, arg): +    ...         print(arg) +    >>> assign_params(Handler().meth, dict(arg='crystal', foo='clear'))() +    crystal +    """ +    sig = inspect.signature(func) +    params = sig.parameters.keys() +    call_ns = {k: namespace[k] for k in params if k in namespace} +    return functools.partial(func, **call_ns) + + +def save_method_args(method): +    """ +    Wrap a method such that when it is called, the args and kwargs are +    saved on the method. + +    >>> class MyClass: +    ...     @save_method_args +    ...     def method(self, a, b): +    ...         print(a, b) +    >>> my_ob = MyClass() +    >>> my_ob.method(1, 2) +    1 2 +    >>> my_ob._saved_method.args +    (1, 2) +    >>> my_ob._saved_method.kwargs +    {} +    >>> my_ob.method(a=3, b='foo') +    3 foo +    >>> my_ob._saved_method.args +    () +    >>> my_ob._saved_method.kwargs == dict(a=3, b='foo') +    True + +    The arguments are stored on the instance, allowing for +    different instance to save different args. + +    >>> your_ob = MyClass() +    >>> your_ob.method({str('x'): 3}, b=[4]) +    {'x': 3} [4] +    >>> your_ob._saved_method.args +    ({'x': 3},) +    >>> my_ob._saved_method.args +    () +    """ +    args_and_kwargs = collections.namedtuple('args_and_kwargs', 'args kwargs') + +    @functools.wraps(method) +    def wrapper(self, *args, **kwargs): +        attr_name = '_saved_' + method.__name__ +        attr = args_and_kwargs(args, kwargs) +        setattr(self, attr_name, attr) +        return method(self, *args, **kwargs) + +    return wrapper + + +def except_(*exceptions, replace=None, use=None): +    """ +    Replace the indicated exceptions, if raised, with the indicated +    literal replacement or evaluated expression (if present). + +    >>> safe_int = except_(ValueError)(int) +    >>> safe_int('five') +    >>> safe_int('5') +    5 + +    Specify a literal replacement with ``replace``. + +    >>> safe_int_r = except_(ValueError, replace=0)(int) +    >>> safe_int_r('five') +    0 + +    Provide an expression to ``use`` to pass through particular parameters. + +    >>> safe_int_pt = except_(ValueError, use='args[0]')(int) +    >>> safe_int_pt('five') +    'five' + +    """ + +    def decorate(func): +        @functools.wraps(func) +        def wrapper(*args, **kwargs): +            try: +                return func(*args, **kwargs) +            except exceptions: +                try: +                    return eval(use) +                except TypeError: +                    return replace + +        return wrapper + +    return decorate diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/text/__init__.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/text/__init__.py new file mode 100644 index 0000000..a0306d5 --- /dev/null +++ b/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/text/__init__.py @@ -0,0 +1,599 @@ +import re +import itertools +import textwrap +import functools + +try: +    from importlib.resources import files  # type: ignore +except ImportError:  # pragma: nocover +    from setuptools.extern.importlib_resources import files  # type: ignore + +from setuptools.extern.jaraco.functools import compose, method_cache +from setuptools.extern.jaraco.context import ExceptionTrap + + +def substitution(old, new): +    """ +    Return a function that will perform a substitution on a string +    """ +    return lambda s: s.replace(old, new) + + +def multi_substitution(*substitutions): +    """ +    Take a sequence of pairs specifying substitutions, and create +    a function that performs those substitutions. + +    >>> multi_substitution(('foo', 'bar'), ('bar', 'baz'))('foo') +    'baz' +    """ +    substitutions = itertools.starmap(substitution, substitutions) +    # compose function applies last function first, so reverse the +    #  substitutions to get the expected order. +    substitutions = reversed(tuple(substitutions)) +    return compose(*substitutions) + + +class FoldedCase(str): +    """ +    A case insensitive string class; behaves just like str +    except compares equal when the only variation is case. + +    >>> s = FoldedCase('hello world') + +    >>> s == 'Hello World' +    True + +    >>> 'Hello World' == s +    True + +    >>> s != 'Hello World' +    False + +    >>> s.index('O') +    4 + +    >>> s.split('O') +    ['hell', ' w', 'rld'] + +    >>> sorted(map(FoldedCase, ['GAMMA', 'alpha', 'Beta'])) +    ['alpha', 'Beta', 'GAMMA'] + +    Sequence membership is straightforward. + +    >>> "Hello World" in [s] +    True +    >>> s in ["Hello World"] +    True + +    You may test for set inclusion, but candidate and elements +    must both be folded. + +    >>> FoldedCase("Hello World") in {s} +    True +    >>> s in {FoldedCase("Hello World")} +    True + +    String inclusion works as long as the FoldedCase object +    is on the right. + +    >>> "hello" in FoldedCase("Hello World") +    True + +    But not if the FoldedCase object is on the left: + +    >>> FoldedCase('hello') in 'Hello World' +    False + +    In that case, use ``in_``: + +    >>> FoldedCase('hello').in_('Hello World') +    True + +    >>> FoldedCase('hello') > FoldedCase('Hello') +    False +    """ + +    def __lt__(self, other): +        return self.lower() < other.lower() + +    def __gt__(self, other): +        return self.lower() > other.lower() + +    def __eq__(self, other): +        return self.lower() == other.lower() + +    def __ne__(self, other): +        return self.lower() != other.lower() + +    def __hash__(self): +        return hash(self.lower()) + +    def __contains__(self, other): +        return super().lower().__contains__(other.lower()) + +    def in_(self, other): +        "Does self appear in other?" +        return self in FoldedCase(other) + +    # cache lower since it's likely to be called frequently. +    @method_cache +    def lower(self): +        return super().lower() + +    def index(self, sub): +        return self.lower().index(sub.lower()) + +    def split(self, splitter=' ', maxsplit=0): +        pattern = re.compile(re.escape(splitter), re.I) +        return pattern.split(self, maxsplit) + + +# Python 3.8 compatibility +_unicode_trap = ExceptionTrap(UnicodeDecodeError) + + +@_unicode_trap.passes +def is_decodable(value): +    r""" +    Return True if the supplied value is decodable (using the default +    encoding). + +    >>> is_decodable(b'\xff') +    False +    >>> is_decodable(b'\x32') +    True +    """ +    value.decode() + + +def is_binary(value): +    r""" +    Return True if the value appears to be binary (that is, it's a byte +    string and isn't decodable). + +    >>> is_binary(b'\xff') +    True +    >>> is_binary('\xff') +    False +    """ +    return isinstance(value, bytes) and not is_decodable(value) + + +def trim(s): +    r""" +    Trim something like a docstring to remove the whitespace that +    is common due to indentation and formatting. + +    >>> trim("\n\tfoo = bar\n\t\tbar = baz\n") +    'foo = bar\n\tbar = baz' +    """ +    return textwrap.dedent(s).strip() + + +def wrap(s): +    """ +    Wrap lines of text, retaining existing newlines as +    paragraph markers. + +    >>> print(wrap(lorem_ipsum)) +    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do +    eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad +    minim veniam, quis nostrud exercitation ullamco laboris nisi ut +    aliquip ex ea commodo consequat. Duis aute irure dolor in +    reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla +    pariatur. Excepteur sint occaecat cupidatat non proident, sunt in +    culpa qui officia deserunt mollit anim id est laborum. +    <BLANKLINE> +    Curabitur pretium tincidunt lacus. Nulla gravida orci a odio. Nullam +    varius, turpis et commodo pharetra, est eros bibendum elit, nec luctus +    magna felis sollicitudin mauris. Integer in mauris eu nibh euismod +    gravida. Duis ac tellus et risus vulputate vehicula. Donec lobortis +    risus a elit. Etiam tempor. Ut ullamcorper, ligula eu tempor congue, +    eros est euismod turpis, id tincidunt sapien risus a quam. Maecenas +    fermentum consequat mi. Donec fermentum. Pellentesque malesuada nulla +    a mi. Duis sapien sem, aliquet nec, commodo eget, consequat quis, +    neque. Aliquam faucibus, elit ut dictum aliquet, felis nisl adipiscing +    sapien, sed malesuada diam lacus eget erat. Cras mollis scelerisque +    nunc. Nullam arcu. Aliquam consequat. Curabitur augue lorem, dapibus +    quis, laoreet et, pretium ac, nisi. Aenean magna nisl, mollis quis, +    molestie eu, feugiat in, orci. In hac habitasse platea dictumst. +    """ +    paragraphs = s.splitlines() +    wrapped = ('\n'.join(textwrap.wrap(para)) for para in paragraphs) +    return '\n\n'.join(wrapped) + + +def unwrap(s): +    r""" +    Given a multi-line string, return an unwrapped version. + +    >>> wrapped = wrap(lorem_ipsum) +    >>> wrapped.count('\n') +    20 +    >>> unwrapped = unwrap(wrapped) +    >>> unwrapped.count('\n') +    1 +    >>> print(unwrapped) +    Lorem ipsum dolor sit amet, consectetur adipiscing ... +    Curabitur pretium tincidunt lacus. Nulla gravida orci ... + +    """ +    paragraphs = re.split(r'\n\n+', s) +    cleaned = (para.replace('\n', ' ') for para in paragraphs) +    return '\n'.join(cleaned) + + + + +class Splitter(object): +    """object that will split a string with the given arguments for each call + +    >>> s = Splitter(',') +    >>> s('hello, world, this is your, master calling') +    ['hello', ' world', ' this is your', ' master calling'] +    """ + +    def __init__(self, *args): +        self.args = args + +    def __call__(self, s): +        return s.split(*self.args) + + +def indent(string, prefix=' ' * 4): +    """ +    >>> indent('foo') +    '    foo' +    """ +    return prefix + string + + +class WordSet(tuple): +    """ +    Given an identifier, return the words that identifier represents, +    whether in camel case, underscore-separated, etc. + +    >>> WordSet.parse("camelCase") +    ('camel', 'Case') + +    >>> WordSet.parse("under_sep") +    ('under', 'sep') + +    Acronyms should be retained + +    >>> WordSet.parse("firstSNL") +    ('first', 'SNL') + +    >>> WordSet.parse("you_and_I") +    ('you', 'and', 'I') + +    >>> WordSet.parse("A simple test") +    ('A', 'simple', 'test') + +    Multiple caps should not interfere with the first cap of another word. + +    >>> WordSet.parse("myABCClass") +    ('my', 'ABC', 'Class') + +    The result is a WordSet, so you can get the form you need. + +    >>> WordSet.parse("myABCClass").underscore_separated() +    'my_ABC_Class' + +    >>> WordSet.parse('a-command').camel_case() +    'ACommand' + +    >>> WordSet.parse('someIdentifier').lowered().space_separated() +    'some identifier' + +    Slices of the result should return another WordSet. + +    >>> WordSet.parse('taken-out-of-context')[1:].underscore_separated() +    'out_of_context' + +    >>> WordSet.from_class_name(WordSet()).lowered().space_separated() +    'word set' + +    >>> example = WordSet.parse('figured it out') +    >>> example.headless_camel_case() +    'figuredItOut' +    >>> example.dash_separated() +    'figured-it-out' + +    """ + +    _pattern = re.compile('([A-Z]?[a-z]+)|([A-Z]+(?![a-z]))') + +    def capitalized(self): +        return WordSet(word.capitalize() for word in self) + +    def lowered(self): +        return WordSet(word.lower() for word in self) + +    def camel_case(self): +        return ''.join(self.capitalized()) + +    def headless_camel_case(self): +        words = iter(self) +        first = next(words).lower() +        new_words = itertools.chain((first,), WordSet(words).camel_case()) +        return ''.join(new_words) + +    def underscore_separated(self): +        return '_'.join(self) + +    def dash_separated(self): +        return '-'.join(self) + +    def space_separated(self): +        return ' '.join(self) + +    def trim_right(self, item): +        """ +        Remove the item from the end of the set. + +        >>> WordSet.parse('foo bar').trim_right('foo') +        ('foo', 'bar') +        >>> WordSet.parse('foo bar').trim_right('bar') +        ('foo',) +        >>> WordSet.parse('').trim_right('bar') +        () +        """ +        return self[:-1] if self and self[-1] == item else self + +    def trim_left(self, item): +        """ +        Remove the item from the beginning of the set. + +        >>> WordSet.parse('foo bar').trim_left('foo') +        ('bar',) +        >>> WordSet.parse('foo bar').trim_left('bar') +        ('foo', 'bar') +        >>> WordSet.parse('').trim_left('bar') +        () +        """ +        return self[1:] if self and self[0] == item else self + +    def trim(self, item): +        """ +        >>> WordSet.parse('foo bar').trim('foo') +        ('bar',) +        """ +        return self.trim_left(item).trim_right(item) + +    def __getitem__(self, item): +        result = super(WordSet, self).__getitem__(item) +        if isinstance(item, slice): +            result = WordSet(result) +        return result + +    @classmethod +    def parse(cls, identifier): +        matches = cls._pattern.finditer(identifier) +        return WordSet(match.group(0) for match in matches) + +    @classmethod +    def from_class_name(cls, subject): +        return cls.parse(subject.__class__.__name__) + + +# for backward compatibility +words = WordSet.parse + + +def simple_html_strip(s): +    r""" +    Remove HTML from the string `s`. + +    >>> str(simple_html_strip('')) +    '' + +    >>> print(simple_html_strip('A <bold>stormy</bold> day in paradise')) +    A stormy day in paradise + +    >>> print(simple_html_strip('Somebody <!-- do not --> tell the truth.')) +    Somebody  tell the truth. + +    >>> print(simple_html_strip('What about<br/>\nmultiple lines?')) +    What about +    multiple lines? +    """ +    html_stripper = re.compile('(<!--.*?-->)|(<[^>]*>)|([^<]+)', re.DOTALL) +    texts = (match.group(3) or '' for match in html_stripper.finditer(s)) +    return ''.join(texts) + + +class SeparatedValues(str): +    """ +    A string separated by a separator. Overrides __iter__ for getting +    the values. + +    >>> list(SeparatedValues('a,b,c')) +    ['a', 'b', 'c'] + +    Whitespace is stripped and empty values are discarded. + +    >>> list(SeparatedValues(' a,   b   , c,  ')) +    ['a', 'b', 'c'] +    """ + +    separator = ',' + +    def __iter__(self): +        parts = self.split(self.separator) +        return filter(None, (part.strip() for part in parts)) + + +class Stripper: +    r""" +    Given a series of lines, find the common prefix and strip it from them. + +    >>> lines = [ +    ...     'abcdefg\n', +    ...     'abc\n', +    ...     'abcde\n', +    ... ] +    >>> res = Stripper.strip_prefix(lines) +    >>> res.prefix +    'abc' +    >>> list(res.lines) +    ['defg\n', '\n', 'de\n'] + +    If no prefix is common, nothing should be stripped. + +    >>> lines = [ +    ...     'abcd\n', +    ...     '1234\n', +    ... ] +    >>> res = Stripper.strip_prefix(lines) +    >>> res.prefix = '' +    >>> list(res.lines) +    ['abcd\n', '1234\n'] +    """ + +    def __init__(self, prefix, lines): +        self.prefix = prefix +        self.lines = map(self, lines) + +    @classmethod +    def strip_prefix(cls, lines): +        prefix_lines, lines = itertools.tee(lines) +        prefix = functools.reduce(cls.common_prefix, prefix_lines) +        return cls(prefix, lines) + +    def __call__(self, line): +        if not self.prefix: +            return line +        null, prefix, rest = line.partition(self.prefix) +        return rest + +    @staticmethod +    def common_prefix(s1, s2): +        """ +        Return the common prefix of two lines. +        """ +        index = min(len(s1), len(s2)) +        while s1[:index] != s2[:index]: +            index -= 1 +        return s1[:index] + + +def remove_prefix(text, prefix): +    """ +    Remove the prefix from the text if it exists. + +    >>> remove_prefix('underwhelming performance', 'underwhelming ') +    'performance' + +    >>> remove_prefix('something special', 'sample') +    'something special' +    """ +    null, prefix, rest = text.rpartition(prefix) +    return rest + + +def remove_suffix(text, suffix): +    """ +    Remove the suffix from the text if it exists. + +    >>> remove_suffix('name.git', '.git') +    'name' + +    >>> remove_suffix('something special', 'sample') +    'something special' +    """ +    rest, suffix, null = text.partition(suffix) +    return rest + + +def normalize_newlines(text): +    r""" +    Replace alternate newlines with the canonical newline. + +    >>> normalize_newlines('Lorem Ipsum\u2029') +    'Lorem Ipsum\n' +    >>> normalize_newlines('Lorem Ipsum\r\n') +    'Lorem Ipsum\n' +    >>> normalize_newlines('Lorem Ipsum\x85') +    'Lorem Ipsum\n' +    """ +    newlines = ['\r\n', '\r', '\n', '\u0085', '\u2028', '\u2029'] +    pattern = '|'.join(newlines) +    return re.sub(pattern, '\n', text) + + +def _nonblank(str): +    return str and not str.startswith('#') + + +@functools.singledispatch +def yield_lines(iterable): +    r""" +    Yield valid lines of a string or iterable. + +    >>> list(yield_lines('')) +    [] +    >>> list(yield_lines(['foo', 'bar'])) +    ['foo', 'bar'] +    >>> list(yield_lines('foo\nbar')) +    ['foo', 'bar'] +    >>> list(yield_lines('\nfoo\n#bar\nbaz #comment')) +    ['foo', 'baz #comment'] +    >>> list(yield_lines(['foo\nbar', 'baz', 'bing\n\n\n'])) +    ['foo', 'bar', 'baz', 'bing'] +    """ +    return itertools.chain.from_iterable(map(yield_lines, iterable)) + + +@yield_lines.register(str) +def _(text): +    return filter(_nonblank, map(str.strip, text.splitlines())) + + +def drop_comment(line): +    """ +    Drop comments. + +    >>> drop_comment('foo # bar') +    'foo' + +    A hash without a space may be in a URL. + +    >>> drop_comment('http://example.com/foo#bar') +    'http://example.com/foo#bar' +    """ +    return line.partition(' #')[0] + + +def join_continuation(lines): +    r""" +    Join lines continued by a trailing backslash. + +    >>> list(join_continuation(['foo \\', 'bar', 'baz'])) +    ['foobar', 'baz'] +    >>> list(join_continuation(['foo \\', 'bar', 'baz'])) +    ['foobar', 'baz'] +    >>> list(join_continuation(['foo \\', 'bar \\', 'baz'])) +    ['foobarbaz'] + +    Not sure why, but... +    The character preceeding the backslash is also elided. + +    >>> list(join_continuation(['goo\\', 'dly'])) +    ['godly'] + +    A terrible idea, but... +    If no line is available to continue, suppress the lines. + +    >>> list(join_continuation(['foo', 'bar\\', 'baz\\'])) +    ['foo'] +    """ +    lines = iter(lines) +    for item in lines: +        while item.endswith('\\'): +            try: +                item = item[:-2].strip() + next(lines) +            except StopIteration: +                return +        yield item diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/text/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/text/__pycache__/__init__.cpython-311.pycBinary files differ new file mode 100644 index 0000000..1303ba4 --- /dev/null +++ b/venv/lib/python3.11/site-packages/setuptools/_vendor/jaraco/text/__pycache__/__init__.cpython-311.pyc | 
