# This file is automatically generated by pyo3_stub_gen
# ruff: noqa: E501, F401

import builtins
import typing
from enum import Enum, auto

class PyBlockInfo:
    r"""
    A single MDF block discovered while walking the file's link graph.
    
    Attributes
    ----------
    offset, end_offset, size : int
        On-disk byte range of the block.
    block_type : str
        Four-character MDF block tag (e.g. ``"##HD"``, ``"##CN"``).
    description : str
        Short human-readable summary (e.g. ``"channel 'Speed' [f64@0..8]"``).
    links : list[PyLinkInfo]
        Outbound links to other blocks.
    extra : Optional[str]
        Block-type-specific extra information, when applicable.
    """
    offset: builtins.int
    end_offset: builtins.int
    size: builtins.int
    block_type: builtins.str
    description: builtins.str
    links: builtins.list[PyLinkInfo]
    extra: typing.Optional[builtins.str]
    def __repr__(self) -> builtins.str:
        ...


class PyChannelGroupInfo:
    r"""
    Read-only metadata describing a channel group (``##CG`` block).
    
    Returned by :py:meth:`PyMDF.channel_groups`.
    
    Attributes
    ----------
    name : Optional[str]
        Group / acquisition name (often ``None`` for files written by mf4-rs).
    comment : Optional[str]
        Free-form comment.
    channel_count : int
        Number of channels in this group.
    record_count : int
        Number of records (cycles) recorded for this group.
    """
    name: typing.Optional[builtins.str]
    comment: typing.Optional[builtins.str]
    channel_count: builtins.int
    record_count: builtins.int
    def __str__(self) -> builtins.str:
        ...

    def __repr__(self) -> builtins.str:
        ...


class PyChannelInfo:
    r"""
    Read-only metadata describing a single channel.
    
    Returned by :py:meth:`PyMDF.get_all_channels`,
    :py:meth:`PyMDF.get_channels_for_group`, and
    :py:meth:`PyMdfIndex.get_channel_info_by_name`.
    
    Attributes
    ----------
    name : Optional[str]
        Channel name from the ``##TX`` block, or ``None`` if not set.
    unit : Optional[str]
        Engineering unit string, or ``None``.
    comment : Optional[str]
        Free-form comment, or ``None``. Always ``None`` when obtained via the
        index (not stored in `IndexedChannel`).
    data_type : PyDataType
        The MDF data type of the raw samples.
    bit_count : int
        Width of the raw value in bits (e.g. 32 for f32, 64 for f64/u64).
    """
    name: typing.Optional[builtins.str]
    unit: typing.Optional[builtins.str]
    comment: typing.Optional[builtins.str]
    data_type: PyDataType
    bit_count: builtins.int
    def __str__(self) -> builtins.str:
        ...

    def __repr__(self) -> builtins.str:
        ...


class PyDataType:
    r"""
    MDF channel data type descriptor.
    
    Wraps the on-disk MDF 4 data type code (`cn_data_type`) together with a
    human-readable name. Use the ``create_data_type_*`` helper functions to
    construct one for the writer API.
    
    Attributes
    ----------
    name : str
        Symbolic name, e.g. ``"FloatLE"``, ``"UnsignedIntegerLE"``.
    value : int
        The MDF spec numeric code (0-16, or 255 for unknown).
    """
    name: builtins.str
    value: builtins.int
    def __str__(self) -> builtins.str:
        ...

    def __repr__(self) -> builtins.str:
        ...


class PyFileLayout:
    r"""
    Full structural layout of an MDF file: blocks, links, and gaps.
    
    Build one with :py:meth:`from_file` or :py:meth:`PyMDF.file_layout`. Use
    it to debug file structure, audit storage efficiency, or render a
    human-readable map of an MDF.
    """
    file_size: builtins.int
    blocks: builtins.list[PyBlockInfo]
    gaps: builtins.list[PyGapInfo]
    @staticmethod
    def from_file(path:builtins.str) -> PyFileLayout:
        r"""
        Build a layout by parsing an MDF file from disk.
        
        Parameters
        ----------
        path : str
        """
        ...

    def to_text(self) -> builtins.str:
        r"""
        Render the layout as a flat, sorted text listing.
        
        Each line is ``offset .. end_offset  block_type  description``,
        including link targets — easy to ``grep`` / diff.
        """
        ...

    def to_tree(self) -> builtins.str:
        r"""
        Render the link graph as an indented tree rooted at ``##ID``.
        """
        ...

    def to_json(self) -> builtins.str:
        r"""
        Serialize the layout to a pretty-printed JSON string.
        """
        ...

    def write_text_to_file(self, path:builtins.str) -> None:
        r"""
        Write the flat text listing (see :py:meth:`to_text`) to ``path``.
        """
        ...

    def write_tree_to_file(self, path:builtins.str) -> None:
        r"""
        Write the indented tree view (see :py:meth:`to_tree`) to ``path``.
        """
        ...

    def write_json_to_file(self, path:builtins.str) -> None:
        r"""
        Write the JSON representation (see :py:meth:`to_json`) to ``path``.
        """
        ...

    def __repr__(self) -> builtins.str:
        ...


