"""

CSV parsing and writing.

This module provides classes that assist in the reading and writing
of Comma Separated Value (CSV) files, and implements the interface
described by PEP 305.  Although many CSV files are simple to parse,
the format is not formally defined by a stable specification and
is subtle enough that parsing lines of a CSV file with something
like line.split(",") is bound to fail.  The module supports three
basic APIs: reading, writing, and registration of dialects.


DIALECT REGISTRATION:

Readers and writers support a dialect argument, which is a convenient
handle on a group of settings.  When the dialect argument is a string,
it identifies one of the dialects previously registered with the module.
If it is a class or instance, the attributes of the argument are used as
the settings for the reader or writer:

    class excel:
        delimiter = ','
        quotechar = '"'
        escapechar = None
        doublequote = True
        skipinitialspace = False
        lineterminator = '\\r\\n'
        quoting = QUOTE_MINIMAL

SETTINGS:

    * quotechar - specifies a one-character string to use as the
        quoting character.  It defaults to '"'.
    * delimiter - specifies a one-character string to use as the
        field separator.  It defaults to ','.
    * skipinitialspace - specifies how to interpret spaces which
        immediately follow a delimiter.  It defaults to False, which
        means that spaces immediately following a delimiter is part
        of the following field.
    * lineterminator - specifies the character sequence which should
        terminate rows.
    * quoting - controls when quotes should be generated by the writer.
        It can take on any of the following module constants:

        csv.QUOTE_MINIMAL means only when required, for example, when a
            field contains either the quotechar or the delimiter
        csv.QUOTE_ALL means that quotes are always placed around fields.
        csv.QUOTE_NONNUMERIC means that quotes are always placed around
            fields which do not parse as integers or floating-point
            numbers.
        csv.QUOTE_STRINGS means that quotes are always placed around
            fields which are strings.  Note that the Python value None
            is not a string.
        csv.QUOTE_NOTNULL means that quotes are only placed around fields
            that are not the Python value None.
        csv.QUOTE_NONE means that quotes are never placed around fields.
    * escapechar - specifies a one-character string used to escape
        the delimiter when quoting is set to QUOTE_NONE.
    * doublequote - controls the handling of quotes inside fields.  When
        True, two consecutive quotes are interpreted as one during read,
        and when writing, each quote character embedded in the data is
        written as two quotes
"""

import sys
from _csv import (
    QUOTE_ALL as QUOTE_ALL,
    QUOTE_MINIMAL as QUOTE_MINIMAL,
    QUOTE_NONE as QUOTE_NONE,
    QUOTE_NONNUMERIC as QUOTE_NONNUMERIC,
    Error as Error,
    __version__ as __version__,
    _DialectLike,
    _QuotingType,
    field_size_limit as field_size_limit,
    get_dialect as get_dialect,
    list_dialects as list_dialects,
    reader as reader,
    register_dialect as register_dialect,
    unregister_dialect as unregister_dialect,
    writer as writer,
)

if sys.version_info >= (3, 12):
    from _csv import QUOTE_NOTNULL as QUOTE_NOTNULL, QUOTE_STRINGS as QUOTE_STRINGS
if sys.version_info >= (3, 10):
    from _csv import Reader, Writer
else:
    from _csv import _reader as Reader, _writer as Writer

from _typeshed import SupportsWrite
from collections.abc import Collection, Iterable, Mapping, Sequence
from types import GenericAlias
from typing import Any, Generic, Literal, TypeVar, overload
from typing_extensions import Self

__all__ = [
    "QUOTE_MINIMAL",
    "QUOTE_ALL",
    "QUOTE_NONNUMERIC",
    "QUOTE_NONE",
    "Error",
    "Dialect",
    "excel",
    "excel_tab",
    "field_size_limit",
    "reader",
    "writer",
    "register_dialect",
    "get_dialect",
    "list_dialects",
    "Sniffer",
    "unregister_dialect",
    "DictReader",
    "DictWriter",
    "unix_dialect",
]
if sys.version_info >= (3, 12):
    __all__ += ["QUOTE_STRINGS", "QUOTE_NOTNULL"]
