updated: 2025-03-24T16:17:19.123450768+00:00[Etc/UTC]


README

ry

ry = rust and python and bears, oh my!

PyPI PyPI - Python Version PyPI - Wheel PyPI - Downloads PyPI - Status PyPI - License

DOCS: ryo3.dev (WIP)

  • ry is a library of python shims/bindings to popular rust crates
  • ryo3-* is the collection of rust crates providing the shims used by ry and possibly your pyo3 rust-python library

THIS IS A WORK IN PROGRESS ~ FEEDBACK/PRs WELCOME!

Install

pip install ry
uv add ry

Check install: python -m ry

Quickstart

Check out the examples directory for some quickstart examples.


What and why?

This is a collection of pyo3-wrappers for rust crates I wish existed in python.

It all started with me wanting a fast python xxhash and fnv-64

Who?

FAQ

(aka: questions that I have been asking myself)

  • Q: Why?
    • A: I (jesse) needed several hashing functions for python and then kept adding things as I needed them
  • Q: Does this have anything to do with the (excellent) package manager rye?
    • A: short answer: no. long answer: no, it does not.
  • Q: Why is the repo split into ry and ryo3?
    • A: ry is the python package, ryo3 is a rust crate setup to let you “register” functions you may want if you were writing your own pyo3-python bindings library; maybe someday the ryo3::libs module will be split up into separate packages

Crate bindings

ryo3-std

  • wrapped crates:
    • heck
    • jiter
    • shlex
    • sqlformat
    • url
    • which
    • compression:
      • brotli
      • bzip2
      • flate2
      • zstd
    • hashing:
      • fnv
      • xxhash
    • burnt-sushi:

FUTURE?

  • subprocess.redo (subprocesses that are lessy finicky and support tee-ing)
  • wrappers:
    • ignore
    • http
    • regex
    • reqwest (async http client / waiting on pyo3 asyncio to stabilize and for me to have more time)
    • tokio (fs and process)
    • tracing (could be nicer than python’s awful logging lib – currently a part of ry/ryo3 for my dev purposes - currently has impl thingy in utiles)
    • tracing (eg logging)
    • uuid
  • organization
    • split up the ryo3 type annotations?
    • chunk things into smaller sub-packages within the ry package?

API

API

Table of Contents

ry.ryo3.__init__

"""ry api ~ type annotations"""

from __future__ import annotations

import datetime as pydt
import typing as t
from os import PathLike

from ry import dirs as dirs  # noqa: RUF100
from ry import http as http  # noqa: RUF100
from ry import xxhash as xxhash  # noqa: RUF100
from ry import zstd as zstd  # noqa: RUF100
from ry._types import Buffer as Buffer  # noqa: RUF100
from ry.http import Headers as Headers  # noqa: RUF100
from ry.http import HttpStatus as HttpStatus  # noqa: RUF100
from ry.zstd import is_zstd as is_zstd
from ry.zstd import zstd_compress as zstd_compress
from ry.zstd import zstd_decode as zstd_decode
from ry.zstd import zstd_decompress as zstd_decompress
from ry.zstd import zstd_encode as zstd_encode

from ._brotli import brotli as brotli
from ._brotli import brotli_decode as brotli_decode
from ._brotli import brotli_encode as brotli_encode
from ._bytes import Bytes as Bytes
from ._bzip2 import bzip2 as bzip2
from ._bzip2 import bzip2_decode as bzip2_decode
from ._bzip2 import bzip2_encode as bzip2_encode
from ._flate2 import gunzip as gunzip
from ._flate2 import gzip as gzip
from ._flate2 import gzip_decode as gzip_decode
from ._flate2 import gzip_encode as gzip_encode
from ._flate2 import is_gzipped as is_gzipped
from ._fnv import FnvHasher as FnvHasher
from ._fnv import fnv1a as fnv1a
from ._fspath import FsPath as FsPath
from ._glob import Pattern as Pattern
from ._glob import glob as glob
from ._globset import Glob as Glob
from ._globset import GlobSet as GlobSet
from ._globset import Globster as Globster
from ._globset import globster as globster
from ._heck import camel_case as camel_case
from ._heck import kebab_case as kebab_case
from ._heck import pascal_case as pascal_case
from ._heck import shouty_kebab_case as shouty_kebab_case
from ._heck import shouty_snake_case as shouty_snake_case
from ._heck import snake_case as snake_case
from ._heck import snek_case as snek_case
from ._heck import title_case as title_case
from ._heck import train_case as train_case
from ._jiff import Date as Date
from ._jiff import DateDifference as DateDifference
from ._jiff import DateTime as DateTime
from ._jiff import DateTimeDifference as DateTimeDifference
from ._jiff import DateTimeRound as DateTimeRound
from ._jiff import ISOWeekDate as ISOWeekDate
from ._jiff import Offset as Offset
from ._jiff import SignedDuration as SignedDuration
from ._jiff import Time as Time
from ._jiff import TimeDifference as TimeDifference
from ._jiff import TimeSpan as TimeSpan
from ._jiff import Timestamp as Timestamp
from ._jiff import TimestampDifference as TimestampDifference
from ._jiff import TimestampRound as TimestampRound
from ._jiff import TimeZone as TimeZone
from ._jiff import TimeZoneDatabase as TimeZoneDatabase
from ._jiff import ZonedDateTime as ZonedDateTime
from ._jiff import ZonedDateTimeDifference as ZonedDateTimeDifference
from ._jiff import ZonedDateTimeRound as ZonedDateTimeRound
from ._jiff import date as date
from ._jiff import datetime as datetime
from ._jiff import offset as offset
from ._jiff import time as time
from ._jiff import timespan as timespan
from ._jiter import JsonParseKwargs as JsonParseKwargs
from ._jiter import JsonPrimitive as JsonPrimitive
from ._jiter import JsonValue as JsonValue
from ._jiter import json_cache_clear as json_cache_clear
from ._jiter import json_cache_usage as json_cache_usage
from ._jiter import parse_json as parse_json
from ._jiter import parse_json_bytes as parse_json_bytes
from ._quick_maths import quick_maths as quick_maths
from ._regex import Regex as Regex
from ._reqwest import HttpClient as HttpClient
from ._reqwest import ReqwestError as ReqwestError
from ._reqwest import Response as Response
from ._reqwest import ResponseStream as ResponseStream
from ._reqwest import fetch as fetch
from ._same_file import is_same_file as is_same_file
from ._shlex import shplit as shplit
from ._size import Size as Size
from ._size import SizeFormatter as SizeFormatter
from ._size import fmt_size as fmt_size
from ._size import parse_size as parse_size
from ._sqlformat import SqlfmtQueryParams as SqlfmtQueryParams
from ._sqlformat import sqlfmt as sqlfmt
from ._sqlformat import sqlfmt_params as sqlfmt_params
from ._std import Duration as Duration
from ._std import FileType as FileType
from ._std import Instant as Instant
from ._std import Metadata as Metadata
from ._std import canonicalize as canonicalize
from ._std import copy as copy
from ._std import create_dir as create_dir
from ._std import create_dir_all as create_dir_all
from ._std import exists as exists
from ._std import instant as instant
from ._std import is_dir as is_dir
from ._std import is_file as is_file
from ._std import is_symlink as is_symlink
from ._std import metadata as metadata
from ._std import read as read
from ._std import read_bytes as read_bytes
from ._std import read_stream as read_stream
from ._std import read_text as read_text
from ._std import remove_dir as remove_dir
from ._std import remove_dir_all as remove_dir_all
from ._std import remove_file as remove_file
from ._std import rename as rename
from ._std import sleep as sleep
from ._std import write as write
from ._std import write_bytes as write_bytes
from ._std import write_text as write_text
from ._tokio import asleep as asleep
from ._tokio import copy_async as copy_async
from ._tokio import create_dir_async as create_dir_async
from ._tokio import metadata_async as metadata_async
from ._tokio import read_async as read_async
from ._tokio import read_dir_async as read_dir_async
from ._tokio import remove_dir_async as remove_dir_async
from ._tokio import remove_file_async as remove_file_async
from ._tokio import rename_async as rename_async
from ._tokio import sleep_async as sleep_async
from ._tokio import write_async as write_async
from ._unindent import unindent as unindent
from ._unindent import unindent_bytes as unindent_bytes
from ._url import URL as URL
from ._walkdir import WalkDirEntry as WalkDirEntry
from ._walkdir import WalkdirGen as WalkdirGen
from ._walkdir import walkdir as walkdir
from ._which import which as which
from ._which import which_all as which_all
from ._which import which_re as which_re
from .errors import FeatureNotEnabledError as FeatureNotEnabledError

# =============================================================================
# CONSTANTS
# =============================================================================
__version__: str
__authors__: str
__build_profile__: str
__build_timestamp__: str
__pkg_name__: str
__description__: str


# =============================================================================
# SH
# =============================================================================
def pwd() -> str: ...
def home() -> str: ...
def cd(path: str | PathLike[str]) -> None: ...
@t.overload
def ls(
    path: str | PathLike[str] | None = None,  # defaults to '.' if None
    *,
    absolute: bool = False,
    sort: bool = False,
    objects: t.Literal[False] = False,
) -> list[str]:
    """List directory contents - returns list of strings"""


@t.overload
def ls(
    path: str | PathLike[str] | None = None,  # defaults to '.' if None
    *,
    absolute: bool = False,
    sort: bool = False,
    objects: t.Literal[True] = True,
) -> list[FsPath]:
    """List directory contents - returns list of FsPath objects"""

ry.ryo3.errors

from __future__ import annotations


class FeatureNotEnabledError(RuntimeError):
    """Raised when a feature is not enabled in the current build."""

ry.ryo3.JSON

"""ry.ryo3.JSON"""

from typing import Literal

JsonPrimitive = None | bool | int | float | str
JsonValue = (
    JsonPrimitive
    | dict[str, JsonPrimitive | JsonValue]
    | list[JsonPrimitive | JsonValue]
)


def parse_json(
    data: bytes | str,
    /,
    *,
    allow_inf_nan: bool = True,
    cache_mode: Literal[True, False, "all", "keys", "none"] = "all",
    partial_mode: Literal[True, False, "off", "on", "trailing-strings"] = False,
    catch_duplicate_keys: bool = False,
    float_mode: Literal["float", "decimal", "lossless-float"] | bool = False,
) -> JsonValue: ...
def parse_json_bytes(
    data: bytes,
    /,
    *,
    allow_inf_nan: bool = True,
    cache_mode: Literal[True, False, "all", "keys", "none"] = "all",
    partial_mode: Literal[True, False, "off", "on", "trailing-strings"] = False,
    catch_duplicate_keys: bool = False,
    float_mode: Literal["float", "decimal", "lossless-float"] | bool = False,
) -> JsonValue: ...
def json_cache_clear() -> None: ...
def json_cache_usage() -> int: ...

ry.ryo3._brotli

"""ryo3-brotli types"""

from __future__ import annotations


# =============================================================================
# BROTLI
# =============================================================================
def brotli_encode(
    input: bytes, quality: int = 11, magic_number: bool = False
) -> bytes: ...
def brotli_decode(input: bytes) -> bytes: ...
def brotli(
    input: bytes, quality: int = 11, magic_number: bool = False
) -> bytes:
    """Alias for brotli_encode"""

ry.ryo3._bytes

import sys
from typing import overload

if sys.version_info >= (3, 12):
    from collections.abc import Buffer as Buffer
else:
    from typing_extensions import Buffer as Buffer


class Bytes(Buffer):
    """
    A buffer implementing the Python buffer protocol, allowing zero-copy access
    to underlying Rust memory.

    You can pass this to `memoryview` for a zero-copy view into the underlying
    data or to `bytes` to copy the underlying data into a Python `bytes`.

    Many methods from the Python `bytes` class are implemented on this,
    """

    def __init__(self, buf: Buffer = b"") -> None:
        """Construct a new Bytes object.

        This will be a zero-copy view on the Python byte slice.
        """

    def __add__(self, other: Buffer) -> Bytes: ...
    def __buffer__(self, flags: int) -> memoryview[int]: ...
    def __contains__(self, other: Buffer) -> bool: ...
    def __eq__(self, other: object) -> bool: ...
    @overload
    def __getitem__(self, other: int) -> int: ...
    @overload
    def __getitem__(self, other: slice) -> Bytes: ...
    def __mul__(self, other: Buffer) -> int: ...
    def __len__(self) -> int: ...
    def __repr__(self) -> str: ...
    def removeprefix(self, prefix: Buffer, /) -> Bytes:
        """
        If the binary data starts with the prefix string, return `bytes[len(prefix):]`.
        Otherwise, return the original binary data.
        """

    def removesuffix(self, suffix: Buffer, /) -> Bytes:
        """
        If the binary data ends with the suffix string and that suffix is not empty,
        return `bytes[:-len(suffix)]`. Otherwise, return the original binary data.
        """

    def isalnum(self) -> bool:
        """
        Return `True` if all bytes in the sequence are alphabetical ASCII characters or
        ASCII decimal digits and the sequence is not empty, `False` otherwise.

        Alphabetic ASCII characters are those byte values in the sequence
        `b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'`. ASCII decimal digits
        are those byte values in the sequence `b'0123456789'`.
        """

    def isalpha(self) -> bool:
        """
        Return `True` if all bytes in the sequence are alphabetic ASCII characters and
        the sequence is not empty, `False` otherwise.

        Alphabetic ASCII characters are those byte values in the sequence
        `b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'`.
        """

    def isascii(self) -> bool:
        """
        Return `True` if the sequence is empty or all bytes in the sequence are ASCII,
        `False` otherwise.

        ASCII bytes are in the range `0-0x7F`.
        """

    def isdigit(self) -> bool:
        """
        Return `True` if all bytes in the sequence are ASCII decimal digits and the
        sequence is not empty, `False` otherwise.

        ASCII decimal digits are those byte values in the sequence `b'0123456789'`.
        """

    def islower(self) -> bool:
        """
        Return `True` if there is at least one lowercase ASCII character in the sequence
        and no uppercase ASCII characters, `False` otherwise.
        """

    def isspace(self) -> bool:
        """
        Return `True` if all bytes in the sequence are ASCII whitespace and the sequence
        is not empty, `False` otherwise.

        ASCII whitespace characters are those byte values
        in the sequence `b' \t\n\r\x0b\f'` (space, tab, newline, carriage return,
        vertical tab, form feed).
        """

    def isupper(self) -> bool:
        """
        Return `True` if there is at least one uppercase alphabetic ASCII character in
        the sequence and no lowercase ASCII characters, `False` otherwise.
        """

    def lower(self) -> Bytes:
        """
        Return a copy of the sequence with all the uppercase ASCII characters converted
        to their corresponding lowercase counterpart.
        """

    def upper(self) -> Bytes:
        """
        Return a copy of the sequence with all the lowercase ASCII characters converted
        to their corresponding uppercase counterpart.
        """

    def to_bytes(self) -> bytes:
        """Copy this buffer's contents into a Python `bytes` object."""

    # =========================================================================
    # IMPL IN RY
    # =========================================================================

    def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str:
        """Decode the binary data using the given encoding."""

    def hex(
        self, sep: str | None = None, bytes_per_sep: int | None = None
    ) -> str:
        """Return a hexadecimal representation of the binary data."""

    @classmethod
    def fromhex(cls, hexstr: str) -> Bytes:
        """Construct a `Bytes` object from a hexadecimal string."""


BytesLike = Buffer | bytes | bytearray | memoryview | Bytes

ry.ryo3._bzip2

"""ryo3-bzip2 types"""

from __future__ import annotations

from ry._types import Buffer


# =============================================================================
# BZIP2
# =============================================================================
def bzip2_encode(input: Buffer, quality: int = 9) -> bytes: ...
def bzip2_decode(input: Buffer) -> bytes: ...
def bzip2(input: Buffer, quality: int = 9) -> bytes:
    """Alias for bzip2_encode"""

ry.ryo3._dev

"""ry.ryo3.dev"""

from __future__ import annotations

import typing as t


# =============================================================================
# SUBPROCESS (VERY MUCH WIP)
# =============================================================================
def run(
    *args: str | list[str],
    capture_output: bool = True,
    input: bytes | None = None,
) -> t.Any: ...


# =============================================================================
# STRING-DEV
# =============================================================================


def anystr_noop(s: t.AnyStr) -> t.AnyStr: ...
def string_noop(s: str) -> str: ...
def bytes_noop(s: bytes) -> bytes: ...

ry.ryo3._flate2

"""ryo3-flate2 types"""

from __future__ import annotations

from ry import Bytes
from ry._types import Buffer


# =============================================================================
# GZIP
# =============================================================================
def gzip_encode(input: Buffer, quality: int = 9) -> Bytes: ...
def gzip_decode(input: Buffer) -> Bytes: ...
def gzip(input: Buffer, quality: int = 9) -> Bytes:
    """Alias for gzip_encode"""


def gunzip(input: Buffer) -> Bytes:
    """Alias for gzip_decode"""


def is_gzipped(input: Buffer) -> bool: ...

ry.ryo3._fnv

"""ryo3-fnv types"""

import typing as t

from ry._types import Buffer


# =============================================================================
# FNV
# =============================================================================
class FnvHasher:
    name: t.Literal["fnv1a"]

    def __init__(self, input: Buffer | None = None) -> None: ...
    def update(self, input: Buffer) -> None: ...
    def digest(self) -> int: ...
    def hexdigest(self) -> str: ...
    def copy(self) -> FnvHasher: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...


def fnv1a(input: Buffer) -> FnvHasher: ...

ry.ryo3._fspath

"""ryo3-fspath types"""

from __future__ import annotations

import typing as t
from os import PathLike
from pathlib import Path

from ry import Bytes
from ry._types import Buffer, ToPy


# =============================================================================
# FSPATH
# =============================================================================
class FsPath(ToPy[Path]):
    def __init__(self, path: PathLike[str] | str | None = None) -> None: ...
    def __fspath__(self) -> str: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def __hash__(self) -> int: ...
    def __eq__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __lt__(self, other: PathLike[str] | str) -> bool: ...
    def __le__(self, other: PathLike[str] | str) -> bool: ...
    def __gt__(self, other: PathLike[str] | str) -> bool: ...
    def __ge__(self, other: PathLike[str] | str) -> bool: ...
    def __truediv__(self, other: PathLike[str] | str) -> FsPath: ...
    def __rtruediv__(self, other: PathLike[str] | str) -> FsPath: ...
    def __bytes__(self) -> bytes: ...
    def to_py(self) -> Path: ...
    def to_pathlib(self) -> Path: ...
    def read(self) -> Bytes: ...
    def read_text(self) -> str: ...
    def read_bytes(self) -> bytes: ...
    def absolute(self) -> FsPath: ...
    def resolve(self) -> FsPath: ...
    def write(self, data: Buffer | bytes) -> None: ...
    def write_bytes(self, data: Buffer | bytes) -> None: ...
    def write_text(self, data: str) -> None: ...
    def joinpath(self, *paths: str) -> FsPath: ...
    def exists(self) -> bool: ...
    def with_name(self, name: str) -> FsPath: ...
    def with_suffix(self, suffix: str) -> FsPath: ...
    def iterdir(self) -> t.Iterator[FsPath]: ...
    def relative_to(self, other: PathLike[str] | str | FsPath) -> FsPath: ...
    def as_posix(self) -> str: ...
    def as_uri(self) -> str: ...
    def equiv(self, other: PathLike[str] | str | FsPath) -> bool: ...
    def string(self) -> str: ...
    def clone(self) -> FsPath: ...

    # =========================================================================
    # CLASSMETHODS
    # =========================================================================
    @classmethod
    def cwd(cls) -> FsPath: ...
    @classmethod
    def home(cls) -> FsPath: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def anchor(self) -> str: ...
    @property
    def drive(self) -> str: ...
    @property
    def name(self) -> str: ...
    @property
    def parent(self) -> FsPath: ...
    @property
    def parents(self) -> t.Sequence[FsPath]: ...
    @property
    def parts(self) -> tuple[str, ...]: ...
    @property
    def root(self) -> str: ...
    @property
    def stem(self) -> str: ...
    @property
    def suffix(self) -> str: ...
    @property
    def suffixes(self) -> list[str]: ...

    # =========================================================================
    # std::path::PathBuf (deref -> std::path::Path)
    # =========================================================================
    def ancestors(self) -> t.Iterator[FsPath]: ...
    def canonicalize(self) -> FsPath: ...
    def components(self) -> t.Iterator[FsPath]: ...
    def display(self) -> str: ...
    def ends_with(self, path: PathLike[str] | str) -> bool: ...
    def extension(self) -> str: ...
    def file_name(self) -> str: ...
    def file_prefix(self) -> FsPath: ...
    def file_stem(self) -> str: ...
    def has_root(self) -> bool: ...
    def is_absolute(self) -> bool: ...
    def is_dir(self) -> bool: ...
    def is_file(self) -> bool: ...
    def is_relative(self) -> bool: ...
    def is_symlink(self) -> bool: ...
    def starts_with(self, path: PathLike[str] | str) -> bool: ...
    def strip_prefix(self, prefix: PathLike[str] | str) -> FsPath: ...
    def with_extension(self, ext: str) -> FsPath: ...
    def with_file_name(self, name: str) -> FsPath: ...

ry.ryo3._glob

"""ryo3-glob types"""

from __future__ import annotations

import typing as t
from os import PathLike
from pathlib import Path

import typing_extensions as te

T = t.TypeVar("T")


class _MatchOptions(t.TypedDict, total=False):
    case_sensitive: bool
    require_literal_separator: bool
    require_literal_leading_dot: bool


class GlobPaths(t.Generic[T]):
    """glob::Paths iterable wrapper"""

    def __next__(self) -> T: ...
    def __iter__(self) -> t.Iterator[T]: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def collect(self) -> list[T]: ...
    def take(self, n: int) -> list[T]: ...


def glob(
    pattern: str,
    **kwargs: te.Unpack[_MatchOptions],
) -> GlobPaths[Path]:
    """Return glob iterable for paths matching the pattern."""


class Pattern:
    def __init__(self, pattern: str) -> None: ...
    def __call__(
        self,
        ob: str | PathLike[str],
        **kwargs: te.Unpack[_MatchOptions],
    ) -> bool: ...
    def matches(self, s: str) -> bool: ...
    def matches_path(self, path: PathLike[str]) -> bool: ...
    def matches_with(
        self,
        s: str,
        **kwargs: te.Unpack[_MatchOptions],
    ) -> bool: ...
    def matches_path_with(
        self,
        path: PathLike[str],
        **kwargs: te.Unpack[_MatchOptions],
    ) -> bool: ...
    @staticmethod
    def escape(pattern: str) -> str: ...

ry.ryo3._globset

"""ryo3-globset types"""

from __future__ import annotations

from os import PathLike


class Glob:
    """globset::Glob wrapper"""

    def __init__(
        self,
        pattern: str,
        /,
        *,
        case_insensitive: bool | None = None,
        literal_separator: bool | None = None,
        backslash_escape: bool | None = None,
    ) -> None: ...
    def regex(self) -> str: ...
    def is_match(self, path: str | PathLike[str]) -> bool: ...
    def __call__(self, path: str | PathLike[str]) -> bool: ...
    def __invert__(self) -> Glob: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def globset(self) -> GlobSet: ...
    def globster(self) -> Globster: ...


class GlobSet:
    """globset::GlobSet wrapper"""

    def __init__(
        self,
        patterns: list[str],
        /,
        *,
        case_insensitive: bool | None = None,
        literal_separator: bool | None = None,
        backslash_escape: bool | None = None,
    ) -> None: ...
    def is_empty(self) -> bool: ...
    def is_match(self, path: str) -> bool: ...
    def matches(self, path: str) -> list[int]: ...
    def __call__(self, path: str) -> bool: ...
    def __invert__(self) -> GlobSet: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def globster(self) -> Globster: ...


class Globster:
    """Globster is a matcher with claws!

    Note: The north american `Globster` is similar to the european `Globset`
          but allows for negative patterns (prefixed with '!')

    """

    def __init__(
        self,
        patterns: list[str],
        /,
        *,
        case_insensitive: bool | None = None,
        literal_separator: bool | None = None,
        backslash_escape: bool | None = None,
    ) -> None: ...
    def is_empty(self) -> bool: ...
    def is_match(self, path: str | PathLike[str]) -> bool: ...
    def __call__(self, path: str | PathLike[str]) -> bool: ...
    def __invert__(self) -> GlobSet: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...


def globster(
    patterns: list[str] | tuple[str, ...],
    /,
    *,
    case_insensitive: bool | None = None,
    literal_separator: bool | None = None,
    backslash_escape: bool | None = None,
) -> Globster: ...

ry.ryo3._heck

"""ryo3-heck types"""

from __future__ import annotations


def camel_case(string: str) -> str: ...
def kebab_case(string: str) -> str: ...
def pascal_case(string: str) -> str: ...
def shouty_kebab_case(string: str) -> str: ...
def shouty_snake_case(string: str) -> str: ...
def snake_case(string: str) -> str: ...
def snek_case(string: str) -> str: ...
def title_case(string: str) -> str: ...
def train_case(string: str) -> str: ...

ry.ryo3._jiff

"""jiff types"""

import datetime as pydt
import typing as t
from typing import Protocol

import typing_extensions as te

from ry._types import (
    DateTimeTypedDict,
    DateTypedDict,
    TimeSpanTypedDict,
    TimeTypedDict,
    ToPy,
)
from ry.ryo3 import Duration

T = t.TypeVar("T")
# =============================================================================
# JIFF
# =============================================================================
JIFF_UNIT = t.Literal[
    "year",
    "month",
    "week",
    "day",
    "hour",
    "minute",
    "second",
    "millisecond",
    "microsecond",
    "nanosecond",
]

JIFF_ROUND_MODE = t.Literal[
    "ceil",
    "floor",
    "expand",
    "trunc",
    "half_ceil",
    "half_floor",
    "half_expand",
    "half_trunc",
    "half_even",
]

WEEKDAY_STR = t.Literal[
    "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"
]

WEEKDAY_INT = t.Literal[
    1,  # Monday
    2,  # Tuesday
    3,  # Wednesday
    4,  # Thursday
    5,  # Friday
    6,  # Saturday
    7,  # Sunday
]

WEEKDAY: te.TypeAlias = WEEKDAY_STR | WEEKDAY_INT


class ToPyDate(Protocol):
    def to_pydate(self) -> pydt.date: ...


class ToPyTime(Protocol):
    def to_pytime(self) -> pydt.time: ...


class ToPyDateTime(Protocol):
    def to_pydatetime(self) -> pydt.datetime: ...


class ToPyTimeDelta(Protocol):
    def to_pytimedelta(self) -> pydt.timedelta: ...


class ToPyTzInfo(Protocol):
    def to_pytzinfo(self) -> pydt.tzinfo: ...