class PyGapInfo:
    r"""
    A range of bytes in the file not covered by any visited block.
    
    Gaps usually represent alignment padding, abandoned scratch space, or
    (rarely) blocks that aren't reachable from the link graph.
    
    Attributes
    ----------
    start, end, size : int
    """
    start: builtins.int
    end: builtins.int
    size: builtins.int
    def __repr__(self) -> builtins.str:
        ...


class PyLinkInfo:
    r"""
    A single outbound link from a block to another block.
    
    Attributes
    ----------
    name : str
        Link's role inside the source block (e.g. ``"first_dg_addr"``).
    target : int
        Absolute file offset of the target block (0 means null link).
    target_type : Optional[str]
        Block type at the target offset, when known (e.g. ``"##DG"``).
    """
    name: builtins.str
    target: builtins.int
    target_type: typing.Optional[builtins.str]
    def __repr__(self) -> builtins.str:
        ...


class PyMDF:
    r"""
    Read-only handle to an MDF 4 file, backed by a memory-mapped buffer.
    
    Opens the file lazily: metadata (block tree, channel names, conversions)
    is parsed up front, but sample data is only decoded when you call one of
    the ``get_channel_*`` methods. The mmap stays alive for the lifetime of
    the ``PyMDF`` instance.
    
    Example
    -------
    >>> import mf4_rs
    >>> mdf = mf4_rs.PyMDF("recording.mf4")
    >>> for group in mdf.channel_groups():
    ...     print(group.name, group.record_count)
    >>> values = mdf.get_channel_values("Temperature")  # numpy.ndarray
    """
    def __new__(cls,path:builtins.str): ...
    def channel_groups(self) -> builtins.list[PyChannelGroupInfo]:
        r"""
        List metadata for every channel group in the file.
        
        Returns
        -------
        list[PyChannelGroupInfo]
            One entry per ``##CG`` block, in file order.
        """
        ...

    def get_all_channels(self) -> builtins.list[PyChannelInfo]:
        r"""
        Return metadata for every channel across every group.
        
        Returns
        -------
        list[PyChannelInfo]
            Channels are emitted in file order, group-by-group. Channels with
            duplicate names (common across groups) appear multiple times — use
            :py:meth:`get_channels_for_group` if you need per-group context.
        """
        ...

    def get_channels_for_group(self, group_index:builtins.int) -> builtins.list[PyChannelInfo]:
        r"""
        Return metadata for every channel in a single group.
        
        Parameters
        ----------
        group_index : int
            Zero-based index into :py:meth:`channel_groups`.
        
        Returns
        -------
        list[PyChannelInfo]
        
        Raises
        ------
        MdfException
            If ``group_index`` is out of bounds.
        """
        ...

    def get_all_channel_names(self) -> builtins.list[builtins.str]:
        r"""
        Return the names of every named channel across all groups.
        
        Channels without a name (``##TX`` link is null) are skipped.
        Duplicates are preserved when the same name appears in multiple groups.
        
        Returns
        -------
        list[str]
        """
        ...

    def get_channel_values(self, channel_name:builtins.str) -> typing.Optional[typing.Any]:
        r"""
        Read a channel's samples as a contiguous numpy ``float64`` array.
        
        Searches every group and returns the first channel whose name matches
        ``channel_name``. This is the fastest read path for numeric channels —
        values are decoded directly into a numpy buffer, with any
        non-decodable / invalid samples set to ``NaN``. Conversions stored on
        the channel (linear, rational, table-lookup) are applied automatically.
        
        Parameters
        ----------
        channel_name : str
            Exact channel name (case-sensitive).
        
        Returns
        -------
        Optional[numpy.ndarray]
            1-D ``float64`` array of length ``record_count``, or ``None`` if no
            channel with that name exists.
        """
        ...

    def get_channel_values_by_group_and_name(self, group_name:builtins.str, channel_name:builtins.str) -> typing.Optional[typing.Any]:
        r"""
        Read a channel from a *specific* group, by group and channel name.
        
        Use this when the same channel name appears in multiple groups (e.g.
        each group has its own ``Time``) and you need to disambiguate.
        
        Parameters
        ----------
        group_name : str
            Exact channel-group name.
        channel_name : str
            Exact channel name within that group.
        
        Returns
        -------
        Optional[numpy.ndarray]
            1-D ``float64`` array, or ``None`` if either name is not found.
        """
        ...

    def get_channel_as_series(self, channel_name:builtins.str) -> typing.Optional[typing.Any]:
        r"""
        Read a channel as a ``pandas.Series`` indexed by absolute timestamps.
        
        The series is indexed by the group's master channel (channel-type 2)
        converted to a ``DatetimeIndex`` — relative master values (in seconds)
        are added to the file's ``HD.abs_time`` start instant. If the channel
        has no master, or the master channel itself is being requested, the
        returned series uses the default integer index. If the file has no
        recorded start time, the master values are kept as a numeric index.
        
        Parameters
        ----------
        channel_name : str
            Exact channel name; first match across all groups is used.
        
        Returns
        -------
        Optional[pandas.Series]
            ``None`` if no channel with that name exists.
        
        Raises
        ------
        MdfException
            If pandas is not installed.
        """
        ...

    def file_layout(self) -> PyFileLayout:
        r"""
        Build a :class:`PyFileLayout` describing every block in this file.
        
        Useful for debugging or analysing the on-disk structure: returns the
        offset, size, type, link targets and unreferenced gaps for each
        MDF block (``##ID``, ``##HD``, ``##DG``, ``##CG``, ``##CN``, ``##DT``,
        ``##DL``, ``##TX``, ``##CC``, ``##SI``, ``##SD`` …).
        
        Returns
        -------
        PyFileLayout
        """
        ...


