# Path: src/werkzeug/_internal.py
# def _check_str_tuple(value: t.Tuple[t.AnyStr, ...]) -> None:
#     """Ensure tuple items are all strings or all bytes."""
#     if not value:
#         return
# 
#     item_type = str if isinstance(value[0], str) else bytes
# 
#     if any(not isinstance(item, item_type) for item in value):
#         raise TypeError(f"Cannot mix str and bytes arguments (got {value!r})")
# 
# Path: src/werkzeug/_internal.py
# def _decode_idna(domain: t.Union[str, bytes]) -> str:
#     # If the input is a string try to encode it to ascii to do the idna
#     # decoding. If that fails because of a unicode error, then we
#     # already have a decoded idna domain.
#     if isinstance(domain, str):
#         try:
#             domain = domain.encode("ascii")
#         except UnicodeError:
#             return domain  # type: ignore
# 
#     # Decode each part separately. If a part fails, try to decode it
#     # with ascii and silently ignore errors. This makes sense because
#     # the idna codec does not have error handling.
#     def decode_part(part: bytes) -> str:
#         try:
#             return part.decode("idna")
#         except UnicodeError:
#             return part.decode("ascii", "ignore")
# 
#     return ".".join(decode_part(p) for p in domain.split(b"."))
# 
# Path: src/werkzeug/_internal.py
# def _encode_idna(domain: str) -> bytes:
#     # If we're given bytes, make sure they fit into ASCII
#     if isinstance(domain, bytes):
#         domain.decode("ascii")
#         return domain
# 
#     # Otherwise check if it's already ascii, then return
#     try:
#         return domain.encode("ascii")
#     except UnicodeError:
#         pass
# 
#     # Otherwise encode each part separately
#     return b".".join(p.encode("idna") for p in domain.split("."))
# 
# Path: src/werkzeug/_internal.py
# @typing.overload
# def _make_encode_wrapper(reference: str) -> t.Callable[[str], str]:
#     ...
# 
# Path: src/werkzeug/_internal.py
# @typing.overload
# def _to_str(  # type: ignore
#     x: None,
#     charset: t.Optional[str] = ...,
#     errors: str = ...,
#     allow_none_charset: bool = ...,
# ) -> None:
#     ...


import codecs
import os
import re
import typing as t
            import ntpath
            import posixpath
from ._internal import _check_str_tuple
from ._internal import _decode_idna
from ._internal import _encode_idna
from ._internal import _make_encode_wrapper
from ._internal import _to_str
    from . import datastructures as ds
    from .datastructures import iter_multi_items
        from .datastructures import MultiDict  # noqa: F811
    from .wsgi import make_chunk_iter
        from .datastructures import MultiDict  # noqa: F811
    .. versionadded:: 0.8
    """
    separator = _to_str(separator, "ascii")
    gen = _url_encode_impl(obj, charset, sort, key)
    if stream is None:
        return gen  # type: ignore
    for idx, chunk in enumerate(gen):
        if idx:
            stream.write(separator)
        stream.write(chunk)
    return None


def url_join(
    base: t.Union[str, t.Tuple[str, str, str, str, str]],
    url: t.Union[str, t.Tuple[str, str, str, str, str]],
    allow_fragments: bool = True,
) -> str:
    """Join a base URL and a possibly relative URL to form an absolute
    interpretation of the latter.

    :param base: the base URL for the join operation.
    :param url: the URL to join.
    :param allow_fragments: indicates whether fragments should be allowed.
    """
    if isinstance(base, tuple):
        base = url_unparse(base)
    if isinstance(url, tuple):
        url = url_unparse(url)


# Path: src/werkzeug/_internal.py
# def _check_str_tuple(value: t.Tuple[t.AnyStr, ...]) -> None:
#     """Ensure tuple items are all strings or all bytes."""
#     if not value:
#         return
# 
#     item_type = str if isinstance(value[0], str) else bytes
# 
#     if any(not isinstance(item, item_type) for item in value):
#         raise TypeError(f"Cannot mix str and bytes arguments (got {value!r})")
# 
# Path: src/werkzeug/_internal.py
# def _decode_idna(domain: t.Union[str, bytes]) -> str:
#     # If the input is a string try to encode it to ascii to do the idna
#     # decoding. If that fails because of a unicode error, then we
#     # already have a decoded idna domain.
#     if isinstance(domain, str):
#         try:
#             domain = domain.encode("ascii")
#         except UnicodeError:
#             return domain  # type: ignore
# 
#     # Decode each part separately. If a part fails, try to decode it
#     # with ascii and silently ignore errors. This makes sense because
#     # the idna codec does not have error handling.
#     def decode_part(part: bytes) -> str:
#         try:
#             return part.decode("idna")
#         except UnicodeError:
#             return part.decode("ascii", "ignore")
# 
#     return ".".join(decode_part(p) for p in domain.split(b"."))
# 
# Path: src/werkzeug/_internal.py
# def _encode_idna(domain: str) -> bytes:
#     # If we're given bytes, make sure they fit into ASCII
#     if isinstance(domain, bytes):
#         domain.decode("ascii")
#         return domain
# 
#     # Otherwise check if it's already ascii, then return
#     try:
#         return domain.encode("ascii")
#     except UnicodeError:
#         pass
# 
#     # Otherwise encode each part separately
#     return b".".join(p.encode("idna") for p in domain.split("."))
# 
# Path: src/werkzeug/_internal.py
# @typing.overload
# def _make_encode_wrapper(reference: str) -> t.Callable[[str], str]:
#     ...
# 
# Path: src/werkzeug/_internal.py
# @typing.overload
# def _to_str(  # type: ignore
#     x: None,
#     charset: t.Optional[str] = ...,
#     errors: str = ...,
#     allow_none_charset: bool = ...,
# ) -> None:
#     ...


# Path: src/werkzeug/urls.py
import codecs
import os
import re
import typing as t
            import ntpath
            import posixpath
from ._internal import _check_str_tuple
from ._internal import _decode_idna
from ._internal import _encode_idna
from ._internal import _make_encode_wrapper
from ._internal import _to_str
    from . import datastructures as ds
    from .datastructures import iter_multi_items
        from .datastructures import MultiDict  # noqa: F811
    from .wsgi import make_chunk_iter
        from .datastructures import MultiDict  # noqa: F811

    .. versionadded:: 0.8
    """
    separator = _to_str(separator, "ascii")
    gen = _url_encode_impl(obj, charset, sort, key)
    if stream is None:
        return gen  # type: ignore
    for idx, chunk in enumerate(gen):
        if idx:
            stream.write(separator)
        stream.write(chunk)
    return None


def url_join(
    base: t.Union[str, t.Tuple[str, str, str, str, str]],
    url: t.Union[str, t.Tuple[str, str, str, str, str]],
    allow_fragments: bool = True,
) -> str:
    """Join a base URL and a possibly relative URL to form an absolute
    interpretation of the latter.

    :param base: the base URL for the join operation.
    :param url: the URL to join.
    :param allow_fragments: indicates whether fragments should be allowed.
    """
    if isinstance(base, tuple):
        base = url_unparse(base)
    if isinstance(url, tuple):
        url = url_unparse(url)


    _check_str_tuple((base, url))