class Date(ToPy[pydt.date], ToPyDate):
    MIN: Date
    MAX: Date
    ZERO: Date

    def __init__(self, year: int, month: int, day: int) -> None: ...

    # =========================================================================
    # STRING
    # =========================================================================
    def string(self) -> str: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...

    # =========================================================================
    # PYTHON_CONVERSIONS
    # =========================================================================
    def to_py(self) -> pydt.date: ...
    def to_pydate(self) -> pydt.date: ...
    @classmethod
    def from_pydate(cls: type[Date], date: pydt.date) -> Date: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def year(self) -> int: ...
    @property
    def month(self) -> int: ...
    @property
    def day(self) -> int: ...
    @property
    def weekday(self) -> int: ...

    # =========================================================================
    # CLASSMETHODS
    # =========================================================================
    @classmethod
    def from_iso_week_date(
        cls: type[Date], year: int, week: int, weekday: int
    ) -> Date: ...
    @classmethod
    def today(cls: type[Date]) -> Date: ...

    # =========================================================================
    # STRPTIME/STRFTIME
    # =========================================================================
    @classmethod
    def strptime(cls: type[Date], format: str, string: str) -> Date: ...
    def strftime(self, format: str) -> str: ...

    # =========================================================================
    # OPERATORS
    # =========================================================================
    def __add__(self, other: TimeSpan | SignedDuration | Duration) -> Date: ...
    @t.overload
    def __sub__(self, other: Date) -> TimeSpan: ...
    @t.overload
    def __sub__(self, other: TimeSpan | SignedDuration | Duration) -> Date: ...
    @t.overload
    def __isub__(self, other: Date) -> TimeSpan: ...
    @t.overload
    def __isub__(self, other: TimeSpan | SignedDuration | Duration) -> Date: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================
    def at(
        self, hour: int, minute: int, second: int, nanosecond: int
    ) -> DateTime: ...
    def asdict(self) -> DateTypedDict: ...
    def astuple(self) -> tuple[int, int, int]: ...
    def checked_add(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Date: ...
    def day_of_year(self) -> int: ...
    def day_of_year_no_leap(self) -> int | None: ...
    def days_in_month(self) -> int: ...
    def days_in_year(self) -> int: ...
    def duration_since(self, other: Date) -> Date: ...
    def duration_until(self, other: Date) -> Date: ...
    def era_year(self) -> tuple[int, t.Literal["BCE", "CE"]]: ...
    def first_of_month(self) -> Date: ...
    def first_of_year(self) -> Date: ...
    def iso_week_date(self) -> ISOWeekDate: ...
    def in_leap_year(self) -> bool: ...
    def in_tz(self, tz: str) -> ZonedDateTime: ...
    def intz(self, tz: str) -> ZonedDateTime: ...
    def last_of_month(self) -> Date: ...
    def last_of_year(self) -> Date: ...
    def nth_weekday(self, nth: int, weekday: WEEKDAY) -> Date: ...
    def nth_weekday_of_month(self, nth: int, weekday: WEEKDAY) -> Date: ...
    def saturating_add(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Date: ...
    def saturating_sub(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Date: ...
    def series(self, span: TimeSpan) -> JiffSeries[Date]: ...
    def sub_date(self, other: Date) -> TimeSpan: ...
    def to_datetime(self, time: Time) -> DateTime: ...
    def to_zoned(self, tz: TimeZone) -> ZonedDateTime: ...
    def tomorrow(self) -> Date: ...
    def yesterday(self) -> Date: ...

    # =========================================================================
    # SINCE/UNTIL
    # =========================================================================
    def _since(self, other: DateDifference) -> TimeSpan: ...
    def _until(self, other: DateDifference) -> TimeSpan: ...
    def since(
        self,
        other: Date | DateTime | ZonedDateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> TimeSpan: ...
    def until(
        self,
        other: Date | DateTime | ZonedDateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> TimeSpan: ...

    # =========================================================================
    # INSTANCE METHODS W/ OVERLOADS
    # =========================================================================
    @t.overload
    def checked_sub(self, other: Date) -> TimeSpan: ...
    @t.overload
    def checked_sub(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Date: ...


class DateDifference:
    def __init__(
        self,
        date: Date,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> None: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def smallest(self, unit: JIFF_UNIT) -> DateDifference: ...
    def largest(self, unit: JIFF_UNIT) -> DateDifference: ...
    def mode(self, mode: JIFF_ROUND_MODE) -> DateDifference: ...
    def increment(self, increment: int) -> DateDifference: ...


class Time(ToPy[pydt.time], ToPyTime):
    MIN: Time
    MAX: Time

    def __init__(
        self,
        hour: int = 0,
        minute: int = 0,
        second: int = 0,
        nanosecond: int = 0,
    ) -> None: ...

    # =========================================================================
    # STRING
    # =========================================================================
    def string(self) -> str: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...

    # =========================================================================
    # OPERATORS/DUNDERS
    # =========================================================================
    def __add__(self, other: TimeSpan | SignedDuration | Duration) -> Time: ...
    @t.overload
    def __sub__(self, other: Time) -> TimeSpan: ...
    @t.overload
    def __sub__(self, other: TimeSpan | SignedDuration | Duration) -> Time: ...
    @t.overload
    def __isub__(self, other: Time) -> TimeSpan: ...
    @t.overload
    def __isub__(self, other: TimeSpan | SignedDuration | Duration) -> Time: ...

    # =========================================================================
    # STRPTIME/STRFTIME/PARSE
    # =========================================================================
    @classmethod
    def strptime(cls: type[Time], format: str, string: str) -> Time: ...
    def strftime(self, format: str) -> str: ...

    # =========================================================================
    # PYTHON CONVERSIONS
    # =========================================================================
    def to_py(self) -> pydt.time: ...
    def to_pytime(self) -> pydt.time: ...
    @classmethod
    def from_pytime(cls: type[Time], t: pydt.time) -> Time: ...

    # =========================================================================
    # CLASS METHODS
    # =========================================================================
    @classmethod
    def midnight(cls: type[Time]) -> Time: ...
    @classmethod
    def now(cls: type[Time]) -> Time: ...
    @classmethod
    def parse(cls: type[Time], s: str) -> Time: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def hour(self) -> int: ...
    @property
    def minute(self) -> int: ...
    @property
    def second(self) -> int: ...
    @property
    def millisecond(self) -> int: ...
    @property
    def microsecond(self) -> int: ...
    @property
    def nanosecond(self) -> int: ...
    @property
    def subsec_nanosecond(self) -> None: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================
    def astuple(self) -> tuple[int, int, int, int]: ...
    def asdict(self) -> TimeTypedDict: ...
    def series(self, span: TimeSpan) -> JiffSeries[Time]: ...
    def checked_add(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Time: ...
    @t.overload
    def checked_sub(self, other: Time) -> TimeSpan: ...
    @t.overload
    def checked_sub(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Time: ...
    def saturating_add(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Time: ...
    def saturating_sub(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Time: ...
    def wrapping_add(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Time: ...
    def wrapping_sub(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Time: ...
    def on(self, year: int, month: int, day: int) -> DateTime: ...
    def duration_until(self, other: Time) -> SignedDuration: ...
    def duration_since(self, other: Time) -> SignedDuration: ...
    def round(
        self,
        smallest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> Time: ...
    def to_datetime(self, d: Date) -> DateTime: ...

    # =========================================================================
    # SINCE/UNTIL
    # =========================================================================
    def _since(self, other: TimeDifference) -> TimeSpan: ...
    def _until(self, other: TimeDifference) -> TimeSpan: ...
    def since(
        self,
        other: Time | DateTime | ZonedDateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> TimeSpan: ...
    def until(
        self,
        other: Time | DateTime | ZonedDateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> TimeSpan: ...


class TimeDifference:
    def __init__(
        self,
        date: Time,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> None: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def smallest(self, unit: JIFF_UNIT) -> TimeDifference: ...
    def largest(self, unit: JIFF_UNIT) -> TimeDifference: ...
    def mode(self, mode: JIFF_ROUND_MODE) -> TimeDifference: ...
    def increment(self, increment: int) -> TimeDifference: ...


class DateTime(ToPy[pydt.datetime], ToPyDate, ToPyTime, ToPyDateTime):
    MIN: DateTime
    MAX: DateTime
    ZERO: DateTime

    def __init__(
        self,
        year: int,
        month: int,
        day: int,
        hour: int = 0,
        minute: int = 0,
        second: int = 0,
        nanosecond: int = 0,
    ) -> None: ...
    def __str__(self) -> str: ...
    def string(self) -> str: ...

    # =========================================================================
    # STRPTIME/STRFTIME/PARSE
    # =========================================================================
    def strftime(self, format: str) -> str: ...
    @classmethod
    def strptime(cls: type[DateTime], format: str, string: str) -> DateTime: ...
    @classmethod
    def parse(cls: type[DateTime], s: str) -> DateTime: ...

    # =========================================================================
    # PYTHON CONVERSIONS
    # =========================================================================
    @classmethod
    def from_pydatetime(cls: type[DateTime], dt: pydt.datetime) -> DateTime: ...
    def to_py(self) -> pydt.datetime: ...
    def to_pydate(self) -> pydt.date: ...
    def to_pydatetime(self) -> pydt.datetime: ...
    def to_pytime(self) -> pydt.time: ...
    # =========================================================================
    # CLASS METHODS
    # =========================================================================
    @classmethod
    def now(cls: type[DateTime]) -> DateTime: ...
    @classmethod
    def from_parts(cls: type[DateTime], date: Date, time: Time) -> DateTime: ...

    # =========================================================================
    # OPERATORS
    # =========================================================================
    def __repr__(self) -> str: ...
    def __add__(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> DateTime: ...
    @t.overload
    def __sub__(self, other: DateTime) -> TimeSpan: ...
    @t.overload
    def __sub__(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> DateTime: ...
    @t.overload
    def __isub__(self, other: DateTime) -> TimeSpan: ...
    @t.overload
    def __isub__(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> DateTime: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================
    def asdict(self) -> DateTimeTypedDict: ...
    def checked_add(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> DateTime: ...
    def date(self) -> Date: ...
    def day_of_year(self) -> int: ...
    def day_of_year_no_leap(self) -> int | None: ...
    def days_in_month(self) -> int: ...
    def days_in_year(self) -> int: ...
    def duration_since(self, other: DateTime) -> SignedDuration: ...
    def duration_until(self, other: DateTime) -> SignedDuration: ...
    def end_of_day(self) -> DateTime: ...
    def era_year(self) -> tuple[int, t.Literal["BCE", "CE"]]: ...
    def first_of_month(self) -> DateTime: ...
    def first_of_year(self) -> DateTime: ...
    def in_leap_year(self) -> bool: ...
    def in_tz(self, tz: str) -> ZonedDateTime: ...
    def intz(self, tz: str) -> ZonedDateTime: ...
    def iso_week_date(self) -> ISOWeekDate: ...
    def last_of_month(self) -> DateTime: ...
    def last_of_year(self) -> DateTime: ...
    def nth_weekday(self, nth: int, weekday: WEEKDAY) -> DateTime: ...
    def nth_weekday_of_month(self, nth: int, weekday: WEEKDAY) -> DateTime: ...
    def round(
        self,
        smallest: JIFF_UNIT | None = None,
        *,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> DateTime: ...
    def _round(self, options: DateTimeRound) -> DateTime: ...
    def saturating_add(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> DateTime: ...
    def series(self, span: TimeSpan) -> JiffSeries[DateTime]: ...
    def start_of_day(self) -> DateTime: ...
    def time(self) -> Time: ...
    def to_zoned(self, tz: TimeZone) -> ZonedDateTime: ...
    def tomorrow(self) -> DateTime: ...
    def yesterday(self) -> DateTime: ...
    # =========================================================================
    # INSTANCE METHODS W/ OVERLOADS
    # =========================================================================
    @t.overload
    def checked_sub(self, other: DateTime) -> TimeSpan: ...
    @t.overload
    def checked_sub(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> DateTime: ...
    @t.overload
    def saturating_sub(self, other: DateTime) -> TimeSpan: ...
    @t.overload
    def saturating_sub(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> DateTime: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def year(self) -> int: ...
    @property
    def month(self) -> int: ...
    @property
    def day(self) -> int: ...
    @property
    def hour(self) -> int: ...
    @property
    def minute(self) -> int: ...
    @property
    def second(self) -> int: ...
    @property
    def millisecond(self) -> int: ...
    @property
    def microsecond(self) -> int: ...
    @property
    def nanosecond(self) -> int: ...
    @property
    def subsec_nanosecond(self) -> int: ...
    @property
    def weekday(self) -> int: ...

    # =========================================================================
    # SINCE/UNTIL
    # =========================================================================
    def _since(self, other: DateTimeDifference) -> TimeSpan: ...
    def _until(self, other: DateTimeDifference) -> TimeSpan: ...
    def since(
        self,
        other: Date | Time | DateTime | ZonedDateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> TimeSpan: ...
    def until(
        self,
        other: Date | Time | DateTime | ZonedDateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> TimeSpan: ...


class DateTimeDifference:
    def __init__(
        self,
        date: DateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> None: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def smallest(self, unit: JIFF_UNIT) -> DateTimeDifference: ...
    def largest(self, unit: JIFF_UNIT) -> DateTimeDifference: ...
    def mode(self, mode: JIFF_ROUND_MODE) -> DateTimeDifference: ...
    def increment(self, increment: int) -> DateTimeDifference: ...


class TimeZone(ToPy[pydt.tzinfo], ToPyTzInfo):
    def __init__(self, name: str) -> None: ...
    def __eq__(self, other: object) -> bool: ...

    # =========================================================================
    # STRING
    # =========================================================================
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...

    # =========================================================================
    # PYTHON CONVERSIONS
    # =========================================================================

    def to_py(self) -> pydt.tzinfo: ...
    def to_pytzinfo(self) -> pydt.tzinfo: ...
    @classmethod
    def from_pytzinfo(cls: type[TimeZone], tz: pydt.tzinfo) -> TimeZone: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def name(self) -> str: ...

    # =========================================================================
    # CLASS METHODS
    # =========================================================================
    @classmethod
    def fixed(cls: type[TimeZone], offset: Offset) -> TimeZone: ...
    @classmethod
    def get(cls: type[TimeZone], name: str) -> TimeZone: ...
    @classmethod
    def posix(cls: type[TimeZone], name: str) -> TimeZone: ...
    @classmethod
    def system(cls: type[TimeZone]) -> TimeZone: ...
    @classmethod
    def try_system(cls: type[TimeZone]) -> TimeZone: ...
    @classmethod
    def tzif(cls: type[TimeZone], name: str, data: bytes) -> TimeZone: ...
    @classmethod
    def utc(cls: type[TimeZone]) -> TimeZone: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================
    def iana_name(self) -> str | None: ...
    def to_datetime(self, dt: Timestamp) -> DateTime: ...
    def to_offset(self, timestamp: Timestamp) -> Offset: ...
    def to_timestamp(self, dt: DateTime) -> Timestamp: ...
    def to_zoned(self, other: DateTime) -> ZonedDateTime: ...

    # =========================================================================
    # NOT IMPLEMENTED
    # =========================================================================
    def to_ambiguous_timestamp(self) -> t.NoReturn: ...
    def to_ambiguous_zoned(self) -> t.NoReturn: ...


class SignedDuration(ToPy[pydt.timedelta], ToPyTimeDelta):
    MIN: SignedDuration
    MAX: SignedDuration
    ZERO: SignedDuration

    def __init__(self, secs: int = 0, nanos: int = 0) -> None: ...

    # =========================================================================
    # OPERATORS/DUNDERS
    # =========================================================================
    def __hash__(self) -> int: ...
    def __mul__(self, other: int) -> SignedDuration: ...
    def __rmul__(self, other: int) -> SignedDuration: ...
    def __eq__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __lt__(self, other: object) -> bool: ...
    def __le__(self, other: object) -> bool: ...
    def __gt__(self, other: object) -> bool: ...
    def __ge__(self, other: object) -> bool: ...
    def __neg__(self) -> SignedDuration: ...
    def __add__(self, other: SignedDuration) -> SignedDuration: ...
    def __abs__(self) -> SignedDuration: ...
    def __div__(self, other: int) -> SignedDuration: ...
    def abs(self) -> SignedDuration: ...
    def unsigned_abs(self) -> Duration: ...
    def __richcmp__(
        self, other: SignedDuration | pydt.timedelta, op: int
    ) -> bool: ...

    # =========================================================================
    # STRING
    # =========================================================================
    def __str__(self) -> str: ...
    def string(self, human: bool = False) -> str: ...

    # =========================================================================
    # PYTHON CONVERSIONS
    # =========================================================================
    @classmethod
    def from_pytimedelta(
        cls: type[SignedDuration], td: pydt.timedelta
    ) -> SignedDuration: ...
    def to_py(self) -> pydt.timedelta: ...
    def to_pytimedelta(self) -> pydt.timedelta: ...

    # =========================================================================
    # CLASS METHODS
    # =========================================================================
    @classmethod
    def parse(cls: type[SignedDuration], s: str) -> SignedDuration: ...
    @classmethod
    def from_hours(cls: type[SignedDuration], n: int) -> SignedDuration: ...
    @classmethod
    def from_micros(cls: type[SignedDuration], n: int) -> SignedDuration: ...
    @classmethod
    def from_millis(cls: type[SignedDuration], n: int) -> SignedDuration: ...
    @classmethod
    def from_mins(cls: type[SignedDuration], n: int) -> SignedDuration: ...
    @classmethod
    def from_nanos(cls: type[SignedDuration], n: int) -> SignedDuration: ...
    @classmethod
    def from_secs(cls: type[SignedDuration], n: int) -> SignedDuration: ...
    @classmethod
    def from_secs_f32(
        cls: type[SignedDuration], n: float
    ) -> SignedDuration: ...
    @classmethod
    def from_secs_f64(
        cls: type[SignedDuration], n: float
    ) -> SignedDuration: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def is_negative(self) -> bool: ...
    @property
    def is_zero(self) -> bool: ...
    @property
    def secs(self) -> int: ...
    @property
    def nanos(self) -> int: ...
    @property
    def days(self) -> int: ...
    @property
    def seconds(self) -> int: ...
    @property
    def microseconds(self) -> int: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================
    def as_hours(self) -> int: ...
    def as_micros(self) -> int: ...
    def as_millis(self) -> int: ...
    def as_millis_f32(self) -> float: ...
    def as_millis_f64(self) -> float: ...
    def as_mins(self) -> int: ...
    def as_nanos(self) -> int: ...
    def as_secs(self) -> int: ...
    def as_secs_f32(self) -> float: ...
    def as_secs_f64(self) -> float: ...
    def checked_add(self, other: SignedDuration) -> SignedDuration | None: ...
    def checked_div(self, other: int) -> SignedDuration | None: ...
    def checked_mul(self, other: int) -> SignedDuration | None: ...
    def checked_neg(self) -> SignedDuration | None: ...
    def checked_sub(self, other: SignedDuration) -> SignedDuration | None: ...
    def div_duration_f32(self, other: SignedDuration) -> float: ...
    def div_duration_f64(self, other: SignedDuration) -> float: ...
    def div_f32(self, other: int) -> float: ...
    def div_f64(self, other: int) -> float: ...
    def is_positive(self) -> bool: ...
    def mul_f32(self, other: int) -> SignedDuration: ...
    def mul_f64(self, other: int) -> SignedDuration: ...
    def saturating_add(self, other: SignedDuration) -> SignedDuration: ...
    def saturating_mul(self, other: int) -> SignedDuration: ...
    def saturating_sub(self, other: SignedDuration) -> SignedDuration: ...
    def signum(self) -> t.Literal[-1, 0, 1]: ...
    def subsec_micros(self) -> int: ...
    def subsec_millis(self) -> int: ...
    def subsec_nanos(self) -> int: ...
    def to_timespan(self) -> TimeSpan: ...


# put in quotes to avoid ruff F821 - undefined name
_TimeSpanArithmeticSingle = TimeSpan | Duration | SignedDuration
_TimeSpanArithmeticTuple = tuple[
    _TimeSpanArithmeticSingle, ZonedDateTime | Date | DateTime
]
TimeSpanArithmetic = _TimeSpanArithmeticSingle | _TimeSpanArithmeticTuple


class TimeSpan(ToPy[pydt.timedelta], ToPyTimeDelta):
    def __init__(
        self,
        years: int = 0,
        months: int = 0,
        weeks: int = 0,
        days: int = 0,
        hours: int = 0,
        minutes: int = 0,
        seconds: int = 0,
        milliseconds: int = 0,
        microseconds: int = 0,
        nanoseconds: int = 0,
    ) -> None: ...

    # =========================================================================
    # STRING
    # =========================================================================
    def string(self, human: bool = False) -> str: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def repr_full(self) -> str: ...

    # =========================================================================
    # PYTHON CONVERSIONS
    # =========================================================================
    @classmethod
    def from_pytimedelta(cls, td: pydt.timedelta) -> TimeSpan: ...
    def to_pytimedelta(self) -> pydt.timedelta: ...
    def to_py(self) -> pydt.timedelta: ...

    # =========================================================================
    # CLASS METHODS
    # =========================================================================
    @classmethod
    def parse(cls, s: str) -> TimeSpan: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def is_positive(self) -> bool: ...
    @property
    def is_negative(self) -> bool: ...
    @property
    def is_zero(self) -> bool: ...
    @property
    def years(self) -> int: ...
    @property
    def months(self) -> int: ...
    @property
    def weeks(self) -> int: ...
    @property
    def days(self) -> int: ...
    @property
    def hours(self) -> int: ...
    @property
    def minutes(self) -> int: ...
    @property
    def seconds(self) -> int: ...
    @property
    def milliseconds(self) -> int: ...
    @property
    def microseconds(self) -> int: ...
    @property
    def nanoseconds(self) -> int: ...

    # =========================================================================
    # OPERATORS
    # =========================================================================
    def __add__(
        self,
        val: TimeSpanArithmetic,
    ) -> te.Self: ...
    def __sub__(
        self,
        val: TimeSpanArithmetic,
    ) -> te.Self: ...
    def __mul__(self, other: int) -> te.Self: ...
    def __neg__(self) -> te.Self: ...
    def __abs__(self) -> te.Self: ...
    def __invert__(self) -> te.Self: ...
    def __eq__(self, other: object) -> bool: ...
    def __ge__(self, other: TimeSpan) -> bool: ...
    def __gt__(self, other: TimeSpan) -> bool: ...
    def __le__(self, other: TimeSpan) -> bool: ...
    def __lt__(self, other: TimeSpan) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __rmul__(self, other: TimeSpan) -> bool: ...
    def __hash__(self) -> int: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================

    def abs(self) -> te.Self: ...
    def asdict(self) -> TimeSpanTypedDict: ...
    def checked_add(self, val: TimeSpanArithmetic) -> te.Self: ...
    def checked_mul(self, other: int) -> te.Self: ...
    def checked_sub(self, val: TimeSpanArithmetic) -> te.Self: ...
    def compare(
        self,
        other: TimeSpan,
        relative: ZonedDateTime | DateTime | Date | None = None,
        days_are_24_hours: bool = False,
    ) -> int: ...
    def negate(self) -> te.Self: ...
    def replace(
        self,
        years: int | None = None,
        months: int | None = None,
        weeks: int | None = None,
        days: int | None = None,
        hours: int | None = None,
        minutes: int | None = None,
        seconds: int | None = None,
        milliseconds: int | None = None,
        microseconds: int | None = None,
        nanoseconds: int | None = None,
    ) -> te.Self: ...
    def round(
        self,
        smallest: JIFF_UNIT,
        increment: int = 1,
        *,
        relative: ZonedDateTime | Date | DateTime | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
    ) -> te.Self: ...
    def signum(self) -> t.Literal[-1, 0, 1]: ...
    def to_signed_duration(
        self, relative: ZonedDateTime | Date | DateTime
    ) -> SignedDuration: ...
    def total(
        self,
        unit: JIFF_UNIT,
        relative: ZonedDateTime | Date | DateTime | None = None,
        days_are_24_hours: bool = False,
    ) -> int: ...
    def total_seconds(self) -> int: ...
    def try_years(self, years: int) -> te.Self: ...
    def try_months(self, months: int) -> te.Self: ...
    def try_weeks(self, weeks: int) -> te.Self: ...
    def try_days(self, days: int) -> te.Self: ...
    def try_hours(self, hours: int) -> te.Self: ...
    def try_minutes(self, minutes: int) -> te.Self: ...
    def try_seconds(self, seconds: int) -> te.Self: ...
    def try_milliseconds(self, milliseconds: int) -> te.Self: ...
    def try_microseconds(self, microseconds: int) -> te.Self: ...
    def try_nanoseconds(self, nanoseconds: int) -> te.Self: ...

    # -------------------------------------------------------------------------
    # PANIC-INDUCING METHODS
    # -------------------------------------------------------------------------
    def _years(self, years: int) -> te.Self: ...
    def _months(self, months: int) -> te.Self: ...
    def _weeks(self, weeks: int) -> te.Self: ...
    def _days(self, days: int) -> te.Self: ...
    def _hours(self, hours: int) -> te.Self: ...
    def _minutes(self, minutes: int) -> te.Self: ...
    def _seconds(self, seconds: int) -> te.Self: ...
    def _milliseconds(self, milliseconds: int) -> te.Self: ...
    def _microseconds(self, microseconds: int) -> te.Self: ...
    def _nanoseconds(self, nanoseconds: int) -> te.Self: ...


class Timestamp(ToPy[pydt.datetime], ToPyDate, ToPyTime, ToPyDateTime):
    """
    A representation of a timestamp with second and nanosecond precision.
    """

    MIN: Timestamp
    MAX: Timestamp
    UNIX_EPOCH: Timestamp

    def __init__(
        self, second: int | None = None, nanosecond: int | None = None
    ) -> None: ...

    # =========================================================================
    # CLASS METHODS
    # =========================================================================
    @classmethod
    def now(cls) -> Timestamp: ...
    @classmethod
    def parse(cls, s: str) -> Timestamp: ...
    @classmethod
    def from_millisecond(cls, millisecond: int) -> Timestamp: ...
    @classmethod
    def from_microsecond(cls, microsecond: int) -> Timestamp: ...
    @classmethod
    def from_nanosecond(cls, nanosecond: int) -> Timestamp: ...
    @classmethod
    def from_second(cls, second: int) -> Timestamp: ...

    # =========================================================================
    # STRING
    # =========================================================================
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...

    # =========================================================================
    # OPERATORS/DUNDERS
    # =========================================================================
    def __add__(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> te.Self: ...
    def __eq__(self, other: object) -> bool: ...
    def __ge__(self, other: Timestamp) -> bool: ...
    def __gt__(self, other: Timestamp) -> bool: ...
    def __le__(self, other: Timestamp) -> bool: ...
    def __lt__(self, other: Timestamp) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __richcmp__(self, other: Timestamp, op: int) -> bool: ...

    # =========================================================================
    # OPERATORS/DUNDERS W/ OVERLOADS
    # =========================================================================
    @t.overload
    def __isub__(self, other: Timestamp) -> TimeSpan: ...
    @t.overload
    def __isub__(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> te.Self: ...
    @t.overload
    def __sub__(self, other: Timestamp) -> TimeSpan: ...
    @t.overload
    def __sub__(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> te.Self: ...

    # =========================================================================
    # PYTHON CONVERSIONS
    # =========================================================================
    @classmethod
    def from_pydatetime(cls, dt: pydt.datetime) -> Timestamp: ...
    def to_py(self) -> pydt.datetime: ...
    def to_pydate(self) -> pydt.date: ...
    def to_pydatetime(self) -> pydt.datetime: ...
    def to_pytime(self) -> pydt.time: ...

    # =========================================================================
    # STRPTIME/STRFTIME
    # =========================================================================
    def strftime(self, format: str) -> str: ...
    @classmethod
    def strptime(cls, format: str, input: str) -> Timestamp: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================

    def as_microsecond(self) -> int: ...
    def as_millisecond(self) -> int: ...
    def as_nanosecond(self) -> int: ...
    def as_second(self) -> int: ...
    def checked_add(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Timestamp: ...
    @t.overload
    def checked_sub(self, other: Timestamp) -> TimeSpan: ...
    @t.overload
    def checked_sub(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Timestamp: ...
    def display_with_offset(self, offset: Offset) -> str: ...
    def in_tz(self, tz: str) -> ZonedDateTime: ...
    def intz(self, tz: str) -> ZonedDateTime:
        """Deprecated ~ use `in_tz`"""

    def is_zero(self) -> bool: ...
    def saturating_add(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Timestamp: ...
    def saturating_sub(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Timestamp: ...
    def series(self, span: TimeSpan) -> JiffSeries[Timestamp]: ...
    def signum(self) -> t.Literal[-1, 0, 1]: ...
    def string(self) -> str: ...
    def subsec_microsecond(self) -> int: ...
    def subsec_millisecond(self) -> int: ...
    def subsec_nanosecond(self) -> int: ...
    def to_zoned(self, time_zone: TimeZone) -> ZonedDateTime: ...

    # =========================================================================
    # SINCE/UNTIL
    # =========================================================================
    def _since(self, other: TimestampDifference) -> TimeSpan: ...
    def _until(self, other: TimestampDifference) -> TimeSpan: ...
    def since(
        self,
        other: Timestamp | ZonedDateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> TimeSpan: ...
    def until(
        self,
        other: Timestamp | ZonedDateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> TimeSpan: ...
    def duration_since(self, other: Timestamp) -> SignedDuration: ...
    def duration_until(self, other: Timestamp) -> SignedDuration: ...
    def round(
        self,
        unit: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> Timestamp: ...
    def _round(self, options: TimestampRound) -> Timestamp: ...


class TimestampDifference:
    def __init__(
        self,
        date: Timestamp,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> None: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def smallest(self, unit: JIFF_UNIT) -> TimestampDifference: ...
    def largest(self, unit: JIFF_UNIT) -> TimestampDifference: ...
    def mode(self, mode: JIFF_ROUND_MODE) -> TimestampDifference: ...
    def increment(self, increment: int) -> TimestampDifference: ...


class ZonedDateTime(
    ToPy[pydt.datetime], ToPyDate, ToPyTime, ToPyDateTime, ToPyTzInfo
):
    def __init__(self, timestamp: Timestamp, time_zone: TimeZone) -> None: ...

    # =========================================================================
    # PYTHON CONVERSIONS
    # =========================================================================
    @classmethod
    def from_pydatetime(
        cls: type[ZonedDateTime], dt: pydt.datetime
    ) -> ZonedDateTime: ...
    def to_py(self) -> pydt.datetime: ...
    def to_pydate(self) -> pydt.date: ...
    def to_pydatetime(self) -> pydt.datetime: ...
    def to_pytime(self) -> pydt.time: ...
    def to_pytzinfo(self) -> pydt.tzinfo: ...
    # =========================================================================
    # CLASS METHODS
    # =========================================================================
    @classmethod
    def now(
        cls: type[ZonedDateTime], tz: str | None = None
    ) -> ZonedDateTime: ...
    @classmethod
    def utcnow(cls: type[ZonedDateTime]) -> ZonedDateTime: ...
    @classmethod
    def parse(cls: type[ZonedDateTime], s: str) -> ZonedDateTime: ...
    @classmethod
    def from_rfc2822(cls: type[ZonedDateTime], s: str) -> ZonedDateTime: ...

    # =========================================================================
    # STRPTIME/STRFTIME
    # =========================================================================
    @classmethod
    def strptime(
        cls: type[ZonedDateTime], format: str, input: str
    ) -> ZonedDateTime: ...
    def strftime(self, format: str) -> str: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def year(self) -> int: ...
    @property
    def month(self) -> int: ...
    @property
    def day(self) -> int: ...
    @property
    def hour(self) -> int: ...
    @property
    def minute(self) -> int: ...
    @property
    def second(self) -> int: ...
    @property
    def millisecond(self) -> int: ...
    @property
    def microsecond(self) -> int: ...
    @property
    def nanosecond(self) -> int: ...
    @property
    def subsec_nanosecond(self) -> int: ...
    @property
    def weekday(self) -> int: ...

    # =========================================================================
    # STRING
    # =========================================================================
    def __str__(self) -> str: ...
    def string(self) -> str: ...

    # =========================================================================
    # OPERATORS/DUNDERS
    # =========================================================================
    def __add__(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> te.Self: ...
    def __eq__(self, other: object) -> bool: ...
    def __ge__(self, other: ZonedDateTime) -> bool: ...
    def __gt__(self, other: ZonedDateTime) -> bool: ...
    def __hash__(self) -> int: ...
    def __le__(self, other: ZonedDateTime) -> bool: ...
    def __lt__(self, other: ZonedDateTime) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __richcmp__(self, other: ZonedDateTime, op: int) -> bool: ...

    # =========================================================================
    # OPERATORS/DUNDERS W/ OVERLOADS
    # =========================================================================
    @t.overload
    def __isub__(self, other: ZonedDateTime) -> TimeSpan: ...
    @t.overload
    def __isub__(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> te.Self: ...
    @t.overload
    def __sub__(self, other: ZonedDateTime) -> TimeSpan: ...
    @t.overload
    def __sub__(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> te.Self: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================
    def astimezone(self, tz: str) -> ZonedDateTime: ...
    def checked_add(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> te.Self: ...
    @t.overload
    def checked_sub(self, other: ZonedDateTime) -> TimeSpan: ...
    @t.overload
    def checked_sub(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> te.Self: ...
    def date(self) -> Date: ...
    def datetime(self) -> DateTime: ...
    def iso_week_date(self) -> ISOWeekDate: ...
    def day_of_year(self) -> int: ...
    def day_of_year_no_leap(self) -> int | None: ...
    def days_in_month(self) -> int: ...
    def days_in_year(self) -> int: ...
    def duration_since(self, other: ZonedDateTime) -> SignedDuration: ...
    def duration_until(self, other: ZonedDateTime) -> SignedDuration: ...
    def end_of_day(self) -> ZonedDateTime: ...
    def era_year(self) -> tuple[int, t.Literal["CE", "BCE"]]: ...
    def first_of_month(self) -> ZonedDateTime: ...
    def first_of_year(self) -> ZonedDateTime: ...
    def in_leap_year(self) -> bool: ...
    def in_tz(self, tz: str) -> te.Self: ...
    def intz(self, tz: str) -> te.Self: ...
    def inutc(self) -> ZonedDateTime: ...
    def last_of_month(self) -> ZonedDateTime: ...
    def last_of_year(self) -> ZonedDateTime: ...
    def nth_weekday(self, nth: int, weekday: WEEKDAY) -> Date: ...
    def nth_weekday_of_month(self, nth: int, weekday: WEEKDAY) -> Date: ...
    def offset(self) -> Offset: ...
    def round(
        self,
        smallest: JIFF_UNIT | None = None,
        *,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> DateTime: ...
    def _round(self, options: ZonedDateTimeRound) -> DateTime: ...
    def saturating_add(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> te.Self: ...
    @t.overload
    def saturating_sub(self, other: ZonedDateTime) -> TimeSpan: ...
    @t.overload
    def saturating_sub(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> te.Self: ...
    def start_of_day(self) -> ZonedDateTime: ...
    def time(self) -> Time: ...
    def time_zone(self) -> TimeZone: ...
    def timestamp(self) -> Timestamp: ...
    def timezone(self) -> TimeZone: ...
    def to_rfc2822(self) -> str: ...
    def tomorrow(self) -> ZonedDateTime: ...
    def with_time_zone(self, tz: TimeZone) -> ZonedDateTime: ...
    def yesterday(self) -> ZonedDateTime: ...

    # =========================================================================
    # SINCE/UNTIL
    # =========================================================================
    def since(
        self,
        other: ZonedDateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> TimeSpan: ...
    def until(
        self,
        other: ZonedDateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> TimeSpan: ...


class ZonedDateTimeDifference:
    def __init__(
        self,
        date: ZonedDateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> None: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def smallest(self, unit: JIFF_UNIT) -> ZonedDateTimeDifference: ...
    def largest(self, unit: JIFF_UNIT) -> ZonedDateTimeDifference: ...
    def mode(self, mode: JIFF_ROUND_MODE) -> ZonedDateTimeDifference: ...
    def increment(self, increment: int) -> ZonedDateTimeDifference: ...


class ISOWeekDate:
    MIN: ISOWeekDate
    MAX: ISOWeekDate
    ZERO: ISOWeekDate

    def __init__(self, year: int, week: int, weekday: WEEKDAY) -> None: ...

    # =========================================================================
    # OPERATORS/DUNDERS
    # =========================================================================

    def __eq__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __lt__(self, other: ISOWeekDate) -> bool: ...
    def __le__(self, other: ISOWeekDate) -> bool: ...
    def __gt__(self, other: ISOWeekDate) -> bool: ...
    def __ge__(self, other: ISOWeekDate) -> bool: ...
    def __hash__(self) -> int: ...

    # =========================================================================
    # STRING
    # =========================================================================
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...

    # =========================================================================
    # CLASS METHODS
    # =========================================================================
    @classmethod
    def from_date(cls: type[ISOWeekDate], date: Date) -> ISOWeekDate: ...
    @classmethod
    def today(cls: type[ISOWeekDate]) -> ISOWeekDate: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def year(self) -> int: ...
    @property
    def week(self) -> int: ...
    @property
    def weekday(self) -> WEEKDAY_INT: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================
    def date(self) -> Date: ...


class TimestampRound:
    def __init__(
        self,
        smallest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int = 1,
    ) -> None: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def __eq__(self, other: object) -> bool: ...
    def mode(self, mode: JIFF_ROUND_MODE) -> TimestampRound: ...
    def smallest(self, smallest: JIFF_UNIT) -> TimestampRound: ...
    def increment(self, increment: int) -> TimestampRound: ...
    def _smallest(self) -> JIFF_UNIT: ...
    def _mode(self) -> JIFF_ROUND_MODE: ...
    def _increment(self) -> int: ...
    def replace(
        self,
        smallest: JIFF_UNIT | None,
        mode: JIFF_ROUND_MODE | None,
        increment: int | None,
    ) -> TimestampRound: ...


class DateTimeRound:
    def __init__(
        self,
        smallest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int = 1,
    ) -> None: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def __eq__(self, other: object) -> bool: ...
    def mode(self, mode: JIFF_ROUND_MODE) -> DateTimeRound: ...
    def smallest(self, smallest: JIFF_UNIT) -> DateTimeRound: ...
    def increment(self, increment: int) -> DateTimeRound: ...
    def _smallest(self) -> JIFF_UNIT: ...
    def _mode(self) -> JIFF_ROUND_MODE: ...
    def _increment(self) -> int: ...
    def replace(
        self,
        smallest: JIFF_UNIT | None,
        mode: JIFF_ROUND_MODE | None,
        increment: int | None,
    ) -> DateTimeRound: ...


class ZonedDateTimeRound:
    def __init__(
        self,
        smallest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int = 1,
    ) -> None: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def __eq__(self, other: object) -> bool: ...
    def mode(self, mode: JIFF_ROUND_MODE) -> DateTimeRound: ...
    def smallest(self, smallest: JIFF_UNIT) -> DateTimeRound: ...
    def increment(self, increment: int) -> DateTimeRound: ...
    def _smallest(self) -> JIFF_UNIT: ...
    def _mode(self) -> JIFF_ROUND_MODE: ...
    def _increment(self) -> int: ...
    def replace(
        self,
        smallest: JIFF_UNIT | None,
        mode: JIFF_ROUND_MODE | None,
        increment: int | None,
    ) -> DateTimeRound: ...


class Offset(ToPy[pydt.tzinfo], ToPyTzInfo):
    MIN: Offset
    MAX: Offset
    UTC: Offset
    ZERO: Offset

    def __init__(
        self, hours: int | None = None, seconds: int | None = None
    ) -> None: ...

    # =========================================================================
    # STRING
    # =========================================================================
    def string(self) -> str: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...

    # =========================================================================
    # OPERATORS/DUNDERS
    # =========================================================================
    def __neg__(self) -> Offset: ...
    def __eq__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __lt__(self, other: Offset) -> bool: ...
    def __le__(self, other: Offset) -> bool: ...
    def __gt__(self, other: Offset) -> bool: ...
    def __ge__(self, other: Offset) -> bool: ...
    def __hash__(self) -> int: ...

    # =========================================================================
    # PYTHON CONVERSIONS
    # =========================================================================
    # __FROM__
    @classmethod
    def from_pytzinfo(cls: type[Offset], tz: pydt.tzinfo) -> Offset: ...
    # __TO__
    def to_py(self) -> pydt.tzinfo: ...
    def to_pytzinfo(self) -> pydt.tzinfo: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def seconds(self) -> int: ...
    @property
    def is_negative(self) -> bool: ...
    @property
    def is_positive(self) -> bool: ...

    # =========================================================================
    # FROM
    # =========================================================================
    @classmethod
    def utc(cls: type[Offset]) -> Offset: ...
    @classmethod
    def from_hours(cls: type[Offset], hours: int) -> Offset: ...
    @classmethod
    def from_seconds(cls: type[Offset], seconds: int) -> Offset: ...

    # =========================================================================
    # TO
    # =========================================================================
    def to_datetime(self, timestamp: Timestamp) -> DateTime: ...
    def to_timestamp(self, datetime: DateTime) -> Timestamp: ...
    def to_timezone(self) -> TimeZone: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================
    def checked_add(
        self, other: Duration | SignedDuration | TimeSpan
    ) -> Offset: ...
    def checked_sub(
        self, other: Duration | SignedDuration | TimeSpan
    ) -> Offset: ...
    def duration_since(self, other: Offset) -> SignedDuration: ...
    def duration_until(self, other: Offset) -> SignedDuration: ...
    def negate(self) -> Offset: ...
    def saturating_add(
        self, other: Duration | SignedDuration | TimeSpan
    ) -> Offset: ...
    def saturating_sub(
        self, other: Duration | SignedDuration | TimeSpan
    ) -> Offset: ...
    def since(self, other: Offset) -> TimeSpan: ...
    def until(self, other: Offset) -> TimeSpan: ...


class JiffSeries(
    t.Generic[T],
):
    def __iter__(self) -> t.Iterator[T]: ...
    def __next__(self) -> T: ...
    def take(self, n: int) -> list[T]: ...


def date(year: int, month: int, day: int) -> Date: ...
def time(
    hour: int = 0, minute: int = 0, second: int = 0, nanosecond: int = 0
) -> Time: ...
def datetime(
    year: int,
    month: int,
    day: int,
    hour: int = 0,
    minute: int = 0,
    second: int = 0,
    nanosecond: int = 0,
) -> DateTime: ...
def timespan(
    *,
    years: int = 0,
    months: int = 0,
    weeks: int = 0,
    days: int = 0,
    hours: int = 0,
    minutes: int = 0,
    seconds: int = 0,
    milliseconds: int = 0,
    microseconds: int = 0,
    nanoseconds: int = 0,
    unchecked: bool = False,
) -> TimeSpan: ...
def offset(hours: int) -> Offset: ...


# =============================================================================
# TIMEZONE-DATABASE
# =============================================================================
class TimeZoneDatabase:
    def __init__(self) -> None:
        """Defaults to using the `self.from_env`"""

    @t.overload
    def get(self, name: str, err: t.Literal[False]) -> TimeZone | None:
        """Returns TimeZone or None if the timezone is not found"""

    @t.overload
    def get(self, name: str, err: t.Literal[True] = True) -> TimeZone:
        """Returns TimeZone, if not found raises a ValueError"""

    def available(self) -> list[str]: ...
    def __getitem__(self, name: str) -> TimeZone: ...
    def __len__(self) -> int: ...
    def is_definitively_empty(self) -> bool: ...
    @classmethod
    def from_env(cls) -> TimeZoneDatabase: ...
    @classmethod
    def from_dir(cls, path: str) -> TimeZoneDatabase: ...
    @classmethod
    def from_concatenated_path(cls, path: str) -> TimeZoneDatabase: ...

ry.ryo3._jiter

from __future__ import annotations

import typing as t

import typing_extensions as te

from ry._types import Buffer

# =============================================================================
# JSON
# =============================================================================
JsonPrimitive = None | bool | int | float | str
JsonValue = (
    JsonPrimitive
    | dict[str, JsonPrimitive | JsonValue]
    | list[JsonPrimitive | JsonValue]
)


class JsonParseKwargs(t.TypedDict, total=False):
    allow_inf_nan: bool
    """Allow parsing of `Infinity`, `-Infinity`, `NaN` ~ default: True"""
    cache_mode: t.Literal[True, False, "all", "keys", "none"]
    """Cache mode for JSON parsing ~ default: `all` """
    partial_mode: t.Literal[True, False, "off", "on", "trailing-strings"]
    """Partial mode for JSON parsing ~ default: False"""
    catch_duplicate_keys: bool
    """Catch duplicate keys in JSON objects ~ default: False"""
    float_mode: t.Literal["float", "decimal", "lossless-float"] | bool
    """Mode for parsing JSON floats ~ default: False"""


def parse_json(
    data: Buffer | bytes | str,
    /,
    **kwargs: te.Unpack[JsonParseKwargs],
) -> JsonValue: ...
def parse_json_bytes(
    data: bytes,
    /,
    **kwargs: te.Unpack[JsonParseKwargs],
) -> JsonValue: ...
def json_cache_clear() -> None: ...
def json_cache_usage() -> int: ...

ry.ryo3._quick_maths

"""ryo3-quick-maths types"""

from __future__ import annotations

import typing as t


def quick_maths() -> t.Literal[3]:
    """Performs quick-maths

    Implements the algorithm for performing "quick-maths" as described by
    Big Shaq in his PHD thesis, 2017, in which he states:

    > "2 plus 2 is 4, minus one that's 3, quick maths." (Big Shaq et al., 2017)

    Reference:
        https://youtu.be/3M_5oYU-IsU?t=60

    Example:
        >>> import ry
        >>> result = ry.quick_maths()
        >>> assert result == 3

    NOTE: THIS IS FROM MY TEMPLATE RY03-MODULE
    """

ry.ryo3._regex

"""ryo3-regex types"""

from __future__ import annotations

# =============================================================================
# Regex
# =============================================================================


class Regex:
    def __init__(
        self,
        pattern: str,
        *,
        case_insensitive: bool = False,
        crlf: bool = False,
        dot_matches_new_line: bool = False,
        ignore_whitespace: bool = False,
        line_terminator: str | None = None,
        multi_line: bool = False,
        octal: bool = False,
        size_limit: int | None = None,
        swap_greed: bool = False,
        unicode: bool = False,
    ) -> None: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def is_match(self, string: str) -> bool: ...

ry.ryo3._reqwest

import typing as t
from http import HTTPStatus

import ry

if t.TYPE_CHECKING:
    from ry.http import Headers
    from ry.ryo3 import URL, Duration


class HttpClient:
    def __init__(
        self,
        *,
        headers: dict[str, str] | None = None,
        user_agent: str | None = None,  # default ~ 'ry-reqwest/<VERSION> ...'
        timeout: Duration | None = None,
        connect_timeout: Duration | None = None,
        read_timeout: Duration | None = None,
        gzip: bool = True,
        brotli: bool = True,
        deflate: bool = True,
    ) -> None: ...
    async def get(
        self, url: str | URL, *, headers: dict[str, str] | None = None
    ) -> Response: ...
    async def post(
        self,
        url: str | URL,
        *,
        body: bytes | None = None,
        headers: dict[str, str] | None = None,
    ) -> Response: ...
    async def put(
        self,
        url: str | URL,
        *,
        body: bytes | None = None,
        headers: dict[str, str] | None = None,
    ) -> Response: ...
    async def delete(
        self, url: str | URL, *, headers: dict[str, str] | None = None
    ) -> Response: ...
    async def patch(
        self,
        url: str | URL,
        *,
        body: bytes | None = None,
        headers: dict[str, str] | None = None,
    ) -> Response: ...
    async def head(
        self, url: str | URL, *, headers: dict[str, str] | None = None
    ) -> Response: ...
    async def fetch(
        self,
        url: str | URL,
        *,
        method: str = "GET",
        body: bytes | None = None,
        headers: dict[str, str] | None = None,
    ) -> Response: ...


class ReqwestError(Exception):
    def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def __dbg__(self) -> str: ...
    def is_body(self) -> bool: ...
    def is_builder(self) -> bool: ...
    def is_connect(self) -> bool: ...
    def is_decode(self) -> bool: ...
    def is_redirect(self) -> bool: ...
    def is_request(self) -> bool: ...
    def is_status(self) -> bool: ...
    def is_timeout(self) -> bool: ...
    def status(self) -> HTTPStatus | None: ...
    def url(self) -> URL | None: ...


class Response:
    status_code: int

    @property
    def headers(self) -> Headers: ...
    async def text(self) -> str: ...
    async def json(self) -> t.Any: ...
    async def bytes(self) -> ry.Bytes: ...
    def bytes_stream(self) -> ResponseStream: ...


class ResponseStream:
    def __aiter__(self) -> ResponseStream: ...
    async def __anext__(self) -> ry.Bytes: ...


async def fetch(
    url: str | URL,
    *,
    client: HttpClient | None = None,
    method: str = "GET",
    body: bytes | None = None,
    headers: dict[str, str] | None = None,
) -> Response: ...

ry.ryo3._same_file

"""ryo3-same-file types"""

from __future__ import annotations

from os import PathLike


def is_same_file(a: PathLike[str], b: PathLike[str]) -> bool: ...

ry.ryo3._shlex

"""ryo3-shlex types"""

from __future__ import annotations


def shplit(s: str) -> list[str]:
    """shlex::split wrapper much like python's stdlib shlex.split but faster"""
    ...

ry.ryo3._size

from __future__ import annotations

from typing import Literal

FORMAT_SIZE_BASE = Literal[2, 10]  # default=2
FORMAT_SIZE_STYLE = Literal[  # default="default"
    "default",
    "abbreviated",
    "abbreviated_lowercase",
    "abbreviated-lowercase",
    "full",
    "full-lowercase",
    "full_lowercase",
]


def fmt_size(
    n: int,
    *,
    base: FORMAT_SIZE_BASE | None = 2,
    style: FORMAT_SIZE_STYLE | None = "default",
) -> str:
    """Return human-readable string representation of bytes-size."""


def parse_size(s: str) -> int:
    """Return integer representation of human-readable bytes-size string.

    Raises:
        ValueError: If string is not a valid human-readable bytes-size string.
    """


class SizeFormatter:
    """Human-readable bytes-size formatter."""

    def __init__(
        self,
        base: FORMAT_SIZE_BASE | None = 2,
        style: FORMAT_SIZE_STYLE | None = "default",
    ) -> None:
        """Initialize human-readable bytes-size formatter."""

    def format(self, n: int) -> str:
        """Return human-readable string representation of bytes-size."""

    def __call__(self, n: int) -> str:
        """Return human-readable string representation of bytes-size."""

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


class Size:
    """Bytes-size object."""

    def __init__(self, size: int) -> None: ...
    def __int__(self) -> int: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def __hash__(self) -> int: ...
    def __abs__(self) -> Size: ...
    def __neg__(self) -> Size: ...
    def __eq__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __lt__(self, other: Size | int | float) -> bool: ...
    def __le__(self, other: Size | int | float) -> bool: ...
    def __gt__(self, other: Size | int | float) -> bool: ...
    def __ge__(self, other: Size | int | float) -> bool: ...
    def __bool__(self) -> bool: ...
    def __pos__(self) -> Size: ...
    def __invert__(self) -> Size: ...
    def __add__(self, other: Size | int | float) -> Size: ...
    def __sub__(self, other: Size | int | float) -> Size: ...
    def __mul__(self, other: Size | int | float) -> Size: ...
    def __rmul__(self, other: Size | int | float) -> Size: ...
    @property
    def bytes(self) -> int: ...
    def format(
        self,
        base: FORMAT_SIZE_BASE | None = 2,
        style: FORMAT_SIZE_STYLE | None = "default",
    ) -> str: ...

    # =========================================================================
    # CLASS-METHODS
    # =========================================================================

    # -------------------------------------------------------------------------
    # PARSING
    # -------------------------------------------------------------------------
    @classmethod
    def parse(cls: type[Size], size: str) -> Size: ...
    @classmethod
    def from_str(cls: type[Size], size: str) -> Size: ...

    # -------------------------------------------------------------------------
    # BYTES
    # -------------------------------------------------------------------------
    @classmethod
    def from_bytes(cls: type[Size], size: int | float) -> Size: ...

    # -------------------------------------------------------------------------
    # KILOBYTES
    # -------------------------------------------------------------------------
    @classmethod
    def from_kb(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_kib(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_kibibytes(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_kilobytes(cls: type[Size], size: int | float) -> Size: ...

    # -------------------------------------------------------------------------
    # MEGABYTES
    # -------------------------------------------------------------------------

    @classmethod
    def from_mb(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_mebibytes(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_megabytes(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_mib(cls: type[Size], size: int | float) -> Size: ...

    # -------------------------------------------------------------------------
    # GIGABYTES
    # -------------------------------------------------------------------------
    @classmethod
    def from_gb(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_gib(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_gibibytes(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_gigabytes(cls: type[Size], size: int | float) -> Size: ...

    # -------------------------------------------------------------------------
    # TERABYTES
    # -------------------------------------------------------------------------
    @classmethod
    def from_tb(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_tebibytes(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_terabytes(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_tib(cls: type[Size], size: int | float) -> Size: ...

    # -------------------------------------------------------------------------
    # PETABYTES
    # -------------------------------------------------------------------------
    @classmethod
    def from_pb(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_pebibytes(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_petabytes(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_pib(cls: type[Size], size: int | float) -> Size: ...

    # -------------------------------------------------------------------------
    # EXABYTES
    # -------------------------------------------------------------------------
    @classmethod
    def from_eb(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_eib(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_exabytes(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_exbibytes(cls: type[Size], size: int | float) -> Size: ...

ry.ryo3._sqlformat

from __future__ import annotations

import typing as t

# =============================================================================
# SQLFORMAT
# =============================================================================
SqlfmtParamValue = str | int | float | bool
TSqlfmtParamValue_co = t.TypeVar(
    "TSqlfmtParamValue_co", bound=SqlfmtParamValue, covariant=True
)
SqlfmtParamsLike = (
    dict[str, TSqlfmtParamValue_co]
    | t.Sequence[tuple[str, TSqlfmtParamValue_co]]
    | t.Sequence[TSqlfmtParamValue_co]
)


class SqlfmtQueryParams:
    def __init__(
        self, params: SqlfmtParamsLike[TSqlfmtParamValue_co]
    ) -> None: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...


def sqlfmt_params(
    params: SqlfmtParamsLike[TSqlfmtParamValue_co] | SqlfmtQueryParams,
) -> SqlfmtQueryParams: ...
def sqlfmt(
    sql: str,
    params: SqlfmtParamsLike[TSqlfmtParamValue_co]
    | SqlfmtQueryParams
    | None = None,
    *,
    indent: int = 2,  # -1 or any negative value will use tabs
    uppercase: bool | None = True,
    lines_between_statements: int = 1,
) -> str: ...

ry.ryo3._std

"""ryo3-std types"""

from __future__ import annotations

import datetime as pydt
import typing as t

from ry import Bytes, FsPath
from ry._types import Buffer, FsPathLike


# =============================================================================
# STD::TIME
# =============================================================================
class Duration:
    ZERO: Duration
    MIN: Duration
    MAX: Duration
    NANOSECOND: Duration
    MICROSECOND: Duration
    MILLISECOND: Duration
    SECOND: Duration

    def __init__(self, secs: int = 0, nanos: int = 0) -> None: ...
    def __eq__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __lt__(self, other: Duration) -> bool: ...
    def __le__(self, other: Duration) -> bool: ...
    def __gt__(self, other: Duration) -> bool: ...
    def __ge__(self, other: Duration) -> bool: ...
    def __hash__(self) -> int: ...
    def __richcmp__(
        self, other: Duration | pydt.timedelta, op: int
    ) -> bool: ...
    def __str__(self) -> str: ...
    def abs_diff(self, other: Duration) -> Duration: ...
    def sleep(self) -> None: ...

    # =========================================================================
    # PYTHON_CONVERSIONS
    # =========================================================================
    @classmethod
    def from_pytimedelta(
        cls: type[Duration], td: pydt.timedelta
    ) -> Duration: ...
    def to_pytimedelta(self) -> pydt.timedelta: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def is_zero(self) -> bool: ...
    @property
    def nanos(self) -> int: ...
    @property
    def secs(self) -> int: ...
    @property
    def days(self) -> int: ...
    @property
    def seconds(self) -> int: ...
    @property
    def microseconds(self) -> int: ...
    @property
    def subsec_micros(self) -> int: ...
    @property
    def subsec_millis(self) -> int: ...
    @property
    def subsec_nanos(self) -> int: ...

    # =========================================================================
    # CLASSMETHODS
    # =========================================================================
    @classmethod
    def from_hours(cls, hours: int) -> Duration: ...
    @classmethod
    def from_micros(cls, micros: int) -> Duration: ...
    @classmethod
    def from_millis(cls, millis: int) -> Duration: ...
    @classmethod
    def from_mins(cls, mins: int) -> Duration: ...
    @classmethod
    def from_nanos(cls, nanos: int) -> Duration: ...
    @classmethod
    def from_secs(cls, secs: int) -> Duration: ...
    @classmethod
    def from_secs_f32(cls, secs: float) -> Duration: ...
    @classmethod
    def from_secs_f64(cls, secs: float) -> Duration: ...
    @classmethod
    def from_days(cls, days: int) -> Duration: ...
    @classmethod
    def from_weeks(cls, weeks: int) -> Duration: ...
    def as_micros(self) -> int: ...
    def as_millis(self) -> int: ...
    def as_nanos(self) -> int: ...
    def as_secs(self) -> int: ...
    def as_secs_f32(self) -> float: ...
    def as_secs_f64(self) -> float: ...

    # =========================================================================
    # NOT IMPLEMENTED
    # =========================================================================
    def checked_add(self, other: Duration) -> Duration | None: ...
    def checked_div(self, other: Duration) -> Duration | None: ...
    def checked_mul(self, other: Duration) -> Duration | None: ...
    def checked_sub(self, other: Duration) -> Duration | None: ...
    def div_duration_f32(self, other: Duration) -> float: ...
    def div_duration_f64(self, other: Duration) -> float: ...
    def div_f32(self, other: float) -> Duration: ...
    def div_f64(self, other: float) -> Duration: ...
    def mul_f32(self, other: float) -> Duration: ...
    def mul_f64(self, other: float) -> Duration: ...
    def saturating_add(self, other: Duration) -> Duration: ...
    def saturating_mul(self, other: Duration) -> Duration: ...
    def saturating_sub(self, other: Duration) -> Duration: ...


class Instant:
    def __init__(self) -> None: ...
    @classmethod
    def now(cls) -> Instant: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def __eq__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __lt__(self, other: Instant) -> bool: ...
    def __le__(self, other: Instant) -> bool: ...
    def __gt__(self, other: Instant) -> bool: ...
    def __ge__(self, other: Instant) -> bool: ...
    def __hash__(self) -> int: ...
    def __add__(self, other: Duration) -> Instant: ...
    @t.overload
    def __sub__(self, other: Duration) -> Instant: ...
    @t.overload
    def __sub__(self, other: Instant) -> Duration: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================
    def checked_add(self, other: Duration) -> Instant | None: ...
    def checked_duration_since(self, earlier: Instant) -> Duration | None: ...
    def checked_sub(self, other: Duration) -> Instant | None: ...
    def duration_since(self, earlier: Instant) -> Duration: ...
    def elapsed(self) -> Duration: ...
    def saturating_duration_since(self, earlier: Instant) -> Duration: ...


def instant() -> Instant: ...
def sleep(seconds: float) -> float: ...


# =============================================================================
# STD::FS
# =============================================================================
class FileType:
    def __repr__(self) -> str: ...
    @property
    def is_dir(self) -> bool: ...
    @property
    def is_file(self) -> bool: ...
    @property
    def is_symlink(self) -> bool: ...


class Metadata:
    def __repr__(self) -> str: ...
    @property
    def file_type(self) -> FileType: ...
    @property
    def len(self) -> int: ...
    @property
    def is_empty(self) -> bool: ...
    @property
    def modified(self) -> pydt.datetime: ...
    @property
    def accessed(self) -> pydt.datetime: ...
    @property
    def created(self) -> pydt.datetime: ...
    @property
    def is_dir(self) -> bool: ...
    @property
    def is_file(self) -> bool: ...
    @property
    def is_symlink(self) -> bool: ...


# =============================================================================
# STD::FS ~ functions
# =============================================================================
def read(path: FsPathLike) -> Bytes: ...
def read_bytes(path: FsPathLike) -> bytes: ...
def read_text(path: FsPathLike) -> str: ...
def read_stream(
    path: FsPathLike,
    chunk_size: int = 65536,
    *,
    offset: int = 0,
) -> t.Iterator[Bytes]: ...
def write(path: FsPathLike, data: Buffer | str) -> int: ...
def write_bytes(path: FsPathLike, data: bytes) -> int: ...
def write_text(path: FsPathLike, data: str) -> int: ...
def canonicalize(path: FsPathLike) -> FsPath: ...
def copy(from_path: FsPathLike, to_path: FsPathLike) -> int: ...
def create_dir(path: FsPathLike) -> None: ...
def create_dir_all(path: FsPathLike) -> None: ...
def exists(path: FsPathLike) -> bool: ...
def is_dir(path: FsPathLike) -> bool: ...
def is_file(path: FsPathLike) -> bool: ...
def is_symlink(path: FsPathLike) -> bool: ...
def metadata(path: FsPathLike) -> Metadata: ...
def remove_dir(path: FsPathLike) -> None: ...
def remove_dir_all(path: FsPathLike) -> None: ...
def remove_file(path: FsPathLike) -> None: ...
def rename(from_path: FsPathLike, to_path: FsPathLike) -> None: ...

ry.ryo3._tokio

"""ryo3-tokio types"""

from __future__ import annotations

from typing import NoReturn

from ry import Bytes
from ry._types import Buffer, FsPathLike


# =============================================================================
# FS
# =============================================================================
async def copy_async(src: FsPathLike, dst: FsPathLike) -> None: ...
async def create_dir_async(path: FsPathLike) -> None: ...
async def metadata_async(path: FsPathLike) -> None: ...
async def read_async(path: FsPathLike) -> Bytes: ...
async def read_dir_async(path: FsPathLike) -> NoReturn: ...
async def remove_dir_async(path: FsPathLike) -> None: ...
async def remove_file_async(path: FsPathLike) -> None: ...
async def rename_async(src: FsPathLike, dst: FsPathLike) -> None: ...
async def write_async(path: FsPathLike, data: Buffer) -> None: ...


# =============================================================================
# SLEEP
# =============================================================================
async def sleep_async(seconds: float) -> float: ...
async def asleep(seconds: float) -> float:
    """Alias for sleep_async"""
    ...

ry.ryo3._unindent

"""ryo3-unindent types"""

from __future__ import annotations


def unindent(string: str) -> str: ...
def unindent_bytes(string: bytes) -> bytes: ...

ry.ryo3._url

from __future__ import annotations

from ipaddress import IPv4Address


class URL:
    def __init__(
        self, url: str | URL, *, params: dict[str, str] | None = None
    ) -> None: ...

    # =========================================================================
    # CLASSMETHODS
    # =========================================================================
    @classmethod
    def parse(cls, url: str) -> URL: ...
    @classmethod
    def parse_with_params(cls, url: str, params: dict[str, str]) -> URL: ...
    @classmethod
    def from_directory_path(cls, path: str) -> URL: ...

    # =========================================================================
    # STRING
    # =========================================================================
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def __fspath__(self) -> str: ...

    # =========================================================================
    # OPERATORS/DUNDER
    # =========================================================================
    def __eq__(self, other: object) -> bool: ...
    def __ge__(self, other: URL) -> bool: ...
    def __gt__(self, other: URL) -> bool: ...
    def __hash__(self) -> int: ...
    def __le__(self, other: URL) -> bool: ...
    def __lt__(self, other: URL) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __rtruediv__(self, relative: str) -> URL: ...
    def __truediv__(self, relative: str) -> URL: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def authority(self) -> str: ...
    @property
    def fragment(self) -> str | None: ...
    @property
    def host(self) -> str | None: ...
    @property
    def host_str(self) -> str | None: ...
    @property
    def netloc(self) -> str: ...
    @property
    def password(self) -> str | None: ...
    @property
    def path(self) -> str: ...
    @property
    def path_segments(self) -> tuple[str, ...]: ...
    @property
    def port(self) -> int | None: ...
    @property
    def port_or_known_default(self) -> int | None: ...
    @property
    def query(self) -> str | None: ...
    @property
    def query_pairs(self) -> list[tuple[str, str]]: ...
    @property
    def scheme(self) -> str: ...
    @property
    def username(self) -> str: ...
    @property
    def origin(self) -> str: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================
    def has_authority(self) -> bool: ...
    def has_host(self) -> bool: ...
    def is_special(self) -> bool: ...
    def join(self, *parts: str) -> URL: ...
    def to_filepath(self) -> str: ...
    def replace_fragment(self, fragment: str | None = None) -> URL: ...
    def replace_host(self, host: str | None = None) -> URL: ...
    def replace_ip_host(self, host: IPv4Address | IPv4Address) -> URL: ...
    def replace_password(self, password: str | None = None) -> URL: ...
    def replace_path(self, path: str) -> URL: ...
    def replace_port(self, port: int | None = None) -> URL: ...
    def replace_query(self, query: str | None = None) -> URL: ...
    def replace_scheme(self, scheme: str) -> URL: ...
    def replace_username(self, username: str) -> URL: ...
    def socket_addrs(self) -> None: ...
    def replace(
        self,
        *,
        fragment: str | None = None,
        host: str | None = None,
        ip_host: IPv4Address | None = None,
        password: str | None = None,
        path: str | None = None,
        port: int | None = None,
        query: str | None = None,
        scheme: str | None = None,
        username: str | None = None,
    ) -> URL: ...

ry.ryo3._walkdir

"""ryo3-walkdir types"""

from __future__ import annotations

import typing as t
from os import PathLike

from ry import FileType, FsPath, Glob, GlobSet, Globster


class WalkDirEntry:
    def __fspath__(self) -> str: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    @property
    def path(self) -> FsPath: ...
    @property
    def file_name(self) -> str: ...
    @property
    def depth(self) -> int: ...
    @property
    def path_is_symlink(self) -> bool: ...
    @property
    def file_type(self) -> FileType: ...
    @property
    def is_dir(self) -> bool: ...
    @property
    def is_file(self) -> bool: ...
    @property
    def is_symlink(self) -> bool: ...
    @property
    def len(self) -> int: ...


class WalkdirGen:
    """walkdir::Walkdir iterable wrapper"""

    def __next__(self) -> str: ...
    def __iter__(self) -> t.Iterator[str]: ...
    def collect(self) -> list[str]: ...
    def take(self, n: int) -> list[str]: ...
    def __str__(self) -> str: ...


def walkdir(
    path: str | PathLike[str] | None = None,
    *,
    files: bool = True,
    dirs: bool = True,
    contents_first: bool = False,
    min_depth: int = 0,
    max_depth: int | None = None,
    follow_links: bool = False,
    same_file_system: bool = False,
    glob: Glob | GlobSet | Globster | t.Sequence[str] | str | None = None,
) -> WalkdirGen: ...

ry.ryo3._which

"""ryo3-which types"""

from __future__ import annotations

from pathlib import Path

from ry.ryo3._regex import Regex


def which(cmd: str, path: None | str = None) -> Path | None: ...
def which_all(cmd: str, path: None | str = None) -> list[Path]: ...
def which_re(regex: str | Regex, path: None | str = None) -> list[Path]: ...

ry.dirs

def audio() -> str | None: ...
def audio_dir() -> str | None: ...
def cache() -> str | None: ...
def cache_dir() -> str | None: ...
def config() -> str | None: ...
def config_dir() -> str | None: ...
def config_local() -> str | None: ...
def config_local_dir() -> str | None: ...
def data() -> str | None: ...
def data_dir() -> str | None: ...
def data_local() -> str | None: ...
def data_local_dir() -> str | None: ...
def desktop() -> str | None: ...
def desktop_dir() -> str | None: ...
def document() -> str | None: ...
def document_dir() -> str | None: ...
def download() -> str | None: ...
def download_dir() -> str | None: ...
def executable() -> str | None: ...
def executable_dir() -> str | None: ...
def font() -> str | None: ...
def font_dir() -> str | None: ...
def home() -> str | None: ...
def home_dir() -> str | None: ...
def picture() -> str | None: ...
def picture_dir() -> str | None: ...
def preference() -> str | None: ...
def preference_dir() -> str | None: ...
def public() -> str | None: ...
def public_dir() -> str | None: ...
def runtime() -> str | None: ...
def runtime_dir() -> str | None: ...
def state() -> str | None: ...
def state_dir() -> str | None: ...
def template() -> str | None: ...
def template_dir() -> str | None: ...
def video() -> str | None: ...
def video_dir() -> str | None: ...

ry.http

from __future__ import annotations

import typing as t


class Headers:
    """python-ryo3-http `http::HeadersMap` wrapper"""

    def __init__(self, headers: dict[str, str | t.Sequence[str]]) -> None: ...

    # =========================================================================
    # STRING
    # =========================================================================
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def __dbg__(self) -> str: ...

    # =========================================================================
    # MAGIC METHODS
    # =========================================================================
    def __len__(self) -> int: ...
    def __getitem__(self, key: str) -> str: ...
    def __setitem__(self, key: str, value: str) -> None: ...
    def __delitem__(self, key: str) -> None: ...
    def __contains__(self, key: str) -> bool: ...
    def __or__(self, other: Headers | dict[str, str]) -> Headers: ...
    def asdict(self) -> dict[str, str | t.Sequence[str]]: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================
    def append(self, key: str, value: str) -> None: ...
    def get(self, key: str) -> str | None: ...
    def get_all(self, key: str) -> list[str]: ...
    def keys_len(self) -> int: ...
    def len(self) -> int: ...
    def remove(self, key: str) -> None: ...
    def clear(self) -> None: ...
    def pop(self, key: str) -> str: ...
    def keys(self) -> list[str]: ...
    def update(self, headers: Headers | dict[str, str]) -> None: ...


class HttpStatus:
    def __init__(self, code: int) -> None: ...
    def __int__(self) -> int: ...
    def __bool__(self) -> bool: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def __hash__(self) -> int: ...
    def __eq__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __lt__(self, other: HttpStatus | int) -> bool: ...
    def __le__(self, other: HttpStatus | int) -> bool: ...
    def __gt__(self, other: HttpStatus | int) -> bool: ...
    def __ge__(self, other: HttpStatus | int) -> bool: ...
    def reason(self) -> str: ...
    def is_informational(self) -> bool: ...
    def is_success(self) -> bool: ...
    def is_redirect(self) -> bool: ...
    def is_client_error(self) -> bool: ...
    def is_server_error(self) -> bool: ...
    def is_ok(self) -> bool: ...
    @property
    def ok(self) -> bool: ...

    # =========================================================================
    # CONST STATUS CODES
    # =========================================================================
    CONTINUE: HttpStatus  # 100 ~ Continue
    SWITCHING_PROTOCOLS: HttpStatus  # 101 ~ Switching Protocols
    PROCESSING: HttpStatus  # 102 ~ Processing
    OK: HttpStatus  # 200 ~ OK
    CREATED: HttpStatus  # 201 ~ Created
    ACCEPTED: HttpStatus  # 202 ~ Accepted
    NON_AUTHORITATIVE_INFORMATION: (
        HttpStatus  # 203 ~ Non Authoritative Information
    )
    NO_CONTENT: HttpStatus  # 204 ~ No Content
    RESET_CONTENT: HttpStatus  # 205 ~ Reset Content
    PARTIAL_CONTENT: HttpStatus  # 206 ~ Partial Content
    MULTI_STATUS: HttpStatus  # 207 ~ Multi-Status
    ALREADY_REPORTED: HttpStatus  # 208 ~ Already Reported
    IM_USED: HttpStatus  # 226 ~ IM Used
    MULTIPLE_CHOICES: HttpStatus  # 300 ~ Multiple Choices
    MOVED_PERMANENTLY: HttpStatus  # 301 ~ Moved Permanently
    FOUND: HttpStatus  # 302 ~ Found
    SEE_OTHER: HttpStatus  # 303 ~ See Other
    NOT_MODIFIED: HttpStatus  # 304 ~ Not Modified
    USE_PROXY: HttpStatus  # 305 ~ Use Proxy
    TEMPORARY_REDIRECT: HttpStatus  # 307 ~ Temporary Redirect
    PERMANENT_REDIRECT: HttpStatus  # 308 ~ Permanent Redirect
    BAD_REQUEST: HttpStatus  # 400 ~ Bad Request
    UNAUTHORIZED: HttpStatus  # 401 ~ Unauthorized
    PAYMENT_REQUIRED: HttpStatus  # 402 ~ Payment Required
    FORBIDDEN: HttpStatus  # 403 ~ Forbidden
    NOT_FOUND: HttpStatus  # 404 ~ Not Found
    METHOD_NOT_ALLOWED: HttpStatus  # 405 ~ Method Not Allowed
    NOT_ACCEPTABLE: HttpStatus  # 406 ~ Not Acceptable
    PROXY_AUTHENTICATION_REQUIRED: (
        HttpStatus  # 407 ~ Proxy Authentication Required
    )
    REQUEST_TIMEOUT: HttpStatus  # 408 ~ Request Timeout
    CONFLICT: HttpStatus  # 409 ~ Conflict
    GONE: HttpStatus  # 410 ~ Gone
    LENGTH_REQUIRED: HttpStatus  # 411 ~ Length Required
    PRECONDITION_FAILED: HttpStatus  # 412 ~ Precondition Failed
    PAYLOAD_TOO_LARGE: HttpStatus  # 413 ~ Payload Too Large
    URI_TOO_LONG: HttpStatus  # 414 ~ URI Too Long
    UNSUPPORTED_MEDIA_TYPE: HttpStatus  # 415 ~ Unsupported Media Type
    RANGE_NOT_SATISFIABLE: HttpStatus  # 416 ~ Range Not Satisfiable
    EXPECTATION_FAILED: HttpStatus  # 417 ~ Expectation Failed
    IM_A_TEAPOT: HttpStatus  # 418 ~ I'm a teapot
    MISDIRECTED_REQUEST: HttpStatus  # 421 ~ Misdirected Request
    UNPROCESSABLE_ENTITY: HttpStatus  # 422 ~ Unprocessable Entity
    LOCKED: HttpStatus  # 423 ~ Locked
    FAILED_DEPENDENCY: HttpStatus  # 424 ~ Failed Dependency
    TOO_EARLY: HttpStatus  # 425 ~ Too Early
    UPGRADE_REQUIRED: HttpStatus  # 426 ~ Upgrade Required
    PRECONDITION_REQUIRED: HttpStatus  # 428 ~ Precondition Required
    TOO_MANY_REQUESTS: HttpStatus  # 429 ~ Too Many Requests
    REQUEST_HEADER_FIELDS_TOO_LARGE: (
        HttpStatus  # 431 ~ Request Header Fields Too Large
    )
    UNAVAILABLE_FOR_LEGAL_REASONS: (
        HttpStatus  # 451 ~ Unavailable For Legal Reasons
    )
    INTERNAL_SERVER_ERROR: HttpStatus  # 500 ~ Internal Server Error
    NOT_IMPLEMENTED: HttpStatus  # 501 ~ Not Implemented
    BAD_GATEWAY: HttpStatus  # 502 ~ Bad Gateway
    SERVICE_UNAVAILABLE: HttpStatus  # 503 ~ Service Unavailable
    GATEWAY_TIMEOUT: HttpStatus  # 504 ~ Gateway Timeout
    HTTP_VERSION_NOT_SUPPORTED: HttpStatus  # 505 ~ HTTP Version Not Supported
    VARIANT_ALSO_NEGOTIATES: HttpStatus  # 506 ~ Variant Also Negotiates
    INSUFFICIENT_STORAGE: HttpStatus  # 507 ~ Insufficient Storage
    LOOP_DETECTED: HttpStatus  # 508 ~ Loop Detected
    NOT_EXTENDED: HttpStatus  # 510 ~ Not Extended
    NETWORK_AUTHENTICATION_REQUIRED: (
        HttpStatus  # 511 ~ Network Authentication Required
    )

ry.xxhash

from __future__ import annotations

import typing as t

from ry._types import Buffer


@t.final
class Xxh32:
    name: t.Literal["xxh32"]

    def __init__(self, input: Buffer = ..., seed: int | None = ...) -> None: ...
    def update(self, input: Buffer) -> None: ...
    def digest(self) -> bytes: ...
    def hexdigest(self) -> str: ...
    def intdigest(self) -> int: ...
    def copy(self) -> Xxh32: ...
    def reset(self, seed: int | None = ...) -> None: ...
    @property
    def seed(self) -> int: ...


@t.final
class Xxh64:
    name: t.Literal["xxh64"]

    def __init__(
        self, input: Buffer | None = None, seed: int | None = ...
    ) -> None: ...
    def update(self, input: Buffer) -> None: ...
    def digest(self) -> bytes: ...
    def hexdigest(self) -> str: ...
    def intdigest(self) -> int: ...
    def copy(self) -> Xxh32: ...
    def reset(self, seed: int | None = ...) -> None: ...
    @property
    def seed(self) -> int: ...


@t.final
class Xxh3:
    name: t.Literal["xxh3"]

    def __init__(
        self,
        input: Buffer = ...,
        seed: int | None = ...,
        secret: bytes | None = ...,
    ) -> None: ...
    def update(self, input: Buffer) -> None: ...
    def digest(self) -> bytes: ...
    def hexdigest(self) -> str: ...
    def intdigest(self) -> int: ...
    @property
    def seed(self) -> int: ...
    def digest128(self) -> bytes: ...
    def hexdigest128(self) -> str: ...
    def intdigest128(self) -> int: ...
    def copy(self) -> Xxh3: ...
    def reset(self) -> None: ...


def xxh32(input: Buffer | None = None, seed: int | None = None) -> Xxh32: ...
def xxh64(input: Buffer | None = None, seed: int | None = None) -> Xxh64: ...
def xxh3(
    input: Buffer | None = None,
    seed: int | None = None,
    secret: bytes | None = None,
) -> Xxh3: ...


# xxh32
def xxh32_digest(input: Buffer, seed: int | None = None) -> bytes: ...
def xxh32_hexdigest(input: Buffer, seed: int | None = None) -> str: ...
def xxh32_intdigest(input: Buffer, seed: int | None = None) -> int: ...


# xxh64
def xxh64_digest(input: Buffer, seed: int | None = None) -> bytes: ...
def xxh64_hexdigest(input: Buffer, seed: int | None = None) -> str: ...
def xxh64_intdigest(input: Buffer, seed: int | None = None) -> int: ...


# xxh128
def xxh128_digest(input: Buffer, seed: int | None = None) -> bytes: ...
def xxh128_hexdigest(input: Buffer, seed: int | None = None) -> str: ...
def xxh128_intdigest(input: Buffer, seed: int | None = None) -> int: ...


# xxh3
def xxh3_64_digest(input: Buffer, seed: int | None = None) -> bytes: ...
def xxh3_64_intdigest(input: Buffer, seed: int | None = None) -> int: ...
def xxh3_64_hexdigest(input: Buffer, seed: int | None = None) -> str: ...
def xxh3_digest(input: Buffer, seed: int | None = None) -> bytes: ...
def xxh3_intdigest(input: Buffer, seed: int | None = None) -> int: ...
def xxh3_hexdigest(input: Buffer, seed: int | None = None) -> str: ...


# xxh128
def xxh3_128_digest(input: Buffer, seed: int | None = None) -> bytes: ...
def xxh3_128_intdigest(input: Buffer, seed: int | None = None) -> int: ...
def xxh3_128_hexdigest(input: Buffer, seed: int | None = None) -> str: ...

ry.zstd

from ry import Bytes
from ry._types import Buffer

__zstd_version__: str  # zstd version string ("1.5.7" as of 2025-03-14)
BLOCKSIZELOG_MAX: int
BLOCKSIZE_MAX: int
CLEVEL_DEFAULT: int  # default=3 (as of 2025-03-14)
CONTENTSIZE_ERROR: int
CONTENTSIZE_UNKNOWN: int
MAGICNUMBER: int
MAGIC_DICTIONARY: int
MAGIC_SKIPPABLE_MASK: int
MAGIC_SKIPPABLE_START: int
VERSION_MAJOR: int
VERSION_MINOR: int
VERSION_NUMBER: int
VERSION_RELEASE: int


# =============================================================================
# PYFUNCTIONS
# =============================================================================
# __COMPRESSION__
def compress(data: Buffer, level: int = CLEVEL_DEFAULT) -> Bytes: ...
def encode(data: Buffer, level: int = CLEVEL_DEFAULT) -> Bytes: ...
def zstd(data: Buffer, level: int = CLEVEL_DEFAULT) -> Bytes: ...
def zstd_compress(data: Buffer, level: int = CLEVEL_DEFAULT) -> Bytes: ...
def zstd_encode(data: Buffer, level: int = CLEVEL_DEFAULT) -> Bytes: ...


# __DECOMPRESSION__
def decode(data: Buffer) -> Bytes: ...
def decompress(data: Buffer) -> Bytes: ...
def unzstd(data: Buffer) -> Bytes: ...
def zstd_decode(data: Buffer) -> Bytes: ...
def zstd_decompress(data: Buffer) -> Bytes: ...


# __MAGIC__
def is_zstd(data: Buffer) -> bool: ...


DEV

  • just is used to run tasks
  • Do not use the phrase blazing fast or any emojis in any PRs or issues or docs
  • type annotations are required
  • ruff used for formatting and linting

SEE ALSO

  • utiles (web-map tile utils): https://github.com/jessekrubin/utiles
  • jsonc2json (jsonc to json converter): https://github.com/jessekrubin/jsonc2json

DEVELOPMENT

OPEN TO PRS!

goals

  1. Provide a really nice ergonomic API to work with (this is the highest priority)
  2. Get naming right (this is a hard one!)
  3. Be fast

development-setup

  • clone repo
  • install just (cargo install just)
  • create a virtual env (using ye olde venv or uv or dare I say conda) – I am still working out the kinks of using uv with maturin
  • install the dev-requirements (pip install -r requirements.dev.txt)
  • run just dev to build and test the library
  • run just fmt to format the python and rust code

style guide

  • NO UNWRAPPING
  • NO PANICS
  • NO blazingly-fastry is fast and does not need an adverb
  • USE CLIPPY just clippy or just ci
  • USE RUSTFMT AND RUFF just fmt
  • avoid using macros as they are not as easy to reason about and/or debug, but feel free to say ‘yolo’
  • library style guide:
    • python objects/structs/classes defined in the library should be named either Py<CLASSNAME> or Ry<CLASSNAME> and the prefix should be consistent throughout the library (eg ryo3-jiff uses Ry as the internal prefix to not conflict with the Py<CLASSNAME> structs provided by pyo3)
    • if a pyclass or pyfunction is not mirroring a rust function prefer names that are puns but also semi-descriptive (eg Globsters in ryo3-globset)
    • attempt to mirror the structure of the og library as much as possible
    • wrapper libraries should be of the form ryo3-<LIB_NAME> where <LIB_NAME> is the name of the library they
    • library directories should be kebab-case and should be ryo3-<LIB_NAME>
    • MUST PROVIDE TYPE ANNOTATIONS

Creating a new library/wrapper-thing

  • copy the template library ryo3-quick-maths library to your new library name
  • refer to the above style guide for naming conventions

tools

python

  • we use maturin for building the python wheels
  • we support python-3.9+
  • we use pytest for testing as well as the following plugins:
    • pytest-benchmark
    • pytest-asyncio (may switch to anyio in the future)
    • hypothesis

just

cargo install just

  • we use just for task running
  • to see all tasks run just or just --list (our default task echos the list of tasks)

tasks as of 2024-12-03:

Available recipes:
    dev            # dev run build + tests
    develop        # maturin develop
    cargo-test     # cargo test
    build          # build
    build-release  # build release
    dev-rel        # maturin develop release
    pytest         # run pytest
    pytestv        # run pytest (printing captured output)
    test           # run all test
    test-release   # test ry package
    bench          # benchmark ry python package
    ci             # ci rust checks
    cargo-fmt      # cargo format
    cargo-fmtc     # cargo format check
    sort-all-check # ruff check sorting of '__all__'
    sort-all       # ruff sort '__all__'
    ruff-fmt       # ruff format
    ruff-fmtc      # ruff format check
    black          # python format black
    fmtpy          # python format
    fmtcpy         # python format check
    justfilefmt    # justfile format
    justfilefmtc   # justfile format check
    fmt            # format
    fmtc           # format check
    ruff           # run ruff linter
    ruffix         # run ruff + fix
    clippy         # run clippy
    lint           # lint python and rust
    mypy           # run mypy type checker
    pyright        # run pyright
    pip-compile    # pip compile requirements
    gen            # generate code tasks

ACKNOWLEDGEMENTS

This project would not be possible without the incredible work of many others.

THANK YOU

  • pyo3 developers
  • all authors of all libraries used in this project!
  • burnt-sushi for the incredible set of libraries
  • Kyle Barron for working on pyo3-bytes and letting me contribute to it
  • The academy and the hollywood foreign press

If you want to be added to this list, please open an issue or PR! Happy to add you if you’ve helped in any way!

CHANGELOG

v0.0.39 [2025-03-14]

  • internal
    • cleaned up several dependencies and features
  • ryo3-zstd
    • actually changed to use py buffer protocol this time… I dont know how it got missed before…
    • re-factored a decent bit and made submodule with future plans to expand encoding/decoding dictionary support
    • submodule is ry.zstd and/or ry.ryo3.zstd

v0.0.38 [2025-03-13]

  • ryo3-reqwest
    • client configuration for pickling
    • allow buffer-protocol for body fetching methods (should add string maybe?)
  • ryo3-walkdir
    • Few more options added
  • ryo3-glob
    • new wrapper around glob crate
  • ryo3-jiff
    • Switched to use conversions from jiff feature of pyo3-v24 as opposed to hand-rolled conversions we had before

v0.0.37 [2025-03-11]

  • pyo3 version 0.24.0
  • ryo3-which functions return pathlib.Path now due to changes in pyo3-v24; this may change in the near future…

v0.0.36 [2025-03-11]

  • dependencies updated
  • pickling support and tests for several types
  • bytes/buffer-protocol support for several sub-packages/packages:
    • ryo3-brotli
    • ryo3-bzip2
    • ryo3-flate2
    • ryo3-fnv
    • ryo3-xxhash
    • ryo3-zstd

v0.0.35 [2025-03-06]

  • internal
    • types split up and cleaned up
  • ryo3-size
    • ry.Size object
  • ryo3-jiff
    • series iterators have take function that takes a usize returns a list of size usize
    • updated series types to be JiffSeries class

v0.0.34 [2025-02-28]

  • ryo3-std
    • fs:
      • read_stream function that returns an iterator of ry.Bytes objects from a PathLike object
      • Several more fs functions added
  • ryo3-tokio
    • Several more tokio fs functions added
  • internal
    • reorganized type annotations to be not a HUGE file…

v0.0.33 [2025-02-26]

  • update to pyo3 v0.23.5

v0.0.32 [2025-02-25]

  • ryo3-jiter
    • Allow PyBytes wrapper/buffer protocol to be given
    • renamed jiter_cache_clear to json_cache_clear and jiter_cache_usage to json_cache_usage
    • Removed parse_json_str just use parse_json with str input
  • ryo3-fspath
    • Allow read/write to take ry.Bytes or Bytes objects

v0.0.31 [2025-02-21]

  • ryo3-core
    • got rid of ryo3-types and moved into ryo3-core
  • ryo3-tokio
    • read_async and write_async async functions
  • ryo3-which
    • which_re functions accepts ry.Regex or str now
  • ryo3-std
    • read and write functions which take/return ry.Bytes objects
  • internal
    • Changed many many many of the structs/classes to be pyo3 frozen behaviour should not be different

v0.0.30 [2025-02-18]

  • jiff
    • Upgraded jiff to version 2
  • internal
    • Switch all lints from #[allow(...)]/#![allow(...)] to #[expect(...)]/#![expect(...)]
    • Removed a bunch o commented out code
  • ryo3-std
    • added several std::fs structs
  • ryo3-fspath
    • conversion to pathlib.Path by way of FsPath.to_pathlib()

v0.0.29 [2025-02-03]

  • internal
    • Made sure each ryo3-* crate has a README.md
  • ryo3-bytes & ryo3-fspath
    • added __hash__ dunders to both Bytes and FsPath structs

v0.0.28 [2025-01-31]

  • jiff
    • Per Mr. Sushi’s thoughts changed all until/since methods to use kwargs instead of the rust-like tuples that impl From/Into as it does not translate well to python
    • Gets rid of the following inane types:
IntoDateDifference = (
  DateDifference
  | Date
  | DateTime
  | ZonedDateTime
  | tuple[JIFF_UNIT_STRING, Date]
  | tuple[JIFF_UNIT_STRING, DateTime]
  | tuple[JIFF_UNIT_STRING, ZonedDateTime]
)
IntoTimeDifference = (
  TimeDifference
  | Time
  | DateTime
  | ZonedDateTime
  | tuple[JIFF_UNIT_STRING, Time]
  | tuple[JIFF_UNIT_STRING, DateTime]
  | tuple[JIFF_UNIT_STRING, ZonedDateTime]
)
IntoDateTimeDifference = (
  DateTimeDifference
  | Date
  | Time
  | DateTime
  | ZonedDateTime
  | tuple[JIFF_UNIT_STRING, Date]
  | tuple[JIFF_UNIT_STRING, Time]
  | tuple[JIFF_UNIT_STRING, DateTime]
  | tuple[JIFF_UNIT_STRING, ZonedDateTime]
)
IntoTimestampDifference = (
  TimestampDifference
  | Timestamp
  | ZonedDateTime
  | tuple[JIFF_UNIT_STRING, Timestamp]
  | tuple[JIFF_UNIT_STRING, ZonedDateTime]
)

v0.0.27 [2025-01-23]

  • ry
    • Warning on debug build
  • reqwest
    • headers-property response returns Headers object instead of python dict
  • same-file
    • wrapper module added with is_same_file py-fn (yet another piece of burnt sushi)
  • jiff
    • jiff-version 0.1.25 ~ add in_tz methods and point old intz at new in_tz methods and raise DeprecationWarning for old intz methods
    • Continued adding implementations that previously raised NotImplementedError
      • Date.nth_weekday_of_month
      • Date.nth_weekday
      • DateTime.nth_weekday_of_month
      • DateTime.nth_weekday
      • TimeSpan.compare
      • TimeSpan.total
      • ZonedDateTime.nth_weekday_of_month
      • ZonedDateTime.nth_weekday

v0.0.26 [2025-01-13]

  • reqwest
    • AsyncClient renamed to HttpClient
  • jiff
    • human timespan strings for TimeSpan and SignedDuration objects:
      • ry.TimeSpan.parse("P2M10DT2H30M").string(human=True) == "2mo 10d 2h 30m"
      • ry.SignedDuration.parse("PT2H30M").string(human=True) == "2h 30m"
  • internal
    • workspace-ified all the deps

v0.0.25 [2024-01-07] (25 for 2025)

  • jiff
    • Updated to 0.1.21 which has span and signed duration strings with capital letters

v0.0.24 [2024-12-24] (the night b4 xmas…)

  • http
    • basic headers struct/obj – WIP
  • reqwest
    • reqwest client (currently root-export)
    • default client + root fetch function likely needs work…
    • response byte_stream!

v0.0.23 [2024-12-19]

  • python -m ry.dev repl for ipython/python repl ~ handy nifty secret tool makes it into repo
  • internal
    • in process of renaming all python-rust #[new] functions to be named fn py_new(...)
  • unindent
    • Added unindent module for unindenting strings will move to ryo3-unindent
  • FsPath
    • creeping ever closer to being a full-fledged pathlib.Path replacement
    • Added bindings to all rust std::path::Path(buf) methods for FsPath
  • sub-packaging
    • xxhash is own sub package now ry.xxhash
    • JSON is own subpackage right now – named ry.JSON to avoid conflict with json module but maybe will change…
    • food-for-thought-ing how ryo3 and ry should be organized w/ respsect to sub-packages and where that organization should be
  • type-annotations
    • required to break up the type annotations due to migration to sub-packages
    • breaking up the type annotations file into smaller files under <REPO>/python/ry/ryo3/*.pyi

v0.0.22 [2024-12-16]

  • regex
    • Super simple regex wrapper (must to do here, but was added for ryo3-which::which_re)
  • jiff
    • until/since
      • Basic until/since implementation but I do not like them and they confusingly named *Difference structs/py-objects, so I may change how they work…
    • jiff seems to be about as performant as whenever ~ yay! also the whenever dude appears to be watching this repo (as of 2024-12-16)
  • walkdir
    • collect added to WalkdirGen to collect the results into a list
  • deps
    • thiserror version 2.0.7 -> 2.0.8

v0.0.21 [2024-12-13] (friday the 13th… spoogidy oogidity)

  • walkdir
    • add glob kwarg that takes a ry.Glob or ry.GlobSet or ry.Globster obj to filter the walk on
  • globset
    • Internal refactoring
    • added globster() method to ry.Glob and ry.GlobSet to return a ry.Globster obj
    • added globset() method to ry.Glob to return a ry.GlobSet obj from a ry.Glob obj
  • url
    • python Url changed name URL; aligns with jawascript and other python libs
  • bzip2
    • update to v5
  • jiff
    • conversions for jiff-round-mode/unit/weekday
    • not-implemented placeholders and new impls
      • RyDateTime
      • RyDate
      • RyOffset
      • RySignedDuration
      • RySpan
      • RyTimeZone
      • RyTime
      • RyZoned
    • span builder functions use form s._hours(1) for panic-inducing building, and s.try_hours(1) for non-panic-inducing building
  • type-annotations
    • fixes and updates and a hacky script I wrote to check for discrepancies

v0.0.20 [2024-12-10]

  • regex
    • Templated out regex package but nothing added
  • ry
    • python 3.13 yay!
  • jiter
    • Updated jiter version thanks depbot!

v0.0.19 [2024-12-05]

  • jiff
    • py-conversions
      • JiffDateTime
        • FromPyObject
        • IntoPyObject
        • IntoPyObject (REF)
      • JiffDate
        • FromPyObject
        • IntoPyObject
        • IntoPyObject (REF)
      • JiffOffset
        • FromPyObject
        • IntoPyObject
        • IntoPyObject (REF)
      • JiffSignedDuration
        • FromPyObject
        • IntoPyObject
        • IntoPyObject (REF)
      • JiffSpan
        • FromPyObject
        • IntoPyObject
        • IntoPyObject (REF)
      • JiffTimeZone
        • FromPyObject
        • IntoPyObject
        • IntoPyObject (REF)
      • JiffTime
        • FromPyObject
        • IntoPyObject
        • IntoPyObject (REF)
      • JiffZoned
        • FromPyObject
        • IntoPyObject
        • IntoPyObject (REF)

v0.0.18 [2024-12-03]

  • jiff
    • Renamed ry.Span to ry.TimeSpan
    • Renamed ry.Zoned to ry.ZonedDateTime
    • Updated type stubs to reflect renames
  • docs
    • init-ed the docs
    • style guide under DEVELOPMENT.md file

v0.0.17 [2024-12-02]

  • jiff
    • ry.TimeZone testing and to/from datetime.tzinfo conversions
    • Using nu-types for jiff intermediate types bc of the classic orphans problem (aka batman) w/ traits
    • hypothesis tests
  • jiter
    • Updated to jiter v0.8.1

v0.0.16 [2024-11-29]

  • Moved walkdir to ryo3-walkdir
  • added ryo3-types for custom and shared types
  • heck wrapper(s)
  • jiff
    • Added operators +/+=/-/-= to date/time/datetime/etc
    • TODO: figure out how to take refs in the union enum for the operators
  • fspath
    • further beefing out as well as testing

v0.0.15 [2024-11-20]

  • from __future__ import annotations added to all modules
  • cicd updated to include more targets

v0.0.14 [2024-11-20]

  • Primitive/crude wrappers around Mr. Sushi’s jiff library
  • Updated to use pyo3 (had to use jiter git repo dep)
  • ry.FsPath beefed out
  • Added iterdir gen wrapper
  • (todo undo when jiter + pyo3 23 is public)

v0.0.13 [2024-11-20]

  • VERSION SKIPPED DUE TO 13 BEING SPOOKY AND ME BEING MODERATELY-STITCHOUS (AKA fully ‘superstitchous’)

v0.0.12 [2024-11-14]

  • sqlformat wrapper(s) (this is the first ryo3-* sub-crate)

v0.0.11 [2024-09-22]

  • dependencies updated
  • prepare for python 3.13

v0.0.10 [2024-09-22]

  • dependencies updated

v0.0.9 [2024-08-22]

  • Added globset wrapper(s)
  • Added __init__.py generator

  • Upgraded to pyo3-v0.22

v0.0.8 [2024-06-25]

  • Upgraded to pyo3-v0.22

v0.0.7 [2024-06-08]

  • internal refactoring

v0.0.6 [2024-06-05]

  • Added zstd (zstd_encode/zstd and zstd_decode)
  • Added gzip (gzip_encode/gzip and gzip_decode/gunzip)
  • Added bzip2 (bzip2_encode/bzip2 and bzip2_decode)
  • Added walkdir
  • Reorg libs

v0.0.5 [2024-04-19]

  • Added brotli (brotli_encode and brotli_decode)
  • xxhash
    • const functions
    • hasher streaming objects

Examples

TODO: Add examples

API

API

Table of Contents

ry.ryo3.__init__

"""ry api ~ type annotations"""

from __future__ import annotations

import datetime as pydt
import typing as t
from os import PathLike

from ry import dirs as dirs  # noqa: RUF100
from ry import http as http  # noqa: RUF100
from ry import xxhash as xxhash  # noqa: RUF100
from ry import zstd as zstd  # noqa: RUF100
from ry._types import Buffer as Buffer  # noqa: RUF100
from ry.http import Headers as Headers  # noqa: RUF100
from ry.http import HttpStatus as HttpStatus  # noqa: RUF100
from ry.zstd import is_zstd as is_zstd
from ry.zstd import zstd_compress as zstd_compress
from ry.zstd import zstd_decode as zstd_decode
from ry.zstd import zstd_decompress as zstd_decompress
from ry.zstd import zstd_encode as zstd_encode

from ._brotli import brotli as brotli
from ._brotli import brotli_decode as brotli_decode
from ._brotli import brotli_encode as brotli_encode
from ._bytes import Bytes as Bytes
from ._bzip2 import bzip2 as bzip2
from ._bzip2 import bzip2_decode as bzip2_decode
from ._bzip2 import bzip2_encode as bzip2_encode
from ._flate2 import gunzip as gunzip
from ._flate2 import gzip as gzip
from ._flate2 import gzip_decode as gzip_decode
from ._flate2 import gzip_encode as gzip_encode
from ._flate2 import is_gzipped as is_gzipped
from ._fnv import FnvHasher as FnvHasher
from ._fnv import fnv1a as fnv1a
from ._fspath import FsPath as FsPath
from ._glob import Pattern as Pattern
from ._glob import glob as glob
from ._globset import Glob as Glob
from ._globset import GlobSet as GlobSet
from ._globset import Globster as Globster
from ._globset import globster as globster
from ._heck import camel_case as camel_case
from ._heck import kebab_case as kebab_case
from ._heck import pascal_case as pascal_case
from ._heck import shouty_kebab_case as shouty_kebab_case
from ._heck import shouty_snake_case as shouty_snake_case
from ._heck import snake_case as snake_case
from ._heck import snek_case as snek_case
from ._heck import title_case as title_case
from ._heck import train_case as train_case
from ._jiff import Date as Date
from ._jiff import DateDifference as DateDifference
from ._jiff import DateTime as DateTime
from ._jiff import DateTimeDifference as DateTimeDifference
from ._jiff import DateTimeRound as DateTimeRound
from ._jiff import ISOWeekDate as ISOWeekDate
from ._jiff import Offset as Offset
from ._jiff import SignedDuration as SignedDuration
from ._jiff import Time as Time
from ._jiff import TimeDifference as TimeDifference
from ._jiff import TimeSpan as TimeSpan
from ._jiff import Timestamp as Timestamp
from ._jiff import TimestampDifference as TimestampDifference
from ._jiff import TimestampRound as TimestampRound
from ._jiff import TimeZone as TimeZone
from ._jiff import TimeZoneDatabase as TimeZoneDatabase
from ._jiff import ZonedDateTime as ZonedDateTime
from ._jiff import ZonedDateTimeDifference as ZonedDateTimeDifference
from ._jiff import ZonedDateTimeRound as ZonedDateTimeRound
from ._jiff import date as date
from ._jiff import datetime as datetime
from ._jiff import offset as offset
from ._jiff import time as time
from ._jiff import timespan as timespan
from ._jiter import JsonParseKwargs as JsonParseKwargs
from ._jiter import JsonPrimitive as JsonPrimitive
from ._jiter import JsonValue as JsonValue
from ._jiter import json_cache_clear as json_cache_clear
from ._jiter import json_cache_usage as json_cache_usage
from ._jiter import parse_json as parse_json
from ._jiter import parse_json_bytes as parse_json_bytes
from ._quick_maths import quick_maths as quick_maths
from ._regex import Regex as Regex
from ._reqwest import HttpClient as HttpClient
from ._reqwest import ReqwestError as ReqwestError
from ._reqwest import Response as Response
from ._reqwest import ResponseStream as ResponseStream
from ._reqwest import fetch as fetch
from ._same_file import is_same_file as is_same_file
from ._shlex import shplit as shplit
from ._size import Size as Size
from ._size import SizeFormatter as SizeFormatter
from ._size import fmt_size as fmt_size
from ._size import parse_size as parse_size
from ._sqlformat import SqlfmtQueryParams as SqlfmtQueryParams
from ._sqlformat import sqlfmt as sqlfmt
from ._sqlformat import sqlfmt_params as sqlfmt_params
from ._std import Duration as Duration
from ._std import FileType as FileType
from ._std import Instant as Instant
from ._std import Metadata as Metadata
from ._std import canonicalize as canonicalize
from ._std import copy as copy
from ._std import create_dir as create_dir
from ._std import create_dir_all as create_dir_all
from ._std import exists as exists
from ._std import instant as instant
from ._std import is_dir as is_dir
from ._std import is_file as is_file
from ._std import is_symlink as is_symlink
from ._std import metadata as metadata
from ._std import read as read
from ._std import read_bytes as read_bytes
from ._std import read_stream as read_stream
from ._std import read_text as read_text
from ._std import remove_dir as remove_dir
from ._std import remove_dir_all as remove_dir_all
from ._std import remove_file as remove_file
from ._std import rename as rename
from ._std import sleep as sleep
from ._std import write as write
from ._std import write_bytes as write_bytes
from ._std import write_text as write_text
from ._tokio import asleep as asleep
from ._tokio import copy_async as copy_async
from ._tokio import create_dir_async as create_dir_async
from ._tokio import metadata_async as metadata_async
from ._tokio import read_async as read_async
from ._tokio import read_dir_async as read_dir_async
from ._tokio import remove_dir_async as remove_dir_async
from ._tokio import remove_file_async as remove_file_async
from ._tokio import rename_async as rename_async
from ._tokio import sleep_async as sleep_async
from ._tokio import write_async as write_async
from ._unindent import unindent as unindent
from ._unindent import unindent_bytes as unindent_bytes
from ._url import URL as URL
from ._walkdir import WalkDirEntry as WalkDirEntry
from ._walkdir import WalkdirGen as WalkdirGen
from ._walkdir import walkdir as walkdir
from ._which import which as which
from ._which import which_all as which_all
from ._which import which_re as which_re
from .errors import FeatureNotEnabledError as FeatureNotEnabledError

# =============================================================================
# CONSTANTS
# =============================================================================
__version__: str
__authors__: str
__build_profile__: str
__build_timestamp__: str
__pkg_name__: str
__description__: str


# =============================================================================
# SH
# =============================================================================
def pwd() -> str: ...
def home() -> str: ...
def cd(path: str | PathLike[str]) -> None: ...
@t.overload
def ls(
    path: str | PathLike[str] | None = None,  # defaults to '.' if None
    *,
    absolute: bool = False,
    sort: bool = False,
    objects: t.Literal[False] = False,
) -> list[str]:
    """List directory contents - returns list of strings"""


@t.overload
def ls(
    path: str | PathLike[str] | None = None,  # defaults to '.' if None
    *,
    absolute: bool = False,
    sort: bool = False,
    objects: t.Literal[True] = True,
) -> list[FsPath]:
    """List directory contents - returns list of FsPath objects"""

ry.ryo3.errors

from __future__ import annotations


class FeatureNotEnabledError(RuntimeError):
    """Raised when a feature is not enabled in the current build."""

ry.ryo3.JSON

"""ry.ryo3.JSON"""

from typing import Literal

JsonPrimitive = None | bool | int | float | str
JsonValue = (
    JsonPrimitive
    | dict[str, JsonPrimitive | JsonValue]
    | list[JsonPrimitive | JsonValue]
)


def parse_json(
    data: bytes | str,
    /,
    *,
    allow_inf_nan: bool = True,
    cache_mode: Literal[True, False, "all", "keys", "none"] = "all",
    partial_mode: Literal[True, False, "off", "on", "trailing-strings"] = False,
    catch_duplicate_keys: bool = False,
    float_mode: Literal["float", "decimal", "lossless-float"] | bool = False,
) -> JsonValue: ...
def parse_json_bytes(
    data: bytes,
    /,
    *,
    allow_inf_nan: bool = True,
    cache_mode: Literal[True, False, "all", "keys", "none"] = "all",
    partial_mode: Literal[True, False, "off", "on", "trailing-strings"] = False,
    catch_duplicate_keys: bool = False,
    float_mode: Literal["float", "decimal", "lossless-float"] | bool = False,
) -> JsonValue: ...
def json_cache_clear() -> None: ...
def json_cache_usage() -> int: ...

ry.ryo3._brotli

"""ryo3-brotli types"""

from __future__ import annotations


# =============================================================================
# BROTLI
# =============================================================================
def brotli_encode(
    input: bytes, quality: int = 11, magic_number: bool = False
) -> bytes: ...
def brotli_decode(input: bytes) -> bytes: ...
def brotli(
    input: bytes, quality: int = 11, magic_number: bool = False
) -> bytes:
    """Alias for brotli_encode"""

ry.ryo3._bytes

import sys
from typing import overload

if sys.version_info >= (3, 12):
    from collections.abc import Buffer as Buffer
else:
    from typing_extensions import Buffer as Buffer


class Bytes(Buffer):
    """
    A buffer implementing the Python buffer protocol, allowing zero-copy access
    to underlying Rust memory.

    You can pass this to `memoryview` for a zero-copy view into the underlying
    data or to `bytes` to copy the underlying data into a Python `bytes`.

    Many methods from the Python `bytes` class are implemented on this,
    """

    def __init__(self, buf: Buffer = b"") -> None:
        """Construct a new Bytes object.

        This will be a zero-copy view on the Python byte slice.
        """

    def __add__(self, other: Buffer) -> Bytes: ...
    def __buffer__(self, flags: int) -> memoryview[int]: ...
    def __contains__(self, other: Buffer) -> bool: ...
    def __eq__(self, other: object) -> bool: ...
    @overload
    def __getitem__(self, other: int) -> int: ...
    @overload
    def __getitem__(self, other: slice) -> Bytes: ...
    def __mul__(self, other: Buffer) -> int: ...
    def __len__(self) -> int: ...
    def __repr__(self) -> str: ...
    def removeprefix(self, prefix: Buffer, /) -> Bytes:
        """
        If the binary data starts with the prefix string, return `bytes[len(prefix):]`.
        Otherwise, return the original binary data.
        """

    def removesuffix(self, suffix: Buffer, /) -> Bytes:
        """
        If the binary data ends with the suffix string and that suffix is not empty,
        return `bytes[:-len(suffix)]`. Otherwise, return the original binary data.
        """

    def isalnum(self) -> bool:
        """
        Return `True` if all bytes in the sequence are alphabetical ASCII characters or
        ASCII decimal digits and the sequence is not empty, `False` otherwise.

        Alphabetic ASCII characters are those byte values in the sequence
        `b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'`. ASCII decimal digits
        are those byte values in the sequence `b'0123456789'`.
        """

    def isalpha(self) -> bool:
        """
        Return `True` if all bytes in the sequence are alphabetic ASCII characters and
        the sequence is not empty, `False` otherwise.

        Alphabetic ASCII characters are those byte values in the sequence
        `b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'`.
        """

    def isascii(self) -> bool:
        """
        Return `True` if the sequence is empty or all bytes in the sequence are ASCII,
        `False` otherwise.

        ASCII bytes are in the range `0-0x7F`.
        """

    def isdigit(self) -> bool:
        """
        Return `True` if all bytes in the sequence are ASCII decimal digits and the
        sequence is not empty, `False` otherwise.

        ASCII decimal digits are those byte values in the sequence `b'0123456789'`.
        """

    def islower(self) -> bool:
        """
        Return `True` if there is at least one lowercase ASCII character in the sequence
        and no uppercase ASCII characters, `False` otherwise.
        """

    def isspace(self) -> bool:
        """
        Return `True` if all bytes in the sequence are ASCII whitespace and the sequence
        is not empty, `False` otherwise.

        ASCII whitespace characters are those byte values
        in the sequence `b' \t\n\r\x0b\f'` (space, tab, newline, carriage return,
        vertical tab, form feed).
        """

    def isupper(self) -> bool:
        """
        Return `True` if there is at least one uppercase alphabetic ASCII character in
        the sequence and no lowercase ASCII characters, `False` otherwise.
        """

    def lower(self) -> Bytes:
        """
        Return a copy of the sequence with all the uppercase ASCII characters converted
        to their corresponding lowercase counterpart.
        """

    def upper(self) -> Bytes:
        """
        Return a copy of the sequence with all the lowercase ASCII characters converted
        to their corresponding uppercase counterpart.
        """

    def to_bytes(self) -> bytes:
        """Copy this buffer's contents into a Python `bytes` object."""

    # =========================================================================
    # IMPL IN RY
    # =========================================================================

    def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str:
        """Decode the binary data using the given encoding."""

    def hex(
        self, sep: str | None = None, bytes_per_sep: int | None = None
    ) -> str:
        """Return a hexadecimal representation of the binary data."""

    @classmethod
    def fromhex(cls, hexstr: str) -> Bytes:
        """Construct a `Bytes` object from a hexadecimal string."""


BytesLike = Buffer | bytes | bytearray | memoryview | Bytes

ry.ryo3._bzip2

"""ryo3-bzip2 types"""

from __future__ import annotations

from ry._types import Buffer


# =============================================================================
# BZIP2
# =============================================================================
def bzip2_encode(input: Buffer, quality: int = 9) -> bytes: ...
def bzip2_decode(input: Buffer) -> bytes: ...
def bzip2(input: Buffer, quality: int = 9) -> bytes:
    """Alias for bzip2_encode"""

ry.ryo3._dev

"""ry.ryo3.dev"""

from __future__ import annotations

import typing as t


# =============================================================================
# SUBPROCESS (VERY MUCH WIP)
# =============================================================================
def run(
    *args: str | list[str],
    capture_output: bool = True,
    input: bytes | None = None,
) -> t.Any: ...


# =============================================================================
# STRING-DEV
# =============================================================================


def anystr_noop(s: t.AnyStr) -> t.AnyStr: ...
def string_noop(s: str) -> str: ...
def bytes_noop(s: bytes) -> bytes: ...

ry.ryo3._flate2

"""ryo3-flate2 types"""

from __future__ import annotations

from ry import Bytes
from ry._types import Buffer


# =============================================================================
# GZIP
# =============================================================================
def gzip_encode(input: Buffer, quality: int = 9) -> Bytes: ...
def gzip_decode(input: Buffer) -> Bytes: ...
def gzip(input: Buffer, quality: int = 9) -> Bytes:
    """Alias for gzip_encode"""


def gunzip(input: Buffer) -> Bytes:
    """Alias for gzip_decode"""


def is_gzipped(input: Buffer) -> bool: ...

ry.ryo3._fnv

"""ryo3-fnv types"""

import typing as t

from ry._types import Buffer


# =============================================================================
# FNV
# =============================================================================
class FnvHasher:
    name: t.Literal["fnv1a"]

    def __init__(self, input: Buffer | None = None) -> None: ...
    def update(self, input: Buffer) -> None: ...
    def digest(self) -> int: ...
    def hexdigest(self) -> str: ...
    def copy(self) -> FnvHasher: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...


def fnv1a(input: Buffer) -> FnvHasher: ...

ry.ryo3._fspath

"""ryo3-fspath types"""

from __future__ import annotations

import typing as t
from os import PathLike
from pathlib import Path

from ry import Bytes
from ry._types import Buffer, ToPy


# =============================================================================
# FSPATH
# =============================================================================
class FsPath(ToPy[Path]):
    def __init__(self, path: PathLike[str] | str | None = None) -> None: ...
    def __fspath__(self) -> str: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def __hash__(self) -> int: ...
    def __eq__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __lt__(self, other: PathLike[str] | str) -> bool: ...
    def __le__(self, other: PathLike[str] | str) -> bool: ...
    def __gt__(self, other: PathLike[str] | str) -> bool: ...
    def __ge__(self, other: PathLike[str] | str) -> bool: ...
    def __truediv__(self, other: PathLike[str] | str) -> FsPath: ...
    def __rtruediv__(self, other: PathLike[str] | str) -> FsPath: ...
    def __bytes__(self) -> bytes: ...
    def to_py(self) -> Path: ...
    def to_pathlib(self) -> Path: ...
    def read(self) -> Bytes: ...
    def read_text(self) -> str: ...
    def read_bytes(self) -> bytes: ...
    def absolute(self) -> FsPath: ...
    def resolve(self) -> FsPath: ...
    def write(self, data: Buffer | bytes) -> None: ...
    def write_bytes(self, data: Buffer | bytes) -> None: ...
    def write_text(self, data: str) -> None: ...
    def joinpath(self, *paths: str) -> FsPath: ...
    def exists(self) -> bool: ...
    def with_name(self, name: str) -> FsPath: ...
    def with_suffix(self, suffix: str) -> FsPath: ...
    def iterdir(self) -> t.Iterator[FsPath]: ...
    def relative_to(self, other: PathLike[str] | str | FsPath) -> FsPath: ...
    def as_posix(self) -> str: ...
    def as_uri(self) -> str: ...
    def equiv(self, other: PathLike[str] | str | FsPath) -> bool: ...
    def string(self) -> str: ...
    def clone(self) -> FsPath: ...

    # =========================================================================
    # CLASSMETHODS
    # =========================================================================
    @classmethod
    def cwd(cls) -> FsPath: ...
    @classmethod
    def home(cls) -> FsPath: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def anchor(self) -> str: ...
    @property
    def drive(self) -> str: ...
    @property
    def name(self) -> str: ...
    @property
    def parent(self) -> FsPath: ...
    @property
    def parents(self) -> t.Sequence[FsPath]: ...
    @property
    def parts(self) -> tuple[str, ...]: ...
    @property
    def root(self) -> str: ...
    @property
    def stem(self) -> str: ...
    @property
    def suffix(self) -> str: ...
    @property
    def suffixes(self) -> list[str]: ...

    # =========================================================================
    # std::path::PathBuf (deref -> std::path::Path)
    # =========================================================================
    def ancestors(self) -> t.Iterator[FsPath]: ...
    def canonicalize(self) -> FsPath: ...
    def components(self) -> t.Iterator[FsPath]: ...
    def display(self) -> str: ...
    def ends_with(self, path: PathLike[str] | str) -> bool: ...
    def extension(self) -> str: ...
    def file_name(self) -> str: ...
    def file_prefix(self) -> FsPath: ...
    def file_stem(self) -> str: ...
    def has_root(self) -> bool: ...
    def is_absolute(self) -> bool: ...
    def is_dir(self) -> bool: ...
    def is_file(self) -> bool: ...
    def is_relative(self) -> bool: ...
    def is_symlink(self) -> bool: ...
    def starts_with(self, path: PathLike[str] | str) -> bool: ...
    def strip_prefix(self, prefix: PathLike[str] | str) -> FsPath: ...
    def with_extension(self, ext: str) -> FsPath: ...
    def with_file_name(self, name: str) -> FsPath: ...

ry.ryo3._glob

"""ryo3-glob types"""

from __future__ import annotations

import typing as t
from os import PathLike
from pathlib import Path

import typing_extensions as te

T = t.TypeVar("T")


class _MatchOptions(t.TypedDict, total=False):
    case_sensitive: bool
    require_literal_separator: bool
    require_literal_leading_dot: bool


class GlobPaths(t.Generic[T]):
    """glob::Paths iterable wrapper"""

    def __next__(self) -> T: ...
    def __iter__(self) -> t.Iterator[T]: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def collect(self) -> list[T]: ...
    def take(self, n: int) -> list[T]: ...


def glob(
    pattern: str,
    **kwargs: te.Unpack[_MatchOptions],
) -> GlobPaths[Path]:
    """Return glob iterable for paths matching the pattern."""


class Pattern:
    def __init__(self, pattern: str) -> None: ...
    def __call__(
        self,
        ob: str | PathLike[str],
        **kwargs: te.Unpack[_MatchOptions],
    ) -> bool: ...
    def matches(self, s: str) -> bool: ...
    def matches_path(self, path: PathLike[str]) -> bool: ...
    def matches_with(
        self,
        s: str,
        **kwargs: te.Unpack[_MatchOptions],
    ) -> bool: ...
    def matches_path_with(
        self,
        path: PathLike[str],
        **kwargs: te.Unpack[_MatchOptions],
    ) -> bool: ...
    @staticmethod
    def escape(pattern: str) -> str: ...

ry.ryo3._globset

"""ryo3-globset types"""

from __future__ import annotations

from os import PathLike


class Glob:
    """globset::Glob wrapper"""

    def __init__(
        self,
        pattern: str,
        /,
        *,
        case_insensitive: bool | None = None,
        literal_separator: bool | None = None,
        backslash_escape: bool | None = None,
    ) -> None: ...
    def regex(self) -> str: ...
    def is_match(self, path: str | PathLike[str]) -> bool: ...
    def __call__(self, path: str | PathLike[str]) -> bool: ...
    def __invert__(self) -> Glob: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def globset(self) -> GlobSet: ...
    def globster(self) -> Globster: ...


class GlobSet:
    """globset::GlobSet wrapper"""

    def __init__(
        self,
        patterns: list[str],
        /,
        *,
        case_insensitive: bool | None = None,
        literal_separator: bool | None = None,
        backslash_escape: bool | None = None,
    ) -> None: ...
    def is_empty(self) -> bool: ...
    def is_match(self, path: str) -> bool: ...
    def matches(self, path: str) -> list[int]: ...
    def __call__(self, path: str) -> bool: ...
    def __invert__(self) -> GlobSet: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def globster(self) -> Globster: ...


class Globster:
    """Globster is a matcher with claws!

    Note: The north american `Globster` is similar to the european `Globset`
          but allows for negative patterns (prefixed with '!')

    """

    def __init__(
        self,
        patterns: list[str],
        /,
        *,
        case_insensitive: bool | None = None,
        literal_separator: bool | None = None,
        backslash_escape: bool | None = None,
    ) -> None: ...
    def is_empty(self) -> bool: ...
    def is_match(self, path: str | PathLike[str]) -> bool: ...
    def __call__(self, path: str | PathLike[str]) -> bool: ...
    def __invert__(self) -> GlobSet: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...


def globster(
    patterns: list[str] | tuple[str, ...],
    /,
    *,
    case_insensitive: bool | None = None,
    literal_separator: bool | None = None,
    backslash_escape: bool | None = None,
) -> Globster: ...

ry.ryo3._heck

"""ryo3-heck types"""

from __future__ import annotations


def camel_case(string: str) -> str: ...
def kebab_case(string: str) -> str: ...
def pascal_case(string: str) -> str: ...
def shouty_kebab_case(string: str) -> str: ...
def shouty_snake_case(string: str) -> str: ...
def snake_case(string: str) -> str: ...
def snek_case(string: str) -> str: ...
def title_case(string: str) -> str: ...
def train_case(string: str) -> str: ...

ry.ryo3._jiff

"""jiff types"""

import datetime as pydt
import typing as t
from typing import Protocol

import typing_extensions as te

from ry._types import (
    DateTimeTypedDict,
    DateTypedDict,
    TimeSpanTypedDict,
    TimeTypedDict,
    ToPy,
)
from ry.ryo3 import Duration

T = t.TypeVar("T")
# =============================================================================
# JIFF
# =============================================================================
JIFF_UNIT = t.Literal[
    "year",
    "month",
    "week",
    "day",
    "hour",
    "minute",
    "second",
    "millisecond",
    "microsecond",
    "nanosecond",
]

JIFF_ROUND_MODE = t.Literal[
    "ceil",
    "floor",
    "expand",
    "trunc",
    "half_ceil",
    "half_floor",
    "half_expand",
    "half_trunc",
    "half_even",
]

WEEKDAY_STR = t.Literal[
    "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"
]

WEEKDAY_INT = t.Literal[
    1,  # Monday
    2,  # Tuesday
    3,  # Wednesday
    4,  # Thursday
    5,  # Friday
    6,  # Saturday
    7,  # Sunday
]

WEEKDAY: te.TypeAlias = WEEKDAY_STR | WEEKDAY_INT


class ToPyDate(Protocol):
    def to_pydate(self) -> pydt.date: ...


class ToPyTime(Protocol):
    def to_pytime(self) -> pydt.time: ...


class ToPyDateTime(Protocol):
    def to_pydatetime(self) -> pydt.datetime: ...


class ToPyTimeDelta(Protocol):
    def to_pytimedelta(self) -> pydt.timedelta: ...


class ToPyTzInfo(Protocol):
    def to_pytzinfo(self) -> pydt.tzinfo: ...


class Date(ToPy[pydt.date], ToPyDate):
    MIN: Date
    MAX: Date
    ZERO: Date

    def __init__(self, year: int, month: int, day: int) -> None: ...

    # =========================================================================
    # STRING
    # =========================================================================
    def string(self) -> str: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...

    # =========================================================================
    # PYTHON_CONVERSIONS
    # =========================================================================
    def to_py(self) -> pydt.date: ...
    def to_pydate(self) -> pydt.date: ...
    @classmethod
    def from_pydate(cls: type[Date], date: pydt.date) -> Date: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def year(self) -> int: ...
    @property
    def month(self) -> int: ...
    @property
    def day(self) -> int: ...
    @property
    def weekday(self) -> int: ...

    # =========================================================================
    # CLASSMETHODS
    # =========================================================================
    @classmethod
    def from_iso_week_date(
        cls: type[Date], year: int, week: int, weekday: int
    ) -> Date: ...
    @classmethod
    def today(cls: type[Date]) -> Date: ...

    # =========================================================================
    # STRPTIME/STRFTIME
    # =========================================================================
    @classmethod
    def strptime(cls: type[Date], format: str, string: str) -> Date: ...
    def strftime(self, format: str) -> str: ...

    # =========================================================================
    # OPERATORS
    # =========================================================================
    def __add__(self, other: TimeSpan | SignedDuration | Duration) -> Date: ...
    @t.overload
    def __sub__(self, other: Date) -> TimeSpan: ...
    @t.overload
    def __sub__(self, other: TimeSpan | SignedDuration | Duration) -> Date: ...
    @t.overload
    def __isub__(self, other: Date) -> TimeSpan: ...
    @t.overload
    def __isub__(self, other: TimeSpan | SignedDuration | Duration) -> Date: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================
    def at(
        self, hour: int, minute: int, second: int, nanosecond: int
    ) -> DateTime: ...
    def asdict(self) -> DateTypedDict: ...
    def astuple(self) -> tuple[int, int, int]: ...
    def checked_add(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Date: ...
    def day_of_year(self) -> int: ...
    def day_of_year_no_leap(self) -> int | None: ...
    def days_in_month(self) -> int: ...
    def days_in_year(self) -> int: ...
    def duration_since(self, other: Date) -> Date: ...
    def duration_until(self, other: Date) -> Date: ...
    def era_year(self) -> tuple[int, t.Literal["BCE", "CE"]]: ...
    def first_of_month(self) -> Date: ...
    def first_of_year(self) -> Date: ...
    def iso_week_date(self) -> ISOWeekDate: ...
    def in_leap_year(self) -> bool: ...
    def in_tz(self, tz: str) -> ZonedDateTime: ...
    def intz(self, tz: str) -> ZonedDateTime: ...
    def last_of_month(self) -> Date: ...
    def last_of_year(self) -> Date: ...
    def nth_weekday(self, nth: int, weekday: WEEKDAY) -> Date: ...
    def nth_weekday_of_month(self, nth: int, weekday: WEEKDAY) -> Date: ...
    def saturating_add(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Date: ...
    def saturating_sub(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Date: ...
    def series(self, span: TimeSpan) -> JiffSeries[Date]: ...
    def sub_date(self, other: Date) -> TimeSpan: ...
    def to_datetime(self, time: Time) -> DateTime: ...
    def to_zoned(self, tz: TimeZone) -> ZonedDateTime: ...
    def tomorrow(self) -> Date: ...
    def yesterday(self) -> Date: ...

    # =========================================================================
    # SINCE/UNTIL
    # =========================================================================
    def _since(self, other: DateDifference) -> TimeSpan: ...
    def _until(self, other: DateDifference) -> TimeSpan: ...
    def since(
        self,
        other: Date | DateTime | ZonedDateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> TimeSpan: ...
    def until(
        self,
        other: Date | DateTime | ZonedDateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> TimeSpan: ...

    # =========================================================================
    # INSTANCE METHODS W/ OVERLOADS
    # =========================================================================
    @t.overload
    def checked_sub(self, other: Date) -> TimeSpan: ...
    @t.overload
    def checked_sub(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Date: ...


class DateDifference:
    def __init__(
        self,
        date: Date,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> None: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def smallest(self, unit: JIFF_UNIT) -> DateDifference: ...
    def largest(self, unit: JIFF_UNIT) -> DateDifference: ...
    def mode(self, mode: JIFF_ROUND_MODE) -> DateDifference: ...
    def increment(self, increment: int) -> DateDifference: ...


class Time(ToPy[pydt.time], ToPyTime):
    MIN: Time
    MAX: Time

    def __init__(
        self,
        hour: int = 0,
        minute: int = 0,
        second: int = 0,
        nanosecond: int = 0,
    ) -> None: ...

    # =========================================================================
    # STRING
    # =========================================================================
    def string(self) -> str: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...

    # =========================================================================
    # OPERATORS/DUNDERS
    # =========================================================================
    def __add__(self, other: TimeSpan | SignedDuration | Duration) -> Time: ...
    @t.overload
    def __sub__(self, other: Time) -> TimeSpan: ...
    @t.overload
    def __sub__(self, other: TimeSpan | SignedDuration | Duration) -> Time: ...
    @t.overload
    def __isub__(self, other: Time) -> TimeSpan: ...
    @t.overload
    def __isub__(self, other: TimeSpan | SignedDuration | Duration) -> Time: ...

    # =========================================================================
    # STRPTIME/STRFTIME/PARSE
    # =========================================================================
    @classmethod
    def strptime(cls: type[Time], format: str, string: str) -> Time: ...
    def strftime(self, format: str) -> str: ...

    # =========================================================================
    # PYTHON CONVERSIONS
    # =========================================================================
    def to_py(self) -> pydt.time: ...
    def to_pytime(self) -> pydt.time: ...
    @classmethod
    def from_pytime(cls: type[Time], t: pydt.time) -> Time: ...

    # =========================================================================
    # CLASS METHODS
    # =========================================================================
    @classmethod
    def midnight(cls: type[Time]) -> Time: ...
    @classmethod
    def now(cls: type[Time]) -> Time: ...
    @classmethod
    def parse(cls: type[Time], s: str) -> Time: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def hour(self) -> int: ...
    @property
    def minute(self) -> int: ...
    @property
    def second(self) -> int: ...
    @property
    def millisecond(self) -> int: ...
    @property
    def microsecond(self) -> int: ...
    @property
    def nanosecond(self) -> int: ...
    @property
    def subsec_nanosecond(self) -> None: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================
    def astuple(self) -> tuple[int, int, int, int]: ...
    def asdict(self) -> TimeTypedDict: ...
    def series(self, span: TimeSpan) -> JiffSeries[Time]: ...
    def checked_add(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Time: ...
    @t.overload
    def checked_sub(self, other: Time) -> TimeSpan: ...
    @t.overload
    def checked_sub(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Time: ...
    def saturating_add(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Time: ...
    def saturating_sub(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Time: ...
    def wrapping_add(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Time: ...
    def wrapping_sub(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Time: ...
    def on(self, year: int, month: int, day: int) -> DateTime: ...
    def duration_until(self, other: Time) -> SignedDuration: ...
    def duration_since(self, other: Time) -> SignedDuration: ...
    def round(
        self,
        smallest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> Time: ...
    def to_datetime(self, d: Date) -> DateTime: ...

    # =========================================================================
    # SINCE/UNTIL
    # =========================================================================
    def _since(self, other: TimeDifference) -> TimeSpan: ...
    def _until(self, other: TimeDifference) -> TimeSpan: ...
    def since(
        self,
        other: Time | DateTime | ZonedDateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> TimeSpan: ...
    def until(
        self,
        other: Time | DateTime | ZonedDateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> TimeSpan: ...


class TimeDifference:
    def __init__(
        self,
        date: Time,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> None: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def smallest(self, unit: JIFF_UNIT) -> TimeDifference: ...
    def largest(self, unit: JIFF_UNIT) -> TimeDifference: ...
    def mode(self, mode: JIFF_ROUND_MODE) -> TimeDifference: ...
    def increment(self, increment: int) -> TimeDifference: ...


class DateTime(ToPy[pydt.datetime], ToPyDate, ToPyTime, ToPyDateTime):
    MIN: DateTime
    MAX: DateTime
    ZERO: DateTime

    def __init__(
        self,
        year: int,
        month: int,
        day: int,
        hour: int = 0,
        minute: int = 0,
        second: int = 0,
        nanosecond: int = 0,
    ) -> None: ...
    def __str__(self) -> str: ...
    def string(self) -> str: ...

    # =========================================================================
    # STRPTIME/STRFTIME/PARSE
    # =========================================================================
    def strftime(self, format: str) -> str: ...
    @classmethod
    def strptime(cls: type[DateTime], format: str, string: str) -> DateTime: ...
    @classmethod
    def parse(cls: type[DateTime], s: str) -> DateTime: ...

    # =========================================================================
    # PYTHON CONVERSIONS
    # =========================================================================
    @classmethod
    def from_pydatetime(cls: type[DateTime], dt: pydt.datetime) -> DateTime: ...
    def to_py(self) -> pydt.datetime: ...
    def to_pydate(self) -> pydt.date: ...
    def to_pydatetime(self) -> pydt.datetime: ...
    def to_pytime(self) -> pydt.time: ...
    # =========================================================================
    # CLASS METHODS
    # =========================================================================
    @classmethod
    def now(cls: type[DateTime]) -> DateTime: ...
    @classmethod
    def from_parts(cls: type[DateTime], date: Date, time: Time) -> DateTime: ...

    # =========================================================================
    # OPERATORS
    # =========================================================================
    def __repr__(self) -> str: ...
    def __add__(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> DateTime: ...
    @t.overload
    def __sub__(self, other: DateTime) -> TimeSpan: ...
    @t.overload
    def __sub__(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> DateTime: ...
    @t.overload
    def __isub__(self, other: DateTime) -> TimeSpan: ...
    @t.overload
    def __isub__(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> DateTime: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================
    def asdict(self) -> DateTimeTypedDict: ...
    def checked_add(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> DateTime: ...
    def date(self) -> Date: ...
    def day_of_year(self) -> int: ...
    def day_of_year_no_leap(self) -> int | None: ...
    def days_in_month(self) -> int: ...
    def days_in_year(self) -> int: ...
    def duration_since(self, other: DateTime) -> SignedDuration: ...
    def duration_until(self, other: DateTime) -> SignedDuration: ...
    def end_of_day(self) -> DateTime: ...
    def era_year(self) -> tuple[int, t.Literal["BCE", "CE"]]: ...
    def first_of_month(self) -> DateTime: ...
    def first_of_year(self) -> DateTime: ...
    def in_leap_year(self) -> bool: ...
    def in_tz(self, tz: str) -> ZonedDateTime: ...
    def intz(self, tz: str) -> ZonedDateTime: ...
    def iso_week_date(self) -> ISOWeekDate: ...
    def last_of_month(self) -> DateTime: ...
    def last_of_year(self) -> DateTime: ...
    def nth_weekday(self, nth: int, weekday: WEEKDAY) -> DateTime: ...
    def nth_weekday_of_month(self, nth: int, weekday: WEEKDAY) -> DateTime: ...
    def round(
        self,
        smallest: JIFF_UNIT | None = None,
        *,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> DateTime: ...
    def _round(self, options: DateTimeRound) -> DateTime: ...
    def saturating_add(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> DateTime: ...
    def series(self, span: TimeSpan) -> JiffSeries[DateTime]: ...
    def start_of_day(self) -> DateTime: ...
    def time(self) -> Time: ...
    def to_zoned(self, tz: TimeZone) -> ZonedDateTime: ...
    def tomorrow(self) -> DateTime: ...
    def yesterday(self) -> DateTime: ...
    # =========================================================================
    # INSTANCE METHODS W/ OVERLOADS
    # =========================================================================
    @t.overload
    def checked_sub(self, other: DateTime) -> TimeSpan: ...
    @t.overload
    def checked_sub(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> DateTime: ...
    @t.overload
    def saturating_sub(self, other: DateTime) -> TimeSpan: ...
    @t.overload
    def saturating_sub(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> DateTime: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def year(self) -> int: ...
    @property
    def month(self) -> int: ...
    @property
    def day(self) -> int: ...
    @property
    def hour(self) -> int: ...
    @property
    def minute(self) -> int: ...
    @property
    def second(self) -> int: ...
    @property
    def millisecond(self) -> int: ...
    @property
    def microsecond(self) -> int: ...
    @property
    def nanosecond(self) -> int: ...
    @property
    def subsec_nanosecond(self) -> int: ...
    @property
    def weekday(self) -> int: ...

    # =========================================================================
    # SINCE/UNTIL
    # =========================================================================
    def _since(self, other: DateTimeDifference) -> TimeSpan: ...
    def _until(self, other: DateTimeDifference) -> TimeSpan: ...
    def since(
        self,
        other: Date | Time | DateTime | ZonedDateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> TimeSpan: ...
    def until(
        self,
        other: Date | Time | DateTime | ZonedDateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> TimeSpan: ...


class DateTimeDifference:
    def __init__(
        self,
        date: DateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> None: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def smallest(self, unit: JIFF_UNIT) -> DateTimeDifference: ...
    def largest(self, unit: JIFF_UNIT) -> DateTimeDifference: ...
    def mode(self, mode: JIFF_ROUND_MODE) -> DateTimeDifference: ...
    def increment(self, increment: int) -> DateTimeDifference: ...


class TimeZone(ToPy[pydt.tzinfo], ToPyTzInfo):
    def __init__(self, name: str) -> None: ...
    def __eq__(self, other: object) -> bool: ...

    # =========================================================================
    # STRING
    # =========================================================================
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...

    # =========================================================================
    # PYTHON CONVERSIONS
    # =========================================================================

    def to_py(self) -> pydt.tzinfo: ...
    def to_pytzinfo(self) -> pydt.tzinfo: ...
    @classmethod
    def from_pytzinfo(cls: type[TimeZone], tz: pydt.tzinfo) -> TimeZone: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def name(self) -> str: ...

    # =========================================================================
    # CLASS METHODS
    # =========================================================================
    @classmethod
    def fixed(cls: type[TimeZone], offset: Offset) -> TimeZone: ...
    @classmethod
    def get(cls: type[TimeZone], name: str) -> TimeZone: ...
    @classmethod
    def posix(cls: type[TimeZone], name: str) -> TimeZone: ...
    @classmethod
    def system(cls: type[TimeZone]) -> TimeZone: ...
    @classmethod
    def try_system(cls: type[TimeZone]) -> TimeZone: ...
    @classmethod
    def tzif(cls: type[TimeZone], name: str, data: bytes) -> TimeZone: ...
    @classmethod
    def utc(cls: type[TimeZone]) -> TimeZone: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================
    def iana_name(self) -> str | None: ...
    def to_datetime(self, dt: Timestamp) -> DateTime: ...
    def to_offset(self, timestamp: Timestamp) -> Offset: ...
    def to_timestamp(self, dt: DateTime) -> Timestamp: ...
    def to_zoned(self, other: DateTime) -> ZonedDateTime: ...

    # =========================================================================
    # NOT IMPLEMENTED
    # =========================================================================
    def to_ambiguous_timestamp(self) -> t.NoReturn: ...
    def to_ambiguous_zoned(self) -> t.NoReturn: ...


class SignedDuration(ToPy[pydt.timedelta], ToPyTimeDelta):
    MIN: SignedDuration
    MAX: SignedDuration
    ZERO: SignedDuration

    def __init__(self, secs: int = 0, nanos: int = 0) -> None: ...

    # =========================================================================
    # OPERATORS/DUNDERS
    # =========================================================================
    def __hash__(self) -> int: ...
    def __mul__(self, other: int) -> SignedDuration: ...
    def __rmul__(self, other: int) -> SignedDuration: ...
    def __eq__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __lt__(self, other: object) -> bool: ...
    def __le__(self, other: object) -> bool: ...
    def __gt__(self, other: object) -> bool: ...
    def __ge__(self, other: object) -> bool: ...
    def __neg__(self) -> SignedDuration: ...
    def __add__(self, other: SignedDuration) -> SignedDuration: ...
    def __abs__(self) -> SignedDuration: ...
    def __div__(self, other: int) -> SignedDuration: ...
    def abs(self) -> SignedDuration: ...
    def unsigned_abs(self) -> Duration: ...
    def __richcmp__(
        self, other: SignedDuration | pydt.timedelta, op: int
    ) -> bool: ...

    # =========================================================================
    # STRING
    # =========================================================================
    def __str__(self) -> str: ...
    def string(self, human: bool = False) -> str: ...

    # =========================================================================
    # PYTHON CONVERSIONS
    # =========================================================================
    @classmethod
    def from_pytimedelta(
        cls: type[SignedDuration], td: pydt.timedelta
    ) -> SignedDuration: ...
    def to_py(self) -> pydt.timedelta: ...
    def to_pytimedelta(self) -> pydt.timedelta: ...

    # =========================================================================
    # CLASS METHODS
    # =========================================================================
    @classmethod
    def parse(cls: type[SignedDuration], s: str) -> SignedDuration: ...
    @classmethod
    def from_hours(cls: type[SignedDuration], n: int) -> SignedDuration: ...
    @classmethod
    def from_micros(cls: type[SignedDuration], n: int) -> SignedDuration: ...
    @classmethod
    def from_millis(cls: type[SignedDuration], n: int) -> SignedDuration: ...
    @classmethod
    def from_mins(cls: type[SignedDuration], n: int) -> SignedDuration: ...
    @classmethod
    def from_nanos(cls: type[SignedDuration], n: int) -> SignedDuration: ...
    @classmethod
    def from_secs(cls: type[SignedDuration], n: int) -> SignedDuration: ...
    @classmethod
    def from_secs_f32(
        cls: type[SignedDuration], n: float
    ) -> SignedDuration: ...
    @classmethod
    def from_secs_f64(
        cls: type[SignedDuration], n: float
    ) -> SignedDuration: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def is_negative(self) -> bool: ...
    @property
    def is_zero(self) -> bool: ...
    @property
    def secs(self) -> int: ...
    @property
    def nanos(self) -> int: ...
    @property
    def days(self) -> int: ...
    @property
    def seconds(self) -> int: ...
    @property
    def microseconds(self) -> int: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================
    def as_hours(self) -> int: ...
    def as_micros(self) -> int: ...
    def as_millis(self) -> int: ...
    def as_millis_f32(self) -> float: ...
    def as_millis_f64(self) -> float: ...
    def as_mins(self) -> int: ...
    def as_nanos(self) -> int: ...
    def as_secs(self) -> int: ...
    def as_secs_f32(self) -> float: ...
    def as_secs_f64(self) -> float: ...
    def checked_add(self, other: SignedDuration) -> SignedDuration | None: ...
    def checked_div(self, other: int) -> SignedDuration | None: ...
    def checked_mul(self, other: int) -> SignedDuration | None: ...
    def checked_neg(self) -> SignedDuration | None: ...
    def checked_sub(self, other: SignedDuration) -> SignedDuration | None: ...
    def div_duration_f32(self, other: SignedDuration) -> float: ...
    def div_duration_f64(self, other: SignedDuration) -> float: ...
    def div_f32(self, other: int) -> float: ...
    def div_f64(self, other: int) -> float: ...
    def is_positive(self) -> bool: ...
    def mul_f32(self, other: int) -> SignedDuration: ...
    def mul_f64(self, other: int) -> SignedDuration: ...
    def saturating_add(self, other: SignedDuration) -> SignedDuration: ...
    def saturating_mul(self, other: int) -> SignedDuration: ...
    def saturating_sub(self, other: SignedDuration) -> SignedDuration: ...
    def signum(self) -> t.Literal[-1, 0, 1]: ...
    def subsec_micros(self) -> int: ...
    def subsec_millis(self) -> int: ...
    def subsec_nanos(self) -> int: ...
    def to_timespan(self) -> TimeSpan: ...


# put in quotes to avoid ruff F821 - undefined name
_TimeSpanArithmeticSingle = TimeSpan | Duration | SignedDuration
_TimeSpanArithmeticTuple = tuple[
    _TimeSpanArithmeticSingle, ZonedDateTime | Date | DateTime
]
TimeSpanArithmetic = _TimeSpanArithmeticSingle | _TimeSpanArithmeticTuple


class TimeSpan(ToPy[pydt.timedelta], ToPyTimeDelta):
    def __init__(
        self,
        years: int = 0,
        months: int = 0,
        weeks: int = 0,
        days: int = 0,
        hours: int = 0,
        minutes: int = 0,
        seconds: int = 0,
        milliseconds: int = 0,
        microseconds: int = 0,
        nanoseconds: int = 0,
    ) -> None: ...

    # =========================================================================
    # STRING
    # =========================================================================
    def string(self, human: bool = False) -> str: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def repr_full(self) -> str: ...

    # =========================================================================
    # PYTHON CONVERSIONS
    # =========================================================================
    @classmethod
    def from_pytimedelta(cls, td: pydt.timedelta) -> TimeSpan: ...
    def to_pytimedelta(self) -> pydt.timedelta: ...
    def to_py(self) -> pydt.timedelta: ...

    # =========================================================================
    # CLASS METHODS
    # =========================================================================
    @classmethod
    def parse(cls, s: str) -> TimeSpan: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def is_positive(self) -> bool: ...
    @property
    def is_negative(self) -> bool: ...
    @property
    def is_zero(self) -> bool: ...
    @property
    def years(self) -> int: ...
    @property
    def months(self) -> int: ...
    @property
    def weeks(self) -> int: ...
    @property
    def days(self) -> int: ...
    @property
    def hours(self) -> int: ...
    @property
    def minutes(self) -> int: ...
    @property
    def seconds(self) -> int: ...
    @property
    def milliseconds(self) -> int: ...
    @property
    def microseconds(self) -> int: ...
    @property
    def nanoseconds(self) -> int: ...

    # =========================================================================
    # OPERATORS
    # =========================================================================
    def __add__(
        self,
        val: TimeSpanArithmetic,
    ) -> te.Self: ...
    def __sub__(
        self,
        val: TimeSpanArithmetic,
    ) -> te.Self: ...
    def __mul__(self, other: int) -> te.Self: ...
    def __neg__(self) -> te.Self: ...
    def __abs__(self) -> te.Self: ...
    def __invert__(self) -> te.Self: ...
    def __eq__(self, other: object) -> bool: ...
    def __ge__(self, other: TimeSpan) -> bool: ...
    def __gt__(self, other: TimeSpan) -> bool: ...
    def __le__(self, other: TimeSpan) -> bool: ...
    def __lt__(self, other: TimeSpan) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __rmul__(self, other: TimeSpan) -> bool: ...
    def __hash__(self) -> int: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================

    def abs(self) -> te.Self: ...
    def asdict(self) -> TimeSpanTypedDict: ...
    def checked_add(self, val: TimeSpanArithmetic) -> te.Self: ...
    def checked_mul(self, other: int) -> te.Self: ...
    def checked_sub(self, val: TimeSpanArithmetic) -> te.Self: ...
    def compare(
        self,
        other: TimeSpan,
        relative: ZonedDateTime | DateTime | Date | None = None,
        days_are_24_hours: bool = False,
    ) -> int: ...
    def negate(self) -> te.Self: ...
    def replace(
        self,
        years: int | None = None,
        months: int | None = None,
        weeks: int | None = None,
        days: int | None = None,
        hours: int | None = None,
        minutes: int | None = None,
        seconds: int | None = None,
        milliseconds: int | None = None,
        microseconds: int | None = None,
        nanoseconds: int | None = None,
    ) -> te.Self: ...
    def round(
        self,
        smallest: JIFF_UNIT,
        increment: int = 1,
        *,
        relative: ZonedDateTime | Date | DateTime | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
    ) -> te.Self: ...
    def signum(self) -> t.Literal[-1, 0, 1]: ...
    def to_signed_duration(
        self, relative: ZonedDateTime | Date | DateTime
    ) -> SignedDuration: ...
    def total(
        self,
        unit: JIFF_UNIT,
        relative: ZonedDateTime | Date | DateTime | None = None,
        days_are_24_hours: bool = False,
    ) -> int: ...
    def total_seconds(self) -> int: ...
    def try_years(self, years: int) -> te.Self: ...
    def try_months(self, months: int) -> te.Self: ...
    def try_weeks(self, weeks: int) -> te.Self: ...
    def try_days(self, days: int) -> te.Self: ...
    def try_hours(self, hours: int) -> te.Self: ...
    def try_minutes(self, minutes: int) -> te.Self: ...
    def try_seconds(self, seconds: int) -> te.Self: ...
    def try_milliseconds(self, milliseconds: int) -> te.Self: ...
    def try_microseconds(self, microseconds: int) -> te.Self: ...
    def try_nanoseconds(self, nanoseconds: int) -> te.Self: ...

    # -------------------------------------------------------------------------
    # PANIC-INDUCING METHODS
    # -------------------------------------------------------------------------
    def _years(self, years: int) -> te.Self: ...
    def _months(self, months: int) -> te.Self: ...
    def _weeks(self, weeks: int) -> te.Self: ...
    def _days(self, days: int) -> te.Self: ...
    def _hours(self, hours: int) -> te.Self: ...
    def _minutes(self, minutes: int) -> te.Self: ...
    def _seconds(self, seconds: int) -> te.Self: ...
    def _milliseconds(self, milliseconds: int) -> te.Self: ...
    def _microseconds(self, microseconds: int) -> te.Self: ...
    def _nanoseconds(self, nanoseconds: int) -> te.Self: ...


class Timestamp(ToPy[pydt.datetime], ToPyDate, ToPyTime, ToPyDateTime):
    """
    A representation of a timestamp with second and nanosecond precision.
    """

    MIN: Timestamp
    MAX: Timestamp
    UNIX_EPOCH: Timestamp

    def __init__(
        self, second: int | None = None, nanosecond: int | None = None
    ) -> None: ...

    # =========================================================================
    # CLASS METHODS
    # =========================================================================
    @classmethod
    def now(cls) -> Timestamp: ...
    @classmethod
    def parse(cls, s: str) -> Timestamp: ...
    @classmethod
    def from_millisecond(cls, millisecond: int) -> Timestamp: ...
    @classmethod
    def from_microsecond(cls, microsecond: int) -> Timestamp: ...
    @classmethod
    def from_nanosecond(cls, nanosecond: int) -> Timestamp: ...
    @classmethod
    def from_second(cls, second: int) -> Timestamp: ...

    # =========================================================================
    # STRING
    # =========================================================================
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...

    # =========================================================================
    # OPERATORS/DUNDERS
    # =========================================================================
    def __add__(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> te.Self: ...
    def __eq__(self, other: object) -> bool: ...
    def __ge__(self, other: Timestamp) -> bool: ...
    def __gt__(self, other: Timestamp) -> bool: ...
    def __le__(self, other: Timestamp) -> bool: ...
    def __lt__(self, other: Timestamp) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __richcmp__(self, other: Timestamp, op: int) -> bool: ...

    # =========================================================================
    # OPERATORS/DUNDERS W/ OVERLOADS
    # =========================================================================
    @t.overload
    def __isub__(self, other: Timestamp) -> TimeSpan: ...
    @t.overload
    def __isub__(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> te.Self: ...
    @t.overload
    def __sub__(self, other: Timestamp) -> TimeSpan: ...
    @t.overload
    def __sub__(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> te.Self: ...

    # =========================================================================
    # PYTHON CONVERSIONS
    # =========================================================================
    @classmethod
    def from_pydatetime(cls, dt: pydt.datetime) -> Timestamp: ...
    def to_py(self) -> pydt.datetime: ...
    def to_pydate(self) -> pydt.date: ...
    def to_pydatetime(self) -> pydt.datetime: ...
    def to_pytime(self) -> pydt.time: ...

    # =========================================================================
    # STRPTIME/STRFTIME
    # =========================================================================
    def strftime(self, format: str) -> str: ...
    @classmethod
    def strptime(cls, format: str, input: str) -> Timestamp: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================

    def as_microsecond(self) -> int: ...
    def as_millisecond(self) -> int: ...
    def as_nanosecond(self) -> int: ...
    def as_second(self) -> int: ...
    def checked_add(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Timestamp: ...
    @t.overload
    def checked_sub(self, other: Timestamp) -> TimeSpan: ...
    @t.overload
    def checked_sub(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Timestamp: ...
    def display_with_offset(self, offset: Offset) -> str: ...
    def in_tz(self, tz: str) -> ZonedDateTime: ...
    def intz(self, tz: str) -> ZonedDateTime:
        """Deprecated ~ use `in_tz`"""

    def is_zero(self) -> bool: ...
    def saturating_add(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Timestamp: ...
    def saturating_sub(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> Timestamp: ...
    def series(self, span: TimeSpan) -> JiffSeries[Timestamp]: ...
    def signum(self) -> t.Literal[-1, 0, 1]: ...
    def string(self) -> str: ...
    def subsec_microsecond(self) -> int: ...
    def subsec_millisecond(self) -> int: ...
    def subsec_nanosecond(self) -> int: ...
    def to_zoned(self, time_zone: TimeZone) -> ZonedDateTime: ...

    # =========================================================================
    # SINCE/UNTIL
    # =========================================================================
    def _since(self, other: TimestampDifference) -> TimeSpan: ...
    def _until(self, other: TimestampDifference) -> TimeSpan: ...
    def since(
        self,
        other: Timestamp | ZonedDateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> TimeSpan: ...
    def until(
        self,
        other: Timestamp | ZonedDateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> TimeSpan: ...
    def duration_since(self, other: Timestamp) -> SignedDuration: ...
    def duration_until(self, other: Timestamp) -> SignedDuration: ...
    def round(
        self,
        unit: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> Timestamp: ...
    def _round(self, options: TimestampRound) -> Timestamp: ...


class TimestampDifference:
    def __init__(
        self,
        date: Timestamp,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> None: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def smallest(self, unit: JIFF_UNIT) -> TimestampDifference: ...
    def largest(self, unit: JIFF_UNIT) -> TimestampDifference: ...
    def mode(self, mode: JIFF_ROUND_MODE) -> TimestampDifference: ...
    def increment(self, increment: int) -> TimestampDifference: ...


class ZonedDateTime(
    ToPy[pydt.datetime], ToPyDate, ToPyTime, ToPyDateTime, ToPyTzInfo
):
    def __init__(self, timestamp: Timestamp, time_zone: TimeZone) -> None: ...

    # =========================================================================
    # PYTHON CONVERSIONS
    # =========================================================================
    @classmethod
    def from_pydatetime(
        cls: type[ZonedDateTime], dt: pydt.datetime
    ) -> ZonedDateTime: ...
    def to_py(self) -> pydt.datetime: ...
    def to_pydate(self) -> pydt.date: ...
    def to_pydatetime(self) -> pydt.datetime: ...
    def to_pytime(self) -> pydt.time: ...
    def to_pytzinfo(self) -> pydt.tzinfo: ...
    # =========================================================================
    # CLASS METHODS
    # =========================================================================
    @classmethod
    def now(
        cls: type[ZonedDateTime], tz: str | None = None
    ) -> ZonedDateTime: ...
    @classmethod
    def utcnow(cls: type[ZonedDateTime]) -> ZonedDateTime: ...
    @classmethod
    def parse(cls: type[ZonedDateTime], s: str) -> ZonedDateTime: ...
    @classmethod
    def from_rfc2822(cls: type[ZonedDateTime], s: str) -> ZonedDateTime: ...

    # =========================================================================
    # STRPTIME/STRFTIME
    # =========================================================================
    @classmethod
    def strptime(
        cls: type[ZonedDateTime], format: str, input: str
    ) -> ZonedDateTime: ...
    def strftime(self, format: str) -> str: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def year(self) -> int: ...
    @property
    def month(self) -> int: ...
    @property
    def day(self) -> int: ...
    @property
    def hour(self) -> int: ...
    @property
    def minute(self) -> int: ...
    @property
    def second(self) -> int: ...
    @property
    def millisecond(self) -> int: ...
    @property
    def microsecond(self) -> int: ...
    @property
    def nanosecond(self) -> int: ...
    @property
    def subsec_nanosecond(self) -> int: ...
    @property
    def weekday(self) -> int: ...

    # =========================================================================
    # STRING
    # =========================================================================
    def __str__(self) -> str: ...
    def string(self) -> str: ...

    # =========================================================================
    # OPERATORS/DUNDERS
    # =========================================================================
    def __add__(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> te.Self: ...
    def __eq__(self, other: object) -> bool: ...
    def __ge__(self, other: ZonedDateTime) -> bool: ...
    def __gt__(self, other: ZonedDateTime) -> bool: ...
    def __hash__(self) -> int: ...
    def __le__(self, other: ZonedDateTime) -> bool: ...
    def __lt__(self, other: ZonedDateTime) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __richcmp__(self, other: ZonedDateTime, op: int) -> bool: ...

    # =========================================================================
    # OPERATORS/DUNDERS W/ OVERLOADS
    # =========================================================================
    @t.overload
    def __isub__(self, other: ZonedDateTime) -> TimeSpan: ...
    @t.overload
    def __isub__(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> te.Self: ...
    @t.overload
    def __sub__(self, other: ZonedDateTime) -> TimeSpan: ...
    @t.overload
    def __sub__(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> te.Self: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================
    def astimezone(self, tz: str) -> ZonedDateTime: ...
    def checked_add(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> te.Self: ...
    @t.overload
    def checked_sub(self, other: ZonedDateTime) -> TimeSpan: ...
    @t.overload
    def checked_sub(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> te.Self: ...
    def date(self) -> Date: ...
    def datetime(self) -> DateTime: ...
    def iso_week_date(self) -> ISOWeekDate: ...
    def day_of_year(self) -> int: ...
    def day_of_year_no_leap(self) -> int | None: ...
    def days_in_month(self) -> int: ...
    def days_in_year(self) -> int: ...
    def duration_since(self, other: ZonedDateTime) -> SignedDuration: ...
    def duration_until(self, other: ZonedDateTime) -> SignedDuration: ...
    def end_of_day(self) -> ZonedDateTime: ...
    def era_year(self) -> tuple[int, t.Literal["CE", "BCE"]]: ...
    def first_of_month(self) -> ZonedDateTime: ...
    def first_of_year(self) -> ZonedDateTime: ...
    def in_leap_year(self) -> bool: ...
    def in_tz(self, tz: str) -> te.Self: ...
    def intz(self, tz: str) -> te.Self: ...
    def inutc(self) -> ZonedDateTime: ...
    def last_of_month(self) -> ZonedDateTime: ...
    def last_of_year(self) -> ZonedDateTime: ...
    def nth_weekday(self, nth: int, weekday: WEEKDAY) -> Date: ...
    def nth_weekday_of_month(self, nth: int, weekday: WEEKDAY) -> Date: ...
    def offset(self) -> Offset: ...
    def round(
        self,
        smallest: JIFF_UNIT | None = None,
        *,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> DateTime: ...
    def _round(self, options: ZonedDateTimeRound) -> DateTime: ...
    def saturating_add(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> te.Self: ...
    @t.overload
    def saturating_sub(self, other: ZonedDateTime) -> TimeSpan: ...
    @t.overload
    def saturating_sub(
        self, other: TimeSpan | SignedDuration | Duration
    ) -> te.Self: ...
    def start_of_day(self) -> ZonedDateTime: ...
    def time(self) -> Time: ...
    def time_zone(self) -> TimeZone: ...
    def timestamp(self) -> Timestamp: ...
    def timezone(self) -> TimeZone: ...
    def to_rfc2822(self) -> str: ...
    def tomorrow(self) -> ZonedDateTime: ...
    def with_time_zone(self, tz: TimeZone) -> ZonedDateTime: ...
    def yesterday(self) -> ZonedDateTime: ...

    # =========================================================================
    # SINCE/UNTIL
    # =========================================================================
    def since(
        self,
        other: ZonedDateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> TimeSpan: ...
    def until(
        self,
        other: ZonedDateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> TimeSpan: ...


class ZonedDateTimeDifference:
    def __init__(
        self,
        date: ZonedDateTime,
        *,
        smallest: JIFF_UNIT | None = None,
        largest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int | None = None,
    ) -> None: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def smallest(self, unit: JIFF_UNIT) -> ZonedDateTimeDifference: ...
    def largest(self, unit: JIFF_UNIT) -> ZonedDateTimeDifference: ...
    def mode(self, mode: JIFF_ROUND_MODE) -> ZonedDateTimeDifference: ...
    def increment(self, increment: int) -> ZonedDateTimeDifference: ...


class ISOWeekDate:
    MIN: ISOWeekDate
    MAX: ISOWeekDate
    ZERO: ISOWeekDate

    def __init__(self, year: int, week: int, weekday: WEEKDAY) -> None: ...

    # =========================================================================
    # OPERATORS/DUNDERS
    # =========================================================================

    def __eq__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __lt__(self, other: ISOWeekDate) -> bool: ...
    def __le__(self, other: ISOWeekDate) -> bool: ...
    def __gt__(self, other: ISOWeekDate) -> bool: ...
    def __ge__(self, other: ISOWeekDate) -> bool: ...
    def __hash__(self) -> int: ...

    # =========================================================================
    # STRING
    # =========================================================================
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...

    # =========================================================================
    # CLASS METHODS
    # =========================================================================
    @classmethod
    def from_date(cls: type[ISOWeekDate], date: Date) -> ISOWeekDate: ...
    @classmethod
    def today(cls: type[ISOWeekDate]) -> ISOWeekDate: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def year(self) -> int: ...
    @property
    def week(self) -> int: ...
    @property
    def weekday(self) -> WEEKDAY_INT: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================
    def date(self) -> Date: ...


class TimestampRound:
    def __init__(
        self,
        smallest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int = 1,
    ) -> None: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def __eq__(self, other: object) -> bool: ...
    def mode(self, mode: JIFF_ROUND_MODE) -> TimestampRound: ...
    def smallest(self, smallest: JIFF_UNIT) -> TimestampRound: ...
    def increment(self, increment: int) -> TimestampRound: ...
    def _smallest(self) -> JIFF_UNIT: ...
    def _mode(self) -> JIFF_ROUND_MODE: ...
    def _increment(self) -> int: ...
    def replace(
        self,
        smallest: JIFF_UNIT | None,
        mode: JIFF_ROUND_MODE | None,
        increment: int | None,
    ) -> TimestampRound: ...


class DateTimeRound:
    def __init__(
        self,
        smallest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int = 1,
    ) -> None: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def __eq__(self, other: object) -> bool: ...
    def mode(self, mode: JIFF_ROUND_MODE) -> DateTimeRound: ...
    def smallest(self, smallest: JIFF_UNIT) -> DateTimeRound: ...
    def increment(self, increment: int) -> DateTimeRound: ...
    def _smallest(self) -> JIFF_UNIT: ...
    def _mode(self) -> JIFF_ROUND_MODE: ...
    def _increment(self) -> int: ...
    def replace(
        self,
        smallest: JIFF_UNIT | None,
        mode: JIFF_ROUND_MODE | None,
        increment: int | None,
    ) -> DateTimeRound: ...


class ZonedDateTimeRound:
    def __init__(
        self,
        smallest: JIFF_UNIT | None = None,
        mode: JIFF_ROUND_MODE | None = None,
        increment: int = 1,
    ) -> None: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def __eq__(self, other: object) -> bool: ...
    def mode(self, mode: JIFF_ROUND_MODE) -> DateTimeRound: ...
    def smallest(self, smallest: JIFF_UNIT) -> DateTimeRound: ...
    def increment(self, increment: int) -> DateTimeRound: ...
    def _smallest(self) -> JIFF_UNIT: ...
    def _mode(self) -> JIFF_ROUND_MODE: ...
    def _increment(self) -> int: ...
    def replace(
        self,
        smallest: JIFF_UNIT | None,
        mode: JIFF_ROUND_MODE | None,
        increment: int | None,
    ) -> DateTimeRound: ...


class Offset(ToPy[pydt.tzinfo], ToPyTzInfo):
    MIN: Offset
    MAX: Offset
    UTC: Offset
    ZERO: Offset

    def __init__(
        self, hours: int | None = None, seconds: int | None = None
    ) -> None: ...

    # =========================================================================
    # STRING
    # =========================================================================
    def string(self) -> str: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...

    # =========================================================================
    # OPERATORS/DUNDERS
    # =========================================================================
    def __neg__(self) -> Offset: ...
    def __eq__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __lt__(self, other: Offset) -> bool: ...
    def __le__(self, other: Offset) -> bool: ...
    def __gt__(self, other: Offset) -> bool: ...
    def __ge__(self, other: Offset) -> bool: ...
    def __hash__(self) -> int: ...

    # =========================================================================
    # PYTHON CONVERSIONS
    # =========================================================================
    # __FROM__
    @classmethod
    def from_pytzinfo(cls: type[Offset], tz: pydt.tzinfo) -> Offset: ...
    # __TO__
    def to_py(self) -> pydt.tzinfo: ...
    def to_pytzinfo(self) -> pydt.tzinfo: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def seconds(self) -> int: ...
    @property
    def is_negative(self) -> bool: ...
    @property
    def is_positive(self) -> bool: ...

    # =========================================================================
    # FROM
    # =========================================================================
    @classmethod
    def utc(cls: type[Offset]) -> Offset: ...
    @classmethod
    def from_hours(cls: type[Offset], hours: int) -> Offset: ...
    @classmethod
    def from_seconds(cls: type[Offset], seconds: int) -> Offset: ...

    # =========================================================================
    # TO
    # =========================================================================
    def to_datetime(self, timestamp: Timestamp) -> DateTime: ...
    def to_timestamp(self, datetime: DateTime) -> Timestamp: ...
    def to_timezone(self) -> TimeZone: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================
    def checked_add(
        self, other: Duration | SignedDuration | TimeSpan
    ) -> Offset: ...
    def checked_sub(
        self, other: Duration | SignedDuration | TimeSpan
    ) -> Offset: ...
    def duration_since(self, other: Offset) -> SignedDuration: ...
    def duration_until(self, other: Offset) -> SignedDuration: ...
    def negate(self) -> Offset: ...
    def saturating_add(
        self, other: Duration | SignedDuration | TimeSpan
    ) -> Offset: ...
    def saturating_sub(
        self, other: Duration | SignedDuration | TimeSpan
    ) -> Offset: ...
    def since(self, other: Offset) -> TimeSpan: ...
    def until(self, other: Offset) -> TimeSpan: ...


class JiffSeries(
    t.Generic[T],
):
    def __iter__(self) -> t.Iterator[T]: ...
    def __next__(self) -> T: ...
    def take(self, n: int) -> list[T]: ...


def date(year: int, month: int, day: int) -> Date: ...
def time(
    hour: int = 0, minute: int = 0, second: int = 0, nanosecond: int = 0
) -> Time: ...
def datetime(
    year: int,
    month: int,
    day: int,
    hour: int = 0,
    minute: int = 0,
    second: int = 0,
    nanosecond: int = 0,
) -> DateTime: ...
def timespan(
    *,
    years: int = 0,
    months: int = 0,
    weeks: int = 0,
    days: int = 0,
    hours: int = 0,
    minutes: int = 0,
    seconds: int = 0,
    milliseconds: int = 0,
    microseconds: int = 0,
    nanoseconds: int = 0,
    unchecked: bool = False,
) -> TimeSpan: ...
def offset(hours: int) -> Offset: ...


# =============================================================================
# TIMEZONE-DATABASE
# =============================================================================
class TimeZoneDatabase:
    def __init__(self) -> None:
        """Defaults to using the `self.from_env`"""

    @t.overload
    def get(self, name: str, err: t.Literal[False]) -> TimeZone | None:
        """Returns TimeZone or None if the timezone is not found"""

    @t.overload
    def get(self, name: str, err: t.Literal[True] = True) -> TimeZone:
        """Returns TimeZone, if not found raises a ValueError"""

    def available(self) -> list[str]: ...
    def __getitem__(self, name: str) -> TimeZone: ...
    def __len__(self) -> int: ...
    def is_definitively_empty(self) -> bool: ...
    @classmethod
    def from_env(cls) -> TimeZoneDatabase: ...
    @classmethod
    def from_dir(cls, path: str) -> TimeZoneDatabase: ...
    @classmethod
    def from_concatenated_path(cls, path: str) -> TimeZoneDatabase: ...

ry.ryo3._jiter

from __future__ import annotations

import typing as t

import typing_extensions as te

from ry._types import Buffer

# =============================================================================
# JSON
# =============================================================================
JsonPrimitive = None | bool | int | float | str
JsonValue = (
    JsonPrimitive
    | dict[str, JsonPrimitive | JsonValue]
    | list[JsonPrimitive | JsonValue]
)


class JsonParseKwargs(t.TypedDict, total=False):
    allow_inf_nan: bool
    """Allow parsing of `Infinity`, `-Infinity`, `NaN` ~ default: True"""
    cache_mode: t.Literal[True, False, "all", "keys", "none"]
    """Cache mode for JSON parsing ~ default: `all` """
    partial_mode: t.Literal[True, False, "off", "on", "trailing-strings"]
    """Partial mode for JSON parsing ~ default: False"""
    catch_duplicate_keys: bool
    """Catch duplicate keys in JSON objects ~ default: False"""
    float_mode: t.Literal["float", "decimal", "lossless-float"] | bool
    """Mode for parsing JSON floats ~ default: False"""


def parse_json(
    data: Buffer | bytes | str,
    /,
    **kwargs: te.Unpack[JsonParseKwargs],
) -> JsonValue: ...
def parse_json_bytes(
    data: bytes,
    /,
    **kwargs: te.Unpack[JsonParseKwargs],
) -> JsonValue: ...
def json_cache_clear() -> None: ...
def json_cache_usage() -> int: ...

ry.ryo3._quick_maths

"""ryo3-quick-maths types"""

from __future__ import annotations

import typing as t


def quick_maths() -> t.Literal[3]:
    """Performs quick-maths

    Implements the algorithm for performing "quick-maths" as described by
    Big Shaq in his PHD thesis, 2017, in which he states:

    > "2 plus 2 is 4, minus one that's 3, quick maths." (Big Shaq et al., 2017)

    Reference:
        https://youtu.be/3M_5oYU-IsU?t=60

    Example:
        >>> import ry
        >>> result = ry.quick_maths()
        >>> assert result == 3

    NOTE: THIS IS FROM MY TEMPLATE RY03-MODULE
    """

ry.ryo3._regex

"""ryo3-regex types"""

from __future__ import annotations

# =============================================================================
# Regex
# =============================================================================


class Regex:
    def __init__(
        self,
        pattern: str,
        *,
        case_insensitive: bool = False,
        crlf: bool = False,
        dot_matches_new_line: bool = False,
        ignore_whitespace: bool = False,
        line_terminator: str | None = None,
        multi_line: bool = False,
        octal: bool = False,
        size_limit: int | None = None,
        swap_greed: bool = False,
        unicode: bool = False,
    ) -> None: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def is_match(self, string: str) -> bool: ...

ry.ryo3._reqwest

import typing as t
from http import HTTPStatus

import ry

if t.TYPE_CHECKING:
    from ry.http import Headers
    from ry.ryo3 import URL, Duration


class HttpClient:
    def __init__(
        self,
        *,
        headers: dict[str, str] | None = None,
        user_agent: str | None = None,  # default ~ 'ry-reqwest/<VERSION> ...'
        timeout: Duration | None = None,
        connect_timeout: Duration | None = None,
        read_timeout: Duration | None = None,
        gzip: bool = True,
        brotli: bool = True,
        deflate: bool = True,
    ) -> None: ...
    async def get(
        self, url: str | URL, *, headers: dict[str, str] | None = None
    ) -> Response: ...
    async def post(
        self,
        url: str | URL,
        *,
        body: bytes | None = None,
        headers: dict[str, str] | None = None,
    ) -> Response: ...
    async def put(
        self,
        url: str | URL,
        *,
        body: bytes | None = None,
        headers: dict[str, str] | None = None,
    ) -> Response: ...
    async def delete(
        self, url: str | URL, *, headers: dict[str, str] | None = None
    ) -> Response: ...
    async def patch(
        self,
        url: str | URL,
        *,
        body: bytes | None = None,
        headers: dict[str, str] | None = None,
    ) -> Response: ...
    async def head(
        self, url: str | URL, *, headers: dict[str, str] | None = None
    ) -> Response: ...
    async def fetch(
        self,
        url: str | URL,
        *,
        method: str = "GET",
        body: bytes | None = None,
        headers: dict[str, str] | None = None,
    ) -> Response: ...


class ReqwestError(Exception):
    def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def __dbg__(self) -> str: ...
    def is_body(self) -> bool: ...
    def is_builder(self) -> bool: ...
    def is_connect(self) -> bool: ...
    def is_decode(self) -> bool: ...
    def is_redirect(self) -> bool: ...
    def is_request(self) -> bool: ...
    def is_status(self) -> bool: ...
    def is_timeout(self) -> bool: ...
    def status(self) -> HTTPStatus | None: ...
    def url(self) -> URL | None: ...


class Response:
    status_code: int

    @property
    def headers(self) -> Headers: ...
    async def text(self) -> str: ...
    async def json(self) -> t.Any: ...
    async def bytes(self) -> ry.Bytes: ...
    def bytes_stream(self) -> ResponseStream: ...


class ResponseStream:
    def __aiter__(self) -> ResponseStream: ...
    async def __anext__(self) -> ry.Bytes: ...


async def fetch(
    url: str | URL,
    *,
    client: HttpClient | None = None,
    method: str = "GET",
    body: bytes | None = None,
    headers: dict[str, str] | None = None,
) -> Response: ...

ry.ryo3._same_file

"""ryo3-same-file types"""

from __future__ import annotations

from os import PathLike


def is_same_file(a: PathLike[str], b: PathLike[str]) -> bool: ...

ry.ryo3._shlex

"""ryo3-shlex types"""

from __future__ import annotations


def shplit(s: str) -> list[str]:
    """shlex::split wrapper much like python's stdlib shlex.split but faster"""
    ...

ry.ryo3._size

from __future__ import annotations

from typing import Literal

FORMAT_SIZE_BASE = Literal[2, 10]  # default=2
FORMAT_SIZE_STYLE = Literal[  # default="default"
    "default",
    "abbreviated",
    "abbreviated_lowercase",
    "abbreviated-lowercase",
    "full",
    "full-lowercase",
    "full_lowercase",
]


def fmt_size(
    n: int,
    *,
    base: FORMAT_SIZE_BASE | None = 2,
    style: FORMAT_SIZE_STYLE | None = "default",
) -> str:
    """Return human-readable string representation of bytes-size."""


def parse_size(s: str) -> int:
    """Return integer representation of human-readable bytes-size string.

    Raises:
        ValueError: If string is not a valid human-readable bytes-size string.
    """


class SizeFormatter:
    """Human-readable bytes-size formatter."""

    def __init__(
        self,
        base: FORMAT_SIZE_BASE | None = 2,
        style: FORMAT_SIZE_STYLE | None = "default",
    ) -> None:
        """Initialize human-readable bytes-size formatter."""

    def format(self, n: int) -> str:
        """Return human-readable string representation of bytes-size."""

    def __call__(self, n: int) -> str:
        """Return human-readable string representation of bytes-size."""

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


class Size:
    """Bytes-size object."""

    def __init__(self, size: int) -> None: ...
    def __int__(self) -> int: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def __hash__(self) -> int: ...
    def __abs__(self) -> Size: ...
    def __neg__(self) -> Size: ...
    def __eq__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __lt__(self, other: Size | int | float) -> bool: ...
    def __le__(self, other: Size | int | float) -> bool: ...
    def __gt__(self, other: Size | int | float) -> bool: ...
    def __ge__(self, other: Size | int | float) -> bool: ...
    def __bool__(self) -> bool: ...
    def __pos__(self) -> Size: ...
    def __invert__(self) -> Size: ...
    def __add__(self, other: Size | int | float) -> Size: ...
    def __sub__(self, other: Size | int | float) -> Size: ...
    def __mul__(self, other: Size | int | float) -> Size: ...
    def __rmul__(self, other: Size | int | float) -> Size: ...
    @property
    def bytes(self) -> int: ...
    def format(
        self,
        base: FORMAT_SIZE_BASE | None = 2,
        style: FORMAT_SIZE_STYLE | None = "default",
    ) -> str: ...

    # =========================================================================
    # CLASS-METHODS
    # =========================================================================

    # -------------------------------------------------------------------------
    # PARSING
    # -------------------------------------------------------------------------
    @classmethod
    def parse(cls: type[Size], size: str) -> Size: ...
    @classmethod
    def from_str(cls: type[Size], size: str) -> Size: ...

    # -------------------------------------------------------------------------
    # BYTES
    # -------------------------------------------------------------------------
    @classmethod
    def from_bytes(cls: type[Size], size: int | float) -> Size: ...

    # -------------------------------------------------------------------------
    # KILOBYTES
    # -------------------------------------------------------------------------
    @classmethod
    def from_kb(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_kib(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_kibibytes(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_kilobytes(cls: type[Size], size: int | float) -> Size: ...

    # -------------------------------------------------------------------------
    # MEGABYTES
    # -------------------------------------------------------------------------

    @classmethod
    def from_mb(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_mebibytes(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_megabytes(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_mib(cls: type[Size], size: int | float) -> Size: ...

    # -------------------------------------------------------------------------
    # GIGABYTES
    # -------------------------------------------------------------------------
    @classmethod
    def from_gb(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_gib(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_gibibytes(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_gigabytes(cls: type[Size], size: int | float) -> Size: ...

    # -------------------------------------------------------------------------
    # TERABYTES
    # -------------------------------------------------------------------------
    @classmethod
    def from_tb(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_tebibytes(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_terabytes(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_tib(cls: type[Size], size: int | float) -> Size: ...

    # -------------------------------------------------------------------------
    # PETABYTES
    # -------------------------------------------------------------------------
    @classmethod
    def from_pb(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_pebibytes(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_petabytes(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_pib(cls: type[Size], size: int | float) -> Size: ...

    # -------------------------------------------------------------------------
    # EXABYTES
    # -------------------------------------------------------------------------
    @classmethod
    def from_eb(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_eib(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_exabytes(cls: type[Size], size: int | float) -> Size: ...
    @classmethod
    def from_exbibytes(cls: type[Size], size: int | float) -> Size: ...

ry.ryo3._sqlformat

from __future__ import annotations

import typing as t

# =============================================================================
# SQLFORMAT
# =============================================================================
SqlfmtParamValue = str | int | float | bool
TSqlfmtParamValue_co = t.TypeVar(
    "TSqlfmtParamValue_co", bound=SqlfmtParamValue, covariant=True
)
SqlfmtParamsLike = (
    dict[str, TSqlfmtParamValue_co]
    | t.Sequence[tuple[str, TSqlfmtParamValue_co]]
    | t.Sequence[TSqlfmtParamValue_co]
)


class SqlfmtQueryParams:
    def __init__(
        self, params: SqlfmtParamsLike[TSqlfmtParamValue_co]
    ) -> None: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...


def sqlfmt_params(
    params: SqlfmtParamsLike[TSqlfmtParamValue_co] | SqlfmtQueryParams,
) -> SqlfmtQueryParams: ...
def sqlfmt(
    sql: str,
    params: SqlfmtParamsLike[TSqlfmtParamValue_co]
    | SqlfmtQueryParams
    | None = None,
    *,
    indent: int = 2,  # -1 or any negative value will use tabs
    uppercase: bool | None = True,
    lines_between_statements: int = 1,
) -> str: ...

ry.ryo3._std

"""ryo3-std types"""

from __future__ import annotations

import datetime as pydt
import typing as t

from ry import Bytes, FsPath
from ry._types import Buffer, FsPathLike


# =============================================================================
# STD::TIME
# =============================================================================
class Duration:
    ZERO: Duration
    MIN: Duration
    MAX: Duration
    NANOSECOND: Duration
    MICROSECOND: Duration
    MILLISECOND: Duration
    SECOND: Duration

    def __init__(self, secs: int = 0, nanos: int = 0) -> None: ...
    def __eq__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __lt__(self, other: Duration) -> bool: ...
    def __le__(self, other: Duration) -> bool: ...
    def __gt__(self, other: Duration) -> bool: ...
    def __ge__(self, other: Duration) -> bool: ...
    def __hash__(self) -> int: ...
    def __richcmp__(
        self, other: Duration | pydt.timedelta, op: int
    ) -> bool: ...
    def __str__(self) -> str: ...
    def abs_diff(self, other: Duration) -> Duration: ...
    def sleep(self) -> None: ...

    # =========================================================================
    # PYTHON_CONVERSIONS
    # =========================================================================
    @classmethod
    def from_pytimedelta(
        cls: type[Duration], td: pydt.timedelta
    ) -> Duration: ...
    def to_pytimedelta(self) -> pydt.timedelta: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def is_zero(self) -> bool: ...
    @property
    def nanos(self) -> int: ...
    @property
    def secs(self) -> int: ...
    @property
    def days(self) -> int: ...
    @property
    def seconds(self) -> int: ...
    @property
    def microseconds(self) -> int: ...
    @property
    def subsec_micros(self) -> int: ...
    @property
    def subsec_millis(self) -> int: ...
    @property
    def subsec_nanos(self) -> int: ...

    # =========================================================================
    # CLASSMETHODS
    # =========================================================================
    @classmethod
    def from_hours(cls, hours: int) -> Duration: ...
    @classmethod
    def from_micros(cls, micros: int) -> Duration: ...
    @classmethod
    def from_millis(cls, millis: int) -> Duration: ...
    @classmethod
    def from_mins(cls, mins: int) -> Duration: ...
    @classmethod
    def from_nanos(cls, nanos: int) -> Duration: ...
    @classmethod
    def from_secs(cls, secs: int) -> Duration: ...
    @classmethod
    def from_secs_f32(cls, secs: float) -> Duration: ...
    @classmethod
    def from_secs_f64(cls, secs: float) -> Duration: ...
    @classmethod
    def from_days(cls, days: int) -> Duration: ...
    @classmethod
    def from_weeks(cls, weeks: int) -> Duration: ...
    def as_micros(self) -> int: ...
    def as_millis(self) -> int: ...
    def as_nanos(self) -> int: ...
    def as_secs(self) -> int: ...
    def as_secs_f32(self) -> float: ...
    def as_secs_f64(self) -> float: ...

    # =========================================================================
    # NOT IMPLEMENTED
    # =========================================================================
    def checked_add(self, other: Duration) -> Duration | None: ...
    def checked_div(self, other: Duration) -> Duration | None: ...
    def checked_mul(self, other: Duration) -> Duration | None: ...
    def checked_sub(self, other: Duration) -> Duration | None: ...
    def div_duration_f32(self, other: Duration) -> float: ...
    def div_duration_f64(self, other: Duration) -> float: ...
    def div_f32(self, other: float) -> Duration: ...
    def div_f64(self, other: float) -> Duration: ...
    def mul_f32(self, other: float) -> Duration: ...
    def mul_f64(self, other: float) -> Duration: ...
    def saturating_add(self, other: Duration) -> Duration: ...
    def saturating_mul(self, other: Duration) -> Duration: ...
    def saturating_sub(self, other: Duration) -> Duration: ...


class Instant:
    def __init__(self) -> None: ...
    @classmethod
    def now(cls) -> Instant: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def __eq__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __lt__(self, other: Instant) -> bool: ...
    def __le__(self, other: Instant) -> bool: ...
    def __gt__(self, other: Instant) -> bool: ...
    def __ge__(self, other: Instant) -> bool: ...
    def __hash__(self) -> int: ...
    def __add__(self, other: Duration) -> Instant: ...
    @t.overload
    def __sub__(self, other: Duration) -> Instant: ...
    @t.overload
    def __sub__(self, other: Instant) -> Duration: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================
    def checked_add(self, other: Duration) -> Instant | None: ...
    def checked_duration_since(self, earlier: Instant) -> Duration | None: ...
    def checked_sub(self, other: Duration) -> Instant | None: ...
    def duration_since(self, earlier: Instant) -> Duration: ...
    def elapsed(self) -> Duration: ...
    def saturating_duration_since(self, earlier: Instant) -> Duration: ...


def instant() -> Instant: ...
def sleep(seconds: float) -> float: ...


# =============================================================================
# STD::FS
# =============================================================================
class FileType:
    def __repr__(self) -> str: ...
    @property
    def is_dir(self) -> bool: ...
    @property
    def is_file(self) -> bool: ...
    @property
    def is_symlink(self) -> bool: ...


class Metadata:
    def __repr__(self) -> str: ...
    @property
    def file_type(self) -> FileType: ...
    @property
    def len(self) -> int: ...
    @property
    def is_empty(self) -> bool: ...
    @property
    def modified(self) -> pydt.datetime: ...
    @property
    def accessed(self) -> pydt.datetime: ...
    @property
    def created(self) -> pydt.datetime: ...
    @property
    def is_dir(self) -> bool: ...
    @property
    def is_file(self) -> bool: ...
    @property
    def is_symlink(self) -> bool: ...


# =============================================================================
# STD::FS ~ functions
# =============================================================================
def read(path: FsPathLike) -> Bytes: ...
def read_bytes(path: FsPathLike) -> bytes: ...
def read_text(path: FsPathLike) -> str: ...
def read_stream(
    path: FsPathLike,
    chunk_size: int = 65536,
    *,
    offset: int = 0,
) -> t.Iterator[Bytes]: ...
def write(path: FsPathLike, data: Buffer | str) -> int: ...
def write_bytes(path: FsPathLike, data: bytes) -> int: ...
def write_text(path: FsPathLike, data: str) -> int: ...
def canonicalize(path: FsPathLike) -> FsPath: ...
def copy(from_path: FsPathLike, to_path: FsPathLike) -> int: ...
def create_dir(path: FsPathLike) -> None: ...
def create_dir_all(path: FsPathLike) -> None: ...
def exists(path: FsPathLike) -> bool: ...
def is_dir(path: FsPathLike) -> bool: ...
def is_file(path: FsPathLike) -> bool: ...
def is_symlink(path: FsPathLike) -> bool: ...
def metadata(path: FsPathLike) -> Metadata: ...
def remove_dir(path: FsPathLike) -> None: ...
def remove_dir_all(path: FsPathLike) -> None: ...
def remove_file(path: FsPathLike) -> None: ...
def rename(from_path: FsPathLike, to_path: FsPathLike) -> None: ...

ry.ryo3._tokio

"""ryo3-tokio types"""

from __future__ import annotations

from typing import NoReturn

from ry import Bytes
from ry._types import Buffer, FsPathLike


# =============================================================================
# FS
# =============================================================================
async def copy_async(src: FsPathLike, dst: FsPathLike) -> None: ...
async def create_dir_async(path: FsPathLike) -> None: ...
async def metadata_async(path: FsPathLike) -> None: ...
async def read_async(path: FsPathLike) -> Bytes: ...
async def read_dir_async(path: FsPathLike) -> NoReturn: ...
async def remove_dir_async(path: FsPathLike) -> None: ...
async def remove_file_async(path: FsPathLike) -> None: ...
async def rename_async(src: FsPathLike, dst: FsPathLike) -> None: ...
async def write_async(path: FsPathLike, data: Buffer) -> None: ...


# =============================================================================
# SLEEP
# =============================================================================
async def sleep_async(seconds: float) -> float: ...
async def asleep(seconds: float) -> float:
    """Alias for sleep_async"""
    ...

ry.ryo3._unindent

"""ryo3-unindent types"""

from __future__ import annotations


def unindent(string: str) -> str: ...
def unindent_bytes(string: bytes) -> bytes: ...

ry.ryo3._url

from __future__ import annotations

from ipaddress import IPv4Address


class URL:
    def __init__(
        self, url: str | URL, *, params: dict[str, str] | None = None
    ) -> None: ...

    # =========================================================================
    # CLASSMETHODS
    # =========================================================================
    @classmethod
    def parse(cls, url: str) -> URL: ...
    @classmethod
    def parse_with_params(cls, url: str, params: dict[str, str]) -> URL: ...
    @classmethod
    def from_directory_path(cls, path: str) -> URL: ...

    # =========================================================================
    # STRING
    # =========================================================================
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def __fspath__(self) -> str: ...

    # =========================================================================
    # OPERATORS/DUNDER
    # =========================================================================
    def __eq__(self, other: object) -> bool: ...
    def __ge__(self, other: URL) -> bool: ...
    def __gt__(self, other: URL) -> bool: ...
    def __hash__(self) -> int: ...
    def __le__(self, other: URL) -> bool: ...
    def __lt__(self, other: URL) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __rtruediv__(self, relative: str) -> URL: ...
    def __truediv__(self, relative: str) -> URL: ...

    # =========================================================================
    # PROPERTIES
    # =========================================================================
    @property
    def authority(self) -> str: ...
    @property
    def fragment(self) -> str | None: ...
    @property
    def host(self) -> str | None: ...
    @property
    def host_str(self) -> str | None: ...
    @property
    def netloc(self) -> str: ...
    @property
    def password(self) -> str | None: ...
    @property
    def path(self) -> str: ...
    @property
    def path_segments(self) -> tuple[str, ...]: ...
    @property
    def port(self) -> int | None: ...
    @property
    def port_or_known_default(self) -> int | None: ...
    @property
    def query(self) -> str | None: ...
    @property
    def query_pairs(self) -> list[tuple[str, str]]: ...
    @property
    def scheme(self) -> str: ...
    @property
    def username(self) -> str: ...
    @property
    def origin(self) -> str: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================
    def has_authority(self) -> bool: ...
    def has_host(self) -> bool: ...
    def is_special(self) -> bool: ...
    def join(self, *parts: str) -> URL: ...
    def to_filepath(self) -> str: ...
    def replace_fragment(self, fragment: str | None = None) -> URL: ...
    def replace_host(self, host: str | None = None) -> URL: ...
    def replace_ip_host(self, host: IPv4Address | IPv4Address) -> URL: ...
    def replace_password(self, password: str | None = None) -> URL: ...
    def replace_path(self, path: str) -> URL: ...
    def replace_port(self, port: int | None = None) -> URL: ...
    def replace_query(self, query: str | None = None) -> URL: ...
    def replace_scheme(self, scheme: str) -> URL: ...
    def replace_username(self, username: str) -> URL: ...
    def socket_addrs(self) -> None: ...
    def replace(
        self,
        *,
        fragment: str | None = None,
        host: str | None = None,
        ip_host: IPv4Address | None = None,
        password: str | None = None,
        path: str | None = None,
        port: int | None = None,
        query: str | None = None,
        scheme: str | None = None,
        username: str | None = None,
    ) -> URL: ...

ry.ryo3._walkdir

"""ryo3-walkdir types"""

from __future__ import annotations

import typing as t
from os import PathLike

from ry import FileType, FsPath, Glob, GlobSet, Globster


class WalkDirEntry:
    def __fspath__(self) -> str: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    @property
    def path(self) -> FsPath: ...
    @property
    def file_name(self) -> str: ...
    @property
    def depth(self) -> int: ...
    @property
    def path_is_symlink(self) -> bool: ...
    @property
    def file_type(self) -> FileType: ...
    @property
    def is_dir(self) -> bool: ...
    @property
    def is_file(self) -> bool: ...
    @property
    def is_symlink(self) -> bool: ...
    @property
    def len(self) -> int: ...


class WalkdirGen:
    """walkdir::Walkdir iterable wrapper"""

    def __next__(self) -> str: ...
    def __iter__(self) -> t.Iterator[str]: ...
    def collect(self) -> list[str]: ...
    def take(self, n: int) -> list[str]: ...
    def __str__(self) -> str: ...


def walkdir(
    path: str | PathLike[str] | None = None,
    *,
    files: bool = True,
    dirs: bool = True,
    contents_first: bool = False,
    min_depth: int = 0,
    max_depth: int | None = None,
    follow_links: bool = False,
    same_file_system: bool = False,
    glob: Glob | GlobSet | Globster | t.Sequence[str] | str | None = None,
) -> WalkdirGen: ...

ry.ryo3._which

"""ryo3-which types"""

from __future__ import annotations

from pathlib import Path

from ry.ryo3._regex import Regex


def which(cmd: str, path: None | str = None) -> Path | None: ...
def which_all(cmd: str, path: None | str = None) -> list[Path]: ...
def which_re(regex: str | Regex, path: None | str = None) -> list[Path]: ...

ry.dirs

def audio() -> str | None: ...
def audio_dir() -> str | None: ...
def cache() -> str | None: ...
def cache_dir() -> str | None: ...
def config() -> str | None: ...
def config_dir() -> str | None: ...
def config_local() -> str | None: ...
def config_local_dir() -> str | None: ...
def data() -> str | None: ...
def data_dir() -> str | None: ...
def data_local() -> str | None: ...
def data_local_dir() -> str | None: ...
def desktop() -> str | None: ...
def desktop_dir() -> str | None: ...
def document() -> str | None: ...
def document_dir() -> str | None: ...
def download() -> str | None: ...
def download_dir() -> str | None: ...
def executable() -> str | None: ...
def executable_dir() -> str | None: ...
def font() -> str | None: ...
def font_dir() -> str | None: ...
def home() -> str | None: ...
def home_dir() -> str | None: ...
def picture() -> str | None: ...
def picture_dir() -> str | None: ...
def preference() -> str | None: ...
def preference_dir() -> str | None: ...
def public() -> str | None: ...
def public_dir() -> str | None: ...
def runtime() -> str | None: ...
def runtime_dir() -> str | None: ...
def state() -> str | None: ...
def state_dir() -> str | None: ...
def template() -> str | None: ...
def template_dir() -> str | None: ...
def video() -> str | None: ...
def video_dir() -> str | None: ...

ry.http

from __future__ import annotations

import typing as t


class Headers:
    """python-ryo3-http `http::HeadersMap` wrapper"""

    def __init__(self, headers: dict[str, str | t.Sequence[str]]) -> None: ...

    # =========================================================================
    # STRING
    # =========================================================================
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def __dbg__(self) -> str: ...

    # =========================================================================
    # MAGIC METHODS
    # =========================================================================
    def __len__(self) -> int: ...
    def __getitem__(self, key: str) -> str: ...
    def __setitem__(self, key: str, value: str) -> None: ...
    def __delitem__(self, key: str) -> None: ...
    def __contains__(self, key: str) -> bool: ...
    def __or__(self, other: Headers | dict[str, str]) -> Headers: ...
    def asdict(self) -> dict[str, str | t.Sequence[str]]: ...

    # =========================================================================
    # INSTANCE METHODS
    # =========================================================================
    def append(self, key: str, value: str) -> None: ...
    def get(self, key: str) -> str | None: ...
    def get_all(self, key: str) -> list[str]: ...
    def keys_len(self) -> int: ...
    def len(self) -> int: ...
    def remove(self, key: str) -> None: ...
    def clear(self) -> None: ...
    def pop(self, key: str) -> str: ...
    def keys(self) -> list[str]: ...
    def update(self, headers: Headers | dict[str, str]) -> None: ...


class HttpStatus:
    def __init__(self, code: int) -> None: ...
    def __int__(self) -> int: ...
    def __bool__(self) -> bool: ...
    def __str__(self) -> str: ...
    def __repr__(self) -> str: ...
    def __hash__(self) -> int: ...
    def __eq__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __lt__(self, other: HttpStatus | int) -> bool: ...
    def __le__(self, other: HttpStatus | int) -> bool: ...
    def __gt__(self, other: HttpStatus | int) -> bool: ...
    def __ge__(self, other: HttpStatus | int) -> bool: ...
    def reason(self) -> str: ...
    def is_informational(self) -> bool: ...
    def is_success(self) -> bool: ...
    def is_redirect(self) -> bool: ...
    def is_client_error(self) -> bool: ...
    def is_server_error(self) -> bool: ...
    def is_ok(self) -> bool: ...
    @property
    def ok(self) -> bool: ...

    # =========================================================================
    # CONST STATUS CODES
    # =========================================================================
    CONTINUE: HttpStatus  # 100 ~ Continue
    SWITCHING_PROTOCOLS: HttpStatus  # 101 ~ Switching Protocols
    PROCESSING: HttpStatus  # 102 ~ Processing
    OK: HttpStatus  # 200 ~ OK
    CREATED: HttpStatus  # 201 ~ Created
    ACCEPTED: HttpStatus  # 202 ~ Accepted
    NON_AUTHORITATIVE_INFORMATION: (
        HttpStatus  # 203 ~ Non Authoritative Information
    )
    NO_CONTENT: HttpStatus  # 204 ~ No Content
    RESET_CONTENT: HttpStatus  # 205 ~ Reset Content
    PARTIAL_CONTENT: HttpStatus  # 206 ~ Partial Content
    MULTI_STATUS: HttpStatus  # 207 ~ Multi-Status
    ALREADY_REPORTED: HttpStatus  # 208 ~ Already Reported
    IM_USED: HttpStatus  # 226 ~ IM Used
    MULTIPLE_CHOICES: HttpStatus  # 300 ~ Multiple Choices
    MOVED_PERMANENTLY: HttpStatus  # 301 ~ Moved Permanently
    FOUND: HttpStatus  # 302 ~ Found
    SEE_OTHER: HttpStatus  # 303 ~ See Other
    NOT_MODIFIED: HttpStatus  # 304 ~ Not Modified
    USE_PROXY: HttpStatus  # 305 ~ Use Proxy
    TEMPORARY_REDIRECT: HttpStatus  # 307 ~ Temporary Redirect
    PERMANENT_REDIRECT: HttpStatus  # 308 ~ Permanent Redirect
    BAD_REQUEST: HttpStatus  # 400 ~ Bad Request
    UNAUTHORIZED: HttpStatus  # 401 ~ Unauthorized
    PAYMENT_REQUIRED: HttpStatus  # 402 ~ Payment Required
    FORBIDDEN: HttpStatus  # 403 ~ Forbidden
    NOT_FOUND: HttpStatus  # 404 ~ Not Found
    METHOD_NOT_ALLOWED: HttpStatus  # 405 ~ Method Not Allowed
    NOT_ACCEPTABLE: HttpStatus  # 406 ~ Not Acceptable
    PROXY_AUTHENTICATION_REQUIRED: (
        HttpStatus  # 407 ~ Proxy Authentication Required
    )
    REQUEST_TIMEOUT: HttpStatus  # 408 ~ Request Timeout
    CONFLICT: HttpStatus  # 409 ~ Conflict
    GONE: HttpStatus  # 410 ~ Gone
    LENGTH_REQUIRED: HttpStatus  # 411 ~ Length Required
    PRECONDITION_FAILED: HttpStatus  # 412 ~ Precondition Failed
    PAYLOAD_TOO_LARGE: HttpStatus  # 413 ~ Payload Too Large
    URI_TOO_LONG: HttpStatus  # 414 ~ URI Too Long
    UNSUPPORTED_MEDIA_TYPE: HttpStatus  # 415 ~ Unsupported Media Type
    RANGE_NOT_SATISFIABLE: HttpStatus  # 416 ~ Range Not Satisfiable
    EXPECTATION_FAILED: HttpStatus  # 417 ~ Expectation Failed
    IM_A_TEAPOT: HttpStatus  # 418 ~ I'm a teapot
    MISDIRECTED_REQUEST: HttpStatus  # 421 ~ Misdirected Request
    UNPROCESSABLE_ENTITY: HttpStatus  # 422 ~ Unprocessable Entity
    LOCKED: HttpStatus  # 423 ~ Locked
    FAILED_DEPENDENCY: HttpStatus  # 424 ~ Failed Dependency
    TOO_EARLY: HttpStatus  # 425 ~ Too Early
    UPGRADE_REQUIRED: HttpStatus  # 426 ~ Upgrade Required
    PRECONDITION_REQUIRED: HttpStatus  # 428 ~ Precondition Required
    TOO_MANY_REQUESTS: HttpStatus  # 429 ~ Too Many Requests
    REQUEST_HEADER_FIELDS_TOO_LARGE: (
        HttpStatus  # 431 ~ Request Header Fields Too Large
    )
    UNAVAILABLE_FOR_LEGAL_REASONS: (
        HttpStatus  # 451 ~ Unavailable For Legal Reasons
    )
    INTERNAL_SERVER_ERROR: HttpStatus  # 500 ~ Internal Server Error
    NOT_IMPLEMENTED: HttpStatus  # 501 ~ Not Implemented
    BAD_GATEWAY: HttpStatus  # 502 ~ Bad Gateway
    SERVICE_UNAVAILABLE: HttpStatus  # 503 ~ Service Unavailable
    GATEWAY_TIMEOUT: HttpStatus  # 504 ~ Gateway Timeout
    HTTP_VERSION_NOT_SUPPORTED: HttpStatus  # 505 ~ HTTP Version Not Supported
    VARIANT_ALSO_NEGOTIATES: HttpStatus  # 506 ~ Variant Also Negotiates
    INSUFFICIENT_STORAGE: HttpStatus  # 507 ~ Insufficient Storage
    LOOP_DETECTED: HttpStatus  # 508 ~ Loop Detected
    NOT_EXTENDED: HttpStatus  # 510 ~ Not Extended
    NETWORK_AUTHENTICATION_REQUIRED: (
        HttpStatus  # 511 ~ Network Authentication Required
    )

ry.xxhash

from __future__ import annotations

import typing as t

from ry._types import Buffer


@t.final
class Xxh32:
    name: t.Literal["xxh32"]

    def __init__(self, input: Buffer = ..., seed: int | None = ...) -> None: ...
    def update(self, input: Buffer) -> None: ...
    def digest(self) -> bytes: ...
    def hexdigest(self) -> str: ...
    def intdigest(self) -> int: ...
    def copy(self) -> Xxh32: ...
    def reset(self, seed: int | None = ...) -> None: ...
    @property
    def seed(self) -> int: ...


@t.final
class Xxh64:
    name: t.Literal["xxh64"]

    def __init__(
        self, input: Buffer | None = None, seed: int | None = ...
    ) -> None: ...
    def update(self, input: Buffer) -> None: ...
    def digest(self) -> bytes: ...
    def hexdigest(self) -> str: ...
    def intdigest(self) -> int: ...
    def copy(self) -> Xxh32: ...
    def reset(self, seed: int | None = ...) -> None: ...
    @property
    def seed(self) -> int: ...


@t.final
class Xxh3:
    name: t.Literal["xxh3"]

    def __init__(
        self,
        input: Buffer = ...,
        seed: int | None = ...,
        secret: bytes | None = ...,
    ) -> None: ...
    def update(self, input: Buffer) -> None: ...
    def digest(self) -> bytes: ...
    def hexdigest(self) -> str: ...
    def intdigest(self) -> int: ...
    @property
    def seed(self) -> int: ...
    def digest128(self) -> bytes: ...
    def hexdigest128(self) -> str: ...
    def intdigest128(self) -> int: ...
    def copy(self) -> Xxh3: ...
    def reset(self) -> None: ...


def xxh32(input: Buffer | None = None, seed: int | None = None) -> Xxh32: ...
def xxh64(input: Buffer | None = None, seed: int | None = None) -> Xxh64: ...
def xxh3(
    input: Buffer | None = None,
    seed: int | None = None,
    secret: bytes | None = None,
) -> Xxh3: ...


# xxh32
def xxh32_digest(input: Buffer, seed: int | None = None) -> bytes: ...
def xxh32_hexdigest(input: Buffer, seed: int | None = None) -> str: ...
def xxh32_intdigest(input: Buffer, seed: int | None = None) -> int: ...


# xxh64
def xxh64_digest(input: Buffer, seed: int | None = None) -> bytes: ...
def xxh64_hexdigest(input: Buffer, seed: int | None = None) -> str: ...
def xxh64_intdigest(input: Buffer, seed: int | None = None) -> int: ...


# xxh128
def xxh128_digest(input: Buffer, seed: int | None = None) -> bytes: ...
def xxh128_hexdigest(input: Buffer, seed: int | None = None) -> str: ...
def xxh128_intdigest(input: Buffer, seed: int | None = None) -> int: ...


# xxh3
def xxh3_64_digest(input: Buffer, seed: int | None = None) -> bytes: ...
def xxh3_64_intdigest(input: Buffer, seed: int | None = None) -> int: ...
def xxh3_64_hexdigest(input: Buffer, seed: int | None = None) -> str: ...
def xxh3_digest(input: Buffer, seed: int | None = None) -> bytes: ...
def xxh3_intdigest(input: Buffer, seed: int | None = None) -> int: ...
def xxh3_hexdigest(input: Buffer, seed: int | None = None) -> str: ...


# xxh128
def xxh3_128_digest(input: Buffer, seed: int | None = None) -> bytes: ...
def xxh3_128_intdigest(input: Buffer, seed: int | None = None) -> int: ...
def xxh3_128_hexdigest(input: Buffer, seed: int | None = None) -> str: ...

ry.zstd

from ry import Bytes
from ry._types import Buffer

__zstd_version__: str  # zstd version string ("1.5.7" as of 2025-03-14)
BLOCKSIZELOG_MAX: int
BLOCKSIZE_MAX: int
CLEVEL_DEFAULT: int  # default=3 (as of 2025-03-14)
CONTENTSIZE_ERROR: int
CONTENTSIZE_UNKNOWN: int
MAGICNUMBER: int
MAGIC_DICTIONARY: int
MAGIC_SKIPPABLE_MASK: int
MAGIC_SKIPPABLE_START: int
VERSION_MAJOR: int
VERSION_MINOR: int
VERSION_NUMBER: int
VERSION_RELEASE: int


# =============================================================================
# PYFUNCTIONS
# =============================================================================
# __COMPRESSION__
def compress(data: Buffer, level: int = CLEVEL_DEFAULT) -> Bytes: ...
def encode(data: Buffer, level: int = CLEVEL_DEFAULT) -> Bytes: ...
def zstd(data: Buffer, level: int = CLEVEL_DEFAULT) -> Bytes: ...
def zstd_compress(data: Buffer, level: int = CLEVEL_DEFAULT) -> Bytes: ...
def zstd_encode(data: Buffer, level: int = CLEVEL_DEFAULT) -> Bytes: ...


# __DECOMPRESSION__
def decode(data: Buffer) -> Bytes: ...
def decompress(data: Buffer) -> Bytes: ...
def unzstd(data: Buffer) -> Bytes: ...
def zstd_decode(data: Buffer) -> Bytes: ...
def zstd_decompress(data: Buffer) -> Bytes: ...


# __MAGIC__
def is_zstd(data: Buffer) -> bool: ...

food-4-thought

thinking out loud…


ry.dev

For people who find ry.dev it is a module that exports all the things in ry as well as can be used as a repl; python -m ry.dev will start a repl (with ipython if installed else python-repl) with all of ry already imported. I (jesse) use this super often for testing things out.


string-bridge?

The jiter crate uses a string-cache to store python-strings to avoid the overhead of converting strings to python strings. A global string bridge and/or caching setup for other types of structs that often convert to strings might be worth considering?


Naming

Coming up with names is hard… I (jesse) want to strike a balance between being clear but also close to the wrapped libraries…

  • Should jiff’s Zoned be Zoned in python? or ZonedDateTime? (currently ZonedDateTime)
  • Should jiff’s Span be Span in python? or TimeSpan? (currently TimeSpan)
  • Should reqwest’s Client be Client in python? or HttpClient? (currently HttpClient)

Flat? Nested submodules?

I like flat more, but nesting submodules might be preferable for some people and would allow for more flexibility in naming…

pros & cons:

  • flat:
    • pros:
      • easier to import
      • easier to work on
      • no need to remember where things are
      • type annotations are easier to setup/dist
    • cons:
      • name conflicts
      • type annotations are harder to read bc of huge file
      • harder to remember where things are
  • nested:
    • pros:
      • no name conflicts
      • easier to remember where things are
      • type annotations are easier to read
      • importing ry.jiff (or ry.ryo3.jiff tbd) is more explicitly the jiff wrapper(s)
    • cons:
      • Don’t know how type annotations should be laid out… if there is a submodule called ry.ryo3.reqwest, do you import from ry.ryo3.reqwest or do we reexport from ry.reqwest? Then were doe the type-annotations live and how are they laid out without having to duplicate/shim them?

pypi size limit

The pypi project size limit of 10gb was reached. I (jesse) won’t request a limit raise until the package is more stable and hits some sort of v0.1.x, SOOOOOO for now I will be:

  • deleting older versions of ry from pypi as needed
  • update the release gh-action to push the built wheels to the releases page so they are not lost into the ether…

jiff

docs.rs: https://docs.rs/jiff

crates: https://crates.io/crates/jiff


The jiff crate has a super excellent API that is very ergonomic to use and ry provides a nearly complete wrapper around it.

A good amount of time, and a greater amount of thought has gone into balancing the jiff python api to be both ergonomic and performant.

python-conversions

The structs under ryo3-jiff are convertable to/from python’s datetime.* types and the conversions are pretty well tested (ty hypothesis).

pyo3-v0.24.0 & jiff-02

The conversions to/from python datetime.* types were originally hand rolled ( by me (jesse)) using the ‘new-type’ pattern, HOWEVER pyo3-v0.24.0 provides conversions via the jiff-02 feature flag, which is what is used now.

ry-v0.0.37 will be the last version with the mostly hand rolled conversions.

ry-v0.0.38 will be the first version with the jiff-02 feature flag.

As of 2025-03-12 pyo3 does not seem to support converting Span -> datetime.timedelta, so that is still hand rolled.


ry vs whenever

There is another library called whenever that provides a similar datetime library to that of ryo3-jiff (both jiff and whenever are based on the temporal API).

No formal benchmarks between ry and whenever have been done, but I have copy-pasta-ed some of the benchmarks from the whenever repo and translated them to ry and the results were pretty similar; whenever is faster for some things, ry is faster for others, but both are wildly more performant than python’s built in datetime module and pendulum – differences in performance are almost all measured in nanoseconds.

Big shoutout to “Mr. Dutch Airlines” guy (@ariebovenberg) who wrote whenever! Love the name of the library too!