class PyMdfIndex:
    r"""
    Lightweight, self-contained index over an MDF 4 file.
    
    An index records the byte ranges of each channel, fully resolves all
    conversion blocks, and can be serialized to JSON. Once you have a
    ``PyMdfIndex`` you can:
    
    - Re-read channel values quickly without re-parsing the whole file.
    - Compute exact byte ranges for **partial** / HTTP-range / S3 reads
      (see :py:meth:`get_channel_byte_ranges`,
      :py:meth:`get_channel_byte_ranges_for_records`).
    - Persist with :py:meth:`save_to_file` and reload elsewhere with
      :py:meth:`load_from_file` — the JSON is fully self-contained, the
      original file is only required for the actual data reads.
    
    **Limitation:** indexes do not support compressed (``##DZ``) data blocks.
    
    Example
    -------
    >>> idx = mf4_rs.PyMdfIndex.from_file("recording.mf4")
    >>> idx.save_to_file("recording.idx.json")
    >>> # Later, possibly on another machine that has the same file:
    >>> idx2 = mf4_rs.PyMdfIndex.load_from_file("recording.idx.json")
    >>> values = idx2.read_channel_values_by_name_as_f64("Speed", "recording.mf4")
    """
    @staticmethod
    def from_file(path:builtins.str) -> PyMdfIndex:
        r"""
        Build a fresh index by parsing an MDF file from disk.
        
        All conversions are resolved during construction so the index is
        fully self-contained afterwards.
        
        Parameters
        ----------
        path : str
            Path to a ``.mf4`` file.
        
        Raises
        ------
        MdfException
            If the file cannot be parsed as MDF 4.10+.
        """
        ...

    @staticmethod
    def load_from_file(path:builtins.str) -> PyMdfIndex:
        r"""
        Load a previously saved JSON index file.
        
        The companion to :py:meth:`save_to_file`. Reads do not require the
        original MDF file until you actually call ``read_channel_values_*``
        or ``get_channel_byte_ranges_*``.
        """
        ...

    @staticmethod
    def from_url(url:builtins.str, chunk_size:typing.Optional[builtins.int]) -> PyMdfIndex:
        r"""
        Build an index from an MDF file served over HTTP / S3 using range
        requests, without downloading the whole file.
        
        Issues range reads only for metadata blocks (``##ID``, ``##HD``,
        ``##DG``, ``##CG``, ``##CN``, name / unit / comment ``##TX``,
        conversion ``##CC`` plus its ``cc_ref`` chain, and ``##DT``/``##DV``/
        ``##DZ``/``##DL`` headers). Sample data is never fetched. With the
        default 1 MiB read-ahead chunk, a typical file collapses to a handful
        of underlying HTTP requests regardless of file size.
        
        Parameters
        ----------
        url : str
            ``http://`` or ``https://`` URL of the ``.mf4`` resource. The
            server must honour single-range ``Range: bytes=A-B`` requests.
        chunk_size : int, optional
            Read-ahead chunk size in bytes for the metadata phase
            (default 1 MiB). Smaller values reduce wasted bytes when
            metadata is densely packed near the file head; larger values
            reduce the number of HTTP round-trips when metadata is
            scattered across the file.
        
        Raises
        ------
        MdfException
            If the URL cannot be reached, the server does not honour
            range requests, or the response is not a valid MDF file.
        """
        ...

    def save_to_file(self, path:builtins.str) -> None:
        r"""
        Serialize the index to JSON at ``path``.
        
        Output is dependency-free (no references back to the source MDF) and
        typically a few KB to a few MB depending on channel/conversion count.
        """
        ...

    def list_channel_groups(self) -> builtins.list[tuple[builtins.int, builtins.str, builtins.int]]:
        r"""
        List every channel group in the index.
        
        Returns
        -------
        list[tuple[int, str, int]]
            ``(group_index, group_name, channel_count)`` per group. Unnamed
            groups appear with an empty string for the name.
        """
        ...

    def list_channels(self, group_index:builtins.int) -> typing.Optional[builtins.list[tuple[builtins.int, builtins.str, PyDataType]]]:
        r"""
        List channels in a single group.
        
        Parameters
        ----------
        group_index : int
            Index from :py:meth:`list_channel_groups`.
        
        Returns
        -------
        Optional[list[tuple[int, str, PyDataType]]]
            ``(channel_index, channel_name, data_type)`` per channel, or
            ``None`` if ``group_index`` is out of range.
        """
        ...

    def read_channel_values(self, group_index:builtins.int, channel_index:builtins.int, file_path:builtins.str) -> builtins.list[typing.Optional[typing.Any]]:
        r"""
        Read every sample of a channel, identified by group + channel index.
        
        Conversions stored in the index are applied automatically.
        
        Parameters
        ----------
        group_index : int
        channel_index : int
        file_path : str
            Path to the original MDF file (the index does not embed sample
            bytes).
        
        Returns
        -------
        list[Optional[Union[float, int, str, bytes]]]
            One entry per record. ``None`` indicates an invalid sample
            (invalidation bit set, or undecodable). Otherwise the value is a
            native Python type matching the channel's data type.
        
        Raises
        ------
        MdfException
            If indices are out of range, the file cannot be read, or the
            file contains compressed (``##DZ``) blocks.
        """
        ...

    def read_channel_values_by_name(self, channel_name:builtins.str, file_path:builtins.str) -> builtins.list[typing.Optional[typing.Any]]:
        r"""
        Read every sample of a channel by name (first match across groups).
        
        See :py:meth:`read_channel_values` for the return / error contract.
        If multiple groups contain the same channel name, prefer
        :py:meth:`read_channel_values_by_group_and_name`.
        """
        ...

    def read_channel_values_from_url(self, group_index:builtins.int, channel_index:builtins.int, url:builtins.str) -> builtins.list[typing.Optional[typing.Any]]:
        r"""
        Read every sample of a channel via HTTP range requests.
        
        Issues one HTTP request per data block holding this channel. Cache
        is bypassed because data-block payloads are typically far larger
        than any sensible chunk size; one ranged ``GET`` per block is the
        cheapest pattern.
        
        Parameters
        ----------
        group_index : int
        channel_index : int
        url : str
            URL of the same MDF file the index was built from.
        
        Returns
        -------
        list[Optional[Union[float, int, str, bytes]]]
            One entry per record. ``None`` indicates an invalid sample.
        """
        ...

    def read_channel_values_by_name_from_url(self, channel_name:builtins.str, url:builtins.str) -> builtins.list[typing.Optional[typing.Any]]:
        r"""
        Read every sample of a channel by name via HTTP range requests.
        
        See :py:meth:`read_channel_values_from_url` for the I/O contract.
        """
        ...

    def read_channel_values_as_f64(self, group_index:builtins.int, channel_index:builtins.int, file_path:builtins.str) -> builtins.list[builtins.float]:
        r"""
        Fast path: read a numeric channel as a list of ``float`` values.
        
        Several times faster than :py:meth:`read_channel_values` for numeric
        channels — opens the source file via ``mmap``, decodes directly into
        ``f64`` and skips ``DecodedValue`` boxing. Invalid / non-finite
        samples are returned as ``float('nan')`` rather than ``None``.
        
        Parameters
        ----------
        group_index : int
        channel_index : int
        file_path : str
        
        Returns
        -------
        list[float]
        
        Raises
        ------
        MdfException
            If the channel is non-numeric (string / byte array), indices are
            out of range, or the file cannot be mapped.
        """
        ...

    def read_channel_values_by_name_as_f64(self, channel_name:builtins.str, file_path:builtins.str) -> builtins.list[builtins.float]:
        r"""
        Fast path: read a numeric channel as ``list[float]``, looked up by name.
        
        Combines :py:meth:`find_channel_by_name` and
        :py:meth:`read_channel_values_as_f64`. Invalid samples are
        ``float('nan')``.
        
        Raises
        ------
        MdfException
            If no channel with that name exists, the channel is not numeric,
            or the file cannot be mapped.
        """
        ...

    def find_channel_by_name(self, channel_name:builtins.str) -> typing.Optional[tuple[builtins.int, builtins.int]]:
        r"""
        Locate a channel by name across all groups.
        
        Returns
        -------
        Optional[tuple[int, int]]
            ``(group_index, channel_index)`` of the first match, or ``None``.
        """
        ...

    def get_channel_byte_ranges(self, group_index:builtins.int, channel_index:builtins.int) -> builtins.list[tuple[builtins.int, builtins.int]]:
        r"""
        Compute the byte ranges occupied by a channel across the file.
        
        Each tuple is ``(offset, length)`` and accounts for the channel's
        position inside the record layout *and* any data block splitting
        across multiple ``##DT`` fragments. Useful for issuing HTTP-range
        requests against a remote MDF file.
        """
        ...

    def get_channel_byte_ranges_for_records(self, group_index:builtins.int, channel_index:builtins.int, start_record:builtins.int, record_count:builtins.int) -> builtins.list[tuple[builtins.int, builtins.int]]:
        r"""
        Like :py:meth:`get_channel_byte_ranges`, but limited to a record window.
        
        Parameters
        ----------
        group_index : int
        channel_index : int
        start_record : int
            0-based first record to include.
        record_count : int
            Number of records to cover (clamped to remaining records).
        """
        ...

    def get_channel_byte_summary(self, group_index:builtins.int, channel_index:builtins.int) -> tuple[builtins.int, builtins.int]:
        r"""
        Summarize :py:meth:`get_channel_byte_ranges` without listing each range.
        
        Returns
        -------
        tuple[int, int]
            ``(total_bytes, num_ranges)``.
        """
        ...

    def get_channel_byte_ranges_by_name(self, channel_name:builtins.str) -> builtins.list[tuple[builtins.int, builtins.int]]:
        r"""
        Byte ranges for a channel, looked up by name (first match).
        """
        ...

    def get_channel_info_by_name(self, channel_name:builtins.str) -> typing.Optional[tuple[builtins.int, builtins.int, PyChannelInfo]]:
        r"""
        Look up a channel by name and return its position plus metadata.
        
        Returns
        -------
        Optional[tuple[int, int, PyChannelInfo]]
            ``(group_index, channel_index, info)`` for the first match, or
            ``None``. ``info.comment`` is always ``None`` for indexed
            channels (comments are not stored in the index).
        """
        ...

    def find_all_channels_by_name(self, channel_name:builtins.str) -> builtins.list[tuple[builtins.int, builtins.int]]:
        r"""
        Find every ``(group_index, channel_index)`` whose channel name matches.
        
        Useful when the same name appears in multiple groups (e.g. ``"Time"``
        in each group).
        """
        ...

    def get_file_size(self) -> builtins.int:
        r"""
        Total size, in bytes, of the source MDF file at the time the index
        was built.
        """
        ...

    def has_resolved_conversions(self) -> builtins.bool:
        r"""
        True if any conversion in the index has its dependent ``##TX`` /
        ``##CC`` data resolved inline.
        
        Indexes built with :py:meth:`from_file` resolve all dependencies, so
        this normally returns ``True``.
        """
        ...

    def get_conversion_info(self, group_index:builtins.int, channel_index:builtins.int) -> typing.Optional[builtins.dict[builtins.str, typing.Any]]:
        r"""
        Inspect the conversion attached to a channel.
        
        Returns
        -------
        Optional[dict]
            ``None`` if the channel has no conversion. Otherwise a dict with
            keys:
        
            - ``conversion_type`` — debug rendering of the ``cc_type`` enum
              (e.g. ``"Linear"``, ``"ValueToText"``).
            - ``precision`` — decimal precision hint (``cc_precision``).
            - ``flags`` — raw ``cc_flags`` bitfield.
            - ``values_count`` — number of entries in ``cc_val``.
            - ``values`` — raw ``cc_val`` numeric coefficients / table values.
            - ``resolved_texts`` — dict[int, str] mapping ``cc_ref`` indices
              to their resolved ``##TX`` text (when applicable).
            - ``has_resolved_conversions`` — present when nested conversions
              have been pre-resolved.
            - ``formula`` — algebraic formula string (for type 3 only).
        """
        ...

    def read_channel_values_by_group_and_name(self, group_name:builtins.str, channel_name:builtins.str, file_path:builtins.str) -> builtins.list[typing.Optional[typing.Any]]:
        r"""
        Read a channel by group + channel name, disambiguating duplicates.
        
        Looks up the channel group by name first, then finds the channel
        within that specific group. ``None`` entries in the returned list
        mark invalid samples; valid samples are native Python values
        (``float`` / ``int`` / ``str`` / ``bytes``).
        
        Raises
        ------
        MdfException
            If either ``group_name`` or ``channel_name`` is not found, or
            the source file cannot be read.
        """
        ...

    def read_channel_as_series(self, channel_name:builtins.str, file_path:builtins.str) -> typing.Any:
        r"""
        Read channel data as a pandas Series with time/master channel as DatetimeIndex.
        
        This method reads a channel's values from the index and returns them as a pandas Series
        with the time/master channel values converted to absolute timestamps as a DatetimeIndex.
        The timestamps are created by adding the relative time values to the MDF start time
        stored in the index. If no master channel is found, or if the queried channel IS the
        master channel, a default integer index is used. If the MDF file has no start time,
        falls back to numeric index.
        
        Requires pandas to be installed.
        
        # Arguments
        * `channel_name` - Name of the channel to read
        * `file_path` - Path to the MDF file
        
        # Returns
        Returns an error if the channel is not found, otherwise returns a pandas Series.
        
        # Errors
        Returns an error if:
        - pandas is not installed
        - the channel is not found
        - the master channel has a different number of values than the data channel
        """
        ...