if sys.version_info < (3, 13):
    __all__ += ["__doc__", "__version__"]

_T = TypeVar("_T")

class Dialect:
    """Describe a CSV dialect.

    This must be subclassed (see csv.excel).  Valid attributes are:
    delimiter, quotechar, escapechar, doublequote, skipinitialspace,
    lineterminator, quoting.
    """

    delimiter: str
    quotechar: str | None
    escapechar: str | None
    doublequote: bool
    skipinitialspace: bool
    lineterminator: str
    quoting: _QuotingType
    strict: bool
    def __init__(self) -> None: ...

class excel(Dialect):
    """Describe the usual properties of Excel-generated CSV files."""

class excel_tab(excel):
    """Describe the usual properties of Excel-generated TAB-delimited files."""

class unix_dialect(Dialect):
    """Describe the usual properties of Unix-generated CSV files."""

class DictReader(Generic[_T]):
    fieldnames: Sequence[_T] | None
    restkey: _T | None
    restval: str | Any | None
    reader: Reader
    dialect: _DialectLike
    line_num: int
    @overload
    def __init__(
        self,
        f: Iterable[str],
        fieldnames: Sequence[_T],
        restkey: _T | None = None,
        restval: str | Any | None = None,
        dialect: _DialectLike = "excel",
        *,
        delimiter: str = ",",
        quotechar: str | None = '"',
        escapechar: str | None = None,
        doublequote: bool = True,
        skipinitialspace: bool = False,
        lineterminator: str = "\r\n",
        quoting: _QuotingType = 0,
        strict: bool = False,
    ) -> None: ...
    @overload
    def __init__(
        self: DictReader[str],
        f: Iterable[str],
        fieldnames: Sequence[str] | None = None,
        restkey: str | None = None,
        restval: str | None = None,
        dialect: _DialectLike = "excel",
        *,
        delimiter: str = ",",
        quotechar: str | None = '"',
        escapechar: str | None = None,
        doublequote: bool = True,
        skipinitialspace: bool = False,
        lineterminator: str = "\r\n",
        quoting: _QuotingType = 0,
        strict: bool = False,
    ) -> None: ...
    def __iter__(self) -> Self: ...
    def __next__(self) -> dict[_T | Any, str | Any]: ...
    if sys.version_info >= (3, 12):
        def __class_getitem__(cls, item: Any, /) -> GenericAlias:
            """Represent a PEP 585 generic type

            E.g. for t = list[int], t.__origin__ is list and t.__args__ is (int,).
            """

class DictWriter(Generic[_T]):
    fieldnames: Collection[_T]
    restval: Any | None
    extrasaction: Literal["raise", "ignore"]
    writer: Writer
    def __init__(
        self,
        f: SupportsWrite[str],
        fieldnames: Collection[_T],
        restval: Any | None = "",
        extrasaction: Literal["raise", "ignore"] = "raise",
        dialect: _DialectLike = "excel",
        *,
        delimiter: str = ",",
        quotechar: str | None = '"',
        escapechar: str | None = None,
        doublequote: bool = True,
        skipinitialspace: bool = False,
        lineterminator: str = "\r\n",
        quoting: _QuotingType = 0,
        strict: bool = False,
    ) -> None: ...
    def writeheader(self) -> Any: ...
    def writerow(self, rowdict: Mapping[_T, Any]) -> Any: ...
    def writerows(self, rowdicts: Iterable[Mapping[_T, Any]]) -> None: ...
    if sys.version_info >= (3, 12):
        def __class_getitem__(cls, item: Any, /) -> GenericAlias:
            """Represent a PEP 585 generic type

            E.g. for t = list[int], t.__origin__ is list and t.__args__ is (int,).
            """

class Sniffer:
    """ "Sniffs" the format of a CSV file (i.e. delimiter, quotechar)
    Returns a Dialect object.
    """

    preferred: list[str]
    def sniff(self, sample: str, delimiters: str | None = None) -> type[Dialect]:
        """Returns a dialect (or None) corresponding to the sample"""

    def has_header(self, sample: str) -> bool: ...
