"""
Basic types we will more widely need in DaCHS;  we also import everything
we need from typing, so for our type annotations we only need to say
from utils.dachstypes import ...

This also lets us smuggle in fallbacks for python 3.7 (and we won't go
further back than that).
"""

#c Copyright 2008-2025, the GAVO project <gavo@ari.uni-heidelberg.de>
#c
#c This program is free software, covered by the GNU GPL.  See the
#c COPYING file in the source distribution.

from __future__ import annotations


from typing import ( #noflake: gratuitous imports for re-exporting
	AbstractSet, Any,
	BinaryIO,
	Callable, ClassVar, ContextManager,
	Dict,
	Final,
	FrozenSet,
	Generator,
	Hashable,
	IO, Iterable, Iterator,
	Generic,
	Hashable,
	List,
	Mapping,
	NewType, NoReturn,
	Optional,
	Protocol,
	Sequence, Set,
	TextIO, Tuple, TYPE_CHECKING, Type, TypeVar,
	Union,
	cast)

# things introduced after python 3.7; if their import fails, we replace
# them with None, so type checking will fail with older pythons, but
# that seems fine to me.
try:
	from typing import ( #noflake: gratuitous imports for re-exporting
		Self
	)
except ImportError:
	Self = None  # type: ignore

from types import ModuleType  #noflake: gratuitous imports for re-exporting
from re import Match  #noflake: gratuitous imports for re-exporting

import numpy

try:
	from numpy.typing import NDArray
except ImportError:
	NDArray = NewType('NDArray', object)  # type: ignore

Numeric = Union[int, float, numpy.floating, numpy.integer]

# a base.events event handler
BaseEventHandler = Callable

import pathlib
Filename = Union[str, pathlib.Path]
# positions when doing XML parsing
StrOrBytes = Union[str, bytes]
StrToStrMap = Dict[str, str]

# use this instead of T = TypeVar()... whenever possible.
SomeClass = TypeVar("SomeClass")

# see utils.plainxml
PlainXMLEvent = Tuple[
	str,
	Optional[str],
	Union[Dict[str, str], None, str]]

# Something with a write method accepting bytes
class BytesWritable(Protocol):
	def write(self, data: bytes):
		"outputs data somewhere."

class BytesReadable(Protocol):
	def read(self, nBytes: Optional[int] = None):
		"reads data from somewhere."


if TYPE_CHECKING:
	from gavo.base import Structure
	from gavo.base.sqlsupport import DaCHSConnection
	from gavo.base.parsecontext import ParseContext
	from gavo.rsc.table import BaseTable
else:
	Structure = None # type: ignore
	DaCHSConnection = None # type: ignore
	ParseContext = None # type: ignore
	BaseTable = None # type: ignore

# StanElement should be anything we can process within an utils.xmlstan
# tree; use this whenever we are producing HTML or XML.  For now
# I'm being overly generic.  Let's see if we want to lock this down a bit
StanElement = Any

StructParseContext = ParseContext

# the type of value arguments in struct parser events.
StructParserValue = Optional[Union[Dict[str, str], str]]

# One of these days we ought to be a bit more concrete about which
# source tokens we accept; but it's really up to the grammars...
SourceToken = Any

# We could get a lot more fancy here because the structure of
# vocabularies is fairly strictly defined by desise; but I'd say
# it's unlikely that type checking is a bit help when dealing with
# them.
Vocabulary = Dict[str, Any]