class PyMdfWriter:
    r"""
    Streaming writer for MDF 4 files.
    
    Build an MDF file in five logical steps:
    
    1. ``writer = mf4_rs.PyMdfWriter("out.mf4")``
    2. ``writer.init_mdf_file()`` — write ``##ID`` and ``##HD``.
    3. Define structure: :py:meth:`add_channel_group`, then any combination of
       :py:meth:`add_time_channel`, :py:meth:`add_float_channel`,
       :py:meth:`add_float32_channel`, :py:meth:`add_int_channel`, or the
       generic :py:meth:`add_channel`.
    4. Write data: :py:meth:`start_data_block`, then either
       :py:meth:`write_record` (one record at a time, ergonomic) or
       :py:meth:`write_columns_f64` / :py:meth:`write_columns` (bulk numpy,
       much faster), then :py:meth:`finish_data_block`.
    5. :py:meth:`finalize` — flushes and closes the file. The writer is
       unusable after this; calling any other method raises ``MdfException``.
    
    All identifiers (``cg_*`` for groups, ``ch_*`` for channels) are *opaque
    strings* — pass them back to subsequent methods, but don't try to parse
    them. Channels are auto-linked into a per-group linked list in the order
    they were added.
    
    Example
    -------
    >>> w = mf4_rs.PyMdfWriter("demo.mf4")
    >>> w.init_mdf_file()
    >>> cg = w.add_channel_group("group_0")
    >>> t = w.add_time_channel(cg, "Time")
    >>> y = w.add_float_channel(cg, "Speed")
    >>> w.start_data_block(cg)
    >>> for i in range(100):
    ...     w.write_record(cg, [
    ...         mf4_rs.create_float_value(i * 0.01),
    ...         mf4_rs.create_float_value(i * 1.5),
    ...     ])
    >>> w.finish_data_block(cg)
    >>> w.finalize()
    """
    def __new__(cls,path:builtins.str): ...
    def init_mdf_file(self) -> None:
        r"""
        Write the MDF identification (``##ID``) and header (``##HD``) blocks.
        
        Must be called exactly once, before adding any channel group.
        """
        ...

    def add_channel_group(self, name:typing.Optional[builtins.str]) -> builtins.str:
        r"""
        Append a new channel group (``##CG``) to the file.
        
        Parameters
        ----------
        name : Optional[str]
            Group acquisition name. Written as a ``##TX`` block referenced
            from the new ``##CG`` via ``acq_name_addr``. Pass ``None`` to
            leave it unset.
        
        Returns
        -------
        str
            Opaque group ID (e.g. ``"cg_0"``) — pass to subsequent
            ``add_channel`` / ``write_record`` / ``finish_data_block`` calls.
        """
        ...

    def set_channel_group_comment(self, group_id:builtins.str, comment:builtins.str) -> None:
        r"""
        Attach a comment / description to a channel group.
        
        Writes a ``##TX`` block holding ``comment`` and links it from the
        group's ``comment_addr`` field.
        """
        ...

    def add_channel(self, group_id:builtins.str, name:builtins.str, data_type:PyDataType) -> builtins.str:
        r"""
        Add a generic channel to a channel group, using the data type's
        natural bit width.
        
        The new channel is linked after the most recently added channel in
        the same group, and inherits its byte offset from the running record
        layout. For float channels this defaults to **32 bits** — use
        :py:meth:`add_float_channel` if you want 64-bit precision.
        
        Parameters
        ----------
        group_id : str
            ID returned by :py:meth:`add_channel_group`.
        name : str
            Channel name (written as a ``##TX`` block).
        data_type : PyDataType
            One of the values from the ``create_data_type_*`` helpers.
        
        Returns
        -------
        str
            Opaque channel ID (e.g. ``"ch_3"``).
        """
        ...

    def add_time_channel(self, group_id:builtins.str, name:builtins.str) -> builtins.str:
        r"""
        Add a 64-bit little-endian float channel and mark it as the group's
        master / time channel.
        
        Equivalent to :py:meth:`add_float_channel` followed by
        :py:meth:`set_time_channel`. Should typically be the **first** channel
        added to a group — subsequent channels will be linked after it.
        
        Parameters
        ----------
        group_id : str
        name : str
            Usually ``"Time"`` or ``"t"``.
        
        Returns
        -------
        str
            Channel ID.
        """
        ...

    def add_float_channel(self, group_id:builtins.str, name:builtins.str) -> builtins.str:
        r"""
        Add a 64-bit little-endian float (``f64``) data channel.
        
        Recommended default for scientific / numeric data. Use
        :py:meth:`add_float32_channel` when 32-bit precision is enough and
        file size matters.
        """
        ...

    def add_float32_channel(self, group_id:builtins.str, name:builtins.str) -> builtins.str:
        r"""
        Add a 32-bit little-endian float (``f32``) data channel.
        
        Halves the per-record size compared to :py:meth:`add_float_channel`
        at the cost of precision (~7 decimal digits).
        """
        ...

    def add_int_channel(self, group_id:builtins.str, name:builtins.str) -> builtins.str:
        r"""
        Add a 64-bit little-endian unsigned integer (``u64``) data channel.
        
        For signed integers, build a generic channel with
        :py:meth:`add_channel` and ``create_data_type_*`` helpers (or call
        directly with the raw :class:`PyDataType`).
        """
        ...

    def set_time_channel(self, channel_id:builtins.str) -> None:
        r"""
        Mark an existing channel as the group's master / time channel.
        
        Sets ``channel_type = 2`` and ``sync_type = 1`` on the underlying
        ``##CN`` block. Most users should prefer :py:meth:`add_time_channel`,
        which combines channel creation with this call.
        
        Parameters
        ----------
        channel_id : str
            ID returned by one of the ``add_*_channel`` methods.
        """
        ...

    def start_data_block(self, group_id:builtins.str) -> None:
        r"""
        Open a fresh ``##DT`` data block for a channel group.
        
        Must be called once after all channels have been added, before any
        :py:meth:`write_record` / :py:meth:`write_columns_f64` /
        :py:meth:`write_columns` for that group. The writer will
        automatically split into multiple ``##DT`` fragments at the 4 MB
        boundary, joined by a ``##DL`` block when you call
        :py:meth:`finish_data_block`.
        """
        ...

    def write_record(self, group_id:builtins.str, values:typing.Sequence[PyDecodedValue]) -> None:
        r"""
        Append a single record (one sample for each channel in the group).
        
        ``values`` must contain exactly one entry per channel, in the same
        order channels were added — typically the master channel first, then
        data channels. Each value is encoded according to its channel's data
        type (the variant of :class:`PyDecodedValue` is *not* re-checked, so
        passing the wrong variant will produce nonsense bytes).
        
        This call has Python-level overhead per value; for bulk numeric data,
        prefer :py:meth:`write_columns_f64` or :py:meth:`write_columns`.
        """
        ...

    def finish_data_block(self, group_id:builtins.str) -> None:
        r"""
        Close the open ``##DT`` block for a channel group.
        
        If the group's data exceeded the 4 MB block size and was split
        across multiple ``##DT`` fragments, this also writes the ``##DL``
        (data list) block linking them together. Call once per group after
        all records have been written, and before :py:meth:`finalize`.
        """
        ...

    def write_columns_f64(self, group_id:builtins.str, columns:typing.Sequence[typing.Any]) -> None:
        r"""
        Bulk-write all channels of a group from numpy ``float64`` arrays.
        
        Equivalent to writing every record in row order, but ~10× faster than
        looping over :py:meth:`write_record` because it avoids per-value
        Python-Rust crossings and ``DecodedValue`` boxing.
        
        Parameters
        ----------
        group_id : str
        columns : list[numpy.ndarray]
            One contiguous 1-D ``float64`` array per channel, in channel
            order. **All arrays must have identical length** — that length
            becomes the record count. The float values are converted to each
            channel's declared data type before encoding.
        
        Raises
        ------
        MdfException
            If an array is not contiguous, not ``float64``, or lengths
            mismatch.
        """
        ...

    def write_columns(self, group_id:builtins.str, columns:typing.Sequence[typing.Any], dtypes:typing.Sequence[builtins.str]) -> None:
        r"""
        Bulk-write all channels of a group from heterogeneous numpy arrays.
        
        Like :py:meth:`write_columns_f64` but accepts a per-column dtype, so
        integer / single-precision channels are written without an
        intermediate ``float64`` round-trip.
        
        Parameters
        ----------
        group_id : str
        columns : list[numpy.ndarray]
            One contiguous 1-D array per channel, all of identical length.
        dtypes : list[str]
            One entry per column, matching ``columns``. Allowed values:
            ``"f64"``, ``"f32"``, ``"u64"``, ``"i64"``.
        
        Raises
        ------
        MdfException
            If the dtype string is not one of the supported values, the
            numpy array's element type doesn't match the dtype string, the
            two list lengths differ, or any array is non-contiguous.
        """
        ...

    def finalize(self) -> None:
        r"""
        Flush all buffered bytes to disk and close the file.
        
        After this returns, the writer is consumed: any subsequent method
        call raises ``MdfException``. Calling :py:meth:`finalize` more than
        once also raises.
        """
        ...


