# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/03_util.ipynb.

# %% auto 0
__all__ = ['filtkwds', 'popget', 'classvars', 'getname', 'argname', 'argsname', 'classname', 'unionify', 'opttypes', 'guardtype',
           'qualname']

# %% ../nbs/03_util.ipynb 6
import inspect

# %% ../nbs/03_util.ipynb 8
from types import NoneType, FunctionType
from typing import (
    Self, Type, TypeVar, TypeGuard, TypeAlias, ParamSpec,
    Callable, Iterable, Optional, Protocol, _ProtocolMeta, 
    Any, Set, Dict, List, Tuple, Union, ClassVar, Generic, Literal,
    get_args, get_origin, runtime_checkable, overload, 
)

# %% ../nbs/03_util.ipynb 10
#| export


# %% ../nbs/03_util.ipynb 12
#| export


# %% ../nbs/03_util.ipynb 14
from .cons import ALLATTRS
from ptyp.type import (
    T, P, Types, TypeLike, Guard,
    TGuard, IterT, IterFunc, NanGuard, IterGuard, IterTGuard,
    IterStr, AttrGuards
)

# %% ../nbs/03_util.ipynb 16
def filtkwds(fn: Callable, **kwargs):
    sig = inspect.signature(fn).parameters
    return {k: v for k, v in kwargs.items() if k in sig}

def popget(o, attr: str, default = None, **kwargs):
    return kwargs.pop(attr, getattr(o, attr, default))

def classvars(cls: type, *attrs: str, **kwargs) -> dict:
    return dict((attr, popget(cls, attr, None, **kwargs)) for attr in attrs)

def getname(o: object) -> str: 
    return str(getattr(o, '__name__', o))

def argname(a: T) -> str: 
    return getname((get_args(a) or (a, ))[0])

def argsname(*args) -> str: 
    return ', '.join(list(map(argname, args)))

def classname(cls: type, alt: str = None) -> str:
    if inspect.isclass(alt): return getname(alt)
    if isinstance(alt, str): return alt
    return getname(cls)

def unionify(*t: Types) -> type:
    return None if (l := len(t)) == 0 else t[0] if l == 1 else Union[t[0], *t[1:]]

def opttypes(types: tuple[type], dropnone: bool = True) -> type:
    return types if not dropnone else tuple(Optional[t] for t in types if t is not None)

def guardtype(*types: Types) -> Guard:
    return TypeGuard[unionify(*opttypes(types))]

def qualname(
    cls, *types: Types, prefix: str = '', suffix: str = '', 
    dropnone: bool = True, alt: str = None,
) -> str:
    '''Generates a qualified name for a type or a set of types.'''
    types = opttypes(types, dropnone)
    cname = classname(cls, alt)
    qname = f'{prefix}{{{argsname(*types)}}}{suffix}'    
    qname = f'{cname}({qname})'
    return qname
