import random
import sys
from types import ModuleType
from typing_extensions import Self, TypeAlias

import numpy

__all__ = [
    "flatten",
    "make_list_of_ints",
    "dict_to_numpy_array",
    "arbitrary_element",
    "pairwise",
    "groups",
    "create_random_state",
    "create_py_random_state",
    "PythonRandomInterface",
    "PythonRandomViaNumpyBits",
    "nodes_equal",
    "edges_equal",
    "graphs_equal",
    "_clear_cache",
]

_RandomNumberGenerator: TypeAlias = (
    ModuleType | random.Random | numpy.random.RandomState | numpy.random.Generator | PythonRandomInterface
)
_RandomState: TypeAlias = int | _RandomNumberGenerator | None

def flatten(obj, result=None): ...
def make_list_of_ints(sequence): ...
def dict_to_numpy_array(d, mapping=None): ...
def arbitrary_element(iterable): ...
def pairwise(iterable, cyclic: bool = False): ...
def groups(many_to_one): ...
def create_random_state(random_state=None): ...

class PythonRandomViaNumpyBits(random.Random):
    def __init__(self, rng: numpy.random.Generator | None = None) -> None: ...
    if sys.version_info < (3, 10):
        # this is a workaround for pyright correctly flagging an inconsistent inherited constructor, see #14624
        def __new__(cls, rng: numpy.random.Generator | None = None) -> Self: ...

    def getrandbits(self, k: int) -> int: ...

class PythonRandomInterface:
    def __init__(self, rng=None) -> None: ...
    def random(self): ...
    def uniform(self, a, b): ...
    def randrange(self, a, b=None): ...
    def choice(self, seq): ...
    def gauss(self, mu, sigma): ...
    def shuffle(self, seq): ...
    def sample(self, seq, k): ...
    def randint(self, a, b): ...
    def expovariate(self, scale): ...
    def paretovariate(self, shape): ...

def create_py_random_state(random_state: _RandomState = None): ...
def nodes_equal(nodes1, nodes2) -> bool: ...
def edges_equal(edges1, edges2) -> bool: ...
def graphs_equal(graph1, graph2) -> bool: ...
def _clear_cache(G) -> None: ...