class PyDecodedValue(Enum):
    r"""
    A single decoded channel sample, tagged with its underlying type.
    
    Returned by ``create_*_value`` helpers and consumed by
    :py:meth:`PyMdfWriter.write_record`. When *reading*, most APIs return native
    Python objects (``float`` / ``int`` / ``str`` / ``bytes``) directly, so you
    usually only construct ``PyDecodedValue`` to feed back into the writer.
    
    Variants carry a single ``value`` field (use the ``value`` getter to
    retrieve the inner native Python value):
    
    - ``Float(value: float)``
    - ``UnsignedInteger(value: int)``
    - ``SignedInteger(value: int)``
    - ``String(value: str)``
    - ``ByteArray(value: bytes)``
    - ``Unknown()`` — undecodable / not yet supported
    """
    Float = auto()
    UnsignedInteger = auto()
    SignedInteger = auto()
    String = auto()
    ByteArray = auto()
    Unknown = auto()

def create_data_type_float_le() -> PyDataType:
    r"""
    Return the :class:`PyDataType` for little-endian IEEE-754 floats.
    
    Pair with :py:meth:`PyMdfWriter.add_channel`. Defaults to 32 bits when
    passed to ``add_channel`` — for f64 use :py:meth:`PyMdfWriter.add_float_channel`.
    """
    ...

def create_data_type_string_utf8() -> PyDataType:
    r"""
    Return the :class:`PyDataType` for UTF-8 encoded string channels.
    """
    ...

def create_data_type_uint_le() -> PyDataType:
    r"""
    Return the :class:`PyDataType` for little-endian unsigned integers.
    
    Pair with :py:meth:`PyMdfWriter.add_channel` when you need an unsigned
    integer channel of non-default width (otherwise see
    :py:meth:`PyMdfWriter.add_int_channel`).
    """
    ...

def create_float_value(value:builtins.float) -> PyDecodedValue:
    r"""
    Wrap a Python ``float`` in a :class:`PyDecodedValue` of variant ``Float``.
    
    Use this to feed values into :py:meth:`PyMdfWriter.write_record` for any
    floating-point channel (32- or 64-bit; the value is truncated to the
    channel's declared bit width on encode).
    """
    ...

def create_int_value(value:builtins.int) -> PyDecodedValue:
    r"""
    Wrap a Python ``int`` in a ``SignedInteger`` :class:`PyDecodedValue`.
    """
    ...

def create_string_value(value:builtins.str) -> PyDecodedValue:
    r"""
    Wrap a Python ``str`` in a ``String`` :class:`PyDecodedValue`.
    
    For string channels (``StringUtf8`` etc.). Encoding into the file is
    done according to the channel's declared string data type.
    """
    ...

def create_uint_value(value:builtins.int) -> PyDecodedValue:
    r"""
    Wrap a Python ``int`` in a ``UnsignedInteger`` :class:`PyDecodedValue`.
    
    Suitable for any unsigned integer channel; the value is truncated to the
    channel's bit width on encode.
    """
    ...

def cut_mdf_by_time(input_path:builtins.str, output_path:builtins.str, start_time:builtins.float, end_time:builtins.float) -> None:
    r"""
    Cut an MDF file by time, copying only records whose master channel value
    falls within the inclusive `[start_time, end_time]` window.
    
    The output preserves fixed-length numeric, string, and byte-array
    channels, per-record invalidation bytes, and VLSD ("signal-based")
    channels (a fresh ##SD chain is written for each kept VLSD channel).
    Per-channel conversion / source / metadata blocks are not re-emitted, so
    the output channels read as raw values.
    
    Parameters
    ----------
    input_path : str
        Path to the source MF4 file.
    output_path : str
        Destination path for the trimmed file.
    start_time : float
        Start of the window in seconds (inclusive).
    end_time : float
        End of the window in seconds (inclusive).
    """
    ...

def cut_mdf_by_utc(input_path:builtins.str, output_path:builtins.str, start_utc:typing.Any, end_utc:typing.Any) -> None:
    r"""
    Cut an MDF file by absolute UTC time. Accepts ISO 8601 strings (e.g.
    `"2024-01-15T12:34:56Z"`), `datetime.datetime` objects (naive values are
    assumed to be UTC), or numeric UNIX timestamps in seconds.
    
    The window is inclusive on both ends. The source file must record a
    non-zero `HD.abs_time` (set by the writer / asammdf when creating the
    file) — without it the relative offset cannot be computed and an
    `MdfException` is raised.
    
    Other behaviour matches [`cut_mdf_by_time`]: VLSD payloads, byte-array
    channels, and per-record invalidation bytes are preserved verbatim.
    """
    ...

def file_layout_from_file(path:builtins.str) -> PyFileLayout:
    r"""
    Build a :class:`PyFileLayout` from an MDF file on disk.
    
    Functional alias for :py:meth:`PyFileLayout.from_file`.
    
    Parameters
    ----------
    path : str
    
    Returns
    -------
    PyFileLayout
    """
    ...

def merge_files(output:builtins.str, first:builtins.str, second:builtins.str) -> None:
    r"""
    Merge two MDF files into a new file at ``output``.
    
    Channel groups whose layouts (record-id length and channel list — names,
    data types, bit/byte offsets, bit count, channel type, VLSD flag) match
    are concatenated; non-matching groups are appended as separate groups.
    Supports normal numeric, fixed ``ByteArray``, and VLSD signal channels
    (variable-length strings and byte arrays stored in ``##SD`` blocks).
    
    Parameters
    ----------
    output : str
        Destination path for the merged file.
    first, second : str
        Source file paths. Must be uncompressed MDF 4.10+ files.
    """
    ...

