diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index c5ba20e..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/_manylinux.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/_manylinux.cpython-311.pyc deleted file mode 100755 index 39a5372..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/_manylinux.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/_musllinux.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/_musllinux.cpython-311.pyc deleted file mode 100755 index 8c9ebed..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/_musllinux.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/_structures.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/_structures.cpython-311.pyc deleted file mode 100755 index ea40f91..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/_structures.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/markers.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/markers.cpython-311.pyc deleted file mode 100755 index 660bac7..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/markers.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/requirements.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/requirements.cpython-311.pyc deleted file mode 100755 index ef9150f..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/requirements.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/specifiers.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/specifiers.cpython-311.pyc deleted file mode 100755 index 0d4141e..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/specifiers.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/tags.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/tags.cpython-311.pyc deleted file mode 100755 index 41dbd17..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/tags.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/utils.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/utils.cpython-311.pyc deleted file mode 100755 index b2ca9c4..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/utils.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/version.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/version.cpython-311.pyc deleted file mode 100755 index 9b8f22f..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/__pycache__/version.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/_manylinux.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/_manylinux.py deleted file mode 100755 index 4c379aa..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/_manylinux.py +++ /dev/null @@ -1,301 +0,0 @@ -import collections -import functools -import os -import re -import struct -import sys -import warnings -from typing import IO, Dict, Iterator, NamedTuple, Optional, Tuple - - -# Python does not provide platform information at sufficient granularity to -# identify the architecture of the running executable in some cases, so we -# determine it dynamically by reading the information from the running -# process. This only applies on Linux, which uses the ELF format. -class _ELFFileHeader: - # https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header - class _InvalidELFFileHeader(ValueError): - """ - An invalid ELF file header was found. - """ - - ELF_MAGIC_NUMBER = 0x7F454C46 - ELFCLASS32 = 1 - ELFCLASS64 = 2 - ELFDATA2LSB = 1 - ELFDATA2MSB = 2 - EM_386 = 3 - EM_S390 = 22 - EM_ARM = 40 - EM_X86_64 = 62 - EF_ARM_ABIMASK = 0xFF000000 - EF_ARM_ABI_VER5 = 0x05000000 - EF_ARM_ABI_FLOAT_HARD = 0x00000400 - - def __init__(self, file: IO[bytes]) -> None: - def unpack(fmt: str) -> int: - try: - data = file.read(struct.calcsize(fmt)) - result: Tuple[int, ...] = struct.unpack(fmt, data) - except struct.error: - raise _ELFFileHeader._InvalidELFFileHeader() - return result[0] - - self.e_ident_magic = unpack(">I") - if self.e_ident_magic != self.ELF_MAGIC_NUMBER: - raise _ELFFileHeader._InvalidELFFileHeader() - self.e_ident_class = unpack("B") - if self.e_ident_class not in {self.ELFCLASS32, self.ELFCLASS64}: - raise _ELFFileHeader._InvalidELFFileHeader() - self.e_ident_data = unpack("B") - if self.e_ident_data not in {self.ELFDATA2LSB, self.ELFDATA2MSB}: - raise _ELFFileHeader._InvalidELFFileHeader() - self.e_ident_version = unpack("B") - self.e_ident_osabi = unpack("B") - self.e_ident_abiversion = unpack("B") - self.e_ident_pad = file.read(7) - format_h = "H" - format_i = "I" - format_q = "Q" - format_p = format_i if self.e_ident_class == self.ELFCLASS32 else format_q - self.e_type = unpack(format_h) - self.e_machine = unpack(format_h) - self.e_version = unpack(format_i) - self.e_entry = unpack(format_p) - self.e_phoff = unpack(format_p) - self.e_shoff = unpack(format_p) - self.e_flags = unpack(format_i) - self.e_ehsize = unpack(format_h) - self.e_phentsize = unpack(format_h) - self.e_phnum = unpack(format_h) - self.e_shentsize = unpack(format_h) - self.e_shnum = unpack(format_h) - self.e_shstrndx = unpack(format_h) - - -def _get_elf_header() -> Optional[_ELFFileHeader]: - try: - with open(sys.executable, "rb") as f: - elf_header = _ELFFileHeader(f) - except (OSError, TypeError, _ELFFileHeader._InvalidELFFileHeader): - return None - return elf_header - - -def _is_linux_armhf() -> bool: - # hard-float ABI can be detected from the ELF header of the running - # process - # https://static.docs.arm.com/ihi0044/g/aaelf32.pdf - elf_header = _get_elf_header() - if elf_header is None: - return False - result = elf_header.e_ident_class == elf_header.ELFCLASS32 - result &= elf_header.e_ident_data == elf_header.ELFDATA2LSB - result &= elf_header.e_machine == elf_header.EM_ARM - result &= ( - elf_header.e_flags & elf_header.EF_ARM_ABIMASK - ) == elf_header.EF_ARM_ABI_VER5 - result &= ( - elf_header.e_flags & elf_header.EF_ARM_ABI_FLOAT_HARD - ) == elf_header.EF_ARM_ABI_FLOAT_HARD - return result - - -def _is_linux_i686() -> bool: - elf_header = _get_elf_header() - if elf_header is None: - return False - result = elf_header.e_ident_class == elf_header.ELFCLASS32 - result &= elf_header.e_ident_data == elf_header.ELFDATA2LSB - result &= elf_header.e_machine == elf_header.EM_386 - return result - - -def _have_compatible_abi(arch: str) -> bool: - if arch == "armv7l": - return _is_linux_armhf() - if arch == "i686": - return _is_linux_i686() - return arch in {"x86_64", "aarch64", "ppc64", "ppc64le", "s390x"} - - -# If glibc ever changes its major version, we need to know what the last -# minor version was, so we can build the complete list of all versions. -# For now, guess what the highest minor version might be, assume it will -# be 50 for testing. Once this actually happens, update the dictionary -# with the actual value. -_LAST_GLIBC_MINOR: Dict[int, int] = collections.defaultdict(lambda: 50) - - -class _GLibCVersion(NamedTuple): - major: int - minor: int - - -def _glibc_version_string_confstr() -> Optional[str]: - """ - Primary implementation of glibc_version_string using os.confstr. - """ - # os.confstr is quite a bit faster than ctypes.DLL. It's also less likely - # to be broken or missing. This strategy is used in the standard library - # platform module. - # https://github.com/python/cpython/blob/fcf1d003bf4f0100c/Lib/platform.py#L175-L183 - try: - # os.confstr("CS_GNU_LIBC_VERSION") returns a string like "glibc 2.17". - version_string = os.confstr("CS_GNU_LIBC_VERSION") - assert version_string is not None - _, version = version_string.split() - except (AssertionError, AttributeError, OSError, ValueError): - # os.confstr() or CS_GNU_LIBC_VERSION not available (or a bad value)... - return None - return version - - -def _glibc_version_string_ctypes() -> Optional[str]: - """ - Fallback implementation of glibc_version_string using ctypes. - """ - try: - import ctypes - except ImportError: - return None - - # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen - # manpage says, "If filename is NULL, then the returned handle is for the - # main program". This way we can let the linker do the work to figure out - # which libc our process is actually using. - # - # We must also handle the special case where the executable is not a - # dynamically linked executable. This can occur when using musl libc, - # for example. In this situation, dlopen() will error, leading to an - # OSError. Interestingly, at least in the case of musl, there is no - # errno set on the OSError. The single string argument used to construct - # OSError comes from libc itself and is therefore not portable to - # hard code here. In any case, failure to call dlopen() means we - # can proceed, so we bail on our attempt. - try: - process_namespace = ctypes.CDLL(None) - except OSError: - return None - - try: - gnu_get_libc_version = process_namespace.gnu_get_libc_version - except AttributeError: - # Symbol doesn't exist -> therefore, we are not linked to - # glibc. - return None - - # Call gnu_get_libc_version, which returns a string like "2.5" - gnu_get_libc_version.restype = ctypes.c_char_p - version_str: str = gnu_get_libc_version() - # py2 / py3 compatibility: - if not isinstance(version_str, str): - version_str = version_str.decode("ascii") - - return version_str - - -def _glibc_version_string() -> Optional[str]: - """Returns glibc version string, or None if not using glibc.""" - return _glibc_version_string_confstr() or _glibc_version_string_ctypes() - - -def _parse_glibc_version(version_str: str) -> Tuple[int, int]: - """Parse glibc version. - - We use a regexp instead of str.split because we want to discard any - random junk that might come after the minor version -- this might happen - in patched/forked versions of glibc (e.g. Linaro's version of glibc - uses version strings like "2.20-2014.11"). See gh-3588. - """ - m = re.match(r"(?P[0-9]+)\.(?P[0-9]+)", version_str) - if not m: - warnings.warn( - "Expected glibc version with 2 components major.minor," - " got: %s" % version_str, - RuntimeWarning, - ) - return -1, -1 - return int(m.group("major")), int(m.group("minor")) - - -@functools.lru_cache() -def _get_glibc_version() -> Tuple[int, int]: - version_str = _glibc_version_string() - if version_str is None: - return (-1, -1) - return _parse_glibc_version(version_str) - - -# From PEP 513, PEP 600 -def _is_compatible(name: str, arch: str, version: _GLibCVersion) -> bool: - sys_glibc = _get_glibc_version() - if sys_glibc < version: - return False - # Check for presence of _manylinux module. - try: - import _manylinux # noqa - except ImportError: - return True - if hasattr(_manylinux, "manylinux_compatible"): - result = _manylinux.manylinux_compatible(version[0], version[1], arch) - if result is not None: - return bool(result) - return True - if version == _GLibCVersion(2, 5): - if hasattr(_manylinux, "manylinux1_compatible"): - return bool(_manylinux.manylinux1_compatible) - if version == _GLibCVersion(2, 12): - if hasattr(_manylinux, "manylinux2010_compatible"): - return bool(_manylinux.manylinux2010_compatible) - if version == _GLibCVersion(2, 17): - if hasattr(_manylinux, "manylinux2014_compatible"): - return bool(_manylinux.manylinux2014_compatible) - return True - - -_LEGACY_MANYLINUX_MAP = { - # CentOS 7 w/ glibc 2.17 (PEP 599) - (2, 17): "manylinux2014", - # CentOS 6 w/ glibc 2.12 (PEP 571) - (2, 12): "manylinux2010", - # CentOS 5 w/ glibc 2.5 (PEP 513) - (2, 5): "manylinux1", -} - - -def platform_tags(linux: str, arch: str) -> Iterator[str]: - if not _have_compatible_abi(arch): - return - # Oldest glibc to be supported regardless of architecture is (2, 17). - too_old_glibc2 = _GLibCVersion(2, 16) - if arch in {"x86_64", "i686"}: - # On x86/i686 also oldest glibc to be supported is (2, 5). - too_old_glibc2 = _GLibCVersion(2, 4) - current_glibc = _GLibCVersion(*_get_glibc_version()) - glibc_max_list = [current_glibc] - # We can assume compatibility across glibc major versions. - # https://sourceware.org/bugzilla/show_bug.cgi?id=24636 - # - # Build a list of maximum glibc versions so that we can - # output the canonical list of all glibc from current_glibc - # down to too_old_glibc2, including all intermediary versions. - for glibc_major in range(current_glibc.major - 1, 1, -1): - glibc_minor = _LAST_GLIBC_MINOR[glibc_major] - glibc_max_list.append(_GLibCVersion(glibc_major, glibc_minor)) - for glibc_max in glibc_max_list: - if glibc_max.major == too_old_glibc2.major: - min_minor = too_old_glibc2.minor - else: - # For other glibc major versions oldest supported is (x, 0). - min_minor = -1 - for glibc_minor in range(glibc_max.minor, min_minor, -1): - glibc_version = _GLibCVersion(glibc_max.major, glibc_minor) - tag = "manylinux_{}_{}".format(*glibc_version) - if _is_compatible(tag, arch, glibc_version): - yield linux.replace("linux", tag) - # Handle the legacy manylinux1, manylinux2010, manylinux2014 tags. - if glibc_version in _LEGACY_MANYLINUX_MAP: - legacy_tag = _LEGACY_MANYLINUX_MAP[glibc_version] - if _is_compatible(legacy_tag, arch, glibc_version): - yield linux.replace("linux", legacy_tag) diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/_musllinux.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/_musllinux.py deleted file mode 100755 index 8ac3059..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/_musllinux.py +++ /dev/null @@ -1,136 +0,0 @@ -"""PEP 656 support. - -This module implements logic to detect if the currently running Python is -linked against musl, and what musl version is used. -""" - -import contextlib -import functools -import operator -import os -import re -import struct -import subprocess -import sys -from typing import IO, Iterator, NamedTuple, Optional, Tuple - - -def _read_unpacked(f: IO[bytes], fmt: str) -> Tuple[int, ...]: - return struct.unpack(fmt, f.read(struct.calcsize(fmt))) - - -def _parse_ld_musl_from_elf(f: IO[bytes]) -> Optional[str]: - """Detect musl libc location by parsing the Python executable. - - Based on: https://gist.github.com/lyssdod/f51579ae8d93c8657a5564aefc2ffbca - ELF header: https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html - """ - f.seek(0) - try: - ident = _read_unpacked(f, "16B") - except struct.error: - return None - if ident[:4] != tuple(b"\x7fELF"): # Invalid magic, not ELF. - return None - f.seek(struct.calcsize("HHI"), 1) # Skip file type, machine, and version. - - try: - # e_fmt: Format for program header. - # p_fmt: Format for section header. - # p_idx: Indexes to find p_type, p_offset, and p_filesz. - e_fmt, p_fmt, p_idx = { - 1: ("IIIIHHH", "IIIIIIII", (0, 1, 4)), # 32-bit. - 2: ("QQQIHHH", "IIQQQQQQ", (0, 2, 5)), # 64-bit. - }[ident[4]] - except KeyError: - return None - else: - p_get = operator.itemgetter(*p_idx) - - # Find the interpreter section and return its content. - try: - _, e_phoff, _, _, _, e_phentsize, e_phnum = _read_unpacked(f, e_fmt) - except struct.error: - return None - for i in range(e_phnum + 1): - f.seek(e_phoff + e_phentsize * i) - try: - p_type, p_offset, p_filesz = p_get(_read_unpacked(f, p_fmt)) - except struct.error: - return None - if p_type != 3: # Not PT_INTERP. - continue - f.seek(p_offset) - interpreter = os.fsdecode(f.read(p_filesz)).strip("\0") - if "musl" not in interpreter: - return None - return interpreter - return None - - -class _MuslVersion(NamedTuple): - major: int - minor: int - - -def _parse_musl_version(output: str) -> Optional[_MuslVersion]: - lines = [n for n in (n.strip() for n in output.splitlines()) if n] - if len(lines) < 2 or lines[0][:4] != "musl": - return None - m = re.match(r"Version (\d+)\.(\d+)", lines[1]) - if not m: - return None - return _MuslVersion(major=int(m.group(1)), minor=int(m.group(2))) - - -@functools.lru_cache() -def _get_musl_version(executable: str) -> Optional[_MuslVersion]: - """Detect currently-running musl runtime version. - - This is done by checking the specified executable's dynamic linking - information, and invoking the loader to parse its output for a version - string. If the loader is musl, the output would be something like:: - - musl libc (x86_64) - Version 1.2.2 - Dynamic Program Loader - """ - with contextlib.ExitStack() as stack: - try: - f = stack.enter_context(open(executable, "rb")) - except OSError: - return None - ld = _parse_ld_musl_from_elf(f) - if not ld: - return None - proc = subprocess.run([ld], stderr=subprocess.PIPE, universal_newlines=True) - return _parse_musl_version(proc.stderr) - - -def platform_tags(arch: str) -> Iterator[str]: - """Generate musllinux tags compatible to the current platform. - - :param arch: Should be the part of platform tag after the ``linux_`` - prefix, e.g. ``x86_64``. The ``linux_`` prefix is assumed as a - prerequisite for the current platform to be musllinux-compatible. - - :returns: An iterator of compatible musllinux tags. - """ - sys_musl = _get_musl_version(sys.executable) - if sys_musl is None: # Python not dynamically linked against musl. - return - for minor in range(sys_musl.minor, -1, -1): - yield f"musllinux_{sys_musl.major}_{minor}_{arch}" - - -if __name__ == "__main__": # pragma: no cover - import sysconfig - - plat = sysconfig.get_platform() - assert plat.startswith("linux-"), "not linux" - - print("plat:", plat) - print("musl:", _get_musl_version(sys.executable)) - print("tags:", end=" ") - for t in platform_tags(re.sub(r"[.-]", "_", plat.split("-", 1)[-1])): - print(t, end="\n ") diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/_structures.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/_structures.py deleted file mode 100755 index 90a6465..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/_structures.py +++ /dev/null @@ -1,61 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - - -class InfinityType: - def __repr__(self) -> str: - return "Infinity" - - def __hash__(self) -> int: - return hash(repr(self)) - - def __lt__(self, other: object) -> bool: - return False - - def __le__(self, other: object) -> bool: - return False - - def __eq__(self, other: object) -> bool: - return isinstance(other, self.__class__) - - def __gt__(self, other: object) -> bool: - return True - - def __ge__(self, other: object) -> bool: - return True - - def __neg__(self: object) -> "NegativeInfinityType": - return NegativeInfinity - - -Infinity = InfinityType() - - -class NegativeInfinityType: - def __repr__(self) -> str: - return "-Infinity" - - def __hash__(self) -> int: - return hash(repr(self)) - - def __lt__(self, other: object) -> bool: - return True - - def __le__(self, other: object) -> bool: - return True - - def __eq__(self, other: object) -> bool: - return isinstance(other, self.__class__) - - def __gt__(self, other: object) -> bool: - return False - - def __ge__(self, other: object) -> bool: - return False - - def __neg__(self: object) -> InfinityType: - return Infinity - - -NegativeInfinity = NegativeInfinityType() diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/markers.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/markers.py deleted file mode 100755 index eb0541b..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/markers.py +++ /dev/null @@ -1,304 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import operator -import os -import platform -import sys -from typing import Any, Callable, Dict, List, Optional, Tuple, Union - -from setuptools.extern.pyparsing import ( # noqa: N817 - Forward, - Group, - Literal as L, - ParseException, - ParseResults, - QuotedString, - ZeroOrMore, - stringEnd, - stringStart, -) - -from .specifiers import InvalidSpecifier, Specifier - -__all__ = [ - "InvalidMarker", - "UndefinedComparison", - "UndefinedEnvironmentName", - "Marker", - "default_environment", -] - -Operator = Callable[[str, str], bool] - - -class InvalidMarker(ValueError): - """ - An invalid marker was found, users should refer to PEP 508. - """ - - -class UndefinedComparison(ValueError): - """ - An invalid operation was attempted on a value that doesn't support it. - """ - - -class UndefinedEnvironmentName(ValueError): - """ - A name was attempted to be used that does not exist inside of the - environment. - """ - - -class Node: - def __init__(self, value: Any) -> None: - self.value = value - - def __str__(self) -> str: - return str(self.value) - - def __repr__(self) -> str: - return f"<{self.__class__.__name__}('{self}')>" - - def serialize(self) -> str: - raise NotImplementedError - - -class Variable(Node): - def serialize(self) -> str: - return str(self) - - -class Value(Node): - def serialize(self) -> str: - return f'"{self}"' - - -class Op(Node): - def serialize(self) -> str: - return str(self) - - -VARIABLE = ( - L("implementation_version") - | L("platform_python_implementation") - | L("implementation_name") - | L("python_full_version") - | L("platform_release") - | L("platform_version") - | L("platform_machine") - | L("platform_system") - | L("python_version") - | L("sys_platform") - | L("os_name") - | L("os.name") # PEP-345 - | L("sys.platform") # PEP-345 - | L("platform.version") # PEP-345 - | L("platform.machine") # PEP-345 - | L("platform.python_implementation") # PEP-345 - | L("python_implementation") # undocumented setuptools legacy - | L("extra") # PEP-508 -) -ALIASES = { - "os.name": "os_name", - "sys.platform": "sys_platform", - "platform.version": "platform_version", - "platform.machine": "platform_machine", - "platform.python_implementation": "platform_python_implementation", - "python_implementation": "platform_python_implementation", -} -VARIABLE.setParseAction(lambda s, l, t: Variable(ALIASES.get(t[0], t[0]))) - -VERSION_CMP = ( - L("===") | L("==") | L(">=") | L("<=") | L("!=") | L("~=") | L(">") | L("<") -) - -MARKER_OP = VERSION_CMP | L("not in") | L("in") -MARKER_OP.setParseAction(lambda s, l, t: Op(t[0])) - -MARKER_VALUE = QuotedString("'") | QuotedString('"') -MARKER_VALUE.setParseAction(lambda s, l, t: Value(t[0])) - -BOOLOP = L("and") | L("or") - -MARKER_VAR = VARIABLE | MARKER_VALUE - -MARKER_ITEM = Group(MARKER_VAR + MARKER_OP + MARKER_VAR) -MARKER_ITEM.setParseAction(lambda s, l, t: tuple(t[0])) - -LPAREN = L("(").suppress() -RPAREN = L(")").suppress() - -MARKER_EXPR = Forward() -MARKER_ATOM = MARKER_ITEM | Group(LPAREN + MARKER_EXPR + RPAREN) -MARKER_EXPR << MARKER_ATOM + ZeroOrMore(BOOLOP + MARKER_EXPR) - -MARKER = stringStart + MARKER_EXPR + stringEnd - - -def _coerce_parse_result(results: Union[ParseResults, List[Any]]) -> List[Any]: - if isinstance(results, ParseResults): - return [_coerce_parse_result(i) for i in results] - else: - return results - - -def _format_marker( - marker: Union[List[str], Tuple[Node, ...], str], first: Optional[bool] = True -) -> str: - - assert isinstance(marker, (list, tuple, str)) - - # Sometimes we have a structure like [[...]] which is a single item list - # where the single item is itself it's own list. In that case we want skip - # the rest of this function so that we don't get extraneous () on the - # outside. - if ( - isinstance(marker, list) - and len(marker) == 1 - and isinstance(marker[0], (list, tuple)) - ): - return _format_marker(marker[0]) - - if isinstance(marker, list): - inner = (_format_marker(m, first=False) for m in marker) - if first: - return " ".join(inner) - else: - return "(" + " ".join(inner) + ")" - elif isinstance(marker, tuple): - return " ".join([m.serialize() for m in marker]) - else: - return marker - - -_operators: Dict[str, Operator] = { - "in": lambda lhs, rhs: lhs in rhs, - "not in": lambda lhs, rhs: lhs not in rhs, - "<": operator.lt, - "<=": operator.le, - "==": operator.eq, - "!=": operator.ne, - ">=": operator.ge, - ">": operator.gt, -} - - -def _eval_op(lhs: str, op: Op, rhs: str) -> bool: - try: - spec = Specifier("".join([op.serialize(), rhs])) - except InvalidSpecifier: - pass - else: - return spec.contains(lhs) - - oper: Optional[Operator] = _operators.get(op.serialize()) - if oper is None: - raise UndefinedComparison(f"Undefined {op!r} on {lhs!r} and {rhs!r}.") - - return oper(lhs, rhs) - - -class Undefined: - pass - - -_undefined = Undefined() - - -def _get_env(environment: Dict[str, str], name: str) -> str: - value: Union[str, Undefined] = environment.get(name, _undefined) - - if isinstance(value, Undefined): - raise UndefinedEnvironmentName( - f"{name!r} does not exist in evaluation environment." - ) - - return value - - -def _evaluate_markers(markers: List[Any], environment: Dict[str, str]) -> bool: - groups: List[List[bool]] = [[]] - - for marker in markers: - assert isinstance(marker, (list, tuple, str)) - - if isinstance(marker, list): - groups[-1].append(_evaluate_markers(marker, environment)) - elif isinstance(marker, tuple): - lhs, op, rhs = marker - - if isinstance(lhs, Variable): - lhs_value = _get_env(environment, lhs.value) - rhs_value = rhs.value - else: - lhs_value = lhs.value - rhs_value = _get_env(environment, rhs.value) - - groups[-1].append(_eval_op(lhs_value, op, rhs_value)) - else: - assert marker in ["and", "or"] - if marker == "or": - groups.append([]) - - return any(all(item) for item in groups) - - -def format_full_version(info: "sys._version_info") -> str: - version = "{0.major}.{0.minor}.{0.micro}".format(info) - kind = info.releaselevel - if kind != "final": - version += kind[0] + str(info.serial) - return version - - -def default_environment() -> Dict[str, str]: - iver = format_full_version(sys.implementation.version) - implementation_name = sys.implementation.name - return { - "implementation_name": implementation_name, - "implementation_version": iver, - "os_name": os.name, - "platform_machine": platform.machine(), - "platform_release": platform.release(), - "platform_system": platform.system(), - "platform_version": platform.version(), - "python_full_version": platform.python_version(), - "platform_python_implementation": platform.python_implementation(), - "python_version": ".".join(platform.python_version_tuple()[:2]), - "sys_platform": sys.platform, - } - - -class Marker: - def __init__(self, marker: str) -> None: - try: - self._markers = _coerce_parse_result(MARKER.parseString(marker)) - except ParseException as e: - raise InvalidMarker( - f"Invalid marker: {marker!r}, parse error at " - f"{marker[e.loc : e.loc + 8]!r}" - ) - - def __str__(self) -> str: - return _format_marker(self._markers) - - def __repr__(self) -> str: - return f"" - - def evaluate(self, environment: Optional[Dict[str, str]] = None) -> bool: - """Evaluate a marker. - - Return the boolean from evaluating the given marker against the - environment. environment is an optional argument to override all or - part of the determined environment. - - The environment is determined from the current Python process. - """ - current_environment = default_environment() - if environment is not None: - current_environment.update(environment) - - return _evaluate_markers(self._markers, current_environment) diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/requirements.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/requirements.py deleted file mode 100755 index 0d93231..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/requirements.py +++ /dev/null @@ -1,146 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import re -import string -import urllib.parse -from typing import List, Optional as TOptional, Set - -from setuptools.extern.pyparsing import ( # noqa - Combine, - Literal as L, - Optional, - ParseException, - Regex, - Word, - ZeroOrMore, - originalTextFor, - stringEnd, - stringStart, -) - -from .markers import MARKER_EXPR, Marker -from .specifiers import LegacySpecifier, Specifier, SpecifierSet - - -class InvalidRequirement(ValueError): - """ - An invalid requirement was found, users should refer to PEP 508. - """ - - -ALPHANUM = Word(string.ascii_letters + string.digits) - -LBRACKET = L("[").suppress() -RBRACKET = L("]").suppress() -LPAREN = L("(").suppress() -RPAREN = L(")").suppress() -COMMA = L(",").suppress() -SEMICOLON = L(";").suppress() -AT = L("@").suppress() - -PUNCTUATION = Word("-_.") -IDENTIFIER_END = ALPHANUM | (ZeroOrMore(PUNCTUATION) + ALPHANUM) -IDENTIFIER = Combine(ALPHANUM + ZeroOrMore(IDENTIFIER_END)) - -NAME = IDENTIFIER("name") -EXTRA = IDENTIFIER - -URI = Regex(r"[^ ]+")("url") -URL = AT + URI - -EXTRAS_LIST = EXTRA + ZeroOrMore(COMMA + EXTRA) -EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)("extras") - -VERSION_PEP440 = Regex(Specifier._regex_str, re.VERBOSE | re.IGNORECASE) -VERSION_LEGACY = Regex(LegacySpecifier._regex_str, re.VERBOSE | re.IGNORECASE) - -VERSION_ONE = VERSION_PEP440 ^ VERSION_LEGACY -VERSION_MANY = Combine( - VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE), joinString=",", adjacent=False -)("_raw_spec") -_VERSION_SPEC = Optional((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY) -_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or "") - -VERSION_SPEC = originalTextFor(_VERSION_SPEC)("specifier") -VERSION_SPEC.setParseAction(lambda s, l, t: t[1]) - -MARKER_EXPR = originalTextFor(MARKER_EXPR())("marker") -MARKER_EXPR.setParseAction( - lambda s, l, t: Marker(s[t._original_start : t._original_end]) -) -MARKER_SEPARATOR = SEMICOLON -MARKER = MARKER_SEPARATOR + MARKER_EXPR - -VERSION_AND_MARKER = VERSION_SPEC + Optional(MARKER) -URL_AND_MARKER = URL + Optional(MARKER) - -NAMED_REQUIREMENT = NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER) - -REQUIREMENT = stringStart + NAMED_REQUIREMENT + stringEnd -# setuptools.extern.pyparsing isn't thread safe during initialization, so we do it eagerly, see -# issue #104 -REQUIREMENT.parseString("x[]") - - -class Requirement: - """Parse a requirement. - - Parse a given requirement string into its parts, such as name, specifier, - URL, and extras. Raises InvalidRequirement on a badly-formed requirement - string. - """ - - # TODO: Can we test whether something is contained within a requirement? - # If so how do we do that? Do we need to test against the _name_ of - # the thing as well as the version? What about the markers? - # TODO: Can we normalize the name and extra name? - - def __init__(self, requirement_string: str) -> None: - try: - req = REQUIREMENT.parseString(requirement_string) - except ParseException as e: - raise InvalidRequirement( - f'Parse error at "{ requirement_string[e.loc : e.loc + 8]!r}": {e.msg}' - ) - - self.name: str = req.name - if req.url: - parsed_url = urllib.parse.urlparse(req.url) - if parsed_url.scheme == "file": - if urllib.parse.urlunparse(parsed_url) != req.url: - raise InvalidRequirement("Invalid URL given") - elif not (parsed_url.scheme and parsed_url.netloc) or ( - not parsed_url.scheme and not parsed_url.netloc - ): - raise InvalidRequirement(f"Invalid URL: {req.url}") - self.url: TOptional[str] = req.url - else: - self.url = None - self.extras: Set[str] = set(req.extras.asList() if req.extras else []) - self.specifier: SpecifierSet = SpecifierSet(req.specifier) - self.marker: TOptional[Marker] = req.marker if req.marker else None - - def __str__(self) -> str: - parts: List[str] = [self.name] - - if self.extras: - formatted_extras = ",".join(sorted(self.extras)) - parts.append(f"[{formatted_extras}]") - - if self.specifier: - parts.append(str(self.specifier)) - - if self.url: - parts.append(f"@ {self.url}") - if self.marker: - parts.append(" ") - - if self.marker: - parts.append(f"; {self.marker}") - - return "".join(parts) - - def __repr__(self) -> str: - return f"" diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/specifiers.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/specifiers.py deleted file mode 100755 index 0e218a6..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/specifiers.py +++ /dev/null @@ -1,802 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import abc -import functools -import itertools -import re -import warnings -from typing import ( - Callable, - Dict, - Iterable, - Iterator, - List, - Optional, - Pattern, - Set, - Tuple, - TypeVar, - Union, -) - -from .utils import canonicalize_version -from .version import LegacyVersion, Version, parse - -ParsedVersion = Union[Version, LegacyVersion] -UnparsedVersion = Union[Version, LegacyVersion, str] -VersionTypeVar = TypeVar("VersionTypeVar", bound=UnparsedVersion) -CallableOperator = Callable[[ParsedVersion, str], bool] - - -class InvalidSpecifier(ValueError): - """ - An invalid specifier was found, users should refer to PEP 440. - """ - - -class BaseSpecifier(metaclass=abc.ABCMeta): - @abc.abstractmethod - def __str__(self) -> str: - """ - Returns the str representation of this Specifier like object. This - should be representative of the Specifier itself. - """ - - @abc.abstractmethod - def __hash__(self) -> int: - """ - Returns a hash value for this Specifier like object. - """ - - @abc.abstractmethod - def __eq__(self, other: object) -> bool: - """ - Returns a boolean representing whether or not the two Specifier like - objects are equal. - """ - - @abc.abstractproperty - def prereleases(self) -> Optional[bool]: - """ - Returns whether or not pre-releases as a whole are allowed by this - specifier. - """ - - @prereleases.setter - def prereleases(self, value: bool) -> None: - """ - Sets whether or not pre-releases as a whole are allowed by this - specifier. - """ - - @abc.abstractmethod - def contains(self, item: str, prereleases: Optional[bool] = None) -> bool: - """ - Determines if the given item is contained within this specifier. - """ - - @abc.abstractmethod - def filter( - self, iterable: Iterable[VersionTypeVar], prereleases: Optional[bool] = None - ) -> Iterable[VersionTypeVar]: - """ - Takes an iterable of items and filters them so that only items which - are contained within this specifier are allowed in it. - """ - - -class _IndividualSpecifier(BaseSpecifier): - - _operators: Dict[str, str] = {} - _regex: Pattern[str] - - def __init__(self, spec: str = "", prereleases: Optional[bool] = None) -> None: - match = self._regex.search(spec) - if not match: - raise InvalidSpecifier(f"Invalid specifier: '{spec}'") - - self._spec: Tuple[str, str] = ( - match.group("operator").strip(), - match.group("version").strip(), - ) - - # Store whether or not this Specifier should accept prereleases - self._prereleases = prereleases - - def __repr__(self) -> str: - pre = ( - f", prereleases={self.prereleases!r}" - if self._prereleases is not None - else "" - ) - - return f"<{self.__class__.__name__}({str(self)!r}{pre})>" - - def __str__(self) -> str: - return "{}{}".format(*self._spec) - - @property - def _canonical_spec(self) -> Tuple[str, str]: - return self._spec[0], canonicalize_version(self._spec[1]) - - def __hash__(self) -> int: - return hash(self._canonical_spec) - - def __eq__(self, other: object) -> bool: - if isinstance(other, str): - try: - other = self.__class__(str(other)) - except InvalidSpecifier: - return NotImplemented - elif not isinstance(other, self.__class__): - return NotImplemented - - return self._canonical_spec == other._canonical_spec - - def _get_operator(self, op: str) -> CallableOperator: - operator_callable: CallableOperator = getattr( - self, f"_compare_{self._operators[op]}" - ) - return operator_callable - - def _coerce_version(self, version: UnparsedVersion) -> ParsedVersion: - if not isinstance(version, (LegacyVersion, Version)): - version = parse(version) - return version - - @property - def operator(self) -> str: - return self._spec[0] - - @property - def version(self) -> str: - return self._spec[1] - - @property - def prereleases(self) -> Optional[bool]: - return self._prereleases - - @prereleases.setter - def prereleases(self, value: bool) -> None: - self._prereleases = value - - def __contains__(self, item: str) -> bool: - return self.contains(item) - - def contains( - self, item: UnparsedVersion, prereleases: Optional[bool] = None - ) -> bool: - - # Determine if prereleases are to be allowed or not. - if prereleases is None: - prereleases = self.prereleases - - # Normalize item to a Version or LegacyVersion, this allows us to have - # a shortcut for ``"2.0" in Specifier(">=2") - normalized_item = self._coerce_version(item) - - # Determine if we should be supporting prereleases in this specifier - # or not, if we do not support prereleases than we can short circuit - # logic if this version is a prereleases. - if normalized_item.is_prerelease and not prereleases: - return False - - # Actually do the comparison to determine if this item is contained - # within this Specifier or not. - operator_callable: CallableOperator = self._get_operator(self.operator) - return operator_callable(normalized_item, self.version) - - def filter( - self, iterable: Iterable[VersionTypeVar], prereleases: Optional[bool] = None - ) -> Iterable[VersionTypeVar]: - - yielded = False - found_prereleases = [] - - kw = {"prereleases": prereleases if prereleases is not None else True} - - # Attempt to iterate over all the values in the iterable and if any of - # them match, yield them. - for version in iterable: - parsed_version = self._coerce_version(version) - - if self.contains(parsed_version, **kw): - # If our version is a prerelease, and we were not set to allow - # prereleases, then we'll store it for later in case nothing - # else matches this specifier. - if parsed_version.is_prerelease and not ( - prereleases or self.prereleases - ): - found_prereleases.append(version) - # Either this is not a prerelease, or we should have been - # accepting prereleases from the beginning. - else: - yielded = True - yield version - - # Now that we've iterated over everything, determine if we've yielded - # any values, and if we have not and we have any prereleases stored up - # then we will go ahead and yield the prereleases. - if not yielded and found_prereleases: - for version in found_prereleases: - yield version - - -class LegacySpecifier(_IndividualSpecifier): - - _regex_str = r""" - (?P(==|!=|<=|>=|<|>)) - \s* - (?P - [^,;\s)]* # Since this is a "legacy" specifier, and the version - # string can be just about anything, we match everything - # except for whitespace, a semi-colon for marker support, - # a closing paren since versions can be enclosed in - # them, and a comma since it's a version separator. - ) - """ - - _regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE) - - _operators = { - "==": "equal", - "!=": "not_equal", - "<=": "less_than_equal", - ">=": "greater_than_equal", - "<": "less_than", - ">": "greater_than", - } - - def __init__(self, spec: str = "", prereleases: Optional[bool] = None) -> None: - super().__init__(spec, prereleases) - - warnings.warn( - "Creating a LegacyVersion has been deprecated and will be " - "removed in the next major release", - DeprecationWarning, - ) - - def _coerce_version(self, version: UnparsedVersion) -> LegacyVersion: - if not isinstance(version, LegacyVersion): - version = LegacyVersion(str(version)) - return version - - def _compare_equal(self, prospective: LegacyVersion, spec: str) -> bool: - return prospective == self._coerce_version(spec) - - def _compare_not_equal(self, prospective: LegacyVersion, spec: str) -> bool: - return prospective != self._coerce_version(spec) - - def _compare_less_than_equal(self, prospective: LegacyVersion, spec: str) -> bool: - return prospective <= self._coerce_version(spec) - - def _compare_greater_than_equal( - self, prospective: LegacyVersion, spec: str - ) -> bool: - return prospective >= self._coerce_version(spec) - - def _compare_less_than(self, prospective: LegacyVersion, spec: str) -> bool: - return prospective < self._coerce_version(spec) - - def _compare_greater_than(self, prospective: LegacyVersion, spec: str) -> bool: - return prospective > self._coerce_version(spec) - - -def _require_version_compare( - fn: Callable[["Specifier", ParsedVersion, str], bool] -) -> Callable[["Specifier", ParsedVersion, str], bool]: - @functools.wraps(fn) - def wrapped(self: "Specifier", prospective: ParsedVersion, spec: str) -> bool: - if not isinstance(prospective, Version): - return False - return fn(self, prospective, spec) - - return wrapped - - -class Specifier(_IndividualSpecifier): - - _regex_str = r""" - (?P(~=|==|!=|<=|>=|<|>|===)) - (?P - (?: - # The identity operators allow for an escape hatch that will - # do an exact string match of the version you wish to install. - # This will not be parsed by PEP 440 and we cannot determine - # any semantic meaning from it. This operator is discouraged - # but included entirely as an escape hatch. - (?<====) # Only match for the identity operator - \s* - [^\s]* # We just match everything, except for whitespace - # since we are only testing for strict identity. - ) - | - (?: - # The (non)equality operators allow for wild card and local - # versions to be specified so we have to define these two - # operators separately to enable that. - (?<===|!=) # Only match for equals and not equals - - \s* - v? - (?:[0-9]+!)? # epoch - [0-9]+(?:\.[0-9]+)* # release - (?: # pre release - [-_\.]? - (a|b|c|rc|alpha|beta|pre|preview) - [-_\.]? - [0-9]* - )? - (?: # post release - (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) - )? - - # You cannot use a wild card and a dev or local version - # together so group them with a | and make them optional. - (?: - (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release - (?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local - | - \.\* # Wild card syntax of .* - )? - ) - | - (?: - # The compatible operator requires at least two digits in the - # release segment. - (?<=~=) # Only match for the compatible operator - - \s* - v? - (?:[0-9]+!)? # epoch - [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *) - (?: # pre release - [-_\.]? - (a|b|c|rc|alpha|beta|pre|preview) - [-_\.]? - [0-9]* - )? - (?: # post release - (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) - )? - (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release - ) - | - (?: - # All other operators only allow a sub set of what the - # (non)equality operators do. Specifically they do not allow - # local versions to be specified nor do they allow the prefix - # matching wild cards. - (?=": "greater_than_equal", - "<": "less_than", - ">": "greater_than", - "===": "arbitrary", - } - - @_require_version_compare - def _compare_compatible(self, prospective: ParsedVersion, spec: str) -> bool: - - # Compatible releases have an equivalent combination of >= and ==. That - # is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to - # implement this in terms of the other specifiers instead of - # implementing it ourselves. The only thing we need to do is construct - # the other specifiers. - - # We want everything but the last item in the version, but we want to - # ignore suffix segments. - prefix = ".".join( - list(itertools.takewhile(_is_not_suffix, _version_split(spec)))[:-1] - ) - - # Add the prefix notation to the end of our string - prefix += ".*" - - return self._get_operator(">=")(prospective, spec) and self._get_operator("==")( - prospective, prefix - ) - - @_require_version_compare - def _compare_equal(self, prospective: ParsedVersion, spec: str) -> bool: - - # We need special logic to handle prefix matching - if spec.endswith(".*"): - # In the case of prefix matching we want to ignore local segment. - prospective = Version(prospective.public) - # Split the spec out by dots, and pretend that there is an implicit - # dot in between a release segment and a pre-release segment. - split_spec = _version_split(spec[:-2]) # Remove the trailing .* - - # Split the prospective version out by dots, and pretend that there - # is an implicit dot in between a release segment and a pre-release - # segment. - split_prospective = _version_split(str(prospective)) - - # Shorten the prospective version to be the same length as the spec - # so that we can determine if the specifier is a prefix of the - # prospective version or not. - shortened_prospective = split_prospective[: len(split_spec)] - - # Pad out our two sides with zeros so that they both equal the same - # length. - padded_spec, padded_prospective = _pad_version( - split_spec, shortened_prospective - ) - - return padded_prospective == padded_spec - else: - # Convert our spec string into a Version - spec_version = Version(spec) - - # If the specifier does not have a local segment, then we want to - # act as if the prospective version also does not have a local - # segment. - if not spec_version.local: - prospective = Version(prospective.public) - - return prospective == spec_version - - @_require_version_compare - def _compare_not_equal(self, prospective: ParsedVersion, spec: str) -> bool: - return not self._compare_equal(prospective, spec) - - @_require_version_compare - def _compare_less_than_equal(self, prospective: ParsedVersion, spec: str) -> bool: - - # NB: Local version identifiers are NOT permitted in the version - # specifier, so local version labels can be universally removed from - # the prospective version. - return Version(prospective.public) <= Version(spec) - - @_require_version_compare - def _compare_greater_than_equal( - self, prospective: ParsedVersion, spec: str - ) -> bool: - - # NB: Local version identifiers are NOT permitted in the version - # specifier, so local version labels can be universally removed from - # the prospective version. - return Version(prospective.public) >= Version(spec) - - @_require_version_compare - def _compare_less_than(self, prospective: ParsedVersion, spec_str: str) -> bool: - - # Convert our spec to a Version instance, since we'll want to work with - # it as a version. - spec = Version(spec_str) - - # Check to see if the prospective version is less than the spec - # version. If it's not we can short circuit and just return False now - # instead of doing extra unneeded work. - if not prospective < spec: - return False - - # This special case is here so that, unless the specifier itself - # includes is a pre-release version, that we do not accept pre-release - # versions for the version mentioned in the specifier (e.g. <3.1 should - # not match 3.1.dev0, but should match 3.0.dev0). - if not spec.is_prerelease and prospective.is_prerelease: - if Version(prospective.base_version) == Version(spec.base_version): - return False - - # If we've gotten to here, it means that prospective version is both - # less than the spec version *and* it's not a pre-release of the same - # version in the spec. - return True - - @_require_version_compare - def _compare_greater_than(self, prospective: ParsedVersion, spec_str: str) -> bool: - - # Convert our spec to a Version instance, since we'll want to work with - # it as a version. - spec = Version(spec_str) - - # Check to see if the prospective version is greater than the spec - # version. If it's not we can short circuit and just return False now - # instead of doing extra unneeded work. - if not prospective > spec: - return False - - # This special case is here so that, unless the specifier itself - # includes is a post-release version, that we do not accept - # post-release versions for the version mentioned in the specifier - # (e.g. >3.1 should not match 3.0.post0, but should match 3.2.post0). - if not spec.is_postrelease and prospective.is_postrelease: - if Version(prospective.base_version) == Version(spec.base_version): - return False - - # Ensure that we do not allow a local version of the version mentioned - # in the specifier, which is technically greater than, to match. - if prospective.local is not None: - if Version(prospective.base_version) == Version(spec.base_version): - return False - - # If we've gotten to here, it means that prospective version is both - # greater than the spec version *and* it's not a pre-release of the - # same version in the spec. - return True - - def _compare_arbitrary(self, prospective: Version, spec: str) -> bool: - return str(prospective).lower() == str(spec).lower() - - @property - def prereleases(self) -> bool: - - # If there is an explicit prereleases set for this, then we'll just - # blindly use that. - if self._prereleases is not None: - return self._prereleases - - # Look at all of our specifiers and determine if they are inclusive - # operators, and if they are if they are including an explicit - # prerelease. - operator, version = self._spec - if operator in ["==", ">=", "<=", "~=", "==="]: - # The == specifier can include a trailing .*, if it does we - # want to remove before parsing. - if operator == "==" and version.endswith(".*"): - version = version[:-2] - - # Parse the version, and if it is a pre-release than this - # specifier allows pre-releases. - if parse(version).is_prerelease: - return True - - return False - - @prereleases.setter - def prereleases(self, value: bool) -> None: - self._prereleases = value - - -_prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$") - - -def _version_split(version: str) -> List[str]: - result: List[str] = [] - for item in version.split("."): - match = _prefix_regex.search(item) - if match: - result.extend(match.groups()) - else: - result.append(item) - return result - - -def _is_not_suffix(segment: str) -> bool: - return not any( - segment.startswith(prefix) for prefix in ("dev", "a", "b", "rc", "post") - ) - - -def _pad_version(left: List[str], right: List[str]) -> Tuple[List[str], List[str]]: - left_split, right_split = [], [] - - # Get the release segment of our versions - left_split.append(list(itertools.takewhile(lambda x: x.isdigit(), left))) - right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right))) - - # Get the rest of our versions - left_split.append(left[len(left_split[0]) :]) - right_split.append(right[len(right_split[0]) :]) - - # Insert our padding - left_split.insert(1, ["0"] * max(0, len(right_split[0]) - len(left_split[0]))) - right_split.insert(1, ["0"] * max(0, len(left_split[0]) - len(right_split[0]))) - - return (list(itertools.chain(*left_split)), list(itertools.chain(*right_split))) - - -class SpecifierSet(BaseSpecifier): - def __init__( - self, specifiers: str = "", prereleases: Optional[bool] = None - ) -> None: - - # Split on , to break each individual specifier into it's own item, and - # strip each item to remove leading/trailing whitespace. - split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()] - - # Parsed each individual specifier, attempting first to make it a - # Specifier and falling back to a LegacySpecifier. - parsed: Set[_IndividualSpecifier] = set() - for specifier in split_specifiers: - try: - parsed.add(Specifier(specifier)) - except InvalidSpecifier: - parsed.add(LegacySpecifier(specifier)) - - # Turn our parsed specifiers into a frozen set and save them for later. - self._specs = frozenset(parsed) - - # Store our prereleases value so we can use it later to determine if - # we accept prereleases or not. - self._prereleases = prereleases - - def __repr__(self) -> str: - pre = ( - f", prereleases={self.prereleases!r}" - if self._prereleases is not None - else "" - ) - - return f"" - - def __str__(self) -> str: - return ",".join(sorted(str(s) for s in self._specs)) - - def __hash__(self) -> int: - return hash(self._specs) - - def __and__(self, other: Union["SpecifierSet", str]) -> "SpecifierSet": - if isinstance(other, str): - other = SpecifierSet(other) - elif not isinstance(other, SpecifierSet): - return NotImplemented - - specifier = SpecifierSet() - specifier._specs = frozenset(self._specs | other._specs) - - if self._prereleases is None and other._prereleases is not None: - specifier._prereleases = other._prereleases - elif self._prereleases is not None and other._prereleases is None: - specifier._prereleases = self._prereleases - elif self._prereleases == other._prereleases: - specifier._prereleases = self._prereleases - else: - raise ValueError( - "Cannot combine SpecifierSets with True and False prerelease " - "overrides." - ) - - return specifier - - def __eq__(self, other: object) -> bool: - if isinstance(other, (str, _IndividualSpecifier)): - other = SpecifierSet(str(other)) - elif not isinstance(other, SpecifierSet): - return NotImplemented - - return self._specs == other._specs - - def __len__(self) -> int: - return len(self._specs) - - def __iter__(self) -> Iterator[_IndividualSpecifier]: - return iter(self._specs) - - @property - def prereleases(self) -> Optional[bool]: - - # If we have been given an explicit prerelease modifier, then we'll - # pass that through here. - if self._prereleases is not None: - return self._prereleases - - # If we don't have any specifiers, and we don't have a forced value, - # then we'll just return None since we don't know if this should have - # pre-releases or not. - if not self._specs: - return None - - # Otherwise we'll see if any of the given specifiers accept - # prereleases, if any of them do we'll return True, otherwise False. - return any(s.prereleases for s in self._specs) - - @prereleases.setter - def prereleases(self, value: bool) -> None: - self._prereleases = value - - def __contains__(self, item: UnparsedVersion) -> bool: - return self.contains(item) - - def contains( - self, item: UnparsedVersion, prereleases: Optional[bool] = None - ) -> bool: - - # Ensure that our item is a Version or LegacyVersion instance. - if not isinstance(item, (LegacyVersion, Version)): - item = parse(item) - - # Determine if we're forcing a prerelease or not, if we're not forcing - # one for this particular filter call, then we'll use whatever the - # SpecifierSet thinks for whether or not we should support prereleases. - if prereleases is None: - prereleases = self.prereleases - - # We can determine if we're going to allow pre-releases by looking to - # see if any of the underlying items supports them. If none of them do - # and this item is a pre-release then we do not allow it and we can - # short circuit that here. - # Note: This means that 1.0.dev1 would not be contained in something - # like >=1.0.devabc however it would be in >=1.0.debabc,>0.0.dev0 - if not prereleases and item.is_prerelease: - return False - - # We simply dispatch to the underlying specs here to make sure that the - # given version is contained within all of them. - # Note: This use of all() here means that an empty set of specifiers - # will always return True, this is an explicit design decision. - return all(s.contains(item, prereleases=prereleases) for s in self._specs) - - def filter( - self, iterable: Iterable[VersionTypeVar], prereleases: Optional[bool] = None - ) -> Iterable[VersionTypeVar]: - - # Determine if we're forcing a prerelease or not, if we're not forcing - # one for this particular filter call, then we'll use whatever the - # SpecifierSet thinks for whether or not we should support prereleases. - if prereleases is None: - prereleases = self.prereleases - - # If we have any specifiers, then we want to wrap our iterable in the - # filter method for each one, this will act as a logical AND amongst - # each specifier. - if self._specs: - for spec in self._specs: - iterable = spec.filter(iterable, prereleases=bool(prereleases)) - return iterable - # If we do not have any specifiers, then we need to have a rough filter - # which will filter out any pre-releases, unless there are no final - # releases, and which will filter out LegacyVersion in general. - else: - filtered: List[VersionTypeVar] = [] - found_prereleases: List[VersionTypeVar] = [] - - item: UnparsedVersion - parsed_version: Union[Version, LegacyVersion] - - for item in iterable: - # Ensure that we some kind of Version class for this item. - if not isinstance(item, (LegacyVersion, Version)): - parsed_version = parse(item) - else: - parsed_version = item - - # Filter out any item which is parsed as a LegacyVersion - if isinstance(parsed_version, LegacyVersion): - continue - - # Store any item which is a pre-release for later unless we've - # already found a final version or we are accepting prereleases - if parsed_version.is_prerelease and not prereleases: - if not filtered: - found_prereleases.append(item) - else: - filtered.append(item) - - # If we've found no items except for pre-releases, then we'll go - # ahead and use the pre-releases - if not filtered and found_prereleases and prereleases is None: - return found_prereleases - - return filtered diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/tags.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/tags.py deleted file mode 100755 index 9a3d25a..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/tags.py +++ /dev/null @@ -1,487 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import logging -import platform -import sys -import sysconfig -from importlib.machinery import EXTENSION_SUFFIXES -from typing import ( - Dict, - FrozenSet, - Iterable, - Iterator, - List, - Optional, - Sequence, - Tuple, - Union, - cast, -) - -from . import _manylinux, _musllinux - -logger = logging.getLogger(__name__) - -PythonVersion = Sequence[int] -MacVersion = Tuple[int, int] - -INTERPRETER_SHORT_NAMES: Dict[str, str] = { - "python": "py", # Generic. - "cpython": "cp", - "pypy": "pp", - "ironpython": "ip", - "jython": "jy", -} - - -_32_BIT_INTERPRETER = sys.maxsize <= 2 ** 32 - - -class Tag: - """ - A representation of the tag triple for a wheel. - - Instances are considered immutable and thus are hashable. Equality checking - is also supported. - """ - - __slots__ = ["_interpreter", "_abi", "_platform", "_hash"] - - def __init__(self, interpreter: str, abi: str, platform: str) -> None: - self._interpreter = interpreter.lower() - self._abi = abi.lower() - self._platform = platform.lower() - # The __hash__ of every single element in a Set[Tag] will be evaluated each time - # that a set calls its `.disjoint()` method, which may be called hundreds of - # times when scanning a page of links for packages with tags matching that - # Set[Tag]. Pre-computing the value here produces significant speedups for - # downstream consumers. - self._hash = hash((self._interpreter, self._abi, self._platform)) - - @property - def interpreter(self) -> str: - return self._interpreter - - @property - def abi(self) -> str: - return self._abi - - @property - def platform(self) -> str: - return self._platform - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Tag): - return NotImplemented - - return ( - (self._hash == other._hash) # Short-circuit ASAP for perf reasons. - and (self._platform == other._platform) - and (self._abi == other._abi) - and (self._interpreter == other._interpreter) - ) - - def __hash__(self) -> int: - return self._hash - - def __str__(self) -> str: - return f"{self._interpreter}-{self._abi}-{self._platform}" - - def __repr__(self) -> str: - return f"<{self} @ {id(self)}>" - - -def parse_tag(tag: str) -> FrozenSet[Tag]: - """ - Parses the provided tag (e.g. `py3-none-any`) into a frozenset of Tag instances. - - Returning a set is required due to the possibility that the tag is a - compressed tag set. - """ - tags = set() - interpreters, abis, platforms = tag.split("-") - for interpreter in interpreters.split("."): - for abi in abis.split("."): - for platform_ in platforms.split("."): - tags.add(Tag(interpreter, abi, platform_)) - return frozenset(tags) - - -def _get_config_var(name: str, warn: bool = False) -> Union[int, str, None]: - value = sysconfig.get_config_var(name) - if value is None and warn: - logger.debug( - "Config variable '%s' is unset, Python ABI tag may be incorrect", name - ) - return value - - -def _normalize_string(string: str) -> str: - return string.replace(".", "_").replace("-", "_") - - -def _abi3_applies(python_version: PythonVersion) -> bool: - """ - Determine if the Python version supports abi3. - - PEP 384 was first implemented in Python 3.2. - """ - return len(python_version) > 1 and tuple(python_version) >= (3, 2) - - -def _cpython_abis(py_version: PythonVersion, warn: bool = False) -> List[str]: - py_version = tuple(py_version) # To allow for version comparison. - abis = [] - version = _version_nodot(py_version[:2]) - debug = pymalloc = ucs4 = "" - with_debug = _get_config_var("Py_DEBUG", warn) - has_refcount = hasattr(sys, "gettotalrefcount") - # Windows doesn't set Py_DEBUG, so checking for support of debug-compiled - # extension modules is the best option. - # https://github.com/pypa/pip/issues/3383#issuecomment-173267692 - has_ext = "_d.pyd" in EXTENSION_SUFFIXES - if with_debug or (with_debug is None and (has_refcount or has_ext)): - debug = "d" - if py_version < (3, 8): - with_pymalloc = _get_config_var("WITH_PYMALLOC", warn) - if with_pymalloc or with_pymalloc is None: - pymalloc = "m" - if py_version < (3, 3): - unicode_size = _get_config_var("Py_UNICODE_SIZE", warn) - if unicode_size == 4 or ( - unicode_size is None and sys.maxunicode == 0x10FFFF - ): - ucs4 = "u" - elif debug: - # Debug builds can also load "normal" extension modules. - # We can also assume no UCS-4 or pymalloc requirement. - abis.append(f"cp{version}") - abis.insert( - 0, - "cp{version}{debug}{pymalloc}{ucs4}".format( - version=version, debug=debug, pymalloc=pymalloc, ucs4=ucs4 - ), - ) - return abis - - -def cpython_tags( - python_version: Optional[PythonVersion] = None, - abis: Optional[Iterable[str]] = None, - platforms: Optional[Iterable[str]] = None, - *, - warn: bool = False, -) -> Iterator[Tag]: - """ - Yields the tags for a CPython interpreter. - - The tags consist of: - - cp-- - - cp-abi3- - - cp-none- - - cp-abi3- # Older Python versions down to 3.2. - - If python_version only specifies a major version then user-provided ABIs and - the 'none' ABItag will be used. - - If 'abi3' or 'none' are specified in 'abis' then they will be yielded at - their normal position and not at the beginning. - """ - if not python_version: - python_version = sys.version_info[:2] - - interpreter = f"cp{_version_nodot(python_version[:2])}" - - if abis is None: - if len(python_version) > 1: - abis = _cpython_abis(python_version, warn) - else: - abis = [] - abis = list(abis) - # 'abi3' and 'none' are explicitly handled later. - for explicit_abi in ("abi3", "none"): - try: - abis.remove(explicit_abi) - except ValueError: - pass - - platforms = list(platforms or platform_tags()) - for abi in abis: - for platform_ in platforms: - yield Tag(interpreter, abi, platform_) - if _abi3_applies(python_version): - yield from (Tag(interpreter, "abi3", platform_) for platform_ in platforms) - yield from (Tag(interpreter, "none", platform_) for platform_ in platforms) - - if _abi3_applies(python_version): - for minor_version in range(python_version[1] - 1, 1, -1): - for platform_ in platforms: - interpreter = "cp{version}".format( - version=_version_nodot((python_version[0], minor_version)) - ) - yield Tag(interpreter, "abi3", platform_) - - -def _generic_abi() -> Iterator[str]: - abi = sysconfig.get_config_var("SOABI") - if abi: - yield _normalize_string(abi) - - -def generic_tags( - interpreter: Optional[str] = None, - abis: Optional[Iterable[str]] = None, - platforms: Optional[Iterable[str]] = None, - *, - warn: bool = False, -) -> Iterator[Tag]: - """ - Yields the tags for a generic interpreter. - - The tags consist of: - - -- - - The "none" ABI will be added if it was not explicitly provided. - """ - if not interpreter: - interp_name = interpreter_name() - interp_version = interpreter_version(warn=warn) - interpreter = "".join([interp_name, interp_version]) - if abis is None: - abis = _generic_abi() - platforms = list(platforms or platform_tags()) - abis = list(abis) - if "none" not in abis: - abis.append("none") - for abi in abis: - for platform_ in platforms: - yield Tag(interpreter, abi, platform_) - - -def _py_interpreter_range(py_version: PythonVersion) -> Iterator[str]: - """ - Yields Python versions in descending order. - - After the latest version, the major-only version will be yielded, and then - all previous versions of that major version. - """ - if len(py_version) > 1: - yield f"py{_version_nodot(py_version[:2])}" - yield f"py{py_version[0]}" - if len(py_version) > 1: - for minor in range(py_version[1] - 1, -1, -1): - yield f"py{_version_nodot((py_version[0], minor))}" - - -def compatible_tags( - python_version: Optional[PythonVersion] = None, - interpreter: Optional[str] = None, - platforms: Optional[Iterable[str]] = None, -) -> Iterator[Tag]: - """ - Yields the sequence of tags that are compatible with a specific version of Python. - - The tags consist of: - - py*-none- - - -none-any # ... if `interpreter` is provided. - - py*-none-any - """ - if not python_version: - python_version = sys.version_info[:2] - platforms = list(platforms or platform_tags()) - for version in _py_interpreter_range(python_version): - for platform_ in platforms: - yield Tag(version, "none", platform_) - if interpreter: - yield Tag(interpreter, "none", "any") - for version in _py_interpreter_range(python_version): - yield Tag(version, "none", "any") - - -def _mac_arch(arch: str, is_32bit: bool = _32_BIT_INTERPRETER) -> str: - if not is_32bit: - return arch - - if arch.startswith("ppc"): - return "ppc" - - return "i386" - - -def _mac_binary_formats(version: MacVersion, cpu_arch: str) -> List[str]: - formats = [cpu_arch] - if cpu_arch == "x86_64": - if version < (10, 4): - return [] - formats.extend(["intel", "fat64", "fat32"]) - - elif cpu_arch == "i386": - if version < (10, 4): - return [] - formats.extend(["intel", "fat32", "fat"]) - - elif cpu_arch == "ppc64": - # TODO: Need to care about 32-bit PPC for ppc64 through 10.2? - if version > (10, 5) or version < (10, 4): - return [] - formats.append("fat64") - - elif cpu_arch == "ppc": - if version > (10, 6): - return [] - formats.extend(["fat32", "fat"]) - - if cpu_arch in {"arm64", "x86_64"}: - formats.append("universal2") - - if cpu_arch in {"x86_64", "i386", "ppc64", "ppc", "intel"}: - formats.append("universal") - - return formats - - -def mac_platforms( - version: Optional[MacVersion] = None, arch: Optional[str] = None -) -> Iterator[str]: - """ - Yields the platform tags for a macOS system. - - The `version` parameter is a two-item tuple specifying the macOS version to - generate platform tags for. The `arch` parameter is the CPU architecture to - generate platform tags for. Both parameters default to the appropriate value - for the current system. - """ - version_str, _, cpu_arch = platform.mac_ver() - if version is None: - version = cast("MacVersion", tuple(map(int, version_str.split(".")[:2]))) - else: - version = version - if arch is None: - arch = _mac_arch(cpu_arch) - else: - arch = arch - - if (10, 0) <= version and version < (11, 0): - # Prior to Mac OS 11, each yearly release of Mac OS bumped the - # "minor" version number. The major version was always 10. - for minor_version in range(version[1], -1, -1): - compat_version = 10, minor_version - binary_formats = _mac_binary_formats(compat_version, arch) - for binary_format in binary_formats: - yield "macosx_{major}_{minor}_{binary_format}".format( - major=10, minor=minor_version, binary_format=binary_format - ) - - if version >= (11, 0): - # Starting with Mac OS 11, each yearly release bumps the major version - # number. The minor versions are now the midyear updates. - for major_version in range(version[0], 10, -1): - compat_version = major_version, 0 - binary_formats = _mac_binary_formats(compat_version, arch) - for binary_format in binary_formats: - yield "macosx_{major}_{minor}_{binary_format}".format( - major=major_version, minor=0, binary_format=binary_format - ) - - if version >= (11, 0): - # Mac OS 11 on x86_64 is compatible with binaries from previous releases. - # Arm64 support was introduced in 11.0, so no Arm binaries from previous - # releases exist. - # - # However, the "universal2" binary format can have a - # macOS version earlier than 11.0 when the x86_64 part of the binary supports - # that version of macOS. - if arch == "x86_64": - for minor_version in range(16, 3, -1): - compat_version = 10, minor_version - binary_formats = _mac_binary_formats(compat_version, arch) - for binary_format in binary_formats: - yield "macosx_{major}_{minor}_{binary_format}".format( - major=compat_version[0], - minor=compat_version[1], - binary_format=binary_format, - ) - else: - for minor_version in range(16, 3, -1): - compat_version = 10, minor_version - binary_format = "universal2" - yield "macosx_{major}_{minor}_{binary_format}".format( - major=compat_version[0], - minor=compat_version[1], - binary_format=binary_format, - ) - - -def _linux_platforms(is_32bit: bool = _32_BIT_INTERPRETER) -> Iterator[str]: - linux = _normalize_string(sysconfig.get_platform()) - if is_32bit: - if linux == "linux_x86_64": - linux = "linux_i686" - elif linux == "linux_aarch64": - linux = "linux_armv7l" - _, arch = linux.split("_", 1) - yield from _manylinux.platform_tags(linux, arch) - yield from _musllinux.platform_tags(arch) - yield linux - - -def _generic_platforms() -> Iterator[str]: - yield _normalize_string(sysconfig.get_platform()) - - -def platform_tags() -> Iterator[str]: - """ - Provides the platform tags for this installation. - """ - if platform.system() == "Darwin": - return mac_platforms() - elif platform.system() == "Linux": - return _linux_platforms() - else: - return _generic_platforms() - - -def interpreter_name() -> str: - """ - Returns the name of the running interpreter. - """ - name = sys.implementation.name - return INTERPRETER_SHORT_NAMES.get(name) or name - - -def interpreter_version(*, warn: bool = False) -> str: - """ - Returns the version of the running interpreter. - """ - version = _get_config_var("py_version_nodot", warn=warn) - if version: - version = str(version) - else: - version = _version_nodot(sys.version_info[:2]) - return version - - -def _version_nodot(version: PythonVersion) -> str: - return "".join(map(str, version)) - - -def sys_tags(*, warn: bool = False) -> Iterator[Tag]: - """ - Returns the sequence of tag triples for the running interpreter. - - The order of the sequence corresponds to priority order for the - interpreter, from most to least important. - """ - - interp_name = interpreter_name() - if interp_name == "cp": - yield from cpython_tags(warn=warn) - else: - yield from generic_tags() - - if interp_name == "pp": - yield from compatible_tags(interpreter="pp3") - else: - yield from compatible_tags() diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/utils.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/utils.py deleted file mode 100755 index bab11b8..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/utils.py +++ /dev/null @@ -1,136 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import re -from typing import FrozenSet, NewType, Tuple, Union, cast - -from .tags import Tag, parse_tag -from .version import InvalidVersion, Version - -BuildTag = Union[Tuple[()], Tuple[int, str]] -NormalizedName = NewType("NormalizedName", str) - - -class InvalidWheelFilename(ValueError): - """ - An invalid wheel filename was found, users should refer to PEP 427. - """ - - -class InvalidSdistFilename(ValueError): - """ - An invalid sdist filename was found, users should refer to the packaging user guide. - """ - - -_canonicalize_regex = re.compile(r"[-_.]+") -# PEP 427: The build number must start with a digit. -_build_tag_regex = re.compile(r"(\d+)(.*)") - - -def canonicalize_name(name: str) -> NormalizedName: - # This is taken from PEP 503. - value = _canonicalize_regex.sub("-", name).lower() - return cast(NormalizedName, value) - - -def canonicalize_version(version: Union[Version, str]) -> str: - """ - This is very similar to Version.__str__, but has one subtle difference - with the way it handles the release segment. - """ - if isinstance(version, str): - try: - parsed = Version(version) - except InvalidVersion: - # Legacy versions cannot be normalized - return version - else: - parsed = version - - parts = [] - - # Epoch - if parsed.epoch != 0: - parts.append(f"{parsed.epoch}!") - - # Release segment - # NB: This strips trailing '.0's to normalize - parts.append(re.sub(r"(\.0)+$", "", ".".join(str(x) for x in parsed.release))) - - # Pre-release - if parsed.pre is not None: - parts.append("".join(str(x) for x in parsed.pre)) - - # Post-release - if parsed.post is not None: - parts.append(f".post{parsed.post}") - - # Development release - if parsed.dev is not None: - parts.append(f".dev{parsed.dev}") - - # Local version segment - if parsed.local is not None: - parts.append(f"+{parsed.local}") - - return "".join(parts) - - -def parse_wheel_filename( - filename: str, -) -> Tuple[NormalizedName, Version, BuildTag, FrozenSet[Tag]]: - if not filename.endswith(".whl"): - raise InvalidWheelFilename( - f"Invalid wheel filename (extension must be '.whl'): {filename}" - ) - - filename = filename[:-4] - dashes = filename.count("-") - if dashes not in (4, 5): - raise InvalidWheelFilename( - f"Invalid wheel filename (wrong number of parts): {filename}" - ) - - parts = filename.split("-", dashes - 2) - name_part = parts[0] - # See PEP 427 for the rules on escaping the project name - if "__" in name_part or re.match(r"^[\w\d._]*$", name_part, re.UNICODE) is None: - raise InvalidWheelFilename(f"Invalid project name: {filename}") - name = canonicalize_name(name_part) - version = Version(parts[1]) - if dashes == 5: - build_part = parts[2] - build_match = _build_tag_regex.match(build_part) - if build_match is None: - raise InvalidWheelFilename( - f"Invalid build number: {build_part} in '{filename}'" - ) - build = cast(BuildTag, (int(build_match.group(1)), build_match.group(2))) - else: - build = () - tags = parse_tag(parts[-1]) - return (name, version, build, tags) - - -def parse_sdist_filename(filename: str) -> Tuple[NormalizedName, Version]: - if filename.endswith(".tar.gz"): - file_stem = filename[: -len(".tar.gz")] - elif filename.endswith(".zip"): - file_stem = filename[: -len(".zip")] - else: - raise InvalidSdistFilename( - f"Invalid sdist filename (extension must be '.tar.gz' or '.zip'):" - f" {filename}" - ) - - # We are requiring a PEP 440 version, which cannot contain dashes, - # so we split on the last dash. - name_part, sep, version_part = file_stem.rpartition("-") - if not sep: - raise InvalidSdistFilename(f"Invalid sdist filename: {filename}") - - name = canonicalize_name(name_part) - version = Version(version_part) - return (name, version) diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/version.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/version.py deleted file mode 100755 index de9a09a..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/packaging/version.py +++ /dev/null @@ -1,504 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -import collections -import itertools -import re -import warnings -from typing import Callable, Iterator, List, Optional, SupportsInt, Tuple, Union - -from ._structures import Infinity, InfinityType, NegativeInfinity, NegativeInfinityType - -__all__ = ["parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"] - -InfiniteTypes = Union[InfinityType, NegativeInfinityType] -PrePostDevType = Union[InfiniteTypes, Tuple[str, int]] -SubLocalType = Union[InfiniteTypes, int, str] -LocalType = Union[ - NegativeInfinityType, - Tuple[ - Union[ - SubLocalType, - Tuple[SubLocalType, str], - Tuple[NegativeInfinityType, SubLocalType], - ], - ..., - ], -] -CmpKey = Tuple[ - int, Tuple[int, ...], PrePostDevType, PrePostDevType, PrePostDevType, LocalType -] -LegacyCmpKey = Tuple[int, Tuple[str, ...]] -VersionComparisonMethod = Callable[ - [Union[CmpKey, LegacyCmpKey], Union[CmpKey, LegacyCmpKey]], bool -] - -_Version = collections.namedtuple( - "_Version", ["epoch", "release", "dev", "pre", "post", "local"] -) - - -def parse(version: str) -> Union["LegacyVersion", "Version"]: - """ - Parse the given version string and return either a :class:`Version` object - or a :class:`LegacyVersion` object depending on if the given version is - a valid PEP 440 version or a legacy version. - """ - try: - return Version(version) - except InvalidVersion: - return LegacyVersion(version) - - -class InvalidVersion(ValueError): - """ - An invalid version was found, users should refer to PEP 440. - """ - - -class _BaseVersion: - _key: Union[CmpKey, LegacyCmpKey] - - def __hash__(self) -> int: - return hash(self._key) - - # Please keep the duplicated `isinstance` check - # in the six comparisons hereunder - # unless you find a way to avoid adding overhead function calls. - def __lt__(self, other: "_BaseVersion") -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key < other._key - - def __le__(self, other: "_BaseVersion") -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key <= other._key - - def __eq__(self, other: object) -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key == other._key - - def __ge__(self, other: "_BaseVersion") -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key >= other._key - - def __gt__(self, other: "_BaseVersion") -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key > other._key - - def __ne__(self, other: object) -> bool: - if not isinstance(other, _BaseVersion): - return NotImplemented - - return self._key != other._key - - -class LegacyVersion(_BaseVersion): - def __init__(self, version: str) -> None: - self._version = str(version) - self._key = _legacy_cmpkey(self._version) - - warnings.warn( - "Creating a LegacyVersion has been deprecated and will be " - "removed in the next major release", - DeprecationWarning, - ) - - def __str__(self) -> str: - return self._version - - def __repr__(self) -> str: - return f"" - - @property - def public(self) -> str: - return self._version - - @property - def base_version(self) -> str: - return self._version - - @property - def epoch(self) -> int: - return -1 - - @property - def release(self) -> None: - return None - - @property - def pre(self) -> None: - return None - - @property - def post(self) -> None: - return None - - @property - def dev(self) -> None: - return None - - @property - def local(self) -> None: - return None - - @property - def is_prerelease(self) -> bool: - return False - - @property - def is_postrelease(self) -> bool: - return False - - @property - def is_devrelease(self) -> bool: - return False - - -_legacy_version_component_re = re.compile(r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE) - -_legacy_version_replacement_map = { - "pre": "c", - "preview": "c", - "-": "final-", - "rc": "c", - "dev": "@", -} - - -def _parse_version_parts(s: str) -> Iterator[str]: - for part in _legacy_version_component_re.split(s): - part = _legacy_version_replacement_map.get(part, part) - - if not part or part == ".": - continue - - if part[:1] in "0123456789": - # pad for numeric comparison - yield part.zfill(8) - else: - yield "*" + part - - # ensure that alpha/beta/candidate are before final - yield "*final" - - -def _legacy_cmpkey(version: str) -> LegacyCmpKey: - - # We hardcode an epoch of -1 here. A PEP 440 version can only have a epoch - # greater than or equal to 0. This will effectively put the LegacyVersion, - # which uses the defacto standard originally implemented by setuptools, - # as before all PEP 440 versions. - epoch = -1 - - # This scheme is taken from pkg_resources.parse_version setuptools prior to - # it's adoption of the packaging library. - parts: List[str] = [] - for part in _parse_version_parts(version.lower()): - if part.startswith("*"): - # remove "-" before a prerelease tag - if part < "*final": - while parts and parts[-1] == "*final-": - parts.pop() - - # remove trailing zeros from each series of numeric parts - while parts and parts[-1] == "00000000": - parts.pop() - - parts.append(part) - - return epoch, tuple(parts) - - -# Deliberately not anchored to the start and end of the string, to make it -# easier for 3rd party code to reuse -VERSION_PATTERN = r""" - v? - (?: - (?:(?P[0-9]+)!)? # epoch - (?P[0-9]+(?:\.[0-9]+)*) # release segment - (?P
                                          # pre-release
-            [-_\.]?
-            (?P(a|b|c|rc|alpha|beta|pre|preview))
-            [-_\.]?
-            (?P[0-9]+)?
-        )?
-        (?P                                         # post release
-            (?:-(?P[0-9]+))
-            |
-            (?:
-                [-_\.]?
-                (?Ppost|rev|r)
-                [-_\.]?
-                (?P[0-9]+)?
-            )
-        )?
-        (?P                                          # dev release
-            [-_\.]?
-            (?Pdev)
-            [-_\.]?
-            (?P[0-9]+)?
-        )?
-    )
-    (?:\+(?P[a-z0-9]+(?:[-_\.][a-z0-9]+)*))?       # local version
-"""
-
-
-class Version(_BaseVersion):
-
-    _regex = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE)
-
-    def __init__(self, version: str) -> None:
-
-        # Validate the version and parse it into pieces
-        match = self._regex.search(version)
-        if not match:
-            raise InvalidVersion(f"Invalid version: '{version}'")
-
-        # Store the parsed out pieces of the version
-        self._version = _Version(
-            epoch=int(match.group("epoch")) if match.group("epoch") else 0,
-            release=tuple(int(i) for i in match.group("release").split(".")),
-            pre=_parse_letter_version(match.group("pre_l"), match.group("pre_n")),
-            post=_parse_letter_version(
-                match.group("post_l"), match.group("post_n1") or match.group("post_n2")
-            ),
-            dev=_parse_letter_version(match.group("dev_l"), match.group("dev_n")),
-            local=_parse_local_version(match.group("local")),
-        )
-
-        # Generate a key which will be used for sorting
-        self._key = _cmpkey(
-            self._version.epoch,
-            self._version.release,
-            self._version.pre,
-            self._version.post,
-            self._version.dev,
-            self._version.local,
-        )
-
-    def __repr__(self) -> str:
-        return f""
-
-    def __str__(self) -> str:
-        parts = []
-
-        # Epoch
-        if self.epoch != 0:
-            parts.append(f"{self.epoch}!")
-
-        # Release segment
-        parts.append(".".join(str(x) for x in self.release))
-
-        # Pre-release
-        if self.pre is not None:
-            parts.append("".join(str(x) for x in self.pre))
-
-        # Post-release
-        if self.post is not None:
-            parts.append(f".post{self.post}")
-
-        # Development release
-        if self.dev is not None:
-            parts.append(f".dev{self.dev}")
-
-        # Local version segment
-        if self.local is not None:
-            parts.append(f"+{self.local}")
-
-        return "".join(parts)
-
-    @property
-    def epoch(self) -> int:
-        _epoch: int = self._version.epoch
-        return _epoch
-
-    @property
-    def release(self) -> Tuple[int, ...]:
-        _release: Tuple[int, ...] = self._version.release
-        return _release
-
-    @property
-    def pre(self) -> Optional[Tuple[str, int]]:
-        _pre: Optional[Tuple[str, int]] = self._version.pre
-        return _pre
-
-    @property
-    def post(self) -> Optional[int]:
-        return self._version.post[1] if self._version.post else None
-
-    @property
-    def dev(self) -> Optional[int]:
-        return self._version.dev[1] if self._version.dev else None
-
-    @property
-    def local(self) -> Optional[str]:
-        if self._version.local:
-            return ".".join(str(x) for x in self._version.local)
-        else:
-            return None
-
-    @property
-    def public(self) -> str:
-        return str(self).split("+", 1)[0]
-
-    @property
-    def base_version(self) -> str:
-        parts = []
-
-        # Epoch
-        if self.epoch != 0:
-            parts.append(f"{self.epoch}!")
-
-        # Release segment
-        parts.append(".".join(str(x) for x in self.release))
-
-        return "".join(parts)
-
-    @property
-    def is_prerelease(self) -> bool:
-        return self.dev is not None or self.pre is not None
-
-    @property
-    def is_postrelease(self) -> bool:
-        return self.post is not None
-
-    @property
-    def is_devrelease(self) -> bool:
-        return self.dev is not None
-
-    @property
-    def major(self) -> int:
-        return self.release[0] if len(self.release) >= 1 else 0
-
-    @property
-    def minor(self) -> int:
-        return self.release[1] if len(self.release) >= 2 else 0
-
-    @property
-    def micro(self) -> int:
-        return self.release[2] if len(self.release) >= 3 else 0
-
-
-def _parse_letter_version(
-    letter: str, number: Union[str, bytes, SupportsInt]
-) -> Optional[Tuple[str, int]]:
-
-    if letter:
-        # We consider there to be an implicit 0 in a pre-release if there is
-        # not a numeral associated with it.
-        if number is None:
-            number = 0
-
-        # We normalize any letters to their lower case form
-        letter = letter.lower()
-
-        # We consider some words to be alternate spellings of other words and
-        # in those cases we want to normalize the spellings to our preferred
-        # spelling.
-        if letter == "alpha":
-            letter = "a"
-        elif letter == "beta":
-            letter = "b"
-        elif letter in ["c", "pre", "preview"]:
-            letter = "rc"
-        elif letter in ["rev", "r"]:
-            letter = "post"
-
-        return letter, int(number)
-    if not letter and number:
-        # We assume if we are given a number, but we are not given a letter
-        # then this is using the implicit post release syntax (e.g. 1.0-1)
-        letter = "post"
-
-        return letter, int(number)
-
-    return None
-
-
-_local_version_separators = re.compile(r"[\._-]")
-
-
-def _parse_local_version(local: str) -> Optional[LocalType]:
-    """
-    Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve").
-    """
-    if local is not None:
-        return tuple(
-            part.lower() if not part.isdigit() else int(part)
-            for part in _local_version_separators.split(local)
-        )
-    return None
-
-
-def _cmpkey(
-    epoch: int,
-    release: Tuple[int, ...],
-    pre: Optional[Tuple[str, int]],
-    post: Optional[Tuple[str, int]],
-    dev: Optional[Tuple[str, int]],
-    local: Optional[Tuple[SubLocalType]],
-) -> CmpKey:
-
-    # When we compare a release version, we want to compare it with all of the
-    # trailing zeros removed. So we'll use a reverse the list, drop all the now
-    # leading zeros until we come to something non zero, then take the rest
-    # re-reverse it back into the correct order and make it a tuple and use
-    # that for our sorting key.
-    _release = tuple(
-        reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release))))
-    )
-
-    # We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0.
-    # We'll do this by abusing the pre segment, but we _only_ want to do this
-    # if there is not a pre or a post segment. If we have one of those then
-    # the normal sorting rules will handle this case correctly.
-    if pre is None and post is None and dev is not None:
-        _pre: PrePostDevType = NegativeInfinity
-    # Versions without a pre-release (except as noted above) should sort after
-    # those with one.
-    elif pre is None:
-        _pre = Infinity
-    else:
-        _pre = pre
-
-    # Versions without a post segment should sort before those with one.
-    if post is None:
-        _post: PrePostDevType = NegativeInfinity
-
-    else:
-        _post = post
-
-    # Versions without a development segment should sort after those with one.
-    if dev is None:
-        _dev: PrePostDevType = Infinity
-
-    else:
-        _dev = dev
-
-    if local is None:
-        # Versions without a local segment should sort before those with one.
-        _local: LocalType = NegativeInfinity
-    else:
-        # Versions with a local segment need that segment parsed to implement
-        # the sorting rules in PEP440.
-        # - Alpha numeric segments sort before numeric segments
-        # - Alpha numeric segments sort lexicographically
-        # - Numeric segments sort numerically
-        # - Shorter versions sort before longer versions when the prefixes
-        #   match exactly
-        _local = tuple(
-            (i, "") if isinstance(i, int) else (NegativeInfinity, i) for i in local
-        )
-
-    return epoch, _release, _pre, _post, _dev, _local
diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__init__.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__init__.py
deleted file mode 100755
index 7802ff1..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__init__.py
+++ /dev/null
@@ -1,331 +0,0 @@
-# module pyparsing.py
-#
-# Copyright (c) 2003-2022  Paul T. McGuire
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-
-__doc__ = """
-pyparsing module - Classes and methods to define and execute parsing grammars
-=============================================================================
-
-The pyparsing module is an alternative approach to creating and
-executing simple grammars, vs. the traditional lex/yacc approach, or the
-use of regular expressions.  With pyparsing, you don't need to learn
-a new syntax for defining grammars or matching expressions - the parsing
-module provides a library of classes that you use to construct the
-grammar directly in Python.
-
-Here is a program to parse "Hello, World!" (or any greeting of the form
-``", !"``), built up using :class:`Word`,
-:class:`Literal`, and :class:`And` elements
-(the :meth:`'+'` operators create :class:`And` expressions,
-and the strings are auto-converted to :class:`Literal` expressions)::
-
-    from pyparsing import Word, alphas
-
-    # define grammar of a greeting
-    greet = Word(alphas) + "," + Word(alphas) + "!"
-
-    hello = "Hello, World!"
-    print(hello, "->", greet.parse_string(hello))
-
-The program outputs the following::
-
-    Hello, World! -> ['Hello', ',', 'World', '!']
-
-The Python representation of the grammar is quite readable, owing to the
-self-explanatory class names, and the use of :class:`'+'`,
-:class:`'|'`, :class:`'^'` and :class:`'&'` operators.
-
-The :class:`ParseResults` object returned from
-:class:`ParserElement.parseString` can be
-accessed as a nested list, a dictionary, or an object with named
-attributes.
-
-The pyparsing module handles some of the problems that are typically
-vexing when writing text parsers:
-
-  - extra or missing whitespace (the above program will also handle
-    "Hello,World!", "Hello  ,  World  !", etc.)
-  - quoted strings
-  - embedded comments
-
-
-Getting Started -
------------------
-Visit the classes :class:`ParserElement` and :class:`ParseResults` to
-see the base classes that most other pyparsing
-classes inherit from. Use the docstrings for examples of how to:
-
- - construct literal match expressions from :class:`Literal` and
-   :class:`CaselessLiteral` classes
- - construct character word-group expressions using the :class:`Word`
-   class
- - see how to create repetitive expressions using :class:`ZeroOrMore`
-   and :class:`OneOrMore` classes
- - use :class:`'+'`, :class:`'|'`, :class:`'^'`,
-   and :class:`'&'` operators to combine simple expressions into
-   more complex ones
- - associate names with your parsed results using
-   :class:`ParserElement.setResultsName`
- - access the parsed data, which is returned as a :class:`ParseResults`
-   object
- - find some helpful expression short-cuts like :class:`delimitedList`
-   and :class:`oneOf`
- - find more useful common expressions in the :class:`pyparsing_common`
-   namespace class
-"""
-from typing import NamedTuple
-
-
-class version_info(NamedTuple):
-    major: int
-    minor: int
-    micro: int
-    releaselevel: str
-    serial: int
-
-    @property
-    def __version__(self):
-        return (
-            "{}.{}.{}".format(self.major, self.minor, self.micro)
-            + (
-                "{}{}{}".format(
-                    "r" if self.releaselevel[0] == "c" else "",
-                    self.releaselevel[0],
-                    self.serial,
-                ),
-                "",
-            )[self.releaselevel == "final"]
-        )
-
-    def __str__(self):
-        return "{} {} / {}".format(__name__, self.__version__, __version_time__)
-
-    def __repr__(self):
-        return "{}.{}({})".format(
-            __name__,
-            type(self).__name__,
-            ", ".join("{}={!r}".format(*nv) for nv in zip(self._fields, self)),
-        )
-
-
-__version_info__ = version_info(3, 0, 9, "final", 0)
-__version_time__ = "05 May 2022 07:02 UTC"
-__version__ = __version_info__.__version__
-__versionTime__ = __version_time__
-__author__ = "Paul McGuire "
-
-from .util import *
-from .exceptions import *
-from .actions import *
-from .core import __diag__, __compat__
-from .results import *
-from .core import *
-from .core import _builtin_exprs as core_builtin_exprs
-from .helpers import *
-from .helpers import _builtin_exprs as helper_builtin_exprs
-
-from .unicode import unicode_set, UnicodeRangeList, pyparsing_unicode as unicode
-from .testing import pyparsing_test as testing
-from .common import (
-    pyparsing_common as common,
-    _builtin_exprs as common_builtin_exprs,
-)
-
-# define backward compat synonyms
-if "pyparsing_unicode" not in globals():
-    pyparsing_unicode = unicode
-if "pyparsing_common" not in globals():
-    pyparsing_common = common
-if "pyparsing_test" not in globals():
-    pyparsing_test = testing
-
-core_builtin_exprs += common_builtin_exprs + helper_builtin_exprs
-
-
-__all__ = [
-    "__version__",
-    "__version_time__",
-    "__author__",
-    "__compat__",
-    "__diag__",
-    "And",
-    "AtLineStart",
-    "AtStringStart",
-    "CaselessKeyword",
-    "CaselessLiteral",
-    "CharsNotIn",
-    "Combine",
-    "Dict",
-    "Each",
-    "Empty",
-    "FollowedBy",
-    "Forward",
-    "GoToColumn",
-    "Group",
-    "IndentedBlock",
-    "Keyword",
-    "LineEnd",
-    "LineStart",
-    "Literal",
-    "Located",
-    "PrecededBy",
-    "MatchFirst",
-    "NoMatch",
-    "NotAny",
-    "OneOrMore",
-    "OnlyOnce",
-    "OpAssoc",
-    "Opt",
-    "Optional",
-    "Or",
-    "ParseBaseException",
-    "ParseElementEnhance",
-    "ParseException",
-    "ParseExpression",
-    "ParseFatalException",
-    "ParseResults",
-    "ParseSyntaxException",
-    "ParserElement",
-    "PositionToken",
-    "QuotedString",
-    "RecursiveGrammarException",
-    "Regex",
-    "SkipTo",
-    "StringEnd",
-    "StringStart",
-    "Suppress",
-    "Token",
-    "TokenConverter",
-    "White",
-    "Word",
-    "WordEnd",
-    "WordStart",
-    "ZeroOrMore",
-    "Char",
-    "alphanums",
-    "alphas",
-    "alphas8bit",
-    "any_close_tag",
-    "any_open_tag",
-    "c_style_comment",
-    "col",
-    "common_html_entity",
-    "counted_array",
-    "cpp_style_comment",
-    "dbl_quoted_string",
-    "dbl_slash_comment",
-    "delimited_list",
-    "dict_of",
-    "empty",
-    "hexnums",
-    "html_comment",
-    "identchars",
-    "identbodychars",
-    "java_style_comment",
-    "line",
-    "line_end",
-    "line_start",
-    "lineno",
-    "make_html_tags",
-    "make_xml_tags",
-    "match_only_at_col",
-    "match_previous_expr",
-    "match_previous_literal",
-    "nested_expr",
-    "null_debug_action",
-    "nums",
-    "one_of",
-    "printables",
-    "punc8bit",
-    "python_style_comment",
-    "quoted_string",
-    "remove_quotes",
-    "replace_with",
-    "replace_html_entity",
-    "rest_of_line",
-    "sgl_quoted_string",
-    "srange",
-    "string_end",
-    "string_start",
-    "trace_parse_action",
-    "unicode_string",
-    "with_attribute",
-    "indentedBlock",
-    "original_text_for",
-    "ungroup",
-    "infix_notation",
-    "locatedExpr",
-    "with_class",
-    "CloseMatch",
-    "token_map",
-    "pyparsing_common",
-    "pyparsing_unicode",
-    "unicode_set",
-    "condition_as_parse_action",
-    "pyparsing_test",
-    # pre-PEP8 compatibility names
-    "__versionTime__",
-    "anyCloseTag",
-    "anyOpenTag",
-    "cStyleComment",
-    "commonHTMLEntity",
-    "countedArray",
-    "cppStyleComment",
-    "dblQuotedString",
-    "dblSlashComment",
-    "delimitedList",
-    "dictOf",
-    "htmlComment",
-    "javaStyleComment",
-    "lineEnd",
-    "lineStart",
-    "makeHTMLTags",
-    "makeXMLTags",
-    "matchOnlyAtCol",
-    "matchPreviousExpr",
-    "matchPreviousLiteral",
-    "nestedExpr",
-    "nullDebugAction",
-    "oneOf",
-    "opAssoc",
-    "pythonStyleComment",
-    "quotedString",
-    "removeQuotes",
-    "replaceHTMLEntity",
-    "replaceWith",
-    "restOfLine",
-    "sglQuotedString",
-    "stringEnd",
-    "stringStart",
-    "traceParseAction",
-    "unicodeString",
-    "withAttribute",
-    "indentedBlock",
-    "originalTextFor",
-    "infixNotation",
-    "locatedExpr",
-    "withClass",
-    "tokenMap",
-    "conditionAsParseAction",
-    "autoname_elements",
-]
diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/__init__.cpython-311.pyc
deleted file mode 100755
index c86725e..0000000
Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/__init__.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/actions.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/actions.cpython-311.pyc
deleted file mode 100755
index cfc67a0..0000000
Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/actions.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/common.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/common.cpython-311.pyc
deleted file mode 100755
index fe4eed3..0000000
Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/common.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/core.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/core.cpython-311.pyc
deleted file mode 100755
index 3363048..0000000
Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/core.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/exceptions.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/exceptions.cpython-311.pyc
deleted file mode 100755
index 09cf2ad..0000000
Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/exceptions.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/helpers.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/helpers.cpython-311.pyc
deleted file mode 100755
index f0d0f51..0000000
Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/helpers.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/results.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/results.cpython-311.pyc
deleted file mode 100755
index cfe87b0..0000000
Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/results.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/testing.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/testing.cpython-311.pyc
deleted file mode 100755
index 4f193a7..0000000
Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/testing.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/unicode.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/unicode.cpython-311.pyc
deleted file mode 100755
index 28528b7..0000000
Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/unicode.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/util.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/util.cpython-311.pyc
deleted file mode 100755
index b4aafce..0000000
Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/__pycache__/util.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/actions.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/actions.py
deleted file mode 100755
index f72c66e..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/actions.py
+++ /dev/null
@@ -1,207 +0,0 @@
-# actions.py
-
-from .exceptions import ParseException
-from .util import col
-
-
-class OnlyOnce:
-    """
-    Wrapper for parse actions, to ensure they are only called once.
-    """
-
-    def __init__(self, method_call):
-        from .core import _trim_arity
-
-        self.callable = _trim_arity(method_call)
-        self.called = False
-
-    def __call__(self, s, l, t):
-        if not self.called:
-            results = self.callable(s, l, t)
-            self.called = True
-            return results
-        raise ParseException(s, l, "OnlyOnce obj called multiple times w/out reset")
-
-    def reset(self):
-        """
-        Allow the associated parse action to be called once more.
-        """
-
-        self.called = False
-
-
-def match_only_at_col(n):
-    """
-    Helper method for defining parse actions that require matching at
-    a specific column in the input text.
-    """
-
-    def verify_col(strg, locn, toks):
-        if col(locn, strg) != n:
-            raise ParseException(strg, locn, "matched token not at column {}".format(n))
-
-    return verify_col
-
-
-def replace_with(repl_str):
-    """
-    Helper method for common parse actions that simply return
-    a literal value.  Especially useful when used with
-    :class:`transform_string` ().
-
-    Example::
-
-        num = Word(nums).set_parse_action(lambda toks: int(toks[0]))
-        na = one_of("N/A NA").set_parse_action(replace_with(math.nan))
-        term = na | num
-
-        term[1, ...].parse_string("324 234 N/A 234") # -> [324, 234, nan, 234]
-    """
-    return lambda s, l, t: [repl_str]
-
-
-def remove_quotes(s, l, t):
-    """
-    Helper parse action for removing quotation marks from parsed
-    quoted strings.
-
-    Example::
-
-        # by default, quotation marks are included in parsed results
-        quoted_string.parse_string("'Now is the Winter of our Discontent'") # -> ["'Now is the Winter of our Discontent'"]
-
-        # use remove_quotes to strip quotation marks from parsed results
-        quoted_string.set_parse_action(remove_quotes)
-        quoted_string.parse_string("'Now is the Winter of our Discontent'") # -> ["Now is the Winter of our Discontent"]
-    """
-    return t[0][1:-1]
-
-
-def with_attribute(*args, **attr_dict):
-    """
-    Helper to create a validating parse action to be used with start
-    tags created with :class:`make_xml_tags` or
-    :class:`make_html_tags`. Use ``with_attribute`` to qualify
-    a starting tag with a required attribute value, to avoid false
-    matches on common tags such as ```` or ``
``. - - Call ``with_attribute`` with a series of attribute names and - values. Specify the list of filter attributes names and values as: - - - keyword arguments, as in ``(align="right")``, or - - as an explicit dict with ``**`` operator, when an attribute - name is also a Python reserved word, as in ``**{"class":"Customer", "align":"right"}`` - - a list of name-value tuples, as in ``(("ns1:class", "Customer"), ("ns2:align", "right"))`` - - For attribute names with a namespace prefix, you must use the second - form. Attribute names are matched insensitive to upper/lower case. - - If just testing for ``class`` (with or without a namespace), use - :class:`with_class`. - - To verify that the attribute exists, but without specifying a value, - pass ``with_attribute.ANY_VALUE`` as the value. - - Example:: - - html = ''' -
- Some text -
1 4 0 1 0
-
1,3 2,3 1,1
-
this has no type
-
- - ''' - div,div_end = make_html_tags("div") - - # only match div tag having a type attribute with value "grid" - div_grid = div().set_parse_action(with_attribute(type="grid")) - grid_expr = div_grid + SkipTo(div | div_end)("body") - for grid_header in grid_expr.search_string(html): - print(grid_header.body) - - # construct a match with any div tag having a type attribute, regardless of the value - div_any_type = div().set_parse_action(with_attribute(type=with_attribute.ANY_VALUE)) - div_expr = div_any_type + SkipTo(div | div_end)("body") - for div_header in div_expr.search_string(html): - print(div_header.body) - - prints:: - - 1 4 0 1 0 - - 1 4 0 1 0 - 1,3 2,3 1,1 - """ - if args: - attrs = args[:] - else: - attrs = attr_dict.items() - attrs = [(k, v) for k, v in attrs] - - def pa(s, l, tokens): - for attrName, attrValue in attrs: - if attrName not in tokens: - raise ParseException(s, l, "no matching attribute " + attrName) - if attrValue != with_attribute.ANY_VALUE and tokens[attrName] != attrValue: - raise ParseException( - s, - l, - "attribute {!r} has value {!r}, must be {!r}".format( - attrName, tokens[attrName], attrValue - ), - ) - - return pa - - -with_attribute.ANY_VALUE = object() - - -def with_class(classname, namespace=""): - """ - Simplified version of :class:`with_attribute` when - matching on a div class - made difficult because ``class`` is - a reserved word in Python. - - Example:: - - html = ''' -
- Some text -
1 4 0 1 0
-
1,3 2,3 1,1
-
this <div> has no class
-
- - ''' - div,div_end = make_html_tags("div") - div_grid = div().set_parse_action(with_class("grid")) - - grid_expr = div_grid + SkipTo(div | div_end)("body") - for grid_header in grid_expr.search_string(html): - print(grid_header.body) - - div_any_type = div().set_parse_action(with_class(withAttribute.ANY_VALUE)) - div_expr = div_any_type + SkipTo(div | div_end)("body") - for div_header in div_expr.search_string(html): - print(div_header.body) - - prints:: - - 1 4 0 1 0 - - 1 4 0 1 0 - 1,3 2,3 1,1 - """ - classattr = "{}:class".format(namespace) if namespace else "class" - return with_attribute(**{classattr: classname}) - - -# pre-PEP8 compatibility symbols -replaceWith = replace_with -removeQuotes = remove_quotes -withAttribute = with_attribute -withClass = with_class -matchOnlyAtCol = match_only_at_col diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/common.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/common.py deleted file mode 100755 index 1859fb7..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/common.py +++ /dev/null @@ -1,424 +0,0 @@ -# common.py -from .core import * -from .helpers import delimited_list, any_open_tag, any_close_tag -from datetime import datetime - - -# some other useful expressions - using lower-case class name since we are really using this as a namespace -class pyparsing_common: - """Here are some common low-level expressions that may be useful in - jump-starting parser development: - - - numeric forms (:class:`integers`, :class:`reals`, - :class:`scientific notation`) - - common :class:`programming identifiers` - - network addresses (:class:`MAC`, - :class:`IPv4`, :class:`IPv6`) - - ISO8601 :class:`dates` and - :class:`datetime` - - :class:`UUID` - - :class:`comma-separated list` - - :class:`url` - - Parse actions: - - - :class:`convertToInteger` - - :class:`convertToFloat` - - :class:`convertToDate` - - :class:`convertToDatetime` - - :class:`stripHTMLTags` - - :class:`upcaseTokens` - - :class:`downcaseTokens` - - Example:: - - pyparsing_common.number.runTests(''' - # any int or real number, returned as the appropriate type - 100 - -100 - +100 - 3.14159 - 6.02e23 - 1e-12 - ''') - - pyparsing_common.fnumber.runTests(''' - # any int or real number, returned as float - 100 - -100 - +100 - 3.14159 - 6.02e23 - 1e-12 - ''') - - pyparsing_common.hex_integer.runTests(''' - # hex numbers - 100 - FF - ''') - - pyparsing_common.fraction.runTests(''' - # fractions - 1/2 - -3/4 - ''') - - pyparsing_common.mixed_integer.runTests(''' - # mixed fractions - 1 - 1/2 - -3/4 - 1-3/4 - ''') - - import uuid - pyparsing_common.uuid.setParseAction(tokenMap(uuid.UUID)) - pyparsing_common.uuid.runTests(''' - # uuid - 12345678-1234-5678-1234-567812345678 - ''') - - prints:: - - # any int or real number, returned as the appropriate type - 100 - [100] - - -100 - [-100] - - +100 - [100] - - 3.14159 - [3.14159] - - 6.02e23 - [6.02e+23] - - 1e-12 - [1e-12] - - # any int or real number, returned as float - 100 - [100.0] - - -100 - [-100.0] - - +100 - [100.0] - - 3.14159 - [3.14159] - - 6.02e23 - [6.02e+23] - - 1e-12 - [1e-12] - - # hex numbers - 100 - [256] - - FF - [255] - - # fractions - 1/2 - [0.5] - - -3/4 - [-0.75] - - # mixed fractions - 1 - [1] - - 1/2 - [0.5] - - -3/4 - [-0.75] - - 1-3/4 - [1.75] - - # uuid - 12345678-1234-5678-1234-567812345678 - [UUID('12345678-1234-5678-1234-567812345678')] - """ - - convert_to_integer = token_map(int) - """ - Parse action for converting parsed integers to Python int - """ - - convert_to_float = token_map(float) - """ - Parse action for converting parsed numbers to Python float - """ - - integer = Word(nums).set_name("integer").set_parse_action(convert_to_integer) - """expression that parses an unsigned integer, returns an int""" - - hex_integer = ( - Word(hexnums).set_name("hex integer").set_parse_action(token_map(int, 16)) - ) - """expression that parses a hexadecimal integer, returns an int""" - - signed_integer = ( - Regex(r"[+-]?\d+") - .set_name("signed integer") - .set_parse_action(convert_to_integer) - ) - """expression that parses an integer with optional leading sign, returns an int""" - - fraction = ( - signed_integer().set_parse_action(convert_to_float) - + "/" - + signed_integer().set_parse_action(convert_to_float) - ).set_name("fraction") - """fractional expression of an integer divided by an integer, returns a float""" - fraction.add_parse_action(lambda tt: tt[0] / tt[-1]) - - mixed_integer = ( - fraction | signed_integer + Opt(Opt("-").suppress() + fraction) - ).set_name("fraction or mixed integer-fraction") - """mixed integer of the form 'integer - fraction', with optional leading integer, returns float""" - mixed_integer.add_parse_action(sum) - - real = ( - Regex(r"[+-]?(?:\d+\.\d*|\.\d+)") - .set_name("real number") - .set_parse_action(convert_to_float) - ) - """expression that parses a floating point number and returns a float""" - - sci_real = ( - Regex(r"[+-]?(?:\d+(?:[eE][+-]?\d+)|(?:\d+\.\d*|\.\d+)(?:[eE][+-]?\d+)?)") - .set_name("real number with scientific notation") - .set_parse_action(convert_to_float) - ) - """expression that parses a floating point number with optional - scientific notation and returns a float""" - - # streamlining this expression makes the docs nicer-looking - number = (sci_real | real | signed_integer).setName("number").streamline() - """any numeric expression, returns the corresponding Python type""" - - fnumber = ( - Regex(r"[+-]?\d+\.?\d*([eE][+-]?\d+)?") - .set_name("fnumber") - .set_parse_action(convert_to_float) - ) - """any int or real number, returned as float""" - - identifier = Word(identchars, identbodychars).set_name("identifier") - """typical code identifier (leading alpha or '_', followed by 0 or more alphas, nums, or '_')""" - - ipv4_address = Regex( - r"(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})){3}" - ).set_name("IPv4 address") - "IPv4 address (``0.0.0.0 - 255.255.255.255``)" - - _ipv6_part = Regex(r"[0-9a-fA-F]{1,4}").set_name("hex_integer") - _full_ipv6_address = (_ipv6_part + (":" + _ipv6_part) * 7).set_name( - "full IPv6 address" - ) - _short_ipv6_address = ( - Opt(_ipv6_part + (":" + _ipv6_part) * (0, 6)) - + "::" - + Opt(_ipv6_part + (":" + _ipv6_part) * (0, 6)) - ).set_name("short IPv6 address") - _short_ipv6_address.add_condition( - lambda t: sum(1 for tt in t if pyparsing_common._ipv6_part.matches(tt)) < 8 - ) - _mixed_ipv6_address = ("::ffff:" + ipv4_address).set_name("mixed IPv6 address") - ipv6_address = Combine( - (_full_ipv6_address | _mixed_ipv6_address | _short_ipv6_address).set_name( - "IPv6 address" - ) - ).set_name("IPv6 address") - "IPv6 address (long, short, or mixed form)" - - mac_address = Regex( - r"[0-9a-fA-F]{2}([:.-])[0-9a-fA-F]{2}(?:\1[0-9a-fA-F]{2}){4}" - ).set_name("MAC address") - "MAC address xx:xx:xx:xx:xx (may also have '-' or '.' delimiters)" - - @staticmethod - def convert_to_date(fmt: str = "%Y-%m-%d"): - """ - Helper to create a parse action for converting parsed date string to Python datetime.date - - Params - - - fmt - format to be passed to datetime.strptime (default= ``"%Y-%m-%d"``) - - Example:: - - date_expr = pyparsing_common.iso8601_date.copy() - date_expr.setParseAction(pyparsing_common.convertToDate()) - print(date_expr.parseString("1999-12-31")) - - prints:: - - [datetime.date(1999, 12, 31)] - """ - - def cvt_fn(ss, ll, tt): - try: - return datetime.strptime(tt[0], fmt).date() - except ValueError as ve: - raise ParseException(ss, ll, str(ve)) - - return cvt_fn - - @staticmethod - def convert_to_datetime(fmt: str = "%Y-%m-%dT%H:%M:%S.%f"): - """Helper to create a parse action for converting parsed - datetime string to Python datetime.datetime - - Params - - - fmt - format to be passed to datetime.strptime (default= ``"%Y-%m-%dT%H:%M:%S.%f"``) - - Example:: - - dt_expr = pyparsing_common.iso8601_datetime.copy() - dt_expr.setParseAction(pyparsing_common.convertToDatetime()) - print(dt_expr.parseString("1999-12-31T23:59:59.999")) - - prints:: - - [datetime.datetime(1999, 12, 31, 23, 59, 59, 999000)] - """ - - def cvt_fn(s, l, t): - try: - return datetime.strptime(t[0], fmt) - except ValueError as ve: - raise ParseException(s, l, str(ve)) - - return cvt_fn - - iso8601_date = Regex( - r"(?P\d{4})(?:-(?P\d\d)(?:-(?P\d\d))?)?" - ).set_name("ISO8601 date") - "ISO8601 date (``yyyy-mm-dd``)" - - iso8601_datetime = Regex( - r"(?P\d{4})-(?P\d\d)-(?P\d\d)[T ](?P\d\d):(?P\d\d)(:(?P\d\d(\.\d*)?)?)?(?PZ|[+-]\d\d:?\d\d)?" - ).set_name("ISO8601 datetime") - "ISO8601 datetime (``yyyy-mm-ddThh:mm:ss.s(Z|+-00:00)``) - trailing seconds, milliseconds, and timezone optional; accepts separating ``'T'`` or ``' '``" - - uuid = Regex(r"[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}").set_name("UUID") - "UUID (``xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx``)" - - _html_stripper = any_open_tag.suppress() | any_close_tag.suppress() - - @staticmethod - def strip_html_tags(s: str, l: int, tokens: ParseResults): - """Parse action to remove HTML tags from web page HTML source - - Example:: - - # strip HTML links from normal text - text = 'More info at the pyparsing wiki page' - td, td_end = makeHTMLTags("TD") - table_text = td + SkipTo(td_end).setParseAction(pyparsing_common.stripHTMLTags)("body") + td_end - print(table_text.parseString(text).body) - - Prints:: - - More info at the pyparsing wiki page - """ - return pyparsing_common._html_stripper.transform_string(tokens[0]) - - _commasepitem = ( - Combine( - OneOrMore( - ~Literal(",") - + ~LineEnd() - + Word(printables, exclude_chars=",") - + Opt(White(" \t") + ~FollowedBy(LineEnd() | ",")) - ) - ) - .streamline() - .set_name("commaItem") - ) - comma_separated_list = delimited_list( - Opt(quoted_string.copy() | _commasepitem, default="") - ).set_name("comma separated list") - """Predefined expression of 1 or more printable words or quoted strings, separated by commas.""" - - upcase_tokens = staticmethod(token_map(lambda t: t.upper())) - """Parse action to convert tokens to upper case.""" - - downcase_tokens = staticmethod(token_map(lambda t: t.lower())) - """Parse action to convert tokens to lower case.""" - - # fmt: off - url = Regex( - # https://mathiasbynens.be/demo/url-regex - # https://gist.github.com/dperini/729294 - r"^" + - # protocol identifier (optional) - # short syntax // still required - r"(?:(?:(?Phttps?|ftp):)?\/\/)" + - # user:pass BasicAuth (optional) - r"(?:(?P\S+(?::\S*)?)@)?" + - r"(?P" + - # IP address exclusion - # private & local networks - r"(?!(?:10|127)(?:\.\d{1,3}){3})" + - r"(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})" + - r"(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})" + - # IP address dotted notation octets - # excludes loopback network 0.0.0.0 - # excludes reserved space >= 224.0.0.0 - # excludes network & broadcast addresses - # (first & last IP address of each class) - r"(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])" + - r"(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}" + - r"(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))" + - r"|" + - # host & domain names, may end with dot - # can be replaced by a shortest alternative - # (?![-_])(?:[-\w\u00a1-\uffff]{0,63}[^-_]\.)+ - r"(?:" + - r"(?:" + - r"[a-z0-9\u00a1-\uffff]" + - r"[a-z0-9\u00a1-\uffff_-]{0,62}" + - r")?" + - r"[a-z0-9\u00a1-\uffff]\." + - r")+" + - # TLD identifier name, may end with dot - r"(?:[a-z\u00a1-\uffff]{2,}\.?)" + - r")" + - # port number (optional) - r"(:(?P\d{2,5}))?" + - # resource path (optional) - r"(?P\/[^?# ]*)?" + - # query string (optional) - r"(\?(?P[^#]*))?" + - # fragment (optional) - r"(#(?P\S*))?" + - r"$" - ).set_name("url") - # fmt: on - - # pre-PEP8 compatibility names - convertToInteger = convert_to_integer - convertToFloat = convert_to_float - convertToDate = convert_to_date - convertToDatetime = convert_to_datetime - stripHTMLTags = strip_html_tags - upcaseTokens = upcase_tokens - downcaseTokens = downcase_tokens - - -_builtin_exprs = [ - v for v in vars(pyparsing_common).values() if isinstance(v, ParserElement) -] diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/core.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/core.py deleted file mode 100755 index 9acba3f..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/core.py +++ /dev/null @@ -1,5814 +0,0 @@ -# -# core.py -# -import os -import typing -from typing import ( - NamedTuple, - Union, - Callable, - Any, - Generator, - Tuple, - List, - TextIO, - Set, - Sequence, -) -from abc import ABC, abstractmethod -from enum import Enum -import string -import copy -import warnings -import re -import sys -from collections.abc import Iterable -import traceback -import types -from operator import itemgetter -from functools import wraps -from threading import RLock -from pathlib import Path - -from .util import ( - _FifoCache, - _UnboundedCache, - __config_flags, - _collapse_string_to_ranges, - _escape_regex_range_chars, - _bslash, - _flatten, - LRUMemo as _LRUMemo, - UnboundedMemo as _UnboundedMemo, -) -from .exceptions import * -from .actions import * -from .results import ParseResults, _ParseResultsWithOffset -from .unicode import pyparsing_unicode - -_MAX_INT = sys.maxsize -str_type: Tuple[type, ...] = (str, bytes) - -# -# Copyright (c) 2003-2022 Paul T. McGuire -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - - -if sys.version_info >= (3, 8): - from functools import cached_property -else: - - class cached_property: - def __init__(self, func): - self._func = func - - def __get__(self, instance, owner=None): - ret = instance.__dict__[self._func.__name__] = self._func(instance) - return ret - - -class __compat__(__config_flags): - """ - A cross-version compatibility configuration for pyparsing features that will be - released in a future version. By setting values in this configuration to True, - those features can be enabled in prior versions for compatibility development - and testing. - - - ``collect_all_And_tokens`` - flag to enable fix for Issue #63 that fixes erroneous grouping - of results names when an :class:`And` expression is nested within an :class:`Or` or :class:`MatchFirst`; - maintained for compatibility, but setting to ``False`` no longer restores pre-2.3.1 - behavior - """ - - _type_desc = "compatibility" - - collect_all_And_tokens = True - - _all_names = [__ for __ in locals() if not __.startswith("_")] - _fixed_names = """ - collect_all_And_tokens - """.split() - - -class __diag__(__config_flags): - _type_desc = "diagnostic" - - warn_multiple_tokens_in_named_alternation = False - warn_ungrouped_named_tokens_in_collection = False - warn_name_set_on_empty_Forward = False - warn_on_parse_using_empty_Forward = False - warn_on_assignment_to_Forward = False - warn_on_multiple_string_args_to_oneof = False - warn_on_match_first_with_lshift_operator = False - enable_debug_on_named_expressions = False - - _all_names = [__ for __ in locals() if not __.startswith("_")] - _warning_names = [name for name in _all_names if name.startswith("warn")] - _debug_names = [name for name in _all_names if name.startswith("enable_debug")] - - @classmethod - def enable_all_warnings(cls) -> None: - for name in cls._warning_names: - cls.enable(name) - - -class Diagnostics(Enum): - """ - Diagnostic configuration (all default to disabled) - - ``warn_multiple_tokens_in_named_alternation`` - flag to enable warnings when a results - name is defined on a :class:`MatchFirst` or :class:`Or` expression with one or more :class:`And` subexpressions - - ``warn_ungrouped_named_tokens_in_collection`` - flag to enable warnings when a results - name is defined on a containing expression with ungrouped subexpressions that also - have results names - - ``warn_name_set_on_empty_Forward`` - flag to enable warnings when a :class:`Forward` is defined - with a results name, but has no contents defined - - ``warn_on_parse_using_empty_Forward`` - flag to enable warnings when a :class:`Forward` is - defined in a grammar but has never had an expression attached to it - - ``warn_on_assignment_to_Forward`` - flag to enable warnings when a :class:`Forward` is defined - but is overwritten by assigning using ``'='`` instead of ``'<<='`` or ``'<<'`` - - ``warn_on_multiple_string_args_to_oneof`` - flag to enable warnings when :class:`one_of` is - incorrectly called with multiple str arguments - - ``enable_debug_on_named_expressions`` - flag to auto-enable debug on all subsequent - calls to :class:`ParserElement.set_name` - - Diagnostics are enabled/disabled by calling :class:`enable_diag` and :class:`disable_diag`. - All warnings can be enabled by calling :class:`enable_all_warnings`. - """ - - warn_multiple_tokens_in_named_alternation = 0 - warn_ungrouped_named_tokens_in_collection = 1 - warn_name_set_on_empty_Forward = 2 - warn_on_parse_using_empty_Forward = 3 - warn_on_assignment_to_Forward = 4 - warn_on_multiple_string_args_to_oneof = 5 - warn_on_match_first_with_lshift_operator = 6 - enable_debug_on_named_expressions = 7 - - -def enable_diag(diag_enum: Diagnostics) -> None: - """ - Enable a global pyparsing diagnostic flag (see :class:`Diagnostics`). - """ - __diag__.enable(diag_enum.name) - - -def disable_diag(diag_enum: Diagnostics) -> None: - """ - Disable a global pyparsing diagnostic flag (see :class:`Diagnostics`). - """ - __diag__.disable(diag_enum.name) - - -def enable_all_warnings() -> None: - """ - Enable all global pyparsing diagnostic warnings (see :class:`Diagnostics`). - """ - __diag__.enable_all_warnings() - - -# hide abstract class -del __config_flags - - -def _should_enable_warnings( - cmd_line_warn_options: typing.Iterable[str], warn_env_var: typing.Optional[str] -) -> bool: - enable = bool(warn_env_var) - for warn_opt in cmd_line_warn_options: - w_action, w_message, w_category, w_module, w_line = (warn_opt + "::::").split( - ":" - )[:5] - if not w_action.lower().startswith("i") and ( - not (w_message or w_category or w_module) or w_module == "pyparsing" - ): - enable = True - elif w_action.lower().startswith("i") and w_module in ("pyparsing", ""): - enable = False - return enable - - -if _should_enable_warnings( - sys.warnoptions, os.environ.get("PYPARSINGENABLEALLWARNINGS") -): - enable_all_warnings() - - -# build list of single arg builtins, that can be used as parse actions -_single_arg_builtins = { - sum, - len, - sorted, - reversed, - list, - tuple, - set, - any, - all, - min, - max, -} - -_generatorType = types.GeneratorType -ParseAction = Union[ - Callable[[], Any], - Callable[[ParseResults], Any], - Callable[[int, ParseResults], Any], - Callable[[str, int, ParseResults], Any], -] -ParseCondition = Union[ - Callable[[], bool], - Callable[[ParseResults], bool], - Callable[[int, ParseResults], bool], - Callable[[str, int, ParseResults], bool], -] -ParseFailAction = Callable[[str, int, "ParserElement", Exception], None] -DebugStartAction = Callable[[str, int, "ParserElement", bool], None] -DebugSuccessAction = Callable[ - [str, int, int, "ParserElement", ParseResults, bool], None -] -DebugExceptionAction = Callable[[str, int, "ParserElement", Exception, bool], None] - - -alphas = string.ascii_uppercase + string.ascii_lowercase -identchars = pyparsing_unicode.Latin1.identchars -identbodychars = pyparsing_unicode.Latin1.identbodychars -nums = "0123456789" -hexnums = nums + "ABCDEFabcdef" -alphanums = alphas + nums -printables = "".join([c for c in string.printable if c not in string.whitespace]) - -_trim_arity_call_line: traceback.StackSummary = None - - -def _trim_arity(func, max_limit=3): - """decorator to trim function calls to match the arity of the target""" - global _trim_arity_call_line - - if func in _single_arg_builtins: - return lambda s, l, t: func(t) - - limit = 0 - found_arity = False - - def extract_tb(tb, limit=0): - frames = traceback.extract_tb(tb, limit=limit) - frame_summary = frames[-1] - return [frame_summary[:2]] - - # synthesize what would be returned by traceback.extract_stack at the call to - # user's parse action 'func', so that we don't incur call penalty at parse time - - # fmt: off - LINE_DIFF = 7 - # IF ANY CODE CHANGES, EVEN JUST COMMENTS OR BLANK LINES, BETWEEN THE NEXT LINE AND - # THE CALL TO FUNC INSIDE WRAPPER, LINE_DIFF MUST BE MODIFIED!!!! - _trim_arity_call_line = (_trim_arity_call_line or traceback.extract_stack(limit=2)[-1]) - pa_call_line_synth = (_trim_arity_call_line[0], _trim_arity_call_line[1] + LINE_DIFF) - - def wrapper(*args): - nonlocal found_arity, limit - while 1: - try: - ret = func(*args[limit:]) - found_arity = True - return ret - except TypeError as te: - # re-raise TypeErrors if they did not come from our arity testing - if found_arity: - raise - else: - tb = te.__traceback__ - trim_arity_type_error = ( - extract_tb(tb, limit=2)[-1][:2] == pa_call_line_synth - ) - del tb - - if trim_arity_type_error: - if limit < max_limit: - limit += 1 - continue - - raise - # fmt: on - - # copy func name to wrapper for sensible debug output - # (can't use functools.wraps, since that messes with function signature) - func_name = getattr(func, "__name__", getattr(func, "__class__").__name__) - wrapper.__name__ = func_name - wrapper.__doc__ = func.__doc__ - - return wrapper - - -def condition_as_parse_action( - fn: ParseCondition, message: str = None, fatal: bool = False -) -> ParseAction: - """ - Function to convert a simple predicate function that returns ``True`` or ``False`` - into a parse action. Can be used in places when a parse action is required - and :class:`ParserElement.add_condition` cannot be used (such as when adding a condition - to an operator level in :class:`infix_notation`). - - Optional keyword arguments: - - - ``message`` - define a custom message to be used in the raised exception - - ``fatal`` - if True, will raise :class:`ParseFatalException` to stop parsing immediately; - otherwise will raise :class:`ParseException` - - """ - msg = message if message is not None else "failed user-defined condition" - exc_type = ParseFatalException if fatal else ParseException - fn = _trim_arity(fn) - - @wraps(fn) - def pa(s, l, t): - if not bool(fn(s, l, t)): - raise exc_type(s, l, msg) - - return pa - - -def _default_start_debug_action( - instring: str, loc: int, expr: "ParserElement", cache_hit: bool = False -): - cache_hit_str = "*" if cache_hit else "" - print( - ( - "{}Match {} at loc {}({},{})\n {}\n {}^".format( - cache_hit_str, - expr, - loc, - lineno(loc, instring), - col(loc, instring), - line(loc, instring), - " " * (col(loc, instring) - 1), - ) - ) - ) - - -def _default_success_debug_action( - instring: str, - startloc: int, - endloc: int, - expr: "ParserElement", - toks: ParseResults, - cache_hit: bool = False, -): - cache_hit_str = "*" if cache_hit else "" - print("{}Matched {} -> {}".format(cache_hit_str, expr, toks.as_list())) - - -def _default_exception_debug_action( - instring: str, - loc: int, - expr: "ParserElement", - exc: Exception, - cache_hit: bool = False, -): - cache_hit_str = "*" if cache_hit else "" - print( - "{}Match {} failed, {} raised: {}".format( - cache_hit_str, expr, type(exc).__name__, exc - ) - ) - - -def null_debug_action(*args): - """'Do-nothing' debug action, to suppress debugging output during parsing.""" - - -class ParserElement(ABC): - """Abstract base level parser element class.""" - - DEFAULT_WHITE_CHARS: str = " \n\t\r" - verbose_stacktrace: bool = False - _literalStringClass: typing.Optional[type] = None - - @staticmethod - def set_default_whitespace_chars(chars: str) -> None: - r""" - Overrides the default whitespace chars - - Example:: - - # default whitespace chars are space, and newline - Word(alphas)[1, ...].parse_string("abc def\nghi jkl") # -> ['abc', 'def', 'ghi', 'jkl'] - - # change to just treat newline as significant - ParserElement.set_default_whitespace_chars(" \t") - Word(alphas)[1, ...].parse_string("abc def\nghi jkl") # -> ['abc', 'def'] - """ - ParserElement.DEFAULT_WHITE_CHARS = chars - - # update whitespace all parse expressions defined in this module - for expr in _builtin_exprs: - if expr.copyDefaultWhiteChars: - expr.whiteChars = set(chars) - - @staticmethod - def inline_literals_using(cls: type) -> None: - """ - Set class to be used for inclusion of string literals into a parser. - - Example:: - - # default literal class used is Literal - integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - date_str.parse_string("1999/12/31") # -> ['1999', '/', '12', '/', '31'] - - - # change to Suppress - ParserElement.inline_literals_using(Suppress) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - date_str.parse_string("1999/12/31") # -> ['1999', '12', '31'] - """ - ParserElement._literalStringClass = cls - - class DebugActions(NamedTuple): - debug_try: typing.Optional[DebugStartAction] - debug_match: typing.Optional[DebugSuccessAction] - debug_fail: typing.Optional[DebugExceptionAction] - - def __init__(self, savelist: bool = False): - self.parseAction: List[ParseAction] = list() - self.failAction: typing.Optional[ParseFailAction] = None - self.customName = None - self._defaultName = None - self.resultsName = None - self.saveAsList = savelist - self.skipWhitespace = True - self.whiteChars = set(ParserElement.DEFAULT_WHITE_CHARS) - self.copyDefaultWhiteChars = True - # used when checking for left-recursion - self.mayReturnEmpty = False - self.keepTabs = False - self.ignoreExprs: List["ParserElement"] = list() - self.debug = False - self.streamlined = False - # optimize exception handling for subclasses that don't advance parse index - self.mayIndexError = True - self.errmsg = "" - # mark results names as modal (report only last) or cumulative (list all) - self.modalResults = True - # custom debug actions - self.debugActions = self.DebugActions(None, None, None) - # avoid redundant calls to preParse - self.callPreparse = True - self.callDuringTry = False - self.suppress_warnings_: List[Diagnostics] = [] - - def suppress_warning(self, warning_type: Diagnostics) -> "ParserElement": - """ - Suppress warnings emitted for a particular diagnostic on this expression. - - Example:: - - base = pp.Forward() - base.suppress_warning(Diagnostics.warn_on_parse_using_empty_Forward) - - # statement would normally raise a warning, but is now suppressed - print(base.parseString("x")) - - """ - self.suppress_warnings_.append(warning_type) - return self - - def copy(self) -> "ParserElement": - """ - Make a copy of this :class:`ParserElement`. Useful for defining - different parse actions for the same parsing pattern, using copies of - the original parse element. - - Example:: - - integer = Word(nums).set_parse_action(lambda toks: int(toks[0])) - integerK = integer.copy().add_parse_action(lambda toks: toks[0] * 1024) + Suppress("K") - integerM = integer.copy().add_parse_action(lambda toks: toks[0] * 1024 * 1024) + Suppress("M") - - print((integerK | integerM | integer)[1, ...].parse_string("5K 100 640K 256M")) - - prints:: - - [5120, 100, 655360, 268435456] - - Equivalent form of ``expr.copy()`` is just ``expr()``:: - - integerM = integer().add_parse_action(lambda toks: toks[0] * 1024 * 1024) + Suppress("M") - """ - cpy = copy.copy(self) - cpy.parseAction = self.parseAction[:] - cpy.ignoreExprs = self.ignoreExprs[:] - if self.copyDefaultWhiteChars: - cpy.whiteChars = set(ParserElement.DEFAULT_WHITE_CHARS) - return cpy - - def set_results_name( - self, name: str, list_all_matches: bool = False, *, listAllMatches: bool = False - ) -> "ParserElement": - """ - Define name for referencing matching tokens as a nested attribute - of the returned parse results. - - Normally, results names are assigned as you would assign keys in a dict: - any existing value is overwritten by later values. If it is necessary to - keep all values captured for a particular results name, call ``set_results_name`` - with ``list_all_matches`` = True. - - NOTE: ``set_results_name`` returns a *copy* of the original :class:`ParserElement` object; - this is so that the client can define a basic element, such as an - integer, and reference it in multiple places with different names. - - You can also set results names using the abbreviated syntax, - ``expr("name")`` in place of ``expr.set_results_name("name")`` - - see :class:`__call__`. If ``list_all_matches`` is required, use - ``expr("name*")``. - - Example:: - - date_str = (integer.set_results_name("year") + '/' - + integer.set_results_name("month") + '/' - + integer.set_results_name("day")) - - # equivalent form: - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - """ - listAllMatches = listAllMatches or list_all_matches - return self._setResultsName(name, listAllMatches) - - def _setResultsName(self, name, listAllMatches=False): - if name is None: - return self - newself = self.copy() - if name.endswith("*"): - name = name[:-1] - listAllMatches = True - newself.resultsName = name - newself.modalResults = not listAllMatches - return newself - - def set_break(self, break_flag: bool = True) -> "ParserElement": - """ - Method to invoke the Python pdb debugger when this element is - about to be parsed. Set ``break_flag`` to ``True`` to enable, ``False`` to - disable. - """ - if break_flag: - _parseMethod = self._parse - - def breaker(instring, loc, doActions=True, callPreParse=True): - import pdb - - # this call to pdb.set_trace() is intentional, not a checkin error - pdb.set_trace() - return _parseMethod(instring, loc, doActions, callPreParse) - - breaker._originalParseMethod = _parseMethod - self._parse = breaker - else: - if hasattr(self._parse, "_originalParseMethod"): - self._parse = self._parse._originalParseMethod - return self - - def set_parse_action(self, *fns: ParseAction, **kwargs) -> "ParserElement": - """ - Define one or more actions to perform when successfully matching parse element definition. - - Parse actions can be called to perform data conversions, do extra validation, - update external data structures, or enhance or replace the parsed tokens. - Each parse action ``fn`` is a callable method with 0-3 arguments, called as - ``fn(s, loc, toks)`` , ``fn(loc, toks)`` , ``fn(toks)`` , or just ``fn()`` , where: - - - s = the original string being parsed (see note below) - - loc = the location of the matching substring - - toks = a list of the matched tokens, packaged as a :class:`ParseResults` object - - The parsed tokens are passed to the parse action as ParseResults. They can be - modified in place using list-style append, extend, and pop operations to update - the parsed list elements; and with dictionary-style item set and del operations - to add, update, or remove any named results. If the tokens are modified in place, - it is not necessary to return them with a return statement. - - Parse actions can also completely replace the given tokens, with another ``ParseResults`` - object, or with some entirely different object (common for parse actions that perform data - conversions). A convenient way to build a new parse result is to define the values - using a dict, and then create the return value using :class:`ParseResults.from_dict`. - - If None is passed as the ``fn`` parse action, all previously added parse actions for this - expression are cleared. - - Optional keyword arguments: - - - call_during_try = (default= ``False``) indicate if parse action should be run during - lookaheads and alternate testing. For parse actions that have side effects, it is - important to only call the parse action once it is determined that it is being - called as part of a successful parse. For parse actions that perform additional - validation, then call_during_try should be passed as True, so that the validation - code is included in the preliminary "try" parses. - - Note: the default parsing behavior is to expand tabs in the input string - before starting the parsing process. See :class:`parse_string` for more - information on parsing strings containing ```` s, and suggested - methods to maintain a consistent view of the parsed string, the parse - location, and line and column positions within the parsed string. - - Example:: - - # parse dates in the form YYYY/MM/DD - - # use parse action to convert toks from str to int at parse time - def convert_to_int(toks): - return int(toks[0]) - - # use a parse action to verify that the date is a valid date - def is_valid_date(instring, loc, toks): - from datetime import date - year, month, day = toks[::2] - try: - date(year, month, day) - except ValueError: - raise ParseException(instring, loc, "invalid date given") - - integer = Word(nums) - date_str = integer + '/' + integer + '/' + integer - - # add parse actions - integer.set_parse_action(convert_to_int) - date_str.set_parse_action(is_valid_date) - - # note that integer fields are now ints, not strings - date_str.run_tests(''' - # successful parse - note that integer fields were converted to ints - 1999/12/31 - - # fail - invalid date - 1999/13/31 - ''') - """ - if list(fns) == [None]: - self.parseAction = [] - else: - if not all(callable(fn) for fn in fns): - raise TypeError("parse actions must be callable") - self.parseAction = [_trim_arity(fn) for fn in fns] - self.callDuringTry = kwargs.get( - "call_during_try", kwargs.get("callDuringTry", False) - ) - return self - - def add_parse_action(self, *fns: ParseAction, **kwargs) -> "ParserElement": - """ - Add one or more parse actions to expression's list of parse actions. See :class:`set_parse_action`. - - See examples in :class:`copy`. - """ - self.parseAction += [_trim_arity(fn) for fn in fns] - self.callDuringTry = self.callDuringTry or kwargs.get( - "call_during_try", kwargs.get("callDuringTry", False) - ) - return self - - def add_condition(self, *fns: ParseCondition, **kwargs) -> "ParserElement": - """Add a boolean predicate function to expression's list of parse actions. See - :class:`set_parse_action` for function call signatures. Unlike ``set_parse_action``, - functions passed to ``add_condition`` need to return boolean success/fail of the condition. - - Optional keyword arguments: - - - message = define a custom message to be used in the raised exception - - fatal = if True, will raise ParseFatalException to stop parsing immediately; otherwise will raise - ParseException - - call_during_try = boolean to indicate if this method should be called during internal tryParse calls, - default=False - - Example:: - - integer = Word(nums).set_parse_action(lambda toks: int(toks[0])) - year_int = integer.copy() - year_int.add_condition(lambda toks: toks[0] >= 2000, message="Only support years 2000 and later") - date_str = year_int + '/' + integer + '/' + integer - - result = date_str.parse_string("1999/12/31") # -> Exception: Only support years 2000 and later (at char 0), - (line:1, col:1) - """ - for fn in fns: - self.parseAction.append( - condition_as_parse_action( - fn, message=kwargs.get("message"), fatal=kwargs.get("fatal", False) - ) - ) - - self.callDuringTry = self.callDuringTry or kwargs.get( - "call_during_try", kwargs.get("callDuringTry", False) - ) - return self - - def set_fail_action(self, fn: ParseFailAction) -> "ParserElement": - """ - Define action to perform if parsing fails at this expression. - Fail acton fn is a callable function that takes the arguments - ``fn(s, loc, expr, err)`` where: - - - s = string being parsed - - loc = location where expression match was attempted and failed - - expr = the parse expression that failed - - err = the exception thrown - - The function returns no value. It may throw :class:`ParseFatalException` - if it is desired to stop parsing immediately.""" - self.failAction = fn - return self - - def _skipIgnorables(self, instring, loc): - exprsFound = True - while exprsFound: - exprsFound = False - for e in self.ignoreExprs: - try: - while 1: - loc, dummy = e._parse(instring, loc) - exprsFound = True - except ParseException: - pass - return loc - - def preParse(self, instring, loc): - if self.ignoreExprs: - loc = self._skipIgnorables(instring, loc) - - if self.skipWhitespace: - instrlen = len(instring) - white_chars = self.whiteChars - while loc < instrlen and instring[loc] in white_chars: - loc += 1 - - return loc - - def parseImpl(self, instring, loc, doActions=True): - return loc, [] - - def postParse(self, instring, loc, tokenlist): - return tokenlist - - # @profile - def _parseNoCache( - self, instring, loc, doActions=True, callPreParse=True - ) -> Tuple[int, ParseResults]: - TRY, MATCH, FAIL = 0, 1, 2 - debugging = self.debug # and doActions) - len_instring = len(instring) - - if debugging or self.failAction: - # print("Match {} at loc {}({}, {})".format(self, loc, lineno(loc, instring), col(loc, instring))) - try: - if callPreParse and self.callPreparse: - pre_loc = self.preParse(instring, loc) - else: - pre_loc = loc - tokens_start = pre_loc - if self.debugActions.debug_try: - self.debugActions.debug_try(instring, tokens_start, self, False) - if self.mayIndexError or pre_loc >= len_instring: - try: - loc, tokens = self.parseImpl(instring, pre_loc, doActions) - except IndexError: - raise ParseException(instring, len_instring, self.errmsg, self) - else: - loc, tokens = self.parseImpl(instring, pre_loc, doActions) - except Exception as err: - # print("Exception raised:", err) - if self.debugActions.debug_fail: - self.debugActions.debug_fail( - instring, tokens_start, self, err, False - ) - if self.failAction: - self.failAction(instring, tokens_start, self, err) - raise - else: - if callPreParse and self.callPreparse: - pre_loc = self.preParse(instring, loc) - else: - pre_loc = loc - tokens_start = pre_loc - if self.mayIndexError or pre_loc >= len_instring: - try: - loc, tokens = self.parseImpl(instring, pre_loc, doActions) - except IndexError: - raise ParseException(instring, len_instring, self.errmsg, self) - else: - loc, tokens = self.parseImpl(instring, pre_loc, doActions) - - tokens = self.postParse(instring, loc, tokens) - - ret_tokens = ParseResults( - tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults - ) - if self.parseAction and (doActions or self.callDuringTry): - if debugging: - try: - for fn in self.parseAction: - try: - tokens = fn(instring, tokens_start, ret_tokens) - except IndexError as parse_action_exc: - exc = ParseException("exception raised in parse action") - raise exc from parse_action_exc - - if tokens is not None and tokens is not ret_tokens: - ret_tokens = ParseResults( - tokens, - self.resultsName, - asList=self.saveAsList - and isinstance(tokens, (ParseResults, list)), - modal=self.modalResults, - ) - except Exception as err: - # print "Exception raised in user parse action:", err - if self.debugActions.debug_fail: - self.debugActions.debug_fail( - instring, tokens_start, self, err, False - ) - raise - else: - for fn in self.parseAction: - try: - tokens = fn(instring, tokens_start, ret_tokens) - except IndexError as parse_action_exc: - exc = ParseException("exception raised in parse action") - raise exc from parse_action_exc - - if tokens is not None and tokens is not ret_tokens: - ret_tokens = ParseResults( - tokens, - self.resultsName, - asList=self.saveAsList - and isinstance(tokens, (ParseResults, list)), - modal=self.modalResults, - ) - if debugging: - # print("Matched", self, "->", ret_tokens.as_list()) - if self.debugActions.debug_match: - self.debugActions.debug_match( - instring, tokens_start, loc, self, ret_tokens, False - ) - - return loc, ret_tokens - - def try_parse(self, instring: str, loc: int, raise_fatal: bool = False) -> int: - try: - return self._parse(instring, loc, doActions=False)[0] - except ParseFatalException: - if raise_fatal: - raise - raise ParseException(instring, loc, self.errmsg, self) - - def can_parse_next(self, instring: str, loc: int) -> bool: - try: - self.try_parse(instring, loc) - except (ParseException, IndexError): - return False - else: - return True - - # cache for left-recursion in Forward references - recursion_lock = RLock() - recursion_memos: typing.Dict[ - Tuple[int, "Forward", bool], Tuple[int, Union[ParseResults, Exception]] - ] = {} - - # argument cache for optimizing repeated calls when backtracking through recursive expressions - packrat_cache = ( - {} - ) # this is set later by enabled_packrat(); this is here so that reset_cache() doesn't fail - packrat_cache_lock = RLock() - packrat_cache_stats = [0, 0] - - # this method gets repeatedly called during backtracking with the same arguments - - # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression - def _parseCache( - self, instring, loc, doActions=True, callPreParse=True - ) -> Tuple[int, ParseResults]: - HIT, MISS = 0, 1 - TRY, MATCH, FAIL = 0, 1, 2 - lookup = (self, instring, loc, callPreParse, doActions) - with ParserElement.packrat_cache_lock: - cache = ParserElement.packrat_cache - value = cache.get(lookup) - if value is cache.not_in_cache: - ParserElement.packrat_cache_stats[MISS] += 1 - try: - value = self._parseNoCache(instring, loc, doActions, callPreParse) - except ParseBaseException as pe: - # cache a copy of the exception, without the traceback - cache.set(lookup, pe.__class__(*pe.args)) - raise - else: - cache.set(lookup, (value[0], value[1].copy(), loc)) - return value - else: - ParserElement.packrat_cache_stats[HIT] += 1 - if self.debug and self.debugActions.debug_try: - try: - self.debugActions.debug_try(instring, loc, self, cache_hit=True) - except TypeError: - pass - if isinstance(value, Exception): - if self.debug and self.debugActions.debug_fail: - try: - self.debugActions.debug_fail( - instring, loc, self, value, cache_hit=True - ) - except TypeError: - pass - raise value - - loc_, result, endloc = value[0], value[1].copy(), value[2] - if self.debug and self.debugActions.debug_match: - try: - self.debugActions.debug_match( - instring, loc_, endloc, self, result, cache_hit=True - ) - except TypeError: - pass - - return loc_, result - - _parse = _parseNoCache - - @staticmethod - def reset_cache() -> None: - ParserElement.packrat_cache.clear() - ParserElement.packrat_cache_stats[:] = [0] * len( - ParserElement.packrat_cache_stats - ) - ParserElement.recursion_memos.clear() - - _packratEnabled = False - _left_recursion_enabled = False - - @staticmethod - def disable_memoization() -> None: - """ - Disables active Packrat or Left Recursion parsing and their memoization - - This method also works if neither Packrat nor Left Recursion are enabled. - This makes it safe to call before activating Packrat nor Left Recursion - to clear any previous settings. - """ - ParserElement.reset_cache() - ParserElement._left_recursion_enabled = False - ParserElement._packratEnabled = False - ParserElement._parse = ParserElement._parseNoCache - - @staticmethod - def enable_left_recursion( - cache_size_limit: typing.Optional[int] = None, *, force=False - ) -> None: - """ - Enables "bounded recursion" parsing, which allows for both direct and indirect - left-recursion. During parsing, left-recursive :class:`Forward` elements are - repeatedly matched with a fixed recursion depth that is gradually increased - until finding the longest match. - - Example:: - - import pyparsing as pp - pp.ParserElement.enable_left_recursion() - - E = pp.Forward("E") - num = pp.Word(pp.nums) - # match `num`, or `num '+' num`, or `num '+' num '+' num`, ... - E <<= E + '+' - num | num - - print(E.parse_string("1+2+3")) - - Recursion search naturally memoizes matches of ``Forward`` elements and may - thus skip reevaluation of parse actions during backtracking. This may break - programs with parse actions which rely on strict ordering of side-effects. - - Parameters: - - - cache_size_limit - (default=``None``) - memoize at most this many - ``Forward`` elements during matching; if ``None`` (the default), - memoize all ``Forward`` elements. - - Bounded Recursion parsing works similar but not identical to Packrat parsing, - thus the two cannot be used together. Use ``force=True`` to disable any - previous, conflicting settings. - """ - if force: - ParserElement.disable_memoization() - elif ParserElement._packratEnabled: - raise RuntimeError("Packrat and Bounded Recursion are not compatible") - if cache_size_limit is None: - ParserElement.recursion_memos = _UnboundedMemo() - elif cache_size_limit > 0: - ParserElement.recursion_memos = _LRUMemo(capacity=cache_size_limit) - else: - raise NotImplementedError("Memo size of %s" % cache_size_limit) - ParserElement._left_recursion_enabled = True - - @staticmethod - def enable_packrat(cache_size_limit: int = 128, *, force: bool = False) -> None: - """ - Enables "packrat" parsing, which adds memoizing to the parsing logic. - Repeated parse attempts at the same string location (which happens - often in many complex grammars) can immediately return a cached value, - instead of re-executing parsing/validating code. Memoizing is done of - both valid results and parsing exceptions. - - Parameters: - - - cache_size_limit - (default= ``128``) - if an integer value is provided - will limit the size of the packrat cache; if None is passed, then - the cache size will be unbounded; if 0 is passed, the cache will - be effectively disabled. - - This speedup may break existing programs that use parse actions that - have side-effects. For this reason, packrat parsing is disabled when - you first import pyparsing. To activate the packrat feature, your - program must call the class method :class:`ParserElement.enable_packrat`. - For best results, call ``enable_packrat()`` immediately after - importing pyparsing. - - Example:: - - import pyparsing - pyparsing.ParserElement.enable_packrat() - - Packrat parsing works similar but not identical to Bounded Recursion parsing, - thus the two cannot be used together. Use ``force=True`` to disable any - previous, conflicting settings. - """ - if force: - ParserElement.disable_memoization() - elif ParserElement._left_recursion_enabled: - raise RuntimeError("Packrat and Bounded Recursion are not compatible") - if not ParserElement._packratEnabled: - ParserElement._packratEnabled = True - if cache_size_limit is None: - ParserElement.packrat_cache = _UnboundedCache() - else: - ParserElement.packrat_cache = _FifoCache(cache_size_limit) - ParserElement._parse = ParserElement._parseCache - - def parse_string( - self, instring: str, parse_all: bool = False, *, parseAll: bool = False - ) -> ParseResults: - """ - Parse a string with respect to the parser definition. This function is intended as the primary interface to the - client code. - - :param instring: The input string to be parsed. - :param parse_all: If set, the entire input string must match the grammar. - :param parseAll: retained for pre-PEP8 compatibility, will be removed in a future release. - :raises ParseException: Raised if ``parse_all`` is set and the input string does not match the whole grammar. - :returns: the parsed data as a :class:`ParseResults` object, which may be accessed as a `list`, a `dict`, or - an object with attributes if the given parser includes results names. - - If the input string is required to match the entire grammar, ``parse_all`` flag must be set to ``True``. This - is also equivalent to ending the grammar with :class:`StringEnd`(). - - To report proper column numbers, ``parse_string`` operates on a copy of the input string where all tabs are - converted to spaces (8 spaces per tab, as per the default in ``string.expandtabs``). If the input string - contains tabs and the grammar uses parse actions that use the ``loc`` argument to index into the string - being parsed, one can ensure a consistent view of the input string by doing one of the following: - - - calling ``parse_with_tabs`` on your grammar before calling ``parse_string`` (see :class:`parse_with_tabs`), - - define your parse action using the full ``(s,loc,toks)`` signature, and reference the input string using the - parse action's ``s`` argument, or - - explicitly expand the tabs in your input string before calling ``parse_string``. - - Examples: - - By default, partial matches are OK. - - >>> res = Word('a').parse_string('aaaaabaaa') - >>> print(res) - ['aaaaa'] - - The parsing behavior varies by the inheriting class of this abstract class. Please refer to the children - directly to see more examples. - - It raises an exception if parse_all flag is set and instring does not match the whole grammar. - - >>> res = Word('a').parse_string('aaaaabaaa', parse_all=True) - Traceback (most recent call last): - ... - pyparsing.ParseException: Expected end of text, found 'b' (at char 5), (line:1, col:6) - """ - parseAll = parse_all or parseAll - - ParserElement.reset_cache() - if not self.streamlined: - self.streamline() - for e in self.ignoreExprs: - e.streamline() - if not self.keepTabs: - instring = instring.expandtabs() - try: - loc, tokens = self._parse(instring, 0) - if parseAll: - loc = self.preParse(instring, loc) - se = Empty() + StringEnd() - se._parse(instring, loc) - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clearing out pyparsing internal stack trace - raise exc.with_traceback(None) - else: - return tokens - - def scan_string( - self, - instring: str, - max_matches: int = _MAX_INT, - overlap: bool = False, - *, - debug: bool = False, - maxMatches: int = _MAX_INT, - ) -> Generator[Tuple[ParseResults, int, int], None, None]: - """ - Scan the input string for expression matches. Each match will return the - matching tokens, start location, and end location. May be called with optional - ``max_matches`` argument, to clip scanning after 'n' matches are found. If - ``overlap`` is specified, then overlapping matches will be reported. - - Note that the start and end locations are reported relative to the string - being parsed. See :class:`parse_string` for more information on parsing - strings with embedded tabs. - - Example:: - - source = "sldjf123lsdjjkf345sldkjf879lkjsfd987" - print(source) - for tokens, start, end in Word(alphas).scan_string(source): - print(' '*start + '^'*(end-start)) - print(' '*start + tokens[0]) - - prints:: - - sldjf123lsdjjkf345sldkjf879lkjsfd987 - ^^^^^ - sldjf - ^^^^^^^ - lsdjjkf - ^^^^^^ - sldkjf - ^^^^^^ - lkjsfd - """ - maxMatches = min(maxMatches, max_matches) - if not self.streamlined: - self.streamline() - for e in self.ignoreExprs: - e.streamline() - - if not self.keepTabs: - instring = str(instring).expandtabs() - instrlen = len(instring) - loc = 0 - preparseFn = self.preParse - parseFn = self._parse - ParserElement.resetCache() - matches = 0 - try: - while loc <= instrlen and matches < maxMatches: - try: - preloc = preparseFn(instring, loc) - nextLoc, tokens = parseFn(instring, preloc, callPreParse=False) - except ParseException: - loc = preloc + 1 - else: - if nextLoc > loc: - matches += 1 - if debug: - print( - { - "tokens": tokens.asList(), - "start": preloc, - "end": nextLoc, - } - ) - yield tokens, preloc, nextLoc - if overlap: - nextloc = preparseFn(instring, loc) - if nextloc > loc: - loc = nextLoc - else: - loc += 1 - else: - loc = nextLoc - else: - loc = preloc + 1 - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise exc.with_traceback(None) - - def transform_string(self, instring: str, *, debug: bool = False) -> str: - """ - Extension to :class:`scan_string`, to modify matching text with modified tokens that may - be returned from a parse action. To use ``transform_string``, define a grammar and - attach a parse action to it that modifies the returned token list. - Invoking ``transform_string()`` on a target string will then scan for matches, - and replace the matched text patterns according to the logic in the parse - action. ``transform_string()`` returns the resulting transformed string. - - Example:: - - wd = Word(alphas) - wd.set_parse_action(lambda toks: toks[0].title()) - - print(wd.transform_string("now is the winter of our discontent made glorious summer by this sun of york.")) - - prints:: - - Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York. - """ - out: List[str] = [] - lastE = 0 - # force preservation of s, to minimize unwanted transformation of string, and to - # keep string locs straight between transform_string and scan_string - self.keepTabs = True - try: - for t, s, e in self.scan_string(instring, debug=debug): - out.append(instring[lastE:s]) - if t: - if isinstance(t, ParseResults): - out += t.as_list() - elif isinstance(t, Iterable) and not isinstance(t, str_type): - out.extend(t) - else: - out.append(t) - lastE = e - out.append(instring[lastE:]) - out = [o for o in out if o] - return "".join([str(s) for s in _flatten(out)]) - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise exc.with_traceback(None) - - def search_string( - self, - instring: str, - max_matches: int = _MAX_INT, - *, - debug: bool = False, - maxMatches: int = _MAX_INT, - ) -> ParseResults: - """ - Another extension to :class:`scan_string`, simplifying the access to the tokens found - to match the given parse expression. May be called with optional - ``max_matches`` argument, to clip searching after 'n' matches are found. - - Example:: - - # a capitalized word starts with an uppercase letter, followed by zero or more lowercase letters - cap_word = Word(alphas.upper(), alphas.lower()) - - print(cap_word.search_string("More than Iron, more than Lead, more than Gold I need Electricity")) - - # the sum() builtin can be used to merge results into a single ParseResults object - print(sum(cap_word.search_string("More than Iron, more than Lead, more than Gold I need Electricity"))) - - prints:: - - [['More'], ['Iron'], ['Lead'], ['Gold'], ['I'], ['Electricity']] - ['More', 'Iron', 'Lead', 'Gold', 'I', 'Electricity'] - """ - maxMatches = min(maxMatches, max_matches) - try: - return ParseResults( - [t for t, s, e in self.scan_string(instring, maxMatches, debug=debug)] - ) - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise exc.with_traceback(None) - - def split( - self, - instring: str, - maxsplit: int = _MAX_INT, - include_separators: bool = False, - *, - includeSeparators=False, - ) -> Generator[str, None, None]: - """ - Generator method to split a string using the given expression as a separator. - May be called with optional ``maxsplit`` argument, to limit the number of splits; - and the optional ``include_separators`` argument (default= ``False``), if the separating - matching text should be included in the split results. - - Example:: - - punc = one_of(list(".,;:/-!?")) - print(list(punc.split("This, this?, this sentence, is badly punctuated!"))) - - prints:: - - ['This', ' this', '', ' this sentence', ' is badly punctuated', ''] - """ - includeSeparators = includeSeparators or include_separators - last = 0 - for t, s, e in self.scan_string(instring, max_matches=maxsplit): - yield instring[last:s] - if includeSeparators: - yield t[0] - last = e - yield instring[last:] - - def __add__(self, other) -> "ParserElement": - """ - Implementation of ``+`` operator - returns :class:`And`. Adding strings to a :class:`ParserElement` - converts them to :class:`Literal`s by default. - - Example:: - - greet = Word(alphas) + "," + Word(alphas) + "!" - hello = "Hello, World!" - print(hello, "->", greet.parse_string(hello)) - - prints:: - - Hello, World! -> ['Hello', ',', 'World', '!'] - - ``...`` may be used as a parse expression as a short form of :class:`SkipTo`. - - Literal('start') + ... + Literal('end') - - is equivalent to: - - Literal('start') + SkipTo('end')("_skipped*") + Literal('end') - - Note that the skipped text is returned with '_skipped' as a results name, - and to support having multiple skips in the same parser, the value returned is - a list of all skipped text. - """ - if other is Ellipsis: - return _PendingSkip(self) - - if isinstance(other, str_type): - other = self._literalStringClass(other) - if not isinstance(other, ParserElement): - raise TypeError( - "Cannot combine element of type {} with ParserElement".format( - type(other).__name__ - ) - ) - return And([self, other]) - - def __radd__(self, other) -> "ParserElement": - """ - Implementation of ``+`` operator when left operand is not a :class:`ParserElement` - """ - if other is Ellipsis: - return SkipTo(self)("_skipped*") + self - - if isinstance(other, str_type): - other = self._literalStringClass(other) - if not isinstance(other, ParserElement): - raise TypeError( - "Cannot combine element of type {} with ParserElement".format( - type(other).__name__ - ) - ) - return other + self - - def __sub__(self, other) -> "ParserElement": - """ - Implementation of ``-`` operator, returns :class:`And` with error stop - """ - if isinstance(other, str_type): - other = self._literalStringClass(other) - if not isinstance(other, ParserElement): - raise TypeError( - "Cannot combine element of type {} with ParserElement".format( - type(other).__name__ - ) - ) - return self + And._ErrorStop() + other - - def __rsub__(self, other) -> "ParserElement": - """ - Implementation of ``-`` operator when left operand is not a :class:`ParserElement` - """ - if isinstance(other, str_type): - other = self._literalStringClass(other) - if not isinstance(other, ParserElement): - raise TypeError( - "Cannot combine element of type {} with ParserElement".format( - type(other).__name__ - ) - ) - return other - self - - def __mul__(self, other) -> "ParserElement": - """ - Implementation of ``*`` operator, allows use of ``expr * 3`` in place of - ``expr + expr + expr``. Expressions may also be multiplied by a 2-integer - tuple, similar to ``{min, max}`` multipliers in regular expressions. Tuples - may also include ``None`` as in: - - ``expr*(n, None)`` or ``expr*(n, )`` is equivalent - to ``expr*n + ZeroOrMore(expr)`` - (read as "at least n instances of ``expr``") - - ``expr*(None, n)`` is equivalent to ``expr*(0, n)`` - (read as "0 to n instances of ``expr``") - - ``expr*(None, None)`` is equivalent to ``ZeroOrMore(expr)`` - - ``expr*(1, None)`` is equivalent to ``OneOrMore(expr)`` - - Note that ``expr*(None, n)`` does not raise an exception if - more than n exprs exist in the input stream; that is, - ``expr*(None, n)`` does not enforce a maximum number of expr - occurrences. If this behavior is desired, then write - ``expr*(None, n) + ~expr`` - """ - if other is Ellipsis: - other = (0, None) - elif isinstance(other, tuple) and other[:1] == (Ellipsis,): - other = ((0,) + other[1:] + (None,))[:2] - - if isinstance(other, int): - minElements, optElements = other, 0 - elif isinstance(other, tuple): - other = tuple(o if o is not Ellipsis else None for o in other) - other = (other + (None, None))[:2] - if other[0] is None: - other = (0, other[1]) - if isinstance(other[0], int) and other[1] is None: - if other[0] == 0: - return ZeroOrMore(self) - if other[0] == 1: - return OneOrMore(self) - else: - return self * other[0] + ZeroOrMore(self) - elif isinstance(other[0], int) and isinstance(other[1], int): - minElements, optElements = other - optElements -= minElements - else: - raise TypeError( - "cannot multiply ParserElement and ({}) objects".format( - ",".join(type(item).__name__ for item in other) - ) - ) - else: - raise TypeError( - "cannot multiply ParserElement and {} objects".format( - type(other).__name__ - ) - ) - - if minElements < 0: - raise ValueError("cannot multiply ParserElement by negative value") - if optElements < 0: - raise ValueError( - "second tuple value must be greater or equal to first tuple value" - ) - if minElements == optElements == 0: - return And([]) - - if optElements: - - def makeOptionalList(n): - if n > 1: - return Opt(self + makeOptionalList(n - 1)) - else: - return Opt(self) - - if minElements: - if minElements == 1: - ret = self + makeOptionalList(optElements) - else: - ret = And([self] * minElements) + makeOptionalList(optElements) - else: - ret = makeOptionalList(optElements) - else: - if minElements == 1: - ret = self - else: - ret = And([self] * minElements) - return ret - - def __rmul__(self, other) -> "ParserElement": - return self.__mul__(other) - - def __or__(self, other) -> "ParserElement": - """ - Implementation of ``|`` operator - returns :class:`MatchFirst` - """ - if other is Ellipsis: - return _PendingSkip(self, must_skip=True) - - if isinstance(other, str_type): - other = self._literalStringClass(other) - if not isinstance(other, ParserElement): - raise TypeError( - "Cannot combine element of type {} with ParserElement".format( - type(other).__name__ - ) - ) - return MatchFirst([self, other]) - - def __ror__(self, other) -> "ParserElement": - """ - Implementation of ``|`` operator when left operand is not a :class:`ParserElement` - """ - if isinstance(other, str_type): - other = self._literalStringClass(other) - if not isinstance(other, ParserElement): - raise TypeError( - "Cannot combine element of type {} with ParserElement".format( - type(other).__name__ - ) - ) - return other | self - - def __xor__(self, other) -> "ParserElement": - """ - Implementation of ``^`` operator - returns :class:`Or` - """ - if isinstance(other, str_type): - other = self._literalStringClass(other) - if not isinstance(other, ParserElement): - raise TypeError( - "Cannot combine element of type {} with ParserElement".format( - type(other).__name__ - ) - ) - return Or([self, other]) - - def __rxor__(self, other) -> "ParserElement": - """ - Implementation of ``^`` operator when left operand is not a :class:`ParserElement` - """ - if isinstance(other, str_type): - other = self._literalStringClass(other) - if not isinstance(other, ParserElement): - raise TypeError( - "Cannot combine element of type {} with ParserElement".format( - type(other).__name__ - ) - ) - return other ^ self - - def __and__(self, other) -> "ParserElement": - """ - Implementation of ``&`` operator - returns :class:`Each` - """ - if isinstance(other, str_type): - other = self._literalStringClass(other) - if not isinstance(other, ParserElement): - raise TypeError( - "Cannot combine element of type {} with ParserElement".format( - type(other).__name__ - ) - ) - return Each([self, other]) - - def __rand__(self, other) -> "ParserElement": - """ - Implementation of ``&`` operator when left operand is not a :class:`ParserElement` - """ - if isinstance(other, str_type): - other = self._literalStringClass(other) - if not isinstance(other, ParserElement): - raise TypeError( - "Cannot combine element of type {} with ParserElement".format( - type(other).__name__ - ) - ) - return other & self - - def __invert__(self) -> "ParserElement": - """ - Implementation of ``~`` operator - returns :class:`NotAny` - """ - return NotAny(self) - - # disable __iter__ to override legacy use of sequential access to __getitem__ to - # iterate over a sequence - __iter__ = None - - def __getitem__(self, key): - """ - use ``[]`` indexing notation as a short form for expression repetition: - - - ``expr[n]`` is equivalent to ``expr*n`` - - ``expr[m, n]`` is equivalent to ``expr*(m, n)`` - - ``expr[n, ...]`` or ``expr[n,]`` is equivalent - to ``expr*n + ZeroOrMore(expr)`` - (read as "at least n instances of ``expr``") - - ``expr[..., n]`` is equivalent to ``expr*(0, n)`` - (read as "0 to n instances of ``expr``") - - ``expr[...]`` and ``expr[0, ...]`` are equivalent to ``ZeroOrMore(expr)`` - - ``expr[1, ...]`` is equivalent to ``OneOrMore(expr)`` - - ``None`` may be used in place of ``...``. - - Note that ``expr[..., n]`` and ``expr[m, n]``do not raise an exception - if more than ``n`` ``expr``s exist in the input stream. If this behavior is - desired, then write ``expr[..., n] + ~expr``. - """ - - # convert single arg keys to tuples - try: - if isinstance(key, str_type): - key = (key,) - iter(key) - except TypeError: - key = (key, key) - - if len(key) > 2: - raise TypeError( - "only 1 or 2 index arguments supported ({}{})".format( - key[:5], "... [{}]".format(len(key)) if len(key) > 5 else "" - ) - ) - - # clip to 2 elements - ret = self * tuple(key[:2]) - return ret - - def __call__(self, name: str = None) -> "ParserElement": - """ - Shortcut for :class:`set_results_name`, with ``list_all_matches=False``. - - If ``name`` is given with a trailing ``'*'`` character, then ``list_all_matches`` will be - passed as ``True``. - - If ``name` is omitted, same as calling :class:`copy`. - - Example:: - - # these are equivalent - userdata = Word(alphas).set_results_name("name") + Word(nums + "-").set_results_name("socsecno") - userdata = Word(alphas)("name") + Word(nums + "-")("socsecno") - """ - if name is not None: - return self._setResultsName(name) - else: - return self.copy() - - def suppress(self) -> "ParserElement": - """ - Suppresses the output of this :class:`ParserElement`; useful to keep punctuation from - cluttering up returned output. - """ - return Suppress(self) - - def ignore_whitespace(self, recursive: bool = True) -> "ParserElement": - """ - Enables the skipping of whitespace before matching the characters in the - :class:`ParserElement`'s defined pattern. - - :param recursive: If ``True`` (the default), also enable whitespace skipping in child elements (if any) - """ - self.skipWhitespace = True - return self - - def leave_whitespace(self, recursive: bool = True) -> "ParserElement": - """ - Disables the skipping of whitespace before matching the characters in the - :class:`ParserElement`'s defined pattern. This is normally only used internally by - the pyparsing module, but may be needed in some whitespace-sensitive grammars. - - :param recursive: If true (the default), also disable whitespace skipping in child elements (if any) - """ - self.skipWhitespace = False - return self - - def set_whitespace_chars( - self, chars: Union[Set[str], str], copy_defaults: bool = False - ) -> "ParserElement": - """ - Overrides the default whitespace chars - """ - self.skipWhitespace = True - self.whiteChars = set(chars) - self.copyDefaultWhiteChars = copy_defaults - return self - - def parse_with_tabs(self) -> "ParserElement": - """ - Overrides default behavior to expand ```` s to spaces before parsing the input string. - Must be called before ``parse_string`` when the input grammar contains elements that - match ```` characters. - """ - self.keepTabs = True - return self - - def ignore(self, other: "ParserElement") -> "ParserElement": - """ - Define expression to be ignored (e.g., comments) while doing pattern - matching; may be called repeatedly, to define multiple comment or other - ignorable patterns. - - Example:: - - patt = Word(alphas)[1, ...] - patt.parse_string('ablaj /* comment */ lskjd') - # -> ['ablaj'] - - patt.ignore(c_style_comment) - patt.parse_string('ablaj /* comment */ lskjd') - # -> ['ablaj', 'lskjd'] - """ - import typing - - if isinstance(other, str_type): - other = Suppress(other) - - if isinstance(other, Suppress): - if other not in self.ignoreExprs: - self.ignoreExprs.append(other) - else: - self.ignoreExprs.append(Suppress(other.copy())) - return self - - def set_debug_actions( - self, - start_action: DebugStartAction, - success_action: DebugSuccessAction, - exception_action: DebugExceptionAction, - ) -> "ParserElement": - """ - Customize display of debugging messages while doing pattern matching: - - - ``start_action`` - method to be called when an expression is about to be parsed; - should have the signature ``fn(input_string: str, location: int, expression: ParserElement, cache_hit: bool)`` - - - ``success_action`` - method to be called when an expression has successfully parsed; - should have the signature ``fn(input_string: str, start_location: int, end_location: int, expression: ParserELement, parsed_tokens: ParseResults, cache_hit: bool)`` - - - ``exception_action`` - method to be called when expression fails to parse; - should have the signature ``fn(input_string: str, location: int, expression: ParserElement, exception: Exception, cache_hit: bool)`` - """ - self.debugActions = self.DebugActions( - start_action or _default_start_debug_action, - success_action or _default_success_debug_action, - exception_action or _default_exception_debug_action, - ) - self.debug = True - return self - - def set_debug(self, flag: bool = True) -> "ParserElement": - """ - Enable display of debugging messages while doing pattern matching. - Set ``flag`` to ``True`` to enable, ``False`` to disable. - - Example:: - - wd = Word(alphas).set_name("alphaword") - integer = Word(nums).set_name("numword") - term = wd | integer - - # turn on debugging for wd - wd.set_debug() - - term[1, ...].parse_string("abc 123 xyz 890") - - prints:: - - Match alphaword at loc 0(1,1) - Matched alphaword -> ['abc'] - Match alphaword at loc 3(1,4) - Exception raised:Expected alphaword (at char 4), (line:1, col:5) - Match alphaword at loc 7(1,8) - Matched alphaword -> ['xyz'] - Match alphaword at loc 11(1,12) - Exception raised:Expected alphaword (at char 12), (line:1, col:13) - Match alphaword at loc 15(1,16) - Exception raised:Expected alphaword (at char 15), (line:1, col:16) - - The output shown is that produced by the default debug actions - custom debug actions can be - specified using :class:`set_debug_actions`. Prior to attempting - to match the ``wd`` expression, the debugging message ``"Match at loc (,)"`` - is shown. Then if the parse succeeds, a ``"Matched"`` message is shown, or an ``"Exception raised"`` - message is shown. Also note the use of :class:`set_name` to assign a human-readable name to the expression, - which makes debugging and exception messages easier to understand - for instance, the default - name created for the :class:`Word` expression without calling ``set_name`` is ``"W:(A-Za-z)"``. - """ - if flag: - self.set_debug_actions( - _default_start_debug_action, - _default_success_debug_action, - _default_exception_debug_action, - ) - else: - self.debug = False - return self - - @property - def default_name(self) -> str: - if self._defaultName is None: - self._defaultName = self._generateDefaultName() - return self._defaultName - - @abstractmethod - def _generateDefaultName(self): - """ - Child classes must define this method, which defines how the ``default_name`` is set. - """ - - def set_name(self, name: str) -> "ParserElement": - """ - Define name for this expression, makes debugging and exception messages clearer. - Example:: - Word(nums).parse_string("ABC") # -> Exception: Expected W:(0-9) (at char 0), (line:1, col:1) - Word(nums).set_name("integer").parse_string("ABC") # -> Exception: Expected integer (at char 0), (line:1, col:1) - """ - self.customName = name - self.errmsg = "Expected " + self.name - if __diag__.enable_debug_on_named_expressions: - self.set_debug() - return self - - @property - def name(self) -> str: - # This will use a user-defined name if available, but otherwise defaults back to the auto-generated name - return self.customName if self.customName is not None else self.default_name - - def __str__(self) -> str: - return self.name - - def __repr__(self) -> str: - return str(self) - - def streamline(self) -> "ParserElement": - self.streamlined = True - self._defaultName = None - return self - - def recurse(self) -> Sequence["ParserElement"]: - return [] - - def _checkRecursion(self, parseElementList): - subRecCheckList = parseElementList[:] + [self] - for e in self.recurse(): - e._checkRecursion(subRecCheckList) - - def validate(self, validateTrace=None) -> None: - """ - Check defined expressions for valid structure, check for infinite recursive definitions. - """ - self._checkRecursion([]) - - def parse_file( - self, - file_or_filename: Union[str, Path, TextIO], - encoding: str = "utf-8", - parse_all: bool = False, - *, - parseAll: bool = False, - ) -> ParseResults: - """ - Execute the parse expression on the given file or filename. - If a filename is specified (instead of a file object), - the entire file is opened, read, and closed before parsing. - """ - parseAll = parseAll or parse_all - try: - file_contents = file_or_filename.read() - except AttributeError: - with open(file_or_filename, "r", encoding=encoding) as f: - file_contents = f.read() - try: - return self.parse_string(file_contents, parseAll) - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise exc.with_traceback(None) - - def __eq__(self, other): - if self is other: - return True - elif isinstance(other, str_type): - return self.matches(other, parse_all=True) - elif isinstance(other, ParserElement): - return vars(self) == vars(other) - return False - - def __hash__(self): - return id(self) - - def matches( - self, test_string: str, parse_all: bool = True, *, parseAll: bool = True - ) -> bool: - """ - Method for quick testing of a parser against a test string. Good for simple - inline microtests of sub expressions while building up larger parser. - - Parameters: - - ``test_string`` - to test against this expression for a match - - ``parse_all`` - (default= ``True``) - flag to pass to :class:`parse_string` when running tests - - Example:: - - expr = Word(nums) - assert expr.matches("100") - """ - parseAll = parseAll and parse_all - try: - self.parse_string(str(test_string), parse_all=parseAll) - return True - except ParseBaseException: - return False - - def run_tests( - self, - tests: Union[str, List[str]], - parse_all: bool = True, - comment: typing.Optional[Union["ParserElement", str]] = "#", - full_dump: bool = True, - print_results: bool = True, - failure_tests: bool = False, - post_parse: Callable[[str, ParseResults], str] = None, - file: typing.Optional[TextIO] = None, - with_line_numbers: bool = False, - *, - parseAll: bool = True, - fullDump: bool = True, - printResults: bool = True, - failureTests: bool = False, - postParse: Callable[[str, ParseResults], str] = None, - ) -> Tuple[bool, List[Tuple[str, Union[ParseResults, Exception]]]]: - """ - Execute the parse expression on a series of test strings, showing each - test, the parsed results or where the parse failed. Quick and easy way to - run a parse expression against a list of sample strings. - - Parameters: - - ``tests`` - a list of separate test strings, or a multiline string of test strings - - ``parse_all`` - (default= ``True``) - flag to pass to :class:`parse_string` when running tests - - ``comment`` - (default= ``'#'``) - expression for indicating embedded comments in the test - string; pass None to disable comment filtering - - ``full_dump`` - (default= ``True``) - dump results as list followed by results names in nested outline; - if False, only dump nested list - - ``print_results`` - (default= ``True``) prints test output to stdout - - ``failure_tests`` - (default= ``False``) indicates if these tests are expected to fail parsing - - ``post_parse`` - (default= ``None``) optional callback for successful parse results; called as - `fn(test_string, parse_results)` and returns a string to be added to the test output - - ``file`` - (default= ``None``) optional file-like object to which test output will be written; - if None, will default to ``sys.stdout`` - - ``with_line_numbers`` - default= ``False``) show test strings with line and column numbers - - Returns: a (success, results) tuple, where success indicates that all tests succeeded - (or failed if ``failure_tests`` is True), and the results contain a list of lines of each - test's output - - Example:: - - number_expr = pyparsing_common.number.copy() - - result = number_expr.run_tests(''' - # unsigned integer - 100 - # negative integer - -100 - # float with scientific notation - 6.02e23 - # integer with scientific notation - 1e-12 - ''') - print("Success" if result[0] else "Failed!") - - result = number_expr.run_tests(''' - # stray character - 100Z - # missing leading digit before '.' - -.100 - # too many '.' - 3.14.159 - ''', failure_tests=True) - print("Success" if result[0] else "Failed!") - - prints:: - - # unsigned integer - 100 - [100] - - # negative integer - -100 - [-100] - - # float with scientific notation - 6.02e23 - [6.02e+23] - - # integer with scientific notation - 1e-12 - [1e-12] - - Success - - # stray character - 100Z - ^ - FAIL: Expected end of text (at char 3), (line:1, col:4) - - # missing leading digit before '.' - -.100 - ^ - FAIL: Expected {real number with scientific notation | real number | signed integer} (at char 0), (line:1, col:1) - - # too many '.' - 3.14.159 - ^ - FAIL: Expected end of text (at char 4), (line:1, col:5) - - Success - - Each test string must be on a single line. If you want to test a string that spans multiple - lines, create a test like this:: - - expr.run_tests(r"this is a test\\n of strings that spans \\n 3 lines") - - (Note that this is a raw string literal, you must include the leading ``'r'``.) - """ - from .testing import pyparsing_test - - parseAll = parseAll and parse_all - fullDump = fullDump and full_dump - printResults = printResults and print_results - failureTests = failureTests or failure_tests - postParse = postParse or post_parse - if isinstance(tests, str_type): - line_strip = type(tests).strip - tests = [line_strip(test_line) for test_line in tests.rstrip().splitlines()] - if isinstance(comment, str_type): - comment = Literal(comment) - if file is None: - file = sys.stdout - print_ = file.write - - result: Union[ParseResults, Exception] - allResults = [] - comments = [] - success = True - NL = Literal(r"\n").add_parse_action(replace_with("\n")).ignore(quoted_string) - BOM = "\ufeff" - for t in tests: - if comment is not None and comment.matches(t, False) or comments and not t: - comments.append( - pyparsing_test.with_line_numbers(t) if with_line_numbers else t - ) - continue - if not t: - continue - out = [ - "\n" + "\n".join(comments) if comments else "", - pyparsing_test.with_line_numbers(t) if with_line_numbers else t, - ] - comments = [] - try: - # convert newline marks to actual newlines, and strip leading BOM if present - t = NL.transform_string(t.lstrip(BOM)) - result = self.parse_string(t, parse_all=parseAll) - except ParseBaseException as pe: - fatal = "(FATAL)" if isinstance(pe, ParseFatalException) else "" - out.append(pe.explain()) - out.append("FAIL: " + str(pe)) - if ParserElement.verbose_stacktrace: - out.extend(traceback.format_tb(pe.__traceback__)) - success = success and failureTests - result = pe - except Exception as exc: - out.append("FAIL-EXCEPTION: {}: {}".format(type(exc).__name__, exc)) - if ParserElement.verbose_stacktrace: - out.extend(traceback.format_tb(exc.__traceback__)) - success = success and failureTests - result = exc - else: - success = success and not failureTests - if postParse is not None: - try: - pp_value = postParse(t, result) - if pp_value is not None: - if isinstance(pp_value, ParseResults): - out.append(pp_value.dump()) - else: - out.append(str(pp_value)) - else: - out.append(result.dump()) - except Exception as e: - out.append(result.dump(full=fullDump)) - out.append( - "{} failed: {}: {}".format( - postParse.__name__, type(e).__name__, e - ) - ) - else: - out.append(result.dump(full=fullDump)) - out.append("") - - if printResults: - print_("\n".join(out)) - - allResults.append((t, result)) - - return success, allResults - - def create_diagram( - self, - output_html: Union[TextIO, Path, str], - vertical: int = 3, - show_results_names: bool = False, - show_groups: bool = False, - **kwargs, - ) -> None: - """ - Create a railroad diagram for the parser. - - Parameters: - - output_html (str or file-like object) - output target for generated - diagram HTML - - vertical (int) - threshold for formatting multiple alternatives vertically - instead of horizontally (default=3) - - show_results_names - bool flag whether diagram should show annotations for - defined results names - - show_groups - bool flag whether groups should be highlighted with an unlabeled surrounding box - Additional diagram-formatting keyword arguments can also be included; - see railroad.Diagram class. - """ - - try: - from .diagram import to_railroad, railroad_to_html - except ImportError as ie: - raise Exception( - "must ``pip install pyparsing[diagrams]`` to generate parser railroad diagrams" - ) from ie - - self.streamline() - - railroad = to_railroad( - self, - vertical=vertical, - show_results_names=show_results_names, - show_groups=show_groups, - diagram_kwargs=kwargs, - ) - if isinstance(output_html, (str, Path)): - with open(output_html, "w", encoding="utf-8") as diag_file: - diag_file.write(railroad_to_html(railroad)) - else: - # we were passed a file-like object, just write to it - output_html.write(railroad_to_html(railroad)) - - setDefaultWhitespaceChars = set_default_whitespace_chars - inlineLiteralsUsing = inline_literals_using - setResultsName = set_results_name - setBreak = set_break - setParseAction = set_parse_action - addParseAction = add_parse_action - addCondition = add_condition - setFailAction = set_fail_action - tryParse = try_parse - canParseNext = can_parse_next - resetCache = reset_cache - enableLeftRecursion = enable_left_recursion - enablePackrat = enable_packrat - parseString = parse_string - scanString = scan_string - searchString = search_string - transformString = transform_string - setWhitespaceChars = set_whitespace_chars - parseWithTabs = parse_with_tabs - setDebugActions = set_debug_actions - setDebug = set_debug - defaultName = default_name - setName = set_name - parseFile = parse_file - runTests = run_tests - ignoreWhitespace = ignore_whitespace - leaveWhitespace = leave_whitespace - - -class _PendingSkip(ParserElement): - # internal placeholder class to hold a place were '...' is added to a parser element, - # once another ParserElement is added, this placeholder will be replaced with a SkipTo - def __init__(self, expr: ParserElement, must_skip: bool = False): - super().__init__() - self.anchor = expr - self.must_skip = must_skip - - def _generateDefaultName(self): - return str(self.anchor + Empty()).replace("Empty", "...") - - def __add__(self, other) -> "ParserElement": - skipper = SkipTo(other).set_name("...")("_skipped*") - if self.must_skip: - - def must_skip(t): - if not t._skipped or t._skipped.as_list() == [""]: - del t[0] - t.pop("_skipped", None) - - def show_skip(t): - if t._skipped.as_list()[-1:] == [""]: - t.pop("_skipped") - t["_skipped"] = "missing <" + repr(self.anchor) + ">" - - return ( - self.anchor + skipper().add_parse_action(must_skip) - | skipper().add_parse_action(show_skip) - ) + other - - return self.anchor + skipper + other - - def __repr__(self): - return self.defaultName - - def parseImpl(self, *args): - raise Exception( - "use of `...` expression without following SkipTo target expression" - ) - - -class Token(ParserElement): - """Abstract :class:`ParserElement` subclass, for defining atomic - matching patterns. - """ - - def __init__(self): - super().__init__(savelist=False) - - def _generateDefaultName(self): - return type(self).__name__ - - -class Empty(Token): - """ - An empty token, will always match. - """ - - def __init__(self): - super().__init__() - self.mayReturnEmpty = True - self.mayIndexError = False - - -class NoMatch(Token): - """ - A token that will never match. - """ - - def __init__(self): - super().__init__() - self.mayReturnEmpty = True - self.mayIndexError = False - self.errmsg = "Unmatchable token" - - def parseImpl(self, instring, loc, doActions=True): - raise ParseException(instring, loc, self.errmsg, self) - - -class Literal(Token): - """ - Token to exactly match a specified string. - - Example:: - - Literal('blah').parse_string('blah') # -> ['blah'] - Literal('blah').parse_string('blahfooblah') # -> ['blah'] - Literal('blah').parse_string('bla') # -> Exception: Expected "blah" - - For case-insensitive matching, use :class:`CaselessLiteral`. - - For keyword matching (force word break before and after the matched string), - use :class:`Keyword` or :class:`CaselessKeyword`. - """ - - def __init__(self, match_string: str = "", *, matchString: str = ""): - super().__init__() - match_string = matchString or match_string - self.match = match_string - self.matchLen = len(match_string) - try: - self.firstMatchChar = match_string[0] - except IndexError: - raise ValueError("null string passed to Literal; use Empty() instead") - self.errmsg = "Expected " + self.name - self.mayReturnEmpty = False - self.mayIndexError = False - - # Performance tuning: modify __class__ to select - # a parseImpl optimized for single-character check - if self.matchLen == 1 and type(self) is Literal: - self.__class__ = _SingleCharLiteral - - def _generateDefaultName(self): - return repr(self.match) - - def parseImpl(self, instring, loc, doActions=True): - if instring[loc] == self.firstMatchChar and instring.startswith( - self.match, loc - ): - return loc + self.matchLen, self.match - raise ParseException(instring, loc, self.errmsg, self) - - -class _SingleCharLiteral(Literal): - def parseImpl(self, instring, loc, doActions=True): - if instring[loc] == self.firstMatchChar: - return loc + 1, self.match - raise ParseException(instring, loc, self.errmsg, self) - - -ParserElement._literalStringClass = Literal - - -class Keyword(Token): - """ - Token to exactly match a specified string as a keyword, that is, - it must be immediately followed by a non-keyword character. Compare - with :class:`Literal`: - - - ``Literal("if")`` will match the leading ``'if'`` in - ``'ifAndOnlyIf'``. - - ``Keyword("if")`` will not; it will only match the leading - ``'if'`` in ``'if x=1'``, or ``'if(y==2)'`` - - Accepts two optional constructor arguments in addition to the - keyword string: - - - ``identChars`` is a string of characters that would be valid - identifier characters, defaulting to all alphanumerics + "_" and - "$" - - ``caseless`` allows case-insensitive matching, default is ``False``. - - Example:: - - Keyword("start").parse_string("start") # -> ['start'] - Keyword("start").parse_string("starting") # -> Exception - - For case-insensitive matching, use :class:`CaselessKeyword`. - """ - - DEFAULT_KEYWORD_CHARS = alphanums + "_$" - - def __init__( - self, - match_string: str = "", - ident_chars: typing.Optional[str] = None, - caseless: bool = False, - *, - matchString: str = "", - identChars: typing.Optional[str] = None, - ): - super().__init__() - identChars = identChars or ident_chars - if identChars is None: - identChars = Keyword.DEFAULT_KEYWORD_CHARS - match_string = matchString or match_string - self.match = match_string - self.matchLen = len(match_string) - try: - self.firstMatchChar = match_string[0] - except IndexError: - raise ValueError("null string passed to Keyword; use Empty() instead") - self.errmsg = "Expected {} {}".format(type(self).__name__, self.name) - self.mayReturnEmpty = False - self.mayIndexError = False - self.caseless = caseless - if caseless: - self.caselessmatch = match_string.upper() - identChars = identChars.upper() - self.identChars = set(identChars) - - def _generateDefaultName(self): - return repr(self.match) - - def parseImpl(self, instring, loc, doActions=True): - errmsg = self.errmsg - errloc = loc - if self.caseless: - if instring[loc : loc + self.matchLen].upper() == self.caselessmatch: - if loc == 0 or instring[loc - 1].upper() not in self.identChars: - if ( - loc >= len(instring) - self.matchLen - or instring[loc + self.matchLen].upper() not in self.identChars - ): - return loc + self.matchLen, self.match - else: - # followed by keyword char - errmsg += ", was immediately followed by keyword character" - errloc = loc + self.matchLen - else: - # preceded by keyword char - errmsg += ", keyword was immediately preceded by keyword character" - errloc = loc - 1 - # else no match just raise plain exception - - else: - if ( - instring[loc] == self.firstMatchChar - and self.matchLen == 1 - or instring.startswith(self.match, loc) - ): - if loc == 0 or instring[loc - 1] not in self.identChars: - if ( - loc >= len(instring) - self.matchLen - or instring[loc + self.matchLen] not in self.identChars - ): - return loc + self.matchLen, self.match - else: - # followed by keyword char - errmsg += ( - ", keyword was immediately followed by keyword character" - ) - errloc = loc + self.matchLen - else: - # preceded by keyword char - errmsg += ", keyword was immediately preceded by keyword character" - errloc = loc - 1 - # else no match just raise plain exception - - raise ParseException(instring, errloc, errmsg, self) - - @staticmethod - def set_default_keyword_chars(chars) -> None: - """ - Overrides the default characters used by :class:`Keyword` expressions. - """ - Keyword.DEFAULT_KEYWORD_CHARS = chars - - setDefaultKeywordChars = set_default_keyword_chars - - -class CaselessLiteral(Literal): - """ - Token to match a specified string, ignoring case of letters. - Note: the matched results will always be in the case of the given - match string, NOT the case of the input text. - - Example:: - - CaselessLiteral("CMD")[1, ...].parse_string("cmd CMD Cmd10") - # -> ['CMD', 'CMD', 'CMD'] - - (Contrast with example for :class:`CaselessKeyword`.) - """ - - def __init__(self, match_string: str = "", *, matchString: str = ""): - match_string = matchString or match_string - super().__init__(match_string.upper()) - # Preserve the defining literal. - self.returnString = match_string - self.errmsg = "Expected " + self.name - - def parseImpl(self, instring, loc, doActions=True): - if instring[loc : loc + self.matchLen].upper() == self.match: - return loc + self.matchLen, self.returnString - raise ParseException(instring, loc, self.errmsg, self) - - -class CaselessKeyword(Keyword): - """ - Caseless version of :class:`Keyword`. - - Example:: - - CaselessKeyword("CMD")[1, ...].parse_string("cmd CMD Cmd10") - # -> ['CMD', 'CMD'] - - (Contrast with example for :class:`CaselessLiteral`.) - """ - - def __init__( - self, - match_string: str = "", - ident_chars: typing.Optional[str] = None, - *, - matchString: str = "", - identChars: typing.Optional[str] = None, - ): - identChars = identChars or ident_chars - match_string = matchString or match_string - super().__init__(match_string, identChars, caseless=True) - - -class CloseMatch(Token): - """A variation on :class:`Literal` which matches "close" matches, - that is, strings with at most 'n' mismatching characters. - :class:`CloseMatch` takes parameters: - - - ``match_string`` - string to be matched - - ``caseless`` - a boolean indicating whether to ignore casing when comparing characters - - ``max_mismatches`` - (``default=1``) maximum number of - mismatches allowed to count as a match - - The results from a successful parse will contain the matched text - from the input string and the following named results: - - - ``mismatches`` - a list of the positions within the - match_string where mismatches were found - - ``original`` - the original match_string used to compare - against the input string - - If ``mismatches`` is an empty list, then the match was an exact - match. - - Example:: - - patt = CloseMatch("ATCATCGAATGGA") - patt.parse_string("ATCATCGAAXGGA") # -> (['ATCATCGAAXGGA'], {'mismatches': [[9]], 'original': ['ATCATCGAATGGA']}) - patt.parse_string("ATCAXCGAAXGGA") # -> Exception: Expected 'ATCATCGAATGGA' (with up to 1 mismatches) (at char 0), (line:1, col:1) - - # exact match - patt.parse_string("ATCATCGAATGGA") # -> (['ATCATCGAATGGA'], {'mismatches': [[]], 'original': ['ATCATCGAATGGA']}) - - # close match allowing up to 2 mismatches - patt = CloseMatch("ATCATCGAATGGA", max_mismatches=2) - patt.parse_string("ATCAXCGAAXGGA") # -> (['ATCAXCGAAXGGA'], {'mismatches': [[4, 9]], 'original': ['ATCATCGAATGGA']}) - """ - - def __init__( - self, - match_string: str, - max_mismatches: int = None, - *, - maxMismatches: int = 1, - caseless=False, - ): - maxMismatches = max_mismatches if max_mismatches is not None else maxMismatches - super().__init__() - self.match_string = match_string - self.maxMismatches = maxMismatches - self.errmsg = "Expected {!r} (with up to {} mismatches)".format( - self.match_string, self.maxMismatches - ) - self.caseless = caseless - self.mayIndexError = False - self.mayReturnEmpty = False - - def _generateDefaultName(self): - return "{}:{!r}".format(type(self).__name__, self.match_string) - - def parseImpl(self, instring, loc, doActions=True): - start = loc - instrlen = len(instring) - maxloc = start + len(self.match_string) - - if maxloc <= instrlen: - match_string = self.match_string - match_stringloc = 0 - mismatches = [] - maxMismatches = self.maxMismatches - - for match_stringloc, s_m in enumerate( - zip(instring[loc:maxloc], match_string) - ): - src, mat = s_m - if self.caseless: - src, mat = src.lower(), mat.lower() - - if src != mat: - mismatches.append(match_stringloc) - if len(mismatches) > maxMismatches: - break - else: - loc = start + match_stringloc + 1 - results = ParseResults([instring[start:loc]]) - results["original"] = match_string - results["mismatches"] = mismatches - return loc, results - - raise ParseException(instring, loc, self.errmsg, self) - - -class Word(Token): - """Token for matching words composed of allowed character sets. - Parameters: - - ``init_chars`` - string of all characters that should be used to - match as a word; "ABC" will match "AAA", "ABAB", "CBAC", etc.; - if ``body_chars`` is also specified, then this is the string of - initial characters - - ``body_chars`` - string of characters that - can be used for matching after a matched initial character as - given in ``init_chars``; if omitted, same as the initial characters - (default=``None``) - - ``min`` - minimum number of characters to match (default=1) - - ``max`` - maximum number of characters to match (default=0) - - ``exact`` - exact number of characters to match (default=0) - - ``as_keyword`` - match as a keyword (default=``False``) - - ``exclude_chars`` - characters that might be - found in the input ``body_chars`` string but which should not be - accepted for matching ;useful to define a word of all - printables except for one or two characters, for instance - (default=``None``) - - :class:`srange` is useful for defining custom character set strings - for defining :class:`Word` expressions, using range notation from - regular expression character sets. - - A common mistake is to use :class:`Word` to match a specific literal - string, as in ``Word("Address")``. Remember that :class:`Word` - uses the string argument to define *sets* of matchable characters. - This expression would match "Add", "AAA", "dAred", or any other word - made up of the characters 'A', 'd', 'r', 'e', and 's'. To match an - exact literal string, use :class:`Literal` or :class:`Keyword`. - - pyparsing includes helper strings for building Words: - - - :class:`alphas` - - :class:`nums` - - :class:`alphanums` - - :class:`hexnums` - - :class:`alphas8bit` (alphabetic characters in ASCII range 128-255 - - accented, tilded, umlauted, etc.) - - :class:`punc8bit` (non-alphabetic characters in ASCII range - 128-255 - currency, symbols, superscripts, diacriticals, etc.) - - :class:`printables` (any non-whitespace character) - - ``alphas``, ``nums``, and ``printables`` are also defined in several - Unicode sets - see :class:`pyparsing_unicode``. - - Example:: - - # a word composed of digits - integer = Word(nums) # equivalent to Word("0123456789") or Word(srange("0-9")) - - # a word with a leading capital, and zero or more lowercase - capital_word = Word(alphas.upper(), alphas.lower()) - - # hostnames are alphanumeric, with leading alpha, and '-' - hostname = Word(alphas, alphanums + '-') - - # roman numeral (not a strict parser, accepts invalid mix of characters) - roman = Word("IVXLCDM") - - # any string of non-whitespace characters, except for ',' - csv_value = Word(printables, exclude_chars=",") - """ - - def __init__( - self, - init_chars: str = "", - body_chars: typing.Optional[str] = None, - min: int = 1, - max: int = 0, - exact: int = 0, - as_keyword: bool = False, - exclude_chars: typing.Optional[str] = None, - *, - initChars: typing.Optional[str] = None, - bodyChars: typing.Optional[str] = None, - asKeyword: bool = False, - excludeChars: typing.Optional[str] = None, - ): - initChars = initChars or init_chars - bodyChars = bodyChars or body_chars - asKeyword = asKeyword or as_keyword - excludeChars = excludeChars or exclude_chars - super().__init__() - if not initChars: - raise ValueError( - "invalid {}, initChars cannot be empty string".format( - type(self).__name__ - ) - ) - - initChars = set(initChars) - self.initChars = initChars - if excludeChars: - excludeChars = set(excludeChars) - initChars -= excludeChars - if bodyChars: - bodyChars = set(bodyChars) - excludeChars - self.initCharsOrig = "".join(sorted(initChars)) - - if bodyChars: - self.bodyCharsOrig = "".join(sorted(bodyChars)) - self.bodyChars = set(bodyChars) - else: - self.bodyCharsOrig = "".join(sorted(initChars)) - self.bodyChars = set(initChars) - - self.maxSpecified = max > 0 - - if min < 1: - raise ValueError( - "cannot specify a minimum length < 1; use Opt(Word()) if zero-length word is permitted" - ) - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - self.errmsg = "Expected " + self.name - self.mayIndexError = False - self.asKeyword = asKeyword - - # see if we can make a regex for this Word - if " " not in self.initChars | self.bodyChars and (min == 1 and exact == 0): - if self.bodyChars == self.initChars: - if max == 0: - repeat = "+" - elif max == 1: - repeat = "" - else: - repeat = "{{{},{}}}".format( - self.minLen, "" if self.maxLen == _MAX_INT else self.maxLen - ) - self.reString = "[{}]{}".format( - _collapse_string_to_ranges(self.initChars), - repeat, - ) - elif len(self.initChars) == 1: - if max == 0: - repeat = "*" - else: - repeat = "{{0,{}}}".format(max - 1) - self.reString = "{}[{}]{}".format( - re.escape(self.initCharsOrig), - _collapse_string_to_ranges(self.bodyChars), - repeat, - ) - else: - if max == 0: - repeat = "*" - elif max == 2: - repeat = "" - else: - repeat = "{{0,{}}}".format(max - 1) - self.reString = "[{}][{}]{}".format( - _collapse_string_to_ranges(self.initChars), - _collapse_string_to_ranges(self.bodyChars), - repeat, - ) - if self.asKeyword: - self.reString = r"\b" + self.reString + r"\b" - - try: - self.re = re.compile(self.reString) - except re.error: - self.re = None - else: - self.re_match = self.re.match - self.__class__ = _WordRegex - - def _generateDefaultName(self): - def charsAsStr(s): - max_repr_len = 16 - s = _collapse_string_to_ranges(s, re_escape=False) - if len(s) > max_repr_len: - return s[: max_repr_len - 3] + "..." - else: - return s - - if self.initChars != self.bodyChars: - base = "W:({}, {})".format( - charsAsStr(self.initChars), charsAsStr(self.bodyChars) - ) - else: - base = "W:({})".format(charsAsStr(self.initChars)) - - # add length specification - if self.minLen > 1 or self.maxLen != _MAX_INT: - if self.minLen == self.maxLen: - if self.minLen == 1: - return base[2:] - else: - return base + "{{{}}}".format(self.minLen) - elif self.maxLen == _MAX_INT: - return base + "{{{},...}}".format(self.minLen) - else: - return base + "{{{},{}}}".format(self.minLen, self.maxLen) - return base - - def parseImpl(self, instring, loc, doActions=True): - if instring[loc] not in self.initChars: - raise ParseException(instring, loc, self.errmsg, self) - - start = loc - loc += 1 - instrlen = len(instring) - bodychars = self.bodyChars - maxloc = start + self.maxLen - maxloc = min(maxloc, instrlen) - while loc < maxloc and instring[loc] in bodychars: - loc += 1 - - throwException = False - if loc - start < self.minLen: - throwException = True - elif self.maxSpecified and loc < instrlen and instring[loc] in bodychars: - throwException = True - elif self.asKeyword: - if ( - start > 0 - and instring[start - 1] in bodychars - or loc < instrlen - and instring[loc] in bodychars - ): - throwException = True - - if throwException: - raise ParseException(instring, loc, self.errmsg, self) - - return loc, instring[start:loc] - - -class _WordRegex(Word): - def parseImpl(self, instring, loc, doActions=True): - result = self.re_match(instring, loc) - if not result: - raise ParseException(instring, loc, self.errmsg, self) - - loc = result.end() - return loc, result.group() - - -class Char(_WordRegex): - """A short-cut class for defining :class:`Word` ``(characters, exact=1)``, - when defining a match of any single character in a string of - characters. - """ - - def __init__( - self, - charset: str, - as_keyword: bool = False, - exclude_chars: typing.Optional[str] = None, - *, - asKeyword: bool = False, - excludeChars: typing.Optional[str] = None, - ): - asKeyword = asKeyword or as_keyword - excludeChars = excludeChars or exclude_chars - super().__init__( - charset, exact=1, asKeyword=asKeyword, excludeChars=excludeChars - ) - self.reString = "[{}]".format(_collapse_string_to_ranges(self.initChars)) - if asKeyword: - self.reString = r"\b{}\b".format(self.reString) - self.re = re.compile(self.reString) - self.re_match = self.re.match - - -class Regex(Token): - r"""Token for matching strings that match a given regular - expression. Defined with string specifying the regular expression in - a form recognized by the stdlib Python `re module `_. - If the given regex contains named groups (defined using ``(?P...)``), - these will be preserved as named :class:`ParseResults`. - - If instead of the Python stdlib ``re`` module you wish to use a different RE module - (such as the ``regex`` module), you can do so by building your ``Regex`` object with - a compiled RE that was compiled using ``regex``. - - Example:: - - realnum = Regex(r"[+-]?\d+\.\d*") - # ref: https://stackoverflow.com/questions/267399/how-do-you-match-only-valid-roman-numerals-with-a-regular-expression - roman = Regex(r"M{0,4}(CM|CD|D?{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})") - - # named fields in a regex will be returned as named results - date = Regex(r'(?P\d{4})-(?P\d\d?)-(?P\d\d?)') - - # the Regex class will accept re's compiled using the regex module - import regex - parser = pp.Regex(regex.compile(r'[0-9]')) - """ - - def __init__( - self, - pattern: Any, - flags: Union[re.RegexFlag, int] = 0, - as_group_list: bool = False, - as_match: bool = False, - *, - asGroupList: bool = False, - asMatch: bool = False, - ): - """The parameters ``pattern`` and ``flags`` are passed - to the ``re.compile()`` function as-is. See the Python - `re module `_ module for an - explanation of the acceptable patterns and flags. - """ - super().__init__() - asGroupList = asGroupList or as_group_list - asMatch = asMatch or as_match - - if isinstance(pattern, str_type): - if not pattern: - raise ValueError("null string passed to Regex; use Empty() instead") - - self._re = None - self.reString = self.pattern = pattern - self.flags = flags - - elif hasattr(pattern, "pattern") and hasattr(pattern, "match"): - self._re = pattern - self.pattern = self.reString = pattern.pattern - self.flags = flags - - else: - raise TypeError( - "Regex may only be constructed with a string or a compiled RE object" - ) - - self.errmsg = "Expected " + self.name - self.mayIndexError = False - self.asGroupList = asGroupList - self.asMatch = asMatch - if self.asGroupList: - self.parseImpl = self.parseImplAsGroupList - if self.asMatch: - self.parseImpl = self.parseImplAsMatch - - @cached_property - def re(self): - if self._re: - return self._re - else: - try: - return re.compile(self.pattern, self.flags) - except re.error: - raise ValueError( - "invalid pattern ({!r}) passed to Regex".format(self.pattern) - ) - - @cached_property - def re_match(self): - return self.re.match - - @cached_property - def mayReturnEmpty(self): - return self.re_match("") is not None - - def _generateDefaultName(self): - return "Re:({})".format(repr(self.pattern).replace("\\\\", "\\")) - - def parseImpl(self, instring, loc, doActions=True): - result = self.re_match(instring, loc) - if not result: - raise ParseException(instring, loc, self.errmsg, self) - - loc = result.end() - ret = ParseResults(result.group()) - d = result.groupdict() - if d: - for k, v in d.items(): - ret[k] = v - return loc, ret - - def parseImplAsGroupList(self, instring, loc, doActions=True): - result = self.re_match(instring, loc) - if not result: - raise ParseException(instring, loc, self.errmsg, self) - - loc = result.end() - ret = result.groups() - return loc, ret - - def parseImplAsMatch(self, instring, loc, doActions=True): - result = self.re_match(instring, loc) - if not result: - raise ParseException(instring, loc, self.errmsg, self) - - loc = result.end() - ret = result - return loc, ret - - def sub(self, repl: str) -> ParserElement: - r""" - Return :class:`Regex` with an attached parse action to transform the parsed - result as if called using `re.sub(expr, repl, string) `_. - - Example:: - - make_html = Regex(r"(\w+):(.*?):").sub(r"<\1>\2") - print(make_html.transform_string("h1:main title:")) - # prints "

main title

" - """ - if self.asGroupList: - raise TypeError("cannot use sub() with Regex(asGroupList=True)") - - if self.asMatch and callable(repl): - raise TypeError("cannot use sub() with a callable with Regex(asMatch=True)") - - if self.asMatch: - - def pa(tokens): - return tokens[0].expand(repl) - - else: - - def pa(tokens): - return self.re.sub(repl, tokens[0]) - - return self.add_parse_action(pa) - - -class QuotedString(Token): - r""" - Token for matching strings that are delimited by quoting characters. - - Defined with the following parameters: - - - ``quote_char`` - string of one or more characters defining the - quote delimiting string - - ``esc_char`` - character to re_escape quotes, typically backslash - (default= ``None``) - - ``esc_quote`` - special quote sequence to re_escape an embedded quote - string (such as SQL's ``""`` to re_escape an embedded ``"``) - (default= ``None``) - - ``multiline`` - boolean indicating whether quotes can span - multiple lines (default= ``False``) - - ``unquote_results`` - boolean indicating whether the matched text - should be unquoted (default= ``True``) - - ``end_quote_char`` - string of one or more characters defining the - end of the quote delimited string (default= ``None`` => same as - quote_char) - - ``convert_whitespace_escapes`` - convert escaped whitespace - (``'\t'``, ``'\n'``, etc.) to actual whitespace - (default= ``True``) - - Example:: - - qs = QuotedString('"') - print(qs.search_string('lsjdf "This is the quote" sldjf')) - complex_qs = QuotedString('{{', end_quote_char='}}') - print(complex_qs.search_string('lsjdf {{This is the "quote"}} sldjf')) - sql_qs = QuotedString('"', esc_quote='""') - print(sql_qs.search_string('lsjdf "This is the quote with ""embedded"" quotes" sldjf')) - - prints:: - - [['This is the quote']] - [['This is the "quote"']] - [['This is the quote with "embedded" quotes']] - """ - ws_map = ((r"\t", "\t"), (r"\n", "\n"), (r"\f", "\f"), (r"\r", "\r")) - - def __init__( - self, - quote_char: str = "", - esc_char: typing.Optional[str] = None, - esc_quote: typing.Optional[str] = None, - multiline: bool = False, - unquote_results: bool = True, - end_quote_char: typing.Optional[str] = None, - convert_whitespace_escapes: bool = True, - *, - quoteChar: str = "", - escChar: typing.Optional[str] = None, - escQuote: typing.Optional[str] = None, - unquoteResults: bool = True, - endQuoteChar: typing.Optional[str] = None, - convertWhitespaceEscapes: bool = True, - ): - super().__init__() - escChar = escChar or esc_char - escQuote = escQuote or esc_quote - unquoteResults = unquoteResults and unquote_results - endQuoteChar = endQuoteChar or end_quote_char - convertWhitespaceEscapes = ( - convertWhitespaceEscapes and convert_whitespace_escapes - ) - quote_char = quoteChar or quote_char - - # remove white space from quote chars - wont work anyway - quote_char = quote_char.strip() - if not quote_char: - raise ValueError("quote_char cannot be the empty string") - - if endQuoteChar is None: - endQuoteChar = quote_char - else: - endQuoteChar = endQuoteChar.strip() - if not endQuoteChar: - raise ValueError("endQuoteChar cannot be the empty string") - - self.quoteChar = quote_char - self.quoteCharLen = len(quote_char) - self.firstQuoteChar = quote_char[0] - self.endQuoteChar = endQuoteChar - self.endQuoteCharLen = len(endQuoteChar) - self.escChar = escChar - self.escQuote = escQuote - self.unquoteResults = unquoteResults - self.convertWhitespaceEscapes = convertWhitespaceEscapes - - sep = "" - inner_pattern = "" - - if escQuote: - inner_pattern += r"{}(?:{})".format(sep, re.escape(escQuote)) - sep = "|" - - if escChar: - inner_pattern += r"{}(?:{}.)".format(sep, re.escape(escChar)) - sep = "|" - self.escCharReplacePattern = re.escape(self.escChar) + "(.)" - - if len(self.endQuoteChar) > 1: - inner_pattern += ( - "{}(?:".format(sep) - + "|".join( - "(?:{}(?!{}))".format( - re.escape(self.endQuoteChar[:i]), - re.escape(self.endQuoteChar[i:]), - ) - for i in range(len(self.endQuoteChar) - 1, 0, -1) - ) - + ")" - ) - sep = "|" - - if multiline: - self.flags = re.MULTILINE | re.DOTALL - inner_pattern += r"{}(?:[^{}{}])".format( - sep, - _escape_regex_range_chars(self.endQuoteChar[0]), - (_escape_regex_range_chars(escChar) if escChar is not None else ""), - ) - else: - self.flags = 0 - inner_pattern += r"{}(?:[^{}\n\r{}])".format( - sep, - _escape_regex_range_chars(self.endQuoteChar[0]), - (_escape_regex_range_chars(escChar) if escChar is not None else ""), - ) - - self.pattern = "".join( - [ - re.escape(self.quoteChar), - "(?:", - inner_pattern, - ")*", - re.escape(self.endQuoteChar), - ] - ) - - try: - self.re = re.compile(self.pattern, self.flags) - self.reString = self.pattern - self.re_match = self.re.match - except re.error: - raise ValueError( - "invalid pattern {!r} passed to Regex".format(self.pattern) - ) - - self.errmsg = "Expected " + self.name - self.mayIndexError = False - self.mayReturnEmpty = True - - def _generateDefaultName(self): - if self.quoteChar == self.endQuoteChar and isinstance(self.quoteChar, str_type): - return "string enclosed in {!r}".format(self.quoteChar) - - return "quoted string, starting with {} ending with {}".format( - self.quoteChar, self.endQuoteChar - ) - - def parseImpl(self, instring, loc, doActions=True): - result = ( - instring[loc] == self.firstQuoteChar - and self.re_match(instring, loc) - or None - ) - if not result: - raise ParseException(instring, loc, self.errmsg, self) - - loc = result.end() - ret = result.group() - - if self.unquoteResults: - - # strip off quotes - ret = ret[self.quoteCharLen : -self.endQuoteCharLen] - - if isinstance(ret, str_type): - # replace escaped whitespace - if "\\" in ret and self.convertWhitespaceEscapes: - for wslit, wschar in self.ws_map: - ret = ret.replace(wslit, wschar) - - # replace escaped characters - if self.escChar: - ret = re.sub(self.escCharReplacePattern, r"\g<1>", ret) - - # replace escaped quotes - if self.escQuote: - ret = ret.replace(self.escQuote, self.endQuoteChar) - - return loc, ret - - -class CharsNotIn(Token): - """Token for matching words composed of characters *not* in a given - set (will include whitespace in matched characters if not listed in - the provided exclusion set - see example). Defined with string - containing all disallowed characters, and an optional minimum, - maximum, and/or exact length. The default value for ``min`` is - 1 (a minimum value < 1 is not valid); the default values for - ``max`` and ``exact`` are 0, meaning no maximum or exact - length restriction. - - Example:: - - # define a comma-separated-value as anything that is not a ',' - csv_value = CharsNotIn(',') - print(delimited_list(csv_value).parse_string("dkls,lsdkjf,s12 34,@!#,213")) - - prints:: - - ['dkls', 'lsdkjf', 's12 34', '@!#', '213'] - """ - - def __init__( - self, - not_chars: str = "", - min: int = 1, - max: int = 0, - exact: int = 0, - *, - notChars: str = "", - ): - super().__init__() - self.skipWhitespace = False - self.notChars = not_chars or notChars - self.notCharsSet = set(self.notChars) - - if min < 1: - raise ValueError( - "cannot specify a minimum length < 1; use " - "Opt(CharsNotIn()) if zero-length char group is permitted" - ) - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - self.errmsg = "Expected " + self.name - self.mayReturnEmpty = self.minLen == 0 - self.mayIndexError = False - - def _generateDefaultName(self): - not_chars_str = _collapse_string_to_ranges(self.notChars) - if len(not_chars_str) > 16: - return "!W:({}...)".format(self.notChars[: 16 - 3]) - else: - return "!W:({})".format(self.notChars) - - def parseImpl(self, instring, loc, doActions=True): - notchars = self.notCharsSet - if instring[loc] in notchars: - raise ParseException(instring, loc, self.errmsg, self) - - start = loc - loc += 1 - maxlen = min(start + self.maxLen, len(instring)) - while loc < maxlen and instring[loc] not in notchars: - loc += 1 - - if loc - start < self.minLen: - raise ParseException(instring, loc, self.errmsg, self) - - return loc, instring[start:loc] - - -class White(Token): - """Special matching class for matching whitespace. Normally, - whitespace is ignored by pyparsing grammars. This class is included - when some whitespace structures are significant. Define with - a string containing the whitespace characters to be matched; default - is ``" \\t\\r\\n"``. Also takes optional ``min``, - ``max``, and ``exact`` arguments, as defined for the - :class:`Word` class. - """ - - whiteStrs = { - " ": "", - "\t": "", - "\n": "", - "\r": "", - "\f": "", - "\u00A0": "", - "\u1680": "", - "\u180E": "", - "\u2000": "", - "\u2001": "", - "\u2002": "", - "\u2003": "", - "\u2004": "", - "\u2005": "", - "\u2006": "", - "\u2007": "", - "\u2008": "", - "\u2009": "", - "\u200A": "", - "\u200B": "", - "\u202F": "", - "\u205F": "", - "\u3000": "", - } - - def __init__(self, ws: str = " \t\r\n", min: int = 1, max: int = 0, exact: int = 0): - super().__init__() - self.matchWhite = ws - self.set_whitespace_chars( - "".join(c for c in self.whiteStrs if c not in self.matchWhite), - copy_defaults=True, - ) - # self.leave_whitespace() - self.mayReturnEmpty = True - self.errmsg = "Expected " + self.name - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - def _generateDefaultName(self): - return "".join(White.whiteStrs[c] for c in self.matchWhite) - - def parseImpl(self, instring, loc, doActions=True): - if instring[loc] not in self.matchWhite: - raise ParseException(instring, loc, self.errmsg, self) - start = loc - loc += 1 - maxloc = start + self.maxLen - maxloc = min(maxloc, len(instring)) - while loc < maxloc and instring[loc] in self.matchWhite: - loc += 1 - - if loc - start < self.minLen: - raise ParseException(instring, loc, self.errmsg, self) - - return loc, instring[start:loc] - - -class PositionToken(Token): - def __init__(self): - super().__init__() - self.mayReturnEmpty = True - self.mayIndexError = False - - -class GoToColumn(PositionToken): - """Token to advance to a specific column of input text; useful for - tabular report scraping. - """ - - def __init__(self, colno: int): - super().__init__() - self.col = colno - - def preParse(self, instring, loc): - if col(loc, instring) != self.col: - instrlen = len(instring) - if self.ignoreExprs: - loc = self._skipIgnorables(instring, loc) - while ( - loc < instrlen - and instring[loc].isspace() - and col(loc, instring) != self.col - ): - loc += 1 - return loc - - def parseImpl(self, instring, loc, doActions=True): - thiscol = col(loc, instring) - if thiscol > self.col: - raise ParseException(instring, loc, "Text not in expected column", self) - newloc = loc + self.col - thiscol - ret = instring[loc:newloc] - return newloc, ret - - -class LineStart(PositionToken): - r"""Matches if current position is at the beginning of a line within - the parse string - - Example:: - - test = '''\ - AAA this line - AAA and this line - AAA but not this one - B AAA and definitely not this one - ''' - - for t in (LineStart() + 'AAA' + restOfLine).search_string(test): - print(t) - - prints:: - - ['AAA', ' this line'] - ['AAA', ' and this line'] - - """ - - def __init__(self): - super().__init__() - self.leave_whitespace() - self.orig_whiteChars = set() | self.whiteChars - self.whiteChars.discard("\n") - self.skipper = Empty().set_whitespace_chars(self.whiteChars) - self.errmsg = "Expected start of line" - - def preParse(self, instring, loc): - if loc == 0: - return loc - else: - ret = self.skipper.preParse(instring, loc) - if "\n" in self.orig_whiteChars: - while instring[ret : ret + 1] == "\n": - ret = self.skipper.preParse(instring, ret + 1) - return ret - - def parseImpl(self, instring, loc, doActions=True): - if col(loc, instring) == 1: - return loc, [] - raise ParseException(instring, loc, self.errmsg, self) - - -class LineEnd(PositionToken): - """Matches if current position is at the end of a line within the - parse string - """ - - def __init__(self): - super().__init__() - self.whiteChars.discard("\n") - self.set_whitespace_chars(self.whiteChars, copy_defaults=False) - self.errmsg = "Expected end of line" - - def parseImpl(self, instring, loc, doActions=True): - if loc < len(instring): - if instring[loc] == "\n": - return loc + 1, "\n" - else: - raise ParseException(instring, loc, self.errmsg, self) - elif loc == len(instring): - return loc + 1, [] - else: - raise ParseException(instring, loc, self.errmsg, self) - - -class StringStart(PositionToken): - """Matches if current position is at the beginning of the parse - string - """ - - def __init__(self): - super().__init__() - self.errmsg = "Expected start of text" - - def parseImpl(self, instring, loc, doActions=True): - if loc != 0: - # see if entire string up to here is just whitespace and ignoreables - if loc != self.preParse(instring, 0): - raise ParseException(instring, loc, self.errmsg, self) - return loc, [] - - -class StringEnd(PositionToken): - """ - Matches if current position is at the end of the parse string - """ - - def __init__(self): - super().__init__() - self.errmsg = "Expected end of text" - - def parseImpl(self, instring, loc, doActions=True): - if loc < len(instring): - raise ParseException(instring, loc, self.errmsg, self) - elif loc == len(instring): - return loc + 1, [] - elif loc > len(instring): - return loc, [] - else: - raise ParseException(instring, loc, self.errmsg, self) - - -class WordStart(PositionToken): - """Matches if the current position is at the beginning of a - :class:`Word`, and is not preceded by any character in a given - set of ``word_chars`` (default= ``printables``). To emulate the - ``\b`` behavior of regular expressions, use - ``WordStart(alphanums)``. ``WordStart`` will also match at - the beginning of the string being parsed, or at the beginning of - a line. - """ - - def __init__(self, word_chars: str = printables, *, wordChars: str = printables): - wordChars = word_chars if wordChars == printables else wordChars - super().__init__() - self.wordChars = set(wordChars) - self.errmsg = "Not at the start of a word" - - def parseImpl(self, instring, loc, doActions=True): - if loc != 0: - if ( - instring[loc - 1] in self.wordChars - or instring[loc] not in self.wordChars - ): - raise ParseException(instring, loc, self.errmsg, self) - return loc, [] - - -class WordEnd(PositionToken): - """Matches if the current position is at the end of a :class:`Word`, - and is not followed by any character in a given set of ``word_chars`` - (default= ``printables``). To emulate the ``\b`` behavior of - regular expressions, use ``WordEnd(alphanums)``. ``WordEnd`` - will also match at the end of the string being parsed, or at the end - of a line. - """ - - def __init__(self, word_chars: str = printables, *, wordChars: str = printables): - wordChars = word_chars if wordChars == printables else wordChars - super().__init__() - self.wordChars = set(wordChars) - self.skipWhitespace = False - self.errmsg = "Not at the end of a word" - - def parseImpl(self, instring, loc, doActions=True): - instrlen = len(instring) - if instrlen > 0 and loc < instrlen: - if ( - instring[loc] in self.wordChars - or instring[loc - 1] not in self.wordChars - ): - raise ParseException(instring, loc, self.errmsg, self) - return loc, [] - - -class ParseExpression(ParserElement): - """Abstract subclass of ParserElement, for combining and - post-processing parsed tokens. - """ - - def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False): - super().__init__(savelist) - self.exprs: List[ParserElement] - if isinstance(exprs, _generatorType): - exprs = list(exprs) - - if isinstance(exprs, str_type): - self.exprs = [self._literalStringClass(exprs)] - elif isinstance(exprs, ParserElement): - self.exprs = [exprs] - elif isinstance(exprs, Iterable): - exprs = list(exprs) - # if sequence of strings provided, wrap with Literal - if any(isinstance(expr, str_type) for expr in exprs): - exprs = ( - self._literalStringClass(e) if isinstance(e, str_type) else e - for e in exprs - ) - self.exprs = list(exprs) - else: - try: - self.exprs = list(exprs) - except TypeError: - self.exprs = [exprs] - self.callPreparse = False - - def recurse(self) -> Sequence[ParserElement]: - return self.exprs[:] - - def append(self, other) -> ParserElement: - self.exprs.append(other) - self._defaultName = None - return self - - def leave_whitespace(self, recursive: bool = True) -> ParserElement: - """ - Extends ``leave_whitespace`` defined in base class, and also invokes ``leave_whitespace`` on - all contained expressions. - """ - super().leave_whitespace(recursive) - - if recursive: - self.exprs = [e.copy() for e in self.exprs] - for e in self.exprs: - e.leave_whitespace(recursive) - return self - - def ignore_whitespace(self, recursive: bool = True) -> ParserElement: - """ - Extends ``ignore_whitespace`` defined in base class, and also invokes ``leave_whitespace`` on - all contained expressions. - """ - super().ignore_whitespace(recursive) - if recursive: - self.exprs = [e.copy() for e in self.exprs] - for e in self.exprs: - e.ignore_whitespace(recursive) - return self - - def ignore(self, other) -> ParserElement: - if isinstance(other, Suppress): - if other not in self.ignoreExprs: - super().ignore(other) - for e in self.exprs: - e.ignore(self.ignoreExprs[-1]) - else: - super().ignore(other) - for e in self.exprs: - e.ignore(self.ignoreExprs[-1]) - return self - - def _generateDefaultName(self): - return "{}:({})".format(self.__class__.__name__, str(self.exprs)) - - def streamline(self) -> ParserElement: - if self.streamlined: - return self - - super().streamline() - - for e in self.exprs: - e.streamline() - - # collapse nested :class:`And`'s of the form ``And(And(And(a, b), c), d)`` to ``And(a, b, c, d)`` - # but only if there are no parse actions or resultsNames on the nested And's - # (likewise for :class:`Or`'s and :class:`MatchFirst`'s) - if len(self.exprs) == 2: - other = self.exprs[0] - if ( - isinstance(other, self.__class__) - and not other.parseAction - and other.resultsName is None - and not other.debug - ): - self.exprs = other.exprs[:] + [self.exprs[1]] - self._defaultName = None - self.mayReturnEmpty |= other.mayReturnEmpty - self.mayIndexError |= other.mayIndexError - - other = self.exprs[-1] - if ( - isinstance(other, self.__class__) - and not other.parseAction - and other.resultsName is None - and not other.debug - ): - self.exprs = self.exprs[:-1] + other.exprs[:] - self._defaultName = None - self.mayReturnEmpty |= other.mayReturnEmpty - self.mayIndexError |= other.mayIndexError - - self.errmsg = "Expected " + str(self) - - return self - - def validate(self, validateTrace=None) -> None: - tmp = (validateTrace if validateTrace is not None else [])[:] + [self] - for e in self.exprs: - e.validate(tmp) - self._checkRecursion([]) - - def copy(self) -> ParserElement: - ret = super().copy() - ret.exprs = [e.copy() for e in self.exprs] - return ret - - def _setResultsName(self, name, listAllMatches=False): - if ( - __diag__.warn_ungrouped_named_tokens_in_collection - and Diagnostics.warn_ungrouped_named_tokens_in_collection - not in self.suppress_warnings_ - ): - for e in self.exprs: - if ( - isinstance(e, ParserElement) - and e.resultsName - and Diagnostics.warn_ungrouped_named_tokens_in_collection - not in e.suppress_warnings_ - ): - warnings.warn( - "{}: setting results name {!r} on {} expression " - "collides with {!r} on contained expression".format( - "warn_ungrouped_named_tokens_in_collection", - name, - type(self).__name__, - e.resultsName, - ), - stacklevel=3, - ) - - return super()._setResultsName(name, listAllMatches) - - ignoreWhitespace = ignore_whitespace - leaveWhitespace = leave_whitespace - - -class And(ParseExpression): - """ - Requires all given :class:`ParseExpression` s to be found in the given order. - Expressions may be separated by whitespace. - May be constructed using the ``'+'`` operator. - May also be constructed using the ``'-'`` operator, which will - suppress backtracking. - - Example:: - - integer = Word(nums) - name_expr = Word(alphas)[1, ...] - - expr = And([integer("id"), name_expr("name"), integer("age")]) - # more easily written as: - expr = integer("id") + name_expr("name") + integer("age") - """ - - class _ErrorStop(Empty): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.leave_whitespace() - - def _generateDefaultName(self): - return "-" - - def __init__( - self, exprs_arg: typing.Iterable[ParserElement], savelist: bool = True - ): - exprs: List[ParserElement] = list(exprs_arg) - if exprs and Ellipsis in exprs: - tmp = [] - for i, expr in enumerate(exprs): - if expr is Ellipsis: - if i < len(exprs) - 1: - skipto_arg: ParserElement = (Empty() + exprs[i + 1]).exprs[-1] - tmp.append(SkipTo(skipto_arg)("_skipped*")) - else: - raise Exception( - "cannot construct And with sequence ending in ..." - ) - else: - tmp.append(expr) - exprs[:] = tmp - super().__init__(exprs, savelist) - if self.exprs: - self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) - if not isinstance(self.exprs[0], White): - self.set_whitespace_chars( - self.exprs[0].whiteChars, - copy_defaults=self.exprs[0].copyDefaultWhiteChars, - ) - self.skipWhitespace = self.exprs[0].skipWhitespace - else: - self.skipWhitespace = False - else: - self.mayReturnEmpty = True - self.callPreparse = True - - def streamline(self) -> ParserElement: - # collapse any _PendingSkip's - if self.exprs: - if any( - isinstance(e, ParseExpression) - and e.exprs - and isinstance(e.exprs[-1], _PendingSkip) - for e in self.exprs[:-1] - ): - for i, e in enumerate(self.exprs[:-1]): - if e is None: - continue - if ( - isinstance(e, ParseExpression) - and e.exprs - and isinstance(e.exprs[-1], _PendingSkip) - ): - e.exprs[-1] = e.exprs[-1] + self.exprs[i + 1] - self.exprs[i + 1] = None - self.exprs = [e for e in self.exprs if e is not None] - - super().streamline() - - # link any IndentedBlocks to the prior expression - for prev, cur in zip(self.exprs, self.exprs[1:]): - # traverse cur or any first embedded expr of cur looking for an IndentedBlock - # (but watch out for recursive grammar) - seen = set() - while cur: - if id(cur) in seen: - break - seen.add(id(cur)) - if isinstance(cur, IndentedBlock): - prev.add_parse_action( - lambda s, l, t, cur_=cur: setattr( - cur_, "parent_anchor", col(l, s) - ) - ) - break - subs = cur.recurse() - cur = next(iter(subs), None) - - self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) - return self - - def parseImpl(self, instring, loc, doActions=True): - # pass False as callPreParse arg to _parse for first element, since we already - # pre-parsed the string as part of our And pre-parsing - loc, resultlist = self.exprs[0]._parse( - instring, loc, doActions, callPreParse=False - ) - errorStop = False - for e in self.exprs[1:]: - # if isinstance(e, And._ErrorStop): - if type(e) is And._ErrorStop: - errorStop = True - continue - if errorStop: - try: - loc, exprtokens = e._parse(instring, loc, doActions) - except ParseSyntaxException: - raise - except ParseBaseException as pe: - pe.__traceback__ = None - raise ParseSyntaxException._from_exception(pe) - except IndexError: - raise ParseSyntaxException( - instring, len(instring), self.errmsg, self - ) - else: - loc, exprtokens = e._parse(instring, loc, doActions) - if exprtokens or exprtokens.haskeys(): - resultlist += exprtokens - return loc, resultlist - - def __iadd__(self, other): - if isinstance(other, str_type): - other = self._literalStringClass(other) - return self.append(other) # And([self, other]) - - def _checkRecursion(self, parseElementList): - subRecCheckList = parseElementList[:] + [self] - for e in self.exprs: - e._checkRecursion(subRecCheckList) - if not e.mayReturnEmpty: - break - - def _generateDefaultName(self): - inner = " ".join(str(e) for e in self.exprs) - # strip off redundant inner {}'s - while len(inner) > 1 and inner[0 :: len(inner) - 1] == "{}": - inner = inner[1:-1] - return "{" + inner + "}" - - -class Or(ParseExpression): - """Requires that at least one :class:`ParseExpression` is found. If - two expressions match, the expression that matches the longest - string will be used. May be constructed using the ``'^'`` - operator. - - Example:: - - # construct Or using '^' operator - - number = Word(nums) ^ Combine(Word(nums) + '.' + Word(nums)) - print(number.search_string("123 3.1416 789")) - - prints:: - - [['123'], ['3.1416'], ['789']] - """ - - def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False): - super().__init__(exprs, savelist) - if self.exprs: - self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) - self.skipWhitespace = all(e.skipWhitespace for e in self.exprs) - else: - self.mayReturnEmpty = True - - def streamline(self) -> ParserElement: - super().streamline() - if self.exprs: - self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) - self.saveAsList = any(e.saveAsList for e in self.exprs) - self.skipWhitespace = all( - e.skipWhitespace and not isinstance(e, White) for e in self.exprs - ) - else: - self.saveAsList = False - return self - - def parseImpl(self, instring, loc, doActions=True): - maxExcLoc = -1 - maxException = None - matches = [] - fatals = [] - if all(e.callPreparse for e in self.exprs): - loc = self.preParse(instring, loc) - for e in self.exprs: - try: - loc2 = e.try_parse(instring, loc, raise_fatal=True) - except ParseFatalException as pfe: - pfe.__traceback__ = None - pfe.parserElement = e - fatals.append(pfe) - maxException = None - maxExcLoc = -1 - except ParseException as err: - if not fatals: - err.__traceback__ = None - if err.loc > maxExcLoc: - maxException = err - maxExcLoc = err.loc - except IndexError: - if len(instring) > maxExcLoc: - maxException = ParseException( - instring, len(instring), e.errmsg, self - ) - maxExcLoc = len(instring) - else: - # save match among all matches, to retry longest to shortest - matches.append((loc2, e)) - - if matches: - # re-evaluate all matches in descending order of length of match, in case attached actions - # might change whether or how much they match of the input. - matches.sort(key=itemgetter(0), reverse=True) - - if not doActions: - # no further conditions or parse actions to change the selection of - # alternative, so the first match will be the best match - best_expr = matches[0][1] - return best_expr._parse(instring, loc, doActions) - - longest = -1, None - for loc1, expr1 in matches: - if loc1 <= longest[0]: - # already have a longer match than this one will deliver, we are done - return longest - - try: - loc2, toks = expr1._parse(instring, loc, doActions) - except ParseException as err: - err.__traceback__ = None - if err.loc > maxExcLoc: - maxException = err - maxExcLoc = err.loc - else: - if loc2 >= loc1: - return loc2, toks - # didn't match as much as before - elif loc2 > longest[0]: - longest = loc2, toks - - if longest != (-1, None): - return longest - - if fatals: - if len(fatals) > 1: - fatals.sort(key=lambda e: -e.loc) - if fatals[0].loc == fatals[1].loc: - fatals.sort(key=lambda e: (-e.loc, -len(str(e.parserElement)))) - max_fatal = fatals[0] - raise max_fatal - - if maxException is not None: - maxException.msg = self.errmsg - raise maxException - else: - raise ParseException( - instring, loc, "no defined alternatives to match", self - ) - - def __ixor__(self, other): - if isinstance(other, str_type): - other = self._literalStringClass(other) - return self.append(other) # Or([self, other]) - - def _generateDefaultName(self): - return "{" + " ^ ".join(str(e) for e in self.exprs) + "}" - - def _setResultsName(self, name, listAllMatches=False): - if ( - __diag__.warn_multiple_tokens_in_named_alternation - and Diagnostics.warn_multiple_tokens_in_named_alternation - not in self.suppress_warnings_ - ): - if any( - isinstance(e, And) - and Diagnostics.warn_multiple_tokens_in_named_alternation - not in e.suppress_warnings_ - for e in self.exprs - ): - warnings.warn( - "{}: setting results name {!r} on {} expression " - "will return a list of all parsed tokens in an And alternative, " - "in prior versions only the first token was returned; enclose " - "contained argument in Group".format( - "warn_multiple_tokens_in_named_alternation", - name, - type(self).__name__, - ), - stacklevel=3, - ) - - return super()._setResultsName(name, listAllMatches) - - -class MatchFirst(ParseExpression): - """Requires that at least one :class:`ParseExpression` is found. If - more than one expression matches, the first one listed is the one that will - match. May be constructed using the ``'|'`` operator. - - Example:: - - # construct MatchFirst using '|' operator - - # watch the order of expressions to match - number = Word(nums) | Combine(Word(nums) + '.' + Word(nums)) - print(number.search_string("123 3.1416 789")) # Fail! -> [['123'], ['3'], ['1416'], ['789']] - - # put more selective expression first - number = Combine(Word(nums) + '.' + Word(nums)) | Word(nums) - print(number.search_string("123 3.1416 789")) # Better -> [['123'], ['3.1416'], ['789']] - """ - - def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False): - super().__init__(exprs, savelist) - if self.exprs: - self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) - self.skipWhitespace = all(e.skipWhitespace for e in self.exprs) - else: - self.mayReturnEmpty = True - - def streamline(self) -> ParserElement: - if self.streamlined: - return self - - super().streamline() - if self.exprs: - self.saveAsList = any(e.saveAsList for e in self.exprs) - self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) - self.skipWhitespace = all( - e.skipWhitespace and not isinstance(e, White) for e in self.exprs - ) - else: - self.saveAsList = False - self.mayReturnEmpty = True - return self - - def parseImpl(self, instring, loc, doActions=True): - maxExcLoc = -1 - maxException = None - - for e in self.exprs: - try: - return e._parse( - instring, - loc, - doActions, - ) - except ParseFatalException as pfe: - pfe.__traceback__ = None - pfe.parserElement = e - raise - except ParseException as err: - if err.loc > maxExcLoc: - maxException = err - maxExcLoc = err.loc - except IndexError: - if len(instring) > maxExcLoc: - maxException = ParseException( - instring, len(instring), e.errmsg, self - ) - maxExcLoc = len(instring) - - if maxException is not None: - maxException.msg = self.errmsg - raise maxException - else: - raise ParseException( - instring, loc, "no defined alternatives to match", self - ) - - def __ior__(self, other): - if isinstance(other, str_type): - other = self._literalStringClass(other) - return self.append(other) # MatchFirst([self, other]) - - def _generateDefaultName(self): - return "{" + " | ".join(str(e) for e in self.exprs) + "}" - - def _setResultsName(self, name, listAllMatches=False): - if ( - __diag__.warn_multiple_tokens_in_named_alternation - and Diagnostics.warn_multiple_tokens_in_named_alternation - not in self.suppress_warnings_ - ): - if any( - isinstance(e, And) - and Diagnostics.warn_multiple_tokens_in_named_alternation - not in e.suppress_warnings_ - for e in self.exprs - ): - warnings.warn( - "{}: setting results name {!r} on {} expression " - "will return a list of all parsed tokens in an And alternative, " - "in prior versions only the first token was returned; enclose " - "contained argument in Group".format( - "warn_multiple_tokens_in_named_alternation", - name, - type(self).__name__, - ), - stacklevel=3, - ) - - return super()._setResultsName(name, listAllMatches) - - -class Each(ParseExpression): - """Requires all given :class:`ParseExpression` s to be found, but in - any order. Expressions may be separated by whitespace. - - May be constructed using the ``'&'`` operator. - - Example:: - - color = one_of("RED ORANGE YELLOW GREEN BLUE PURPLE BLACK WHITE BROWN") - shape_type = one_of("SQUARE CIRCLE TRIANGLE STAR HEXAGON OCTAGON") - integer = Word(nums) - shape_attr = "shape:" + shape_type("shape") - posn_attr = "posn:" + Group(integer("x") + ',' + integer("y"))("posn") - color_attr = "color:" + color("color") - size_attr = "size:" + integer("size") - - # use Each (using operator '&') to accept attributes in any order - # (shape and posn are required, color and size are optional) - shape_spec = shape_attr & posn_attr & Opt(color_attr) & Opt(size_attr) - - shape_spec.run_tests(''' - shape: SQUARE color: BLACK posn: 100, 120 - shape: CIRCLE size: 50 color: BLUE posn: 50,80 - color:GREEN size:20 shape:TRIANGLE posn:20,40 - ''' - ) - - prints:: - - shape: SQUARE color: BLACK posn: 100, 120 - ['shape:', 'SQUARE', 'color:', 'BLACK', 'posn:', ['100', ',', '120']] - - color: BLACK - - posn: ['100', ',', '120'] - - x: 100 - - y: 120 - - shape: SQUARE - - - shape: CIRCLE size: 50 color: BLUE posn: 50,80 - ['shape:', 'CIRCLE', 'size:', '50', 'color:', 'BLUE', 'posn:', ['50', ',', '80']] - - color: BLUE - - posn: ['50', ',', '80'] - - x: 50 - - y: 80 - - shape: CIRCLE - - size: 50 - - - color: GREEN size: 20 shape: TRIANGLE posn: 20,40 - ['color:', 'GREEN', 'size:', '20', 'shape:', 'TRIANGLE', 'posn:', ['20', ',', '40']] - - color: GREEN - - posn: ['20', ',', '40'] - - x: 20 - - y: 40 - - shape: TRIANGLE - - size: 20 - """ - - def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = True): - super().__init__(exprs, savelist) - if self.exprs: - self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) - else: - self.mayReturnEmpty = True - self.skipWhitespace = True - self.initExprGroups = True - self.saveAsList = True - - def streamline(self) -> ParserElement: - super().streamline() - if self.exprs: - self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) - else: - self.mayReturnEmpty = True - return self - - def parseImpl(self, instring, loc, doActions=True): - if self.initExprGroups: - self.opt1map = dict( - (id(e.expr), e) for e in self.exprs if isinstance(e, Opt) - ) - opt1 = [e.expr for e in self.exprs if isinstance(e, Opt)] - opt2 = [ - e - for e in self.exprs - if e.mayReturnEmpty and not isinstance(e, (Opt, Regex, ZeroOrMore)) - ] - self.optionals = opt1 + opt2 - self.multioptionals = [ - e.expr.set_results_name(e.resultsName, list_all_matches=True) - for e in self.exprs - if isinstance(e, _MultipleMatch) - ] - self.multirequired = [ - e.expr.set_results_name(e.resultsName, list_all_matches=True) - for e in self.exprs - if isinstance(e, OneOrMore) - ] - self.required = [ - e for e in self.exprs if not isinstance(e, (Opt, ZeroOrMore, OneOrMore)) - ] - self.required += self.multirequired - self.initExprGroups = False - - tmpLoc = loc - tmpReqd = self.required[:] - tmpOpt = self.optionals[:] - multis = self.multioptionals[:] - matchOrder = [] - - keepMatching = True - failed = [] - fatals = [] - while keepMatching: - tmpExprs = tmpReqd + tmpOpt + multis - failed.clear() - fatals.clear() - for e in tmpExprs: - try: - tmpLoc = e.try_parse(instring, tmpLoc, raise_fatal=True) - except ParseFatalException as pfe: - pfe.__traceback__ = None - pfe.parserElement = e - fatals.append(pfe) - failed.append(e) - except ParseException: - failed.append(e) - else: - matchOrder.append(self.opt1map.get(id(e), e)) - if e in tmpReqd: - tmpReqd.remove(e) - elif e in tmpOpt: - tmpOpt.remove(e) - if len(failed) == len(tmpExprs): - keepMatching = False - - # look for any ParseFatalExceptions - if fatals: - if len(fatals) > 1: - fatals.sort(key=lambda e: -e.loc) - if fatals[0].loc == fatals[1].loc: - fatals.sort(key=lambda e: (-e.loc, -len(str(e.parserElement)))) - max_fatal = fatals[0] - raise max_fatal - - if tmpReqd: - missing = ", ".join([str(e) for e in tmpReqd]) - raise ParseException( - instring, - loc, - "Missing one or more required elements ({})".format(missing), - ) - - # add any unmatched Opts, in case they have default values defined - matchOrder += [e for e in self.exprs if isinstance(e, Opt) and e.expr in tmpOpt] - - total_results = ParseResults([]) - for e in matchOrder: - loc, results = e._parse(instring, loc, doActions) - total_results += results - - return loc, total_results - - def _generateDefaultName(self): - return "{" + " & ".join(str(e) for e in self.exprs) + "}" - - -class ParseElementEnhance(ParserElement): - """Abstract subclass of :class:`ParserElement`, for combining and - post-processing parsed tokens. - """ - - def __init__(self, expr: Union[ParserElement, str], savelist: bool = False): - super().__init__(savelist) - if isinstance(expr, str_type): - if issubclass(self._literalStringClass, Token): - expr = self._literalStringClass(expr) - elif issubclass(type(self), self._literalStringClass): - expr = Literal(expr) - else: - expr = self._literalStringClass(Literal(expr)) - self.expr = expr - if expr is not None: - self.mayIndexError = expr.mayIndexError - self.mayReturnEmpty = expr.mayReturnEmpty - self.set_whitespace_chars( - expr.whiteChars, copy_defaults=expr.copyDefaultWhiteChars - ) - self.skipWhitespace = expr.skipWhitespace - self.saveAsList = expr.saveAsList - self.callPreparse = expr.callPreparse - self.ignoreExprs.extend(expr.ignoreExprs) - - def recurse(self) -> Sequence[ParserElement]: - return [self.expr] if self.expr is not None else [] - - def parseImpl(self, instring, loc, doActions=True): - if self.expr is not None: - return self.expr._parse(instring, loc, doActions, callPreParse=False) - else: - raise ParseException(instring, loc, "No expression defined", self) - - def leave_whitespace(self, recursive: bool = True) -> ParserElement: - super().leave_whitespace(recursive) - - if recursive: - self.expr = self.expr.copy() - if self.expr is not None: - self.expr.leave_whitespace(recursive) - return self - - def ignore_whitespace(self, recursive: bool = True) -> ParserElement: - super().ignore_whitespace(recursive) - - if recursive: - self.expr = self.expr.copy() - if self.expr is not None: - self.expr.ignore_whitespace(recursive) - return self - - def ignore(self, other) -> ParserElement: - if isinstance(other, Suppress): - if other not in self.ignoreExprs: - super().ignore(other) - if self.expr is not None: - self.expr.ignore(self.ignoreExprs[-1]) - else: - super().ignore(other) - if self.expr is not None: - self.expr.ignore(self.ignoreExprs[-1]) - return self - - def streamline(self) -> ParserElement: - super().streamline() - if self.expr is not None: - self.expr.streamline() - return self - - def _checkRecursion(self, parseElementList): - if self in parseElementList: - raise RecursiveGrammarException(parseElementList + [self]) - subRecCheckList = parseElementList[:] + [self] - if self.expr is not None: - self.expr._checkRecursion(subRecCheckList) - - def validate(self, validateTrace=None) -> None: - if validateTrace is None: - validateTrace = [] - tmp = validateTrace[:] + [self] - if self.expr is not None: - self.expr.validate(tmp) - self._checkRecursion([]) - - def _generateDefaultName(self): - return "{}:({})".format(self.__class__.__name__, str(self.expr)) - - ignoreWhitespace = ignore_whitespace - leaveWhitespace = leave_whitespace - - -class IndentedBlock(ParseElementEnhance): - """ - Expression to match one or more expressions at a given indentation level. - Useful for parsing text where structure is implied by indentation (like Python source code). - """ - - class _Indent(Empty): - def __init__(self, ref_col: int): - super().__init__() - self.errmsg = "expected indent at column {}".format(ref_col) - self.add_condition(lambda s, l, t: col(l, s) == ref_col) - - class _IndentGreater(Empty): - def __init__(self, ref_col: int): - super().__init__() - self.errmsg = "expected indent at column greater than {}".format(ref_col) - self.add_condition(lambda s, l, t: col(l, s) > ref_col) - - def __init__( - self, expr: ParserElement, *, recursive: bool = False, grouped: bool = True - ): - super().__init__(expr, savelist=True) - # if recursive: - # raise NotImplementedError("IndentedBlock with recursive is not implemented") - self._recursive = recursive - self._grouped = grouped - self.parent_anchor = 1 - - def parseImpl(self, instring, loc, doActions=True): - # advance parse position to non-whitespace by using an Empty() - # this should be the column to be used for all subsequent indented lines - anchor_loc = Empty().preParse(instring, loc) - - # see if self.expr matches at the current location - if not it will raise an exception - # and no further work is necessary - self.expr.try_parse(instring, anchor_loc, doActions) - - indent_col = col(anchor_loc, instring) - peer_detect_expr = self._Indent(indent_col) - - inner_expr = Empty() + peer_detect_expr + self.expr - if self._recursive: - sub_indent = self._IndentGreater(indent_col) - nested_block = IndentedBlock( - self.expr, recursive=self._recursive, grouped=self._grouped - ) - nested_block.set_debug(self.debug) - nested_block.parent_anchor = indent_col - inner_expr += Opt(sub_indent + nested_block) - - inner_expr.set_name(f"inner {hex(id(inner_expr))[-4:].upper()}@{indent_col}") - block = OneOrMore(inner_expr) - - trailing_undent = self._Indent(self.parent_anchor) | StringEnd() - - if self._grouped: - wrapper = Group - else: - wrapper = lambda expr: expr - return (wrapper(block) + Optional(trailing_undent)).parseImpl( - instring, anchor_loc, doActions - ) - - -class AtStringStart(ParseElementEnhance): - """Matches if expression matches at the beginning of the parse - string:: - - AtStringStart(Word(nums)).parse_string("123") - # prints ["123"] - - AtStringStart(Word(nums)).parse_string(" 123") - # raises ParseException - """ - - def __init__(self, expr: Union[ParserElement, str]): - super().__init__(expr) - self.callPreparse = False - - def parseImpl(self, instring, loc, doActions=True): - if loc != 0: - raise ParseException(instring, loc, "not found at string start") - return super().parseImpl(instring, loc, doActions) - - -class AtLineStart(ParseElementEnhance): - r"""Matches if an expression matches at the beginning of a line within - the parse string - - Example:: - - test = '''\ - AAA this line - AAA and this line - AAA but not this one - B AAA and definitely not this one - ''' - - for t in (AtLineStart('AAA') + restOfLine).search_string(test): - print(t) - - prints:: - - ['AAA', ' this line'] - ['AAA', ' and this line'] - - """ - - def __init__(self, expr: Union[ParserElement, str]): - super().__init__(expr) - self.callPreparse = False - - def parseImpl(self, instring, loc, doActions=True): - if col(loc, instring) != 1: - raise ParseException(instring, loc, "not found at line start") - return super().parseImpl(instring, loc, doActions) - - -class FollowedBy(ParseElementEnhance): - """Lookahead matching of the given parse expression. - ``FollowedBy`` does *not* advance the parsing position within - the input string, it only verifies that the specified parse - expression matches at the current position. ``FollowedBy`` - always returns a null token list. If any results names are defined - in the lookahead expression, those *will* be returned for access by - name. - - Example:: - - # use FollowedBy to match a label only if it is followed by a ':' - data_word = Word(alphas) - label = data_word + FollowedBy(':') - attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join)) - - attr_expr[1, ...].parse_string("shape: SQUARE color: BLACK posn: upper left").pprint() - - prints:: - - [['shape', 'SQUARE'], ['color', 'BLACK'], ['posn', 'upper left']] - """ - - def __init__(self, expr: Union[ParserElement, str]): - super().__init__(expr) - self.mayReturnEmpty = True - - def parseImpl(self, instring, loc, doActions=True): - # by using self._expr.parse and deleting the contents of the returned ParseResults list - # we keep any named results that were defined in the FollowedBy expression - _, ret = self.expr._parse(instring, loc, doActions=doActions) - del ret[:] - - return loc, ret - - -class PrecededBy(ParseElementEnhance): - """Lookbehind matching of the given parse expression. - ``PrecededBy`` does not advance the parsing position within the - input string, it only verifies that the specified parse expression - matches prior to the current position. ``PrecededBy`` always - returns a null token list, but if a results name is defined on the - given expression, it is returned. - - Parameters: - - - expr - expression that must match prior to the current parse - location - - retreat - (default= ``None``) - (int) maximum number of characters - to lookbehind prior to the current parse location - - If the lookbehind expression is a string, :class:`Literal`, - :class:`Keyword`, or a :class:`Word` or :class:`CharsNotIn` - with a specified exact or maximum length, then the retreat - parameter is not required. Otherwise, retreat must be specified to - give a maximum number of characters to look back from - the current parse position for a lookbehind match. - - Example:: - - # VB-style variable names with type prefixes - int_var = PrecededBy("#") + pyparsing_common.identifier - str_var = PrecededBy("$") + pyparsing_common.identifier - - """ - - def __init__( - self, expr: Union[ParserElement, str], retreat: typing.Optional[int] = None - ): - super().__init__(expr) - self.expr = self.expr().leave_whitespace() - self.mayReturnEmpty = True - self.mayIndexError = False - self.exact = False - if isinstance(expr, str_type): - retreat = len(expr) - self.exact = True - elif isinstance(expr, (Literal, Keyword)): - retreat = expr.matchLen - self.exact = True - elif isinstance(expr, (Word, CharsNotIn)) and expr.maxLen != _MAX_INT: - retreat = expr.maxLen - self.exact = True - elif isinstance(expr, PositionToken): - retreat = 0 - self.exact = True - self.retreat = retreat - self.errmsg = "not preceded by " + str(expr) - self.skipWhitespace = False - self.parseAction.append(lambda s, l, t: t.__delitem__(slice(None, None))) - - def parseImpl(self, instring, loc=0, doActions=True): - if self.exact: - if loc < self.retreat: - raise ParseException(instring, loc, self.errmsg) - start = loc - self.retreat - _, ret = self.expr._parse(instring, start) - else: - # retreat specified a maximum lookbehind window, iterate - test_expr = self.expr + StringEnd() - instring_slice = instring[max(0, loc - self.retreat) : loc] - last_expr = ParseException(instring, loc, self.errmsg) - for offset in range(1, min(loc, self.retreat + 1) + 1): - try: - # print('trying', offset, instring_slice, repr(instring_slice[loc - offset:])) - _, ret = test_expr._parse( - instring_slice, len(instring_slice) - offset - ) - except ParseBaseException as pbe: - last_expr = pbe - else: - break - else: - raise last_expr - return loc, ret - - -class Located(ParseElementEnhance): - """ - Decorates a returned token with its starting and ending - locations in the input string. - - This helper adds the following results names: - - - ``locn_start`` - location where matched expression begins - - ``locn_end`` - location where matched expression ends - - ``value`` - the actual parsed results - - Be careful if the input text contains ```` characters, you - may want to call :class:`ParserElement.parse_with_tabs` - - Example:: - - wd = Word(alphas) - for match in Located(wd).search_string("ljsdf123lksdjjf123lkkjj1222"): - print(match) - - prints:: - - [0, ['ljsdf'], 5] - [8, ['lksdjjf'], 15] - [18, ['lkkjj'], 23] - - """ - - def parseImpl(self, instring, loc, doActions=True): - start = loc - loc, tokens = self.expr._parse(instring, start, doActions, callPreParse=False) - ret_tokens = ParseResults([start, tokens, loc]) - ret_tokens["locn_start"] = start - ret_tokens["value"] = tokens - ret_tokens["locn_end"] = loc - if self.resultsName: - # must return as a list, so that the name will be attached to the complete group - return loc, [ret_tokens] - else: - return loc, ret_tokens - - -class NotAny(ParseElementEnhance): - """ - Lookahead to disallow matching with the given parse expression. - ``NotAny`` does *not* advance the parsing position within the - input string, it only verifies that the specified parse expression - does *not* match at the current position. Also, ``NotAny`` does - *not* skip over leading whitespace. ``NotAny`` always returns - a null token list. May be constructed using the ``'~'`` operator. - - Example:: - - AND, OR, NOT = map(CaselessKeyword, "AND OR NOT".split()) - - # take care not to mistake keywords for identifiers - ident = ~(AND | OR | NOT) + Word(alphas) - boolean_term = Opt(NOT) + ident - - # very crude boolean expression - to support parenthesis groups and - # operation hierarchy, use infix_notation - boolean_expr = boolean_term + ((AND | OR) + boolean_term)[...] - - # integers that are followed by "." are actually floats - integer = Word(nums) + ~Char(".") - """ - - def __init__(self, expr: Union[ParserElement, str]): - super().__init__(expr) - # do NOT use self.leave_whitespace(), don't want to propagate to exprs - # self.leave_whitespace() - self.skipWhitespace = False - - self.mayReturnEmpty = True - self.errmsg = "Found unwanted token, " + str(self.expr) - - def parseImpl(self, instring, loc, doActions=True): - if self.expr.can_parse_next(instring, loc): - raise ParseException(instring, loc, self.errmsg, self) - return loc, [] - - def _generateDefaultName(self): - return "~{" + str(self.expr) + "}" - - -class _MultipleMatch(ParseElementEnhance): - def __init__( - self, - expr: ParserElement, - stop_on: typing.Optional[Union[ParserElement, str]] = None, - *, - stopOn: typing.Optional[Union[ParserElement, str]] = None, - ): - super().__init__(expr) - stopOn = stopOn or stop_on - self.saveAsList = True - ender = stopOn - if isinstance(ender, str_type): - ender = self._literalStringClass(ender) - self.stopOn(ender) - - def stopOn(self, ender) -> ParserElement: - if isinstance(ender, str_type): - ender = self._literalStringClass(ender) - self.not_ender = ~ender if ender is not None else None - return self - - def parseImpl(self, instring, loc, doActions=True): - self_expr_parse = self.expr._parse - self_skip_ignorables = self._skipIgnorables - check_ender = self.not_ender is not None - if check_ender: - try_not_ender = self.not_ender.tryParse - - # must be at least one (but first see if we are the stopOn sentinel; - # if so, fail) - if check_ender: - try_not_ender(instring, loc) - loc, tokens = self_expr_parse(instring, loc, doActions) - try: - hasIgnoreExprs = not not self.ignoreExprs - while 1: - if check_ender: - try_not_ender(instring, loc) - if hasIgnoreExprs: - preloc = self_skip_ignorables(instring, loc) - else: - preloc = loc - loc, tmptokens = self_expr_parse(instring, preloc, doActions) - if tmptokens or tmptokens.haskeys(): - tokens += tmptokens - except (ParseException, IndexError): - pass - - return loc, tokens - - def _setResultsName(self, name, listAllMatches=False): - if ( - __diag__.warn_ungrouped_named_tokens_in_collection - and Diagnostics.warn_ungrouped_named_tokens_in_collection - not in self.suppress_warnings_ - ): - for e in [self.expr] + self.expr.recurse(): - if ( - isinstance(e, ParserElement) - and e.resultsName - and Diagnostics.warn_ungrouped_named_tokens_in_collection - not in e.suppress_warnings_ - ): - warnings.warn( - "{}: setting results name {!r} on {} expression " - "collides with {!r} on contained expression".format( - "warn_ungrouped_named_tokens_in_collection", - name, - type(self).__name__, - e.resultsName, - ), - stacklevel=3, - ) - - return super()._setResultsName(name, listAllMatches) - - -class OneOrMore(_MultipleMatch): - """ - Repetition of one or more of the given expression. - - Parameters: - - expr - expression that must match one or more times - - stop_on - (default= ``None``) - expression for a terminating sentinel - (only required if the sentinel would ordinarily match the repetition - expression) - - Example:: - - data_word = Word(alphas) - label = data_word + FollowedBy(':') - attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).set_parse_action(' '.join)) - - text = "shape: SQUARE posn: upper left color: BLACK" - attr_expr[1, ...].parse_string(text).pprint() # Fail! read 'color' as data instead of next label -> [['shape', 'SQUARE color']] - - # use stop_on attribute for OneOrMore to avoid reading label string as part of the data - attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join)) - OneOrMore(attr_expr).parse_string(text).pprint() # Better -> [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'BLACK']] - - # could also be written as - (attr_expr * (1,)).parse_string(text).pprint() - """ - - def _generateDefaultName(self): - return "{" + str(self.expr) + "}..." - - -class ZeroOrMore(_MultipleMatch): - """ - Optional repetition of zero or more of the given expression. - - Parameters: - - ``expr`` - expression that must match zero or more times - - ``stop_on`` - expression for a terminating sentinel - (only required if the sentinel would ordinarily match the repetition - expression) - (default= ``None``) - - Example: similar to :class:`OneOrMore` - """ - - def __init__( - self, - expr: ParserElement, - stop_on: typing.Optional[Union[ParserElement, str]] = None, - *, - stopOn: typing.Optional[Union[ParserElement, str]] = None, - ): - super().__init__(expr, stopOn=stopOn or stop_on) - self.mayReturnEmpty = True - - def parseImpl(self, instring, loc, doActions=True): - try: - return super().parseImpl(instring, loc, doActions) - except (ParseException, IndexError): - return loc, ParseResults([], name=self.resultsName) - - def _generateDefaultName(self): - return "[" + str(self.expr) + "]..." - - -class _NullToken: - def __bool__(self): - return False - - def __str__(self): - return "" - - -class Opt(ParseElementEnhance): - """ - Optional matching of the given expression. - - Parameters: - - ``expr`` - expression that must match zero or more times - - ``default`` (optional) - value to be returned if the optional expression is not found. - - Example:: - - # US postal code can be a 5-digit zip, plus optional 4-digit qualifier - zip = Combine(Word(nums, exact=5) + Opt('-' + Word(nums, exact=4))) - zip.run_tests(''' - # traditional ZIP code - 12345 - - # ZIP+4 form - 12101-0001 - - # invalid ZIP - 98765- - ''') - - prints:: - - # traditional ZIP code - 12345 - ['12345'] - - # ZIP+4 form - 12101-0001 - ['12101-0001'] - - # invalid ZIP - 98765- - ^ - FAIL: Expected end of text (at char 5), (line:1, col:6) - """ - - __optionalNotMatched = _NullToken() - - def __init__( - self, expr: Union[ParserElement, str], default: Any = __optionalNotMatched - ): - super().__init__(expr, savelist=False) - self.saveAsList = self.expr.saveAsList - self.defaultValue = default - self.mayReturnEmpty = True - - def parseImpl(self, instring, loc, doActions=True): - self_expr = self.expr - try: - loc, tokens = self_expr._parse(instring, loc, doActions, callPreParse=False) - except (ParseException, IndexError): - default_value = self.defaultValue - if default_value is not self.__optionalNotMatched: - if self_expr.resultsName: - tokens = ParseResults([default_value]) - tokens[self_expr.resultsName] = default_value - else: - tokens = [default_value] - else: - tokens = [] - return loc, tokens - - def _generateDefaultName(self): - inner = str(self.expr) - # strip off redundant inner {}'s - while len(inner) > 1 and inner[0 :: len(inner) - 1] == "{}": - inner = inner[1:-1] - return "[" + inner + "]" - - -Optional = Opt - - -class SkipTo(ParseElementEnhance): - """ - Token for skipping over all undefined text until the matched - expression is found. - - Parameters: - - ``expr`` - target expression marking the end of the data to be skipped - - ``include`` - if ``True``, the target expression is also parsed - (the skipped text and target expression are returned as a 2-element - list) (default= ``False``). - - ``ignore`` - (default= ``None``) used to define grammars (typically quoted strings and - comments) that might contain false matches to the target expression - - ``fail_on`` - (default= ``None``) define expressions that are not allowed to be - included in the skipped test; if found before the target expression is found, - the :class:`SkipTo` is not a match - - Example:: - - report = ''' - Outstanding Issues Report - 1 Jan 2000 - - # | Severity | Description | Days Open - -----+----------+-------------------------------------------+----------- - 101 | Critical | Intermittent system crash | 6 - 94 | Cosmetic | Spelling error on Login ('log|n') | 14 - 79 | Minor | System slow when running too many reports | 47 - ''' - integer = Word(nums) - SEP = Suppress('|') - # use SkipTo to simply match everything up until the next SEP - # - ignore quoted strings, so that a '|' character inside a quoted string does not match - # - parse action will call token.strip() for each matched token, i.e., the description body - string_data = SkipTo(SEP, ignore=quoted_string) - string_data.set_parse_action(token_map(str.strip)) - ticket_expr = (integer("issue_num") + SEP - + string_data("sev") + SEP - + string_data("desc") + SEP - + integer("days_open")) - - for tkt in ticket_expr.search_string(report): - print tkt.dump() - - prints:: - - ['101', 'Critical', 'Intermittent system crash', '6'] - - days_open: '6' - - desc: 'Intermittent system crash' - - issue_num: '101' - - sev: 'Critical' - ['94', 'Cosmetic', "Spelling error on Login ('log|n')", '14'] - - days_open: '14' - - desc: "Spelling error on Login ('log|n')" - - issue_num: '94' - - sev: 'Cosmetic' - ['79', 'Minor', 'System slow when running too many reports', '47'] - - days_open: '47' - - desc: 'System slow when running too many reports' - - issue_num: '79' - - sev: 'Minor' - """ - - def __init__( - self, - other: Union[ParserElement, str], - include: bool = False, - ignore: bool = None, - fail_on: typing.Optional[Union[ParserElement, str]] = None, - *, - failOn: Union[ParserElement, str] = None, - ): - super().__init__(other) - failOn = failOn or fail_on - self.ignoreExpr = ignore - self.mayReturnEmpty = True - self.mayIndexError = False - self.includeMatch = include - self.saveAsList = False - if isinstance(failOn, str_type): - self.failOn = self._literalStringClass(failOn) - else: - self.failOn = failOn - self.errmsg = "No match found for " + str(self.expr) - - def parseImpl(self, instring, loc, doActions=True): - startloc = loc - instrlen = len(instring) - self_expr_parse = self.expr._parse - self_failOn_canParseNext = ( - self.failOn.canParseNext if self.failOn is not None else None - ) - self_ignoreExpr_tryParse = ( - self.ignoreExpr.tryParse if self.ignoreExpr is not None else None - ) - - tmploc = loc - while tmploc <= instrlen: - if self_failOn_canParseNext is not None: - # break if failOn expression matches - if self_failOn_canParseNext(instring, tmploc): - break - - if self_ignoreExpr_tryParse is not None: - # advance past ignore expressions - while 1: - try: - tmploc = self_ignoreExpr_tryParse(instring, tmploc) - except ParseBaseException: - break - - try: - self_expr_parse(instring, tmploc, doActions=False, callPreParse=False) - except (ParseException, IndexError): - # no match, advance loc in string - tmploc += 1 - else: - # matched skipto expr, done - break - - else: - # ran off the end of the input string without matching skipto expr, fail - raise ParseException(instring, loc, self.errmsg, self) - - # build up return values - loc = tmploc - skiptext = instring[startloc:loc] - skipresult = ParseResults(skiptext) - - if self.includeMatch: - loc, mat = self_expr_parse(instring, loc, doActions, callPreParse=False) - skipresult += mat - - return loc, skipresult - - -class Forward(ParseElementEnhance): - """ - Forward declaration of an expression to be defined later - - used for recursive grammars, such as algebraic infix notation. - When the expression is known, it is assigned to the ``Forward`` - variable using the ``'<<'`` operator. - - Note: take care when assigning to ``Forward`` not to overlook - precedence of operators. - - Specifically, ``'|'`` has a lower precedence than ``'<<'``, so that:: - - fwd_expr << a | b | c - - will actually be evaluated as:: - - (fwd_expr << a) | b | c - - thereby leaving b and c out as parseable alternatives. It is recommended that you - explicitly group the values inserted into the ``Forward``:: - - fwd_expr << (a | b | c) - - Converting to use the ``'<<='`` operator instead will avoid this problem. - - See :class:`ParseResults.pprint` for an example of a recursive - parser created using ``Forward``. - """ - - def __init__(self, other: typing.Optional[Union[ParserElement, str]] = None): - self.caller_frame = traceback.extract_stack(limit=2)[0] - super().__init__(other, savelist=False) - self.lshift_line = None - - def __lshift__(self, other): - if hasattr(self, "caller_frame"): - del self.caller_frame - if isinstance(other, str_type): - other = self._literalStringClass(other) - self.expr = other - self.mayIndexError = self.expr.mayIndexError - self.mayReturnEmpty = self.expr.mayReturnEmpty - self.set_whitespace_chars( - self.expr.whiteChars, copy_defaults=self.expr.copyDefaultWhiteChars - ) - self.skipWhitespace = self.expr.skipWhitespace - self.saveAsList = self.expr.saveAsList - self.ignoreExprs.extend(self.expr.ignoreExprs) - self.lshift_line = traceback.extract_stack(limit=2)[-2] - return self - - def __ilshift__(self, other): - return self << other - - def __or__(self, other): - caller_line = traceback.extract_stack(limit=2)[-2] - if ( - __diag__.warn_on_match_first_with_lshift_operator - and caller_line == self.lshift_line - and Diagnostics.warn_on_match_first_with_lshift_operator - not in self.suppress_warnings_ - ): - warnings.warn( - "using '<<' operator with '|' is probably an error, use '<<='", - stacklevel=2, - ) - ret = super().__or__(other) - return ret - - def __del__(self): - # see if we are getting dropped because of '=' reassignment of var instead of '<<=' or '<<' - if ( - self.expr is None - and __diag__.warn_on_assignment_to_Forward - and Diagnostics.warn_on_assignment_to_Forward not in self.suppress_warnings_ - ): - warnings.warn_explicit( - "Forward defined here but no expression attached later using '<<=' or '<<'", - UserWarning, - filename=self.caller_frame.filename, - lineno=self.caller_frame.lineno, - ) - - def parseImpl(self, instring, loc, doActions=True): - if ( - self.expr is None - and __diag__.warn_on_parse_using_empty_Forward - and Diagnostics.warn_on_parse_using_empty_Forward - not in self.suppress_warnings_ - ): - # walk stack until parse_string, scan_string, search_string, or transform_string is found - parse_fns = [ - "parse_string", - "scan_string", - "search_string", - "transform_string", - ] - tb = traceback.extract_stack(limit=200) - for i, frm in enumerate(reversed(tb), start=1): - if frm.name in parse_fns: - stacklevel = i + 1 - break - else: - stacklevel = 2 - warnings.warn( - "Forward expression was never assigned a value, will not parse any input", - stacklevel=stacklevel, - ) - if not ParserElement._left_recursion_enabled: - return super().parseImpl(instring, loc, doActions) - # ## Bounded Recursion algorithm ## - # Recursion only needs to be processed at ``Forward`` elements, since they are - # the only ones that can actually refer to themselves. The general idea is - # to handle recursion stepwise: We start at no recursion, then recurse once, - # recurse twice, ..., until more recursion offers no benefit (we hit the bound). - # - # The "trick" here is that each ``Forward`` gets evaluated in two contexts - # - to *match* a specific recursion level, and - # - to *search* the bounded recursion level - # and the two run concurrently. The *search* must *match* each recursion level - # to find the best possible match. This is handled by a memo table, which - # provides the previous match to the next level match attempt. - # - # See also "Left Recursion in Parsing Expression Grammars", Medeiros et al. - # - # There is a complication since we not only *parse* but also *transform* via - # actions: We do not want to run the actions too often while expanding. Thus, - # we expand using `doActions=False` and only run `doActions=True` if the next - # recursion level is acceptable. - with ParserElement.recursion_lock: - memo = ParserElement.recursion_memos - try: - # we are parsing at a specific recursion expansion - use it as-is - prev_loc, prev_result = memo[loc, self, doActions] - if isinstance(prev_result, Exception): - raise prev_result - return prev_loc, prev_result.copy() - except KeyError: - act_key = (loc, self, True) - peek_key = (loc, self, False) - # we are searching for the best recursion expansion - keep on improving - # both `doActions` cases must be tracked separately here! - prev_loc, prev_peek = memo[peek_key] = ( - loc - 1, - ParseException( - instring, loc, "Forward recursion without base case", self - ), - ) - if doActions: - memo[act_key] = memo[peek_key] - while True: - try: - new_loc, new_peek = super().parseImpl(instring, loc, False) - except ParseException: - # we failed before getting any match – do not hide the error - if isinstance(prev_peek, Exception): - raise - new_loc, new_peek = prev_loc, prev_peek - # the match did not get better: we are done - if new_loc <= prev_loc: - if doActions: - # replace the match for doActions=False as well, - # in case the action did backtrack - prev_loc, prev_result = memo[peek_key] = memo[act_key] - del memo[peek_key], memo[act_key] - return prev_loc, prev_result.copy() - del memo[peek_key] - return prev_loc, prev_peek.copy() - # the match did get better: see if we can improve further - else: - if doActions: - try: - memo[act_key] = super().parseImpl(instring, loc, True) - except ParseException as e: - memo[peek_key] = memo[act_key] = (new_loc, e) - raise - prev_loc, prev_peek = memo[peek_key] = new_loc, new_peek - - def leave_whitespace(self, recursive: bool = True) -> ParserElement: - self.skipWhitespace = False - return self - - def ignore_whitespace(self, recursive: bool = True) -> ParserElement: - self.skipWhitespace = True - return self - - def streamline(self) -> ParserElement: - if not self.streamlined: - self.streamlined = True - if self.expr is not None: - self.expr.streamline() - return self - - def validate(self, validateTrace=None) -> None: - if validateTrace is None: - validateTrace = [] - - if self not in validateTrace: - tmp = validateTrace[:] + [self] - if self.expr is not None: - self.expr.validate(tmp) - self._checkRecursion([]) - - def _generateDefaultName(self): - # Avoid infinite recursion by setting a temporary _defaultName - self._defaultName = ": ..." - - # Use the string representation of main expression. - retString = "..." - try: - if self.expr is not None: - retString = str(self.expr)[:1000] - else: - retString = "None" - finally: - return self.__class__.__name__ + ": " + retString - - def copy(self) -> ParserElement: - if self.expr is not None: - return super().copy() - else: - ret = Forward() - ret <<= self - return ret - - def _setResultsName(self, name, list_all_matches=False): - if ( - __diag__.warn_name_set_on_empty_Forward - and Diagnostics.warn_name_set_on_empty_Forward - not in self.suppress_warnings_ - ): - if self.expr is None: - warnings.warn( - "{}: setting results name {!r} on {} expression " - "that has no contained expression".format( - "warn_name_set_on_empty_Forward", name, type(self).__name__ - ), - stacklevel=3, - ) - - return super()._setResultsName(name, list_all_matches) - - ignoreWhitespace = ignore_whitespace - leaveWhitespace = leave_whitespace - - -class TokenConverter(ParseElementEnhance): - """ - Abstract subclass of :class:`ParseExpression`, for converting parsed results. - """ - - def __init__(self, expr: Union[ParserElement, str], savelist=False): - super().__init__(expr) # , savelist) - self.saveAsList = False - - -class Combine(TokenConverter): - """Converter to concatenate all matching tokens to a single string. - By default, the matching patterns must also be contiguous in the - input string; this can be disabled by specifying - ``'adjacent=False'`` in the constructor. - - Example:: - - real = Word(nums) + '.' + Word(nums) - print(real.parse_string('3.1416')) # -> ['3', '.', '1416'] - # will also erroneously match the following - print(real.parse_string('3. 1416')) # -> ['3', '.', '1416'] - - real = Combine(Word(nums) + '.' + Word(nums)) - print(real.parse_string('3.1416')) # -> ['3.1416'] - # no match when there are internal spaces - print(real.parse_string('3. 1416')) # -> Exception: Expected W:(0123...) - """ - - def __init__( - self, - expr: ParserElement, - join_string: str = "", - adjacent: bool = True, - *, - joinString: typing.Optional[str] = None, - ): - super().__init__(expr) - joinString = joinString if joinString is not None else join_string - # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself - if adjacent: - self.leave_whitespace() - self.adjacent = adjacent - self.skipWhitespace = True - self.joinString = joinString - self.callPreparse = True - - def ignore(self, other) -> ParserElement: - if self.adjacent: - ParserElement.ignore(self, other) - else: - super().ignore(other) - return self - - def postParse(self, instring, loc, tokenlist): - retToks = tokenlist.copy() - del retToks[:] - retToks += ParseResults( - ["".join(tokenlist._asStringList(self.joinString))], modal=self.modalResults - ) - - if self.resultsName and retToks.haskeys(): - return [retToks] - else: - return retToks - - -class Group(TokenConverter): - """Converter to return the matched tokens as a list - useful for - returning tokens of :class:`ZeroOrMore` and :class:`OneOrMore` expressions. - - The optional ``aslist`` argument when set to True will return the - parsed tokens as a Python list instead of a pyparsing ParseResults. - - Example:: - - ident = Word(alphas) - num = Word(nums) - term = ident | num - func = ident + Opt(delimited_list(term)) - print(func.parse_string("fn a, b, 100")) - # -> ['fn', 'a', 'b', '100'] - - func = ident + Group(Opt(delimited_list(term))) - print(func.parse_string("fn a, b, 100")) - # -> ['fn', ['a', 'b', '100']] - """ - - def __init__(self, expr: ParserElement, aslist: bool = False): - super().__init__(expr) - self.saveAsList = True - self._asPythonList = aslist - - def postParse(self, instring, loc, tokenlist): - if self._asPythonList: - return ParseResults.List( - tokenlist.asList() - if isinstance(tokenlist, ParseResults) - else list(tokenlist) - ) - else: - return [tokenlist] - - -class Dict(TokenConverter): - """Converter to return a repetitive expression as a list, but also - as a dictionary. Each element can also be referenced using the first - token in the expression as its key. Useful for tabular report - scraping when the first column can be used as a item key. - - The optional ``asdict`` argument when set to True will return the - parsed tokens as a Python dict instead of a pyparsing ParseResults. - - Example:: - - data_word = Word(alphas) - label = data_word + FollowedBy(':') - - text = "shape: SQUARE posn: upper left color: light blue texture: burlap" - attr_expr = (label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join)) - - # print attributes as plain groups - print(attr_expr[1, ...].parse_string(text).dump()) - - # instead of OneOrMore(expr), parse using Dict(Group(expr)[1, ...]) - Dict will auto-assign names - result = Dict(Group(attr_expr)[1, ...]).parse_string(text) - print(result.dump()) - - # access named fields as dict entries, or output as dict - print(result['shape']) - print(result.as_dict()) - - prints:: - - ['shape', 'SQUARE', 'posn', 'upper left', 'color', 'light blue', 'texture', 'burlap'] - [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']] - - color: 'light blue' - - posn: 'upper left' - - shape: 'SQUARE' - - texture: 'burlap' - SQUARE - {'color': 'light blue', 'posn': 'upper left', 'texture': 'burlap', 'shape': 'SQUARE'} - - See more examples at :class:`ParseResults` of accessing fields by results name. - """ - - def __init__(self, expr: ParserElement, asdict: bool = False): - super().__init__(expr) - self.saveAsList = True - self._asPythonDict = asdict - - def postParse(self, instring, loc, tokenlist): - for i, tok in enumerate(tokenlist): - if len(tok) == 0: - continue - - ikey = tok[0] - if isinstance(ikey, int): - ikey = str(ikey).strip() - - if len(tok) == 1: - tokenlist[ikey] = _ParseResultsWithOffset("", i) - - elif len(tok) == 2 and not isinstance(tok[1], ParseResults): - tokenlist[ikey] = _ParseResultsWithOffset(tok[1], i) - - else: - try: - dictvalue = tok.copy() # ParseResults(i) - except Exception: - exc = TypeError( - "could not extract dict values from parsed results" - " - Dict expression must contain Grouped expressions" - ) - raise exc from None - - del dictvalue[0] - - if len(dictvalue) != 1 or ( - isinstance(dictvalue, ParseResults) and dictvalue.haskeys() - ): - tokenlist[ikey] = _ParseResultsWithOffset(dictvalue, i) - else: - tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0], i) - - if self._asPythonDict: - return [tokenlist.as_dict()] if self.resultsName else tokenlist.as_dict() - else: - return [tokenlist] if self.resultsName else tokenlist - - -class Suppress(TokenConverter): - """Converter for ignoring the results of a parsed expression. - - Example:: - - source = "a, b, c,d" - wd = Word(alphas) - wd_list1 = wd + (',' + wd)[...] - print(wd_list1.parse_string(source)) - - # often, delimiters that are useful during parsing are just in the - # way afterward - use Suppress to keep them out of the parsed output - wd_list2 = wd + (Suppress(',') + wd)[...] - print(wd_list2.parse_string(source)) - - # Skipped text (using '...') can be suppressed as well - source = "lead in START relevant text END trailing text" - start_marker = Keyword("START") - end_marker = Keyword("END") - find_body = Suppress(...) + start_marker + ... + end_marker - print(find_body.parse_string(source) - - prints:: - - ['a', ',', 'b', ',', 'c', ',', 'd'] - ['a', 'b', 'c', 'd'] - ['START', 'relevant text ', 'END'] - - (See also :class:`delimited_list`.) - """ - - def __init__(self, expr: Union[ParserElement, str], savelist: bool = False): - if expr is ...: - expr = _PendingSkip(NoMatch()) - super().__init__(expr) - - def __add__(self, other) -> "ParserElement": - if isinstance(self.expr, _PendingSkip): - return Suppress(SkipTo(other)) + other - else: - return super().__add__(other) - - def __sub__(self, other) -> "ParserElement": - if isinstance(self.expr, _PendingSkip): - return Suppress(SkipTo(other)) - other - else: - return super().__sub__(other) - - def postParse(self, instring, loc, tokenlist): - return [] - - def suppress(self) -> ParserElement: - return self - - -def trace_parse_action(f: ParseAction) -> ParseAction: - """Decorator for debugging parse actions. - - When the parse action is called, this decorator will print - ``">> entering method-name(line:, , )"``. - When the parse action completes, the decorator will print - ``"<<"`` followed by the returned value, or any exception that the parse action raised. - - Example:: - - wd = Word(alphas) - - @trace_parse_action - def remove_duplicate_chars(tokens): - return ''.join(sorted(set(''.join(tokens)))) - - wds = wd[1, ...].set_parse_action(remove_duplicate_chars) - print(wds.parse_string("slkdjs sld sldd sdlf sdljf")) - - prints:: - - >>entering remove_duplicate_chars(line: 'slkdjs sld sldd sdlf sdljf', 0, (['slkdjs', 'sld', 'sldd', 'sdlf', 'sdljf'], {})) - < 3: - thisFunc = paArgs[0].__class__.__name__ + "." + thisFunc - sys.stderr.write( - ">>entering {}(line: {!r}, {}, {!r})\n".format(thisFunc, line(l, s), l, t) - ) - try: - ret = f(*paArgs) - except Exception as exc: - sys.stderr.write("< str: - r"""Helper to easily define string ranges for use in :class:`Word` - construction. Borrows syntax from regexp ``'[]'`` string range - definitions:: - - srange("[0-9]") -> "0123456789" - srange("[a-z]") -> "abcdefghijklmnopqrstuvwxyz" - srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_" - - The input string must be enclosed in []'s, and the returned string - is the expanded character set joined into a single string. The - values enclosed in the []'s may be: - - - a single character - - an escaped character with a leading backslash (such as ``\-`` - or ``\]``) - - an escaped hex character with a leading ``'\x'`` - (``\x21``, which is a ``'!'`` character) (``\0x##`` - is also supported for backwards compatibility) - - an escaped octal character with a leading ``'\0'`` - (``\041``, which is a ``'!'`` character) - - a range of any of the above, separated by a dash (``'a-z'``, - etc.) - - any combination of the above (``'aeiouy'``, - ``'a-zA-Z0-9_$'``, etc.) - """ - _expanded = ( - lambda p: p - if not isinstance(p, ParseResults) - else "".join(chr(c) for c in range(ord(p[0]), ord(p[1]) + 1)) - ) - try: - return "".join(_expanded(part) for part in _reBracketExpr.parse_string(s).body) - except Exception: - return "" - - -def token_map(func, *args) -> ParseAction: - """Helper to define a parse action by mapping a function to all - elements of a :class:`ParseResults` list. If any additional args are passed, - they are forwarded to the given function as additional arguments - after the token, as in - ``hex_integer = Word(hexnums).set_parse_action(token_map(int, 16))``, - which will convert the parsed data to an integer using base 16. - - Example (compare the last to example in :class:`ParserElement.transform_string`:: - - hex_ints = Word(hexnums)[1, ...].set_parse_action(token_map(int, 16)) - hex_ints.run_tests(''' - 00 11 22 aa FF 0a 0d 1a - ''') - - upperword = Word(alphas).set_parse_action(token_map(str.upper)) - upperword[1, ...].run_tests(''' - my kingdom for a horse - ''') - - wd = Word(alphas).set_parse_action(token_map(str.title)) - wd[1, ...].set_parse_action(' '.join).run_tests(''' - now is the winter of our discontent made glorious summer by this sun of york - ''') - - prints:: - - 00 11 22 aa FF 0a 0d 1a - [0, 17, 34, 170, 255, 10, 13, 26] - - my kingdom for a horse - ['MY', 'KINGDOM', 'FOR', 'A', 'HORSE'] - - now is the winter of our discontent made glorious summer by this sun of york - ['Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York'] - """ - - def pa(s, l, t): - return [func(tokn, *args) for tokn in t] - - func_name = getattr(func, "__name__", getattr(func, "__class__").__name__) - pa.__name__ = func_name - - return pa - - -def autoname_elements() -> None: - """ - Utility to simplify mass-naming of parser elements, for - generating railroad diagram with named subdiagrams. - """ - for name, var in sys._getframe().f_back.f_locals.items(): - if isinstance(var, ParserElement) and not var.customName: - var.set_name(name) - - -dbl_quoted_string = Combine( - Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*') + '"' -).set_name("string enclosed in double quotes") - -sgl_quoted_string = Combine( - Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*") + "'" -).set_name("string enclosed in single quotes") - -quoted_string = Combine( - Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*') + '"' - | Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*") + "'" -).set_name("quotedString using single or double quotes") - -unicode_string = Combine("u" + quoted_string.copy()).set_name("unicode string literal") - - -alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]") -punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]") - -# build list of built-in expressions, for future reference if a global default value -# gets updated -_builtin_exprs: List[ParserElement] = [ - v for v in vars().values() if isinstance(v, ParserElement) -] - -# backward compatibility names -tokenMap = token_map -conditionAsParseAction = condition_as_parse_action -nullDebugAction = null_debug_action -sglQuotedString = sgl_quoted_string -dblQuotedString = dbl_quoted_string -quotedString = quoted_string -unicodeString = unicode_string -lineStart = line_start -lineEnd = line_end -stringStart = string_start -stringEnd = string_end -traceParseAction = trace_parse_action diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/diagram/__init__.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/diagram/__init__.py deleted file mode 100755 index 8986447..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/diagram/__init__.py +++ /dev/null @@ -1,642 +0,0 @@ -import railroad -import pyparsing -import typing -from typing import ( - List, - NamedTuple, - Generic, - TypeVar, - Dict, - Callable, - Set, - Iterable, -) -from jinja2 import Template -from io import StringIO -import inspect - - -jinja2_template_source = """\ - - - - {% if not head %} - - {% else %} - {{ head | safe }} - {% endif %} - - -{{ body | safe }} -{% for diagram in diagrams %} -
-

{{ diagram.title }}

-
{{ diagram.text }}
-
- {{ diagram.svg }} -
-
-{% endfor %} - - -""" - -template = Template(jinja2_template_source) - -# Note: ideally this would be a dataclass, but we're supporting Python 3.5+ so we can't do this yet -NamedDiagram = NamedTuple( - "NamedDiagram", - [("name", str), ("diagram", typing.Optional[railroad.DiagramItem]), ("index", int)], -) -""" -A simple structure for associating a name with a railroad diagram -""" - -T = TypeVar("T") - - -class EachItem(railroad.Group): - """ - Custom railroad item to compose a: - - Group containing a - - OneOrMore containing a - - Choice of the elements in the Each - with the group label indicating that all must be matched - """ - - all_label = "[ALL]" - - def __init__(self, *items): - choice_item = railroad.Choice(len(items) - 1, *items) - one_or_more_item = railroad.OneOrMore(item=choice_item) - super().__init__(one_or_more_item, label=self.all_label) - - -class AnnotatedItem(railroad.Group): - """ - Simple subclass of Group that creates an annotation label - """ - - def __init__(self, label: str, item): - super().__init__(item=item, label="[{}]".format(label) if label else label) - - -class EditablePartial(Generic[T]): - """ - Acts like a functools.partial, but can be edited. In other words, it represents a type that hasn't yet been - constructed. - """ - - # We need this here because the railroad constructors actually transform the data, so can't be called until the - # entire tree is assembled - - def __init__(self, func: Callable[..., T], args: list, kwargs: dict): - self.func = func - self.args = args - self.kwargs = kwargs - - @classmethod - def from_call(cls, func: Callable[..., T], *args, **kwargs) -> "EditablePartial[T]": - """ - If you call this function in the same way that you would call the constructor, it will store the arguments - as you expect. For example EditablePartial.from_call(Fraction, 1, 3)() == Fraction(1, 3) - """ - return EditablePartial(func=func, args=list(args), kwargs=kwargs) - - @property - def name(self): - return self.kwargs["name"] - - def __call__(self) -> T: - """ - Evaluate the partial and return the result - """ - args = self.args.copy() - kwargs = self.kwargs.copy() - - # This is a helpful hack to allow you to specify varargs parameters (e.g. *args) as keyword args (e.g. - # args=['list', 'of', 'things']) - arg_spec = inspect.getfullargspec(self.func) - if arg_spec.varargs in self.kwargs: - args += kwargs.pop(arg_spec.varargs) - - return self.func(*args, **kwargs) - - -def railroad_to_html(diagrams: List[NamedDiagram], **kwargs) -> str: - """ - Given a list of NamedDiagram, produce a single HTML string that visualises those diagrams - :params kwargs: kwargs to be passed in to the template - """ - data = [] - for diagram in diagrams: - if diagram.diagram is None: - continue - io = StringIO() - diagram.diagram.writeSvg(io.write) - title = diagram.name - if diagram.index == 0: - title += " (root)" - data.append({"title": title, "text": "", "svg": io.getvalue()}) - - return template.render(diagrams=data, **kwargs) - - -def resolve_partial(partial: "EditablePartial[T]") -> T: - """ - Recursively resolves a collection of Partials into whatever type they are - """ - if isinstance(partial, EditablePartial): - partial.args = resolve_partial(partial.args) - partial.kwargs = resolve_partial(partial.kwargs) - return partial() - elif isinstance(partial, list): - return [resolve_partial(x) for x in partial] - elif isinstance(partial, dict): - return {key: resolve_partial(x) for key, x in partial.items()} - else: - return partial - - -def to_railroad( - element: pyparsing.ParserElement, - diagram_kwargs: typing.Optional[dict] = None, - vertical: int = 3, - show_results_names: bool = False, - show_groups: bool = False, -) -> List[NamedDiagram]: - """ - Convert a pyparsing element tree into a list of diagrams. This is the recommended entrypoint to diagram - creation if you want to access the Railroad tree before it is converted to HTML - :param element: base element of the parser being diagrammed - :param diagram_kwargs: kwargs to pass to the Diagram() constructor - :param vertical: (optional) - int - limit at which number of alternatives should be - shown vertically instead of horizontally - :param show_results_names - bool to indicate whether results name annotations should be - included in the diagram - :param show_groups - bool to indicate whether groups should be highlighted with an unlabeled - surrounding box - """ - # Convert the whole tree underneath the root - lookup = ConverterState(diagram_kwargs=diagram_kwargs or {}) - _to_diagram_element( - element, - lookup=lookup, - parent=None, - vertical=vertical, - show_results_names=show_results_names, - show_groups=show_groups, - ) - - root_id = id(element) - # Convert the root if it hasn't been already - if root_id in lookup: - if not element.customName: - lookup[root_id].name = "" - lookup[root_id].mark_for_extraction(root_id, lookup, force=True) - - # Now that we're finished, we can convert from intermediate structures into Railroad elements - diags = list(lookup.diagrams.values()) - if len(diags) > 1: - # collapse out duplicate diags with the same name - seen = set() - deduped_diags = [] - for d in diags: - # don't extract SkipTo elements, they are uninformative as subdiagrams - if d.name == "...": - continue - if d.name is not None and d.name not in seen: - seen.add(d.name) - deduped_diags.append(d) - resolved = [resolve_partial(partial) for partial in deduped_diags] - else: - # special case - if just one diagram, always display it, even if - # it has no name - resolved = [resolve_partial(partial) for partial in diags] - return sorted(resolved, key=lambda diag: diag.index) - - -def _should_vertical( - specification: int, exprs: Iterable[pyparsing.ParserElement] -) -> bool: - """ - Returns true if we should return a vertical list of elements - """ - if specification is None: - return False - else: - return len(_visible_exprs(exprs)) >= specification - - -class ElementState: - """ - State recorded for an individual pyparsing Element - """ - - # Note: this should be a dataclass, but we have to support Python 3.5 - def __init__( - self, - element: pyparsing.ParserElement, - converted: EditablePartial, - parent: EditablePartial, - number: int, - name: str = None, - parent_index: typing.Optional[int] = None, - ): - #: The pyparsing element that this represents - self.element: pyparsing.ParserElement = element - #: The name of the element - self.name: typing.Optional[str] = name - #: The output Railroad element in an unconverted state - self.converted: EditablePartial = converted - #: The parent Railroad element, which we store so that we can extract this if it's duplicated - self.parent: EditablePartial = parent - #: The order in which we found this element, used for sorting diagrams if this is extracted into a diagram - self.number: int = number - #: The index of this inside its parent - self.parent_index: typing.Optional[int] = parent_index - #: If true, we should extract this out into a subdiagram - self.extract: bool = False - #: If true, all of this element's children have been filled out - self.complete: bool = False - - def mark_for_extraction( - self, el_id: int, state: "ConverterState", name: str = None, force: bool = False - ): - """ - Called when this instance has been seen twice, and thus should eventually be extracted into a sub-diagram - :param el_id: id of the element - :param state: element/diagram state tracker - :param name: name to use for this element's text - :param force: If true, force extraction now, regardless of the state of this. Only useful for extracting the - root element when we know we're finished - """ - self.extract = True - - # Set the name - if not self.name: - if name: - # Allow forcing a custom name - self.name = name - elif self.element.customName: - self.name = self.element.customName - else: - self.name = "" - - # Just because this is marked for extraction doesn't mean we can do it yet. We may have to wait for children - # to be added - # Also, if this is just a string literal etc, don't bother extracting it - if force or (self.complete and _worth_extracting(self.element)): - state.extract_into_diagram(el_id) - - -class ConverterState: - """ - Stores some state that persists between recursions into the element tree - """ - - def __init__(self, diagram_kwargs: typing.Optional[dict] = None): - #: A dictionary mapping ParserElements to state relating to them - self._element_diagram_states: Dict[int, ElementState] = {} - #: A dictionary mapping ParserElement IDs to subdiagrams generated from them - self.diagrams: Dict[int, EditablePartial[NamedDiagram]] = {} - #: The index of the next unnamed element - self.unnamed_index: int = 1 - #: The index of the next element. This is used for sorting - self.index: int = 0 - #: Shared kwargs that are used to customize the construction of diagrams - self.diagram_kwargs: dict = diagram_kwargs or {} - self.extracted_diagram_names: Set[str] = set() - - def __setitem__(self, key: int, value: ElementState): - self._element_diagram_states[key] = value - - def __getitem__(self, key: int) -> ElementState: - return self._element_diagram_states[key] - - def __delitem__(self, key: int): - del self._element_diagram_states[key] - - def __contains__(self, key: int): - return key in self._element_diagram_states - - def generate_unnamed(self) -> int: - """ - Generate a number used in the name of an otherwise unnamed diagram - """ - self.unnamed_index += 1 - return self.unnamed_index - - def generate_index(self) -> int: - """ - Generate a number used to index a diagram - """ - self.index += 1 - return self.index - - def extract_into_diagram(self, el_id: int): - """ - Used when we encounter the same token twice in the same tree. When this - happens, we replace all instances of that token with a terminal, and - create a new subdiagram for the token - """ - position = self[el_id] - - # Replace the original definition of this element with a regular block - if position.parent: - ret = EditablePartial.from_call(railroad.NonTerminal, text=position.name) - if "item" in position.parent.kwargs: - position.parent.kwargs["item"] = ret - elif "items" in position.parent.kwargs: - position.parent.kwargs["items"][position.parent_index] = ret - - # If the element we're extracting is a group, skip to its content but keep the title - if position.converted.func == railroad.Group: - content = position.converted.kwargs["item"] - else: - content = position.converted - - self.diagrams[el_id] = EditablePartial.from_call( - NamedDiagram, - name=position.name, - diagram=EditablePartial.from_call( - railroad.Diagram, content, **self.diagram_kwargs - ), - index=position.number, - ) - - del self[el_id] - - -def _worth_extracting(element: pyparsing.ParserElement) -> bool: - """ - Returns true if this element is worth having its own sub-diagram. Simply, if any of its children - themselves have children, then its complex enough to extract - """ - children = element.recurse() - return any(child.recurse() for child in children) - - -def _apply_diagram_item_enhancements(fn): - """ - decorator to ensure enhancements to a diagram item (such as results name annotations) - get applied on return from _to_diagram_element (we do this since there are several - returns in _to_diagram_element) - """ - - def _inner( - element: pyparsing.ParserElement, - parent: typing.Optional[EditablePartial], - lookup: ConverterState = None, - vertical: int = None, - index: int = 0, - name_hint: str = None, - show_results_names: bool = False, - show_groups: bool = False, - ) -> typing.Optional[EditablePartial]: - - ret = fn( - element, - parent, - lookup, - vertical, - index, - name_hint, - show_results_names, - show_groups, - ) - - # apply annotation for results name, if present - if show_results_names and ret is not None: - element_results_name = element.resultsName - if element_results_name: - # add "*" to indicate if this is a "list all results" name - element_results_name += "" if element.modalResults else "*" - ret = EditablePartial.from_call( - railroad.Group, item=ret, label=element_results_name - ) - - return ret - - return _inner - - -def _visible_exprs(exprs: Iterable[pyparsing.ParserElement]): - non_diagramming_exprs = ( - pyparsing.ParseElementEnhance, - pyparsing.PositionToken, - pyparsing.And._ErrorStop, - ) - return [ - e - for e in exprs - if not (e.customName or e.resultsName or isinstance(e, non_diagramming_exprs)) - ] - - -@_apply_diagram_item_enhancements -def _to_diagram_element( - element: pyparsing.ParserElement, - parent: typing.Optional[EditablePartial], - lookup: ConverterState = None, - vertical: int = None, - index: int = 0, - name_hint: str = None, - show_results_names: bool = False, - show_groups: bool = False, -) -> typing.Optional[EditablePartial]: - """ - Recursively converts a PyParsing Element to a railroad Element - :param lookup: The shared converter state that keeps track of useful things - :param index: The index of this element within the parent - :param parent: The parent of this element in the output tree - :param vertical: Controls at what point we make a list of elements vertical. If this is an integer (the default), - it sets the threshold of the number of items before we go vertical. If True, always go vertical, if False, never - do so - :param name_hint: If provided, this will override the generated name - :param show_results_names: bool flag indicating whether to add annotations for results names - :returns: The converted version of the input element, but as a Partial that hasn't yet been constructed - :param show_groups: bool flag indicating whether to show groups using bounding box - """ - exprs = element.recurse() - name = name_hint or element.customName or element.__class__.__name__ - - # Python's id() is used to provide a unique identifier for elements - el_id = id(element) - - element_results_name = element.resultsName - - # Here we basically bypass processing certain wrapper elements if they contribute nothing to the diagram - if not element.customName: - if isinstance( - element, - ( - # pyparsing.TokenConverter, - # pyparsing.Forward, - pyparsing.Located, - ), - ): - # However, if this element has a useful custom name, and its child does not, we can pass it on to the child - if exprs: - if not exprs[0].customName: - propagated_name = name - else: - propagated_name = None - - return _to_diagram_element( - element.expr, - parent=parent, - lookup=lookup, - vertical=vertical, - index=index, - name_hint=propagated_name, - show_results_names=show_results_names, - show_groups=show_groups, - ) - - # If the element isn't worth extracting, we always treat it as the first time we say it - if _worth_extracting(element): - if el_id in lookup: - # If we've seen this element exactly once before, we are only just now finding out that it's a duplicate, - # so we have to extract it into a new diagram. - looked_up = lookup[el_id] - looked_up.mark_for_extraction(el_id, lookup, name=name_hint) - ret = EditablePartial.from_call(railroad.NonTerminal, text=looked_up.name) - return ret - - elif el_id in lookup.diagrams: - # If we have seen the element at least twice before, and have already extracted it into a subdiagram, we - # just put in a marker element that refers to the sub-diagram - ret = EditablePartial.from_call( - railroad.NonTerminal, text=lookup.diagrams[el_id].kwargs["name"] - ) - return ret - - # Recursively convert child elements - # Here we find the most relevant Railroad element for matching pyparsing Element - # We use ``items=[]`` here to hold the place for where the child elements will go once created - if isinstance(element, pyparsing.And): - # detect And's created with ``expr*N`` notation - for these use a OneOrMore with a repeat - # (all will have the same name, and resultsName) - if not exprs: - return None - if len(set((e.name, e.resultsName) for e in exprs)) == 1: - ret = EditablePartial.from_call( - railroad.OneOrMore, item="", repeat=str(len(exprs)) - ) - elif _should_vertical(vertical, exprs): - ret = EditablePartial.from_call(railroad.Stack, items=[]) - else: - ret = EditablePartial.from_call(railroad.Sequence, items=[]) - elif isinstance(element, (pyparsing.Or, pyparsing.MatchFirst)): - if not exprs: - return None - if _should_vertical(vertical, exprs): - ret = EditablePartial.from_call(railroad.Choice, 0, items=[]) - else: - ret = EditablePartial.from_call(railroad.HorizontalChoice, items=[]) - elif isinstance(element, pyparsing.Each): - if not exprs: - return None - ret = EditablePartial.from_call(EachItem, items=[]) - elif isinstance(element, pyparsing.NotAny): - ret = EditablePartial.from_call(AnnotatedItem, label="NOT", item="") - elif isinstance(element, pyparsing.FollowedBy): - ret = EditablePartial.from_call(AnnotatedItem, label="LOOKAHEAD", item="") - elif isinstance(element, pyparsing.PrecededBy): - ret = EditablePartial.from_call(AnnotatedItem, label="LOOKBEHIND", item="") - elif isinstance(element, pyparsing.Group): - if show_groups: - ret = EditablePartial.from_call(AnnotatedItem, label="", item="") - else: - ret = EditablePartial.from_call(railroad.Group, label="", item="") - elif isinstance(element, pyparsing.TokenConverter): - ret = EditablePartial.from_call( - AnnotatedItem, label=type(element).__name__.lower(), item="" - ) - elif isinstance(element, pyparsing.Opt): - ret = EditablePartial.from_call(railroad.Optional, item="") - elif isinstance(element, pyparsing.OneOrMore): - ret = EditablePartial.from_call(railroad.OneOrMore, item="") - elif isinstance(element, pyparsing.ZeroOrMore): - ret = EditablePartial.from_call(railroad.ZeroOrMore, item="") - elif isinstance(element, pyparsing.Group): - ret = EditablePartial.from_call( - railroad.Group, item=None, label=element_results_name - ) - elif isinstance(element, pyparsing.Empty) and not element.customName: - # Skip unnamed "Empty" elements - ret = None - elif len(exprs) > 1: - ret = EditablePartial.from_call(railroad.Sequence, items=[]) - elif len(exprs) > 0 and not element_results_name: - ret = EditablePartial.from_call(railroad.Group, item="", label=name) - else: - terminal = EditablePartial.from_call(railroad.Terminal, element.defaultName) - ret = terminal - - if ret is None: - return - - # Indicate this element's position in the tree so we can extract it if necessary - lookup[el_id] = ElementState( - element=element, - converted=ret, - parent=parent, - parent_index=index, - number=lookup.generate_index(), - ) - if element.customName: - lookup[el_id].mark_for_extraction(el_id, lookup, element.customName) - - i = 0 - for expr in exprs: - # Add a placeholder index in case we have to extract the child before we even add it to the parent - if "items" in ret.kwargs: - ret.kwargs["items"].insert(i, None) - - item = _to_diagram_element( - expr, - parent=ret, - lookup=lookup, - vertical=vertical, - index=i, - show_results_names=show_results_names, - show_groups=show_groups, - ) - - # Some elements don't need to be shown in the diagram - if item is not None: - if "item" in ret.kwargs: - ret.kwargs["item"] = item - elif "items" in ret.kwargs: - # If we've already extracted the child, don't touch this index, since it's occupied by a nonterminal - ret.kwargs["items"][i] = item - i += 1 - elif "items" in ret.kwargs: - # If we're supposed to skip this element, remove it from the parent - del ret.kwargs["items"][i] - - # If all this items children are none, skip this item - if ret and ( - ("items" in ret.kwargs and len(ret.kwargs["items"]) == 0) - or ("item" in ret.kwargs and ret.kwargs["item"] is None) - ): - ret = EditablePartial.from_call(railroad.Terminal, name) - - # Mark this element as "complete", ie it has all of its children - if el_id in lookup: - lookup[el_id].complete = True - - if el_id in lookup and lookup[el_id].extract and lookup[el_id].complete: - lookup.extract_into_diagram(el_id) - if ret is not None: - ret = EditablePartial.from_call( - railroad.NonTerminal, text=lookup.diagrams[el_id].kwargs["name"] - ) - - return ret diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index bdf3015..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/exceptions.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/exceptions.py deleted file mode 100755 index a38447b..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/exceptions.py +++ /dev/null @@ -1,267 +0,0 @@ -# exceptions.py - -import re -import sys -import typing - -from .util import col, line, lineno, _collapse_string_to_ranges -from .unicode import pyparsing_unicode as ppu - - -class ExceptionWordUnicode(ppu.Latin1, ppu.LatinA, ppu.LatinB, ppu.Greek, ppu.Cyrillic): - pass - - -_extract_alphanums = _collapse_string_to_ranges(ExceptionWordUnicode.alphanums) -_exception_word_extractor = re.compile("([" + _extract_alphanums + "]{1,16})|.") - - -class ParseBaseException(Exception): - """base exception class for all parsing runtime exceptions""" - - # Performance tuning: we construct a *lot* of these, so keep this - # constructor as small and fast as possible - def __init__( - self, - pstr: str, - loc: int = 0, - msg: typing.Optional[str] = None, - elem=None, - ): - self.loc = loc - if msg is None: - self.msg = pstr - self.pstr = "" - else: - self.msg = msg - self.pstr = pstr - self.parser_element = self.parserElement = elem - self.args = (pstr, loc, msg) - - @staticmethod - def explain_exception(exc, depth=16): - """ - Method to take an exception and translate the Python internal traceback into a list - of the pyparsing expressions that caused the exception to be raised. - - Parameters: - - - exc - exception raised during parsing (need not be a ParseException, in support - of Python exceptions that might be raised in a parse action) - - depth (default=16) - number of levels back in the stack trace to list expression - and function names; if None, the full stack trace names will be listed; if 0, only - the failing input line, marker, and exception string will be shown - - Returns a multi-line string listing the ParserElements and/or function names in the - exception's stack trace. - """ - import inspect - from .core import ParserElement - - if depth is None: - depth = sys.getrecursionlimit() - ret = [] - if isinstance(exc, ParseBaseException): - ret.append(exc.line) - ret.append(" " * (exc.column - 1) + "^") - ret.append("{}: {}".format(type(exc).__name__, exc)) - - if depth > 0: - callers = inspect.getinnerframes(exc.__traceback__, context=depth) - seen = set() - for i, ff in enumerate(callers[-depth:]): - frm = ff[0] - - f_self = frm.f_locals.get("self", None) - if isinstance(f_self, ParserElement): - if frm.f_code.co_name not in ("parseImpl", "_parseNoCache"): - continue - if id(f_self) in seen: - continue - seen.add(id(f_self)) - - self_type = type(f_self) - ret.append( - "{}.{} - {}".format( - self_type.__module__, self_type.__name__, f_self - ) - ) - - elif f_self is not None: - self_type = type(f_self) - ret.append("{}.{}".format(self_type.__module__, self_type.__name__)) - - else: - code = frm.f_code - if code.co_name in ("wrapper", ""): - continue - - ret.append("{}".format(code.co_name)) - - depth -= 1 - if not depth: - break - - return "\n".join(ret) - - @classmethod - def _from_exception(cls, pe): - """ - internal factory method to simplify creating one type of ParseException - from another - avoids having __init__ signature conflicts among subclasses - """ - return cls(pe.pstr, pe.loc, pe.msg, pe.parserElement) - - @property - def line(self) -> str: - """ - Return the line of text where the exception occurred. - """ - return line(self.loc, self.pstr) - - @property - def lineno(self) -> int: - """ - Return the 1-based line number of text where the exception occurred. - """ - return lineno(self.loc, self.pstr) - - @property - def col(self) -> int: - """ - Return the 1-based column on the line of text where the exception occurred. - """ - return col(self.loc, self.pstr) - - @property - def column(self) -> int: - """ - Return the 1-based column on the line of text where the exception occurred. - """ - return col(self.loc, self.pstr) - - def __str__(self) -> str: - if self.pstr: - if self.loc >= len(self.pstr): - foundstr = ", found end of text" - else: - # pull out next word at error location - found_match = _exception_word_extractor.match(self.pstr, self.loc) - if found_match is not None: - found = found_match.group(0) - else: - found = self.pstr[self.loc : self.loc + 1] - foundstr = (", found %r" % found).replace(r"\\", "\\") - else: - foundstr = "" - return "{}{} (at char {}), (line:{}, col:{})".format( - self.msg, foundstr, self.loc, self.lineno, self.column - ) - - def __repr__(self): - return str(self) - - def mark_input_line(self, marker_string: str = None, *, markerString=">!<") -> str: - """ - Extracts the exception line from the input string, and marks - the location of the exception with a special symbol. - """ - markerString = marker_string if marker_string is not None else markerString - line_str = self.line - line_column = self.column - 1 - if markerString: - line_str = "".join( - (line_str[:line_column], markerString, line_str[line_column:]) - ) - return line_str.strip() - - def explain(self, depth=16) -> str: - """ - Method to translate the Python internal traceback into a list - of the pyparsing expressions that caused the exception to be raised. - - Parameters: - - - depth (default=16) - number of levels back in the stack trace to list expression - and function names; if None, the full stack trace names will be listed; if 0, only - the failing input line, marker, and exception string will be shown - - Returns a multi-line string listing the ParserElements and/or function names in the - exception's stack trace. - - Example:: - - expr = pp.Word(pp.nums) * 3 - try: - expr.parse_string("123 456 A789") - except pp.ParseException as pe: - print(pe.explain(depth=0)) - - prints:: - - 123 456 A789 - ^ - ParseException: Expected W:(0-9), found 'A' (at char 8), (line:1, col:9) - - Note: the diagnostic output will include string representations of the expressions - that failed to parse. These representations will be more helpful if you use `set_name` to - give identifiable names to your expressions. Otherwise they will use the default string - forms, which may be cryptic to read. - - Note: pyparsing's default truncation of exception tracebacks may also truncate the - stack of expressions that are displayed in the ``explain`` output. To get the full listing - of parser expressions, you may have to set ``ParserElement.verbose_stacktrace = True`` - """ - return self.explain_exception(self, depth) - - markInputline = mark_input_line - - -class ParseException(ParseBaseException): - """ - Exception thrown when a parse expression doesn't match the input string - - Example:: - - try: - Word(nums).set_name("integer").parse_string("ABC") - except ParseException as pe: - print(pe) - print("column: {}".format(pe.column)) - - prints:: - - Expected integer (at char 0), (line:1, col:1) - column: 1 - - """ - - -class ParseFatalException(ParseBaseException): - """ - User-throwable exception thrown when inconsistent parse content - is found; stops all parsing immediately - """ - - -class ParseSyntaxException(ParseFatalException): - """ - Just like :class:`ParseFatalException`, but thrown internally - when an :class:`ErrorStop` ('-' operator) indicates - that parsing is to stop immediately because an unbacktrackable - syntax error has been found. - """ - - -class RecursiveGrammarException(Exception): - """ - Exception thrown by :class:`ParserElement.validate` if the - grammar could be left-recursive; parser may need to enable - left recursion using :class:`ParserElement.enable_left_recursion` - """ - - def __init__(self, parseElementList): - self.parseElementTrace = parseElementList - - def __str__(self) -> str: - return "RecursiveGrammarException: {}".format(self.parseElementTrace) diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/helpers.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/helpers.py deleted file mode 100755 index 9588b3b..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/helpers.py +++ /dev/null @@ -1,1088 +0,0 @@ -# helpers.py -import html.entities -import re -import typing - -from . import __diag__ -from .core import * -from .util import _bslash, _flatten, _escape_regex_range_chars - - -# -# global helpers -# -def delimited_list( - expr: Union[str, ParserElement], - delim: Union[str, ParserElement] = ",", - combine: bool = False, - min: typing.Optional[int] = None, - max: typing.Optional[int] = None, - *, - allow_trailing_delim: bool = False, -) -> ParserElement: - """Helper to define a delimited list of expressions - the delimiter - defaults to ','. By default, the list elements and delimiters can - have intervening whitespace, and comments, but this can be - overridden by passing ``combine=True`` in the constructor. If - ``combine`` is set to ``True``, the matching tokens are - returned as a single token string, with the delimiters included; - otherwise, the matching tokens are returned as a list of tokens, - with the delimiters suppressed. - - If ``allow_trailing_delim`` is set to True, then the list may end with - a delimiter. - - Example:: - - delimited_list(Word(alphas)).parse_string("aa,bb,cc") # -> ['aa', 'bb', 'cc'] - delimited_list(Word(hexnums), delim=':', combine=True).parse_string("AA:BB:CC:DD:EE") # -> ['AA:BB:CC:DD:EE'] - """ - if isinstance(expr, str_type): - expr = ParserElement._literalStringClass(expr) - - dlName = "{expr} [{delim} {expr}]...{end}".format( - expr=str(expr.copy().streamline()), - delim=str(delim), - end=" [{}]".format(str(delim)) if allow_trailing_delim else "", - ) - - if not combine: - delim = Suppress(delim) - - if min is not None: - if min < 1: - raise ValueError("min must be greater than 0") - min -= 1 - if max is not None: - if min is not None and max <= min: - raise ValueError("max must be greater than, or equal to min") - max -= 1 - delimited_list_expr = expr + (delim + expr)[min, max] - - if allow_trailing_delim: - delimited_list_expr += Opt(delim) - - if combine: - return Combine(delimited_list_expr).set_name(dlName) - else: - return delimited_list_expr.set_name(dlName) - - -def counted_array( - expr: ParserElement, - int_expr: typing.Optional[ParserElement] = None, - *, - intExpr: typing.Optional[ParserElement] = None, -) -> ParserElement: - """Helper to define a counted list of expressions. - - This helper defines a pattern of the form:: - - integer expr expr expr... - - where the leading integer tells how many expr expressions follow. - The matched tokens returns the array of expr tokens as a list - the - leading count token is suppressed. - - If ``int_expr`` is specified, it should be a pyparsing expression - that produces an integer value. - - Example:: - - counted_array(Word(alphas)).parse_string('2 ab cd ef') # -> ['ab', 'cd'] - - # in this parser, the leading integer value is given in binary, - # '10' indicating that 2 values are in the array - binary_constant = Word('01').set_parse_action(lambda t: int(t[0], 2)) - counted_array(Word(alphas), int_expr=binary_constant).parse_string('10 ab cd ef') # -> ['ab', 'cd'] - - # if other fields must be parsed after the count but before the - # list items, give the fields results names and they will - # be preserved in the returned ParseResults: - count_with_metadata = integer + Word(alphas)("type") - typed_array = counted_array(Word(alphanums), int_expr=count_with_metadata)("items") - result = typed_array.parse_string("3 bool True True False") - print(result.dump()) - - # prints - # ['True', 'True', 'False'] - # - items: ['True', 'True', 'False'] - # - type: 'bool' - """ - intExpr = intExpr or int_expr - array_expr = Forward() - - def count_field_parse_action(s, l, t): - nonlocal array_expr - n = t[0] - array_expr <<= (expr * n) if n else Empty() - # clear list contents, but keep any named results - del t[:] - - if intExpr is None: - intExpr = Word(nums).set_parse_action(lambda t: int(t[0])) - else: - intExpr = intExpr.copy() - intExpr.set_name("arrayLen") - intExpr.add_parse_action(count_field_parse_action, call_during_try=True) - return (intExpr + array_expr).set_name("(len) " + str(expr) + "...") - - -def match_previous_literal(expr: ParserElement) -> ParserElement: - """Helper to define an expression that is indirectly defined from - the tokens matched in a previous expression, that is, it looks for - a 'repeat' of a previous expression. For example:: - - first = Word(nums) - second = match_previous_literal(first) - match_expr = first + ":" + second - - will match ``"1:1"``, but not ``"1:2"``. Because this - matches a previous literal, will also match the leading - ``"1:1"`` in ``"1:10"``. If this is not desired, use - :class:`match_previous_expr`. Do *not* use with packrat parsing - enabled. - """ - rep = Forward() - - def copy_token_to_repeater(s, l, t): - if t: - if len(t) == 1: - rep << t[0] - else: - # flatten t tokens - tflat = _flatten(t.as_list()) - rep << And(Literal(tt) for tt in tflat) - else: - rep << Empty() - - expr.add_parse_action(copy_token_to_repeater, callDuringTry=True) - rep.set_name("(prev) " + str(expr)) - return rep - - -def match_previous_expr(expr: ParserElement) -> ParserElement: - """Helper to define an expression that is indirectly defined from - the tokens matched in a previous expression, that is, it looks for - a 'repeat' of a previous expression. For example:: - - first = Word(nums) - second = match_previous_expr(first) - match_expr = first + ":" + second - - will match ``"1:1"``, but not ``"1:2"``. Because this - matches by expressions, will *not* match the leading ``"1:1"`` - in ``"1:10"``; the expressions are evaluated first, and then - compared, so ``"1"`` is compared with ``"10"``. Do *not* use - with packrat parsing enabled. - """ - rep = Forward() - e2 = expr.copy() - rep <<= e2 - - def copy_token_to_repeater(s, l, t): - matchTokens = _flatten(t.as_list()) - - def must_match_these_tokens(s, l, t): - theseTokens = _flatten(t.as_list()) - if theseTokens != matchTokens: - raise ParseException( - s, l, "Expected {}, found{}".format(matchTokens, theseTokens) - ) - - rep.set_parse_action(must_match_these_tokens, callDuringTry=True) - - expr.add_parse_action(copy_token_to_repeater, callDuringTry=True) - rep.set_name("(prev) " + str(expr)) - return rep - - -def one_of( - strs: Union[typing.Iterable[str], str], - caseless: bool = False, - use_regex: bool = True, - as_keyword: bool = False, - *, - useRegex: bool = True, - asKeyword: bool = False, -) -> ParserElement: - """Helper to quickly define a set of alternative :class:`Literal` s, - and makes sure to do longest-first testing when there is a conflict, - regardless of the input order, but returns - a :class:`MatchFirst` for best performance. - - Parameters: - - - ``strs`` - a string of space-delimited literals, or a collection of - string literals - - ``caseless`` - treat all literals as caseless - (default= ``False``) - - ``use_regex`` - as an optimization, will - generate a :class:`Regex` object; otherwise, will generate - a :class:`MatchFirst` object (if ``caseless=True`` or ``asKeyword=True``, or if - creating a :class:`Regex` raises an exception) - (default= ``True``) - - ``as_keyword`` - enforce :class:`Keyword`-style matching on the - generated expressions - (default= ``False``) - - ``asKeyword`` and ``useRegex`` are retained for pre-PEP8 compatibility, - but will be removed in a future release - - Example:: - - comp_oper = one_of("< = > <= >= !=") - var = Word(alphas) - number = Word(nums) - term = var | number - comparison_expr = term + comp_oper + term - print(comparison_expr.search_string("B = 12 AA=23 B<=AA AA>12")) - - prints:: - - [['B', '=', '12'], ['AA', '=', '23'], ['B', '<=', 'AA'], ['AA', '>', '12']] - """ - asKeyword = asKeyword or as_keyword - useRegex = useRegex and use_regex - - if ( - isinstance(caseless, str_type) - and __diag__.warn_on_multiple_string_args_to_oneof - ): - warnings.warn( - "More than one string argument passed to one_of, pass" - " choices as a list or space-delimited string", - stacklevel=2, - ) - - if caseless: - isequal = lambda a, b: a.upper() == b.upper() - masks = lambda a, b: b.upper().startswith(a.upper()) - parseElementClass = CaselessKeyword if asKeyword else CaselessLiteral - else: - isequal = lambda a, b: a == b - masks = lambda a, b: b.startswith(a) - parseElementClass = Keyword if asKeyword else Literal - - symbols: List[str] = [] - if isinstance(strs, str_type): - symbols = strs.split() - elif isinstance(strs, Iterable): - symbols = list(strs) - else: - raise TypeError("Invalid argument to one_of, expected string or iterable") - if not symbols: - return NoMatch() - - # reorder given symbols to take care to avoid masking longer choices with shorter ones - # (but only if the given symbols are not just single characters) - if any(len(sym) > 1 for sym in symbols): - i = 0 - while i < len(symbols) - 1: - cur = symbols[i] - for j, other in enumerate(symbols[i + 1 :]): - if isequal(other, cur): - del symbols[i + j + 1] - break - elif masks(cur, other): - del symbols[i + j + 1] - symbols.insert(i, other) - break - else: - i += 1 - - if useRegex: - re_flags: int = re.IGNORECASE if caseless else 0 - - try: - if all(len(sym) == 1 for sym in symbols): - # symbols are just single characters, create range regex pattern - patt = "[{}]".format( - "".join(_escape_regex_range_chars(sym) for sym in symbols) - ) - else: - patt = "|".join(re.escape(sym) for sym in symbols) - - # wrap with \b word break markers if defining as keywords - if asKeyword: - patt = r"\b(?:{})\b".format(patt) - - ret = Regex(patt, flags=re_flags).set_name(" | ".join(symbols)) - - if caseless: - # add parse action to return symbols as specified, not in random - # casing as found in input string - symbol_map = {sym.lower(): sym for sym in symbols} - ret.add_parse_action(lambda s, l, t: symbol_map[t[0].lower()]) - - return ret - - except re.error: - warnings.warn( - "Exception creating Regex for one_of, building MatchFirst", stacklevel=2 - ) - - # last resort, just use MatchFirst - return MatchFirst(parseElementClass(sym) for sym in symbols).set_name( - " | ".join(symbols) - ) - - -def dict_of(key: ParserElement, value: ParserElement) -> ParserElement: - """Helper to easily and clearly define a dictionary by specifying - the respective patterns for the key and value. Takes care of - defining the :class:`Dict`, :class:`ZeroOrMore`, and - :class:`Group` tokens in the proper order. The key pattern - can include delimiting markers or punctuation, as long as they are - suppressed, thereby leaving the significant key text. The value - pattern can include named results, so that the :class:`Dict` results - can include named token fields. - - Example:: - - text = "shape: SQUARE posn: upper left color: light blue texture: burlap" - attr_expr = (label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join)) - print(attr_expr[1, ...].parse_string(text).dump()) - - attr_label = label - attr_value = Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join) - - # similar to Dict, but simpler call format - result = dict_of(attr_label, attr_value).parse_string(text) - print(result.dump()) - print(result['shape']) - print(result.shape) # object attribute access works too - print(result.as_dict()) - - prints:: - - [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']] - - color: 'light blue' - - posn: 'upper left' - - shape: 'SQUARE' - - texture: 'burlap' - SQUARE - SQUARE - {'color': 'light blue', 'shape': 'SQUARE', 'posn': 'upper left', 'texture': 'burlap'} - """ - return Dict(OneOrMore(Group(key + value))) - - -def original_text_for( - expr: ParserElement, as_string: bool = True, *, asString: bool = True -) -> ParserElement: - """Helper to return the original, untokenized text for a given - expression. Useful to restore the parsed fields of an HTML start - tag into the raw tag text itself, or to revert separate tokens with - intervening whitespace back to the original matching input text. By - default, returns astring containing the original parsed text. - - If the optional ``as_string`` argument is passed as - ``False``, then the return value is - a :class:`ParseResults` containing any results names that - were originally matched, and a single token containing the original - matched text from the input string. So if the expression passed to - :class:`original_text_for` contains expressions with defined - results names, you must set ``as_string`` to ``False`` if you - want to preserve those results name values. - - The ``asString`` pre-PEP8 argument is retained for compatibility, - but will be removed in a future release. - - Example:: - - src = "this is test bold text normal text " - for tag in ("b", "i"): - opener, closer = make_html_tags(tag) - patt = original_text_for(opener + SkipTo(closer) + closer) - print(patt.search_string(src)[0]) - - prints:: - - [' bold text '] - ['text'] - """ - asString = asString and as_string - - locMarker = Empty().set_parse_action(lambda s, loc, t: loc) - endlocMarker = locMarker.copy() - endlocMarker.callPreparse = False - matchExpr = locMarker("_original_start") + expr + endlocMarker("_original_end") - if asString: - extractText = lambda s, l, t: s[t._original_start : t._original_end] - else: - - def extractText(s, l, t): - t[:] = [s[t.pop("_original_start") : t.pop("_original_end")]] - - matchExpr.set_parse_action(extractText) - matchExpr.ignoreExprs = expr.ignoreExprs - matchExpr.suppress_warning(Diagnostics.warn_ungrouped_named_tokens_in_collection) - return matchExpr - - -def ungroup(expr: ParserElement) -> ParserElement: - """Helper to undo pyparsing's default grouping of And expressions, - even if all but one are non-empty. - """ - return TokenConverter(expr).add_parse_action(lambda t: t[0]) - - -def locatedExpr(expr: ParserElement) -> ParserElement: - """ - (DEPRECATED - future code should use the Located class) - Helper to decorate a returned token with its starting and ending - locations in the input string. - - This helper adds the following results names: - - - ``locn_start`` - location where matched expression begins - - ``locn_end`` - location where matched expression ends - - ``value`` - the actual parsed results - - Be careful if the input text contains ```` characters, you - may want to call :class:`ParserElement.parseWithTabs` - - Example:: - - wd = Word(alphas) - for match in locatedExpr(wd).searchString("ljsdf123lksdjjf123lkkjj1222"): - print(match) - - prints:: - - [[0, 'ljsdf', 5]] - [[8, 'lksdjjf', 15]] - [[18, 'lkkjj', 23]] - """ - locator = Empty().set_parse_action(lambda ss, ll, tt: ll) - return Group( - locator("locn_start") - + expr("value") - + locator.copy().leaveWhitespace()("locn_end") - ) - - -def nested_expr( - opener: Union[str, ParserElement] = "(", - closer: Union[str, ParserElement] = ")", - content: typing.Optional[ParserElement] = None, - ignore_expr: ParserElement = quoted_string(), - *, - ignoreExpr: ParserElement = quoted_string(), -) -> ParserElement: - """Helper method for defining nested lists enclosed in opening and - closing delimiters (``"("`` and ``")"`` are the default). - - Parameters: - - ``opener`` - opening character for a nested list - (default= ``"("``); can also be a pyparsing expression - - ``closer`` - closing character for a nested list - (default= ``")"``); can also be a pyparsing expression - - ``content`` - expression for items within the nested lists - (default= ``None``) - - ``ignore_expr`` - expression for ignoring opening and closing delimiters - (default= :class:`quoted_string`) - - ``ignoreExpr`` - this pre-PEP8 argument is retained for compatibility - but will be removed in a future release - - If an expression is not provided for the content argument, the - nested expression will capture all whitespace-delimited content - between delimiters as a list of separate values. - - Use the ``ignore_expr`` argument to define expressions that may - contain opening or closing characters that should not be treated as - opening or closing characters for nesting, such as quoted_string or - a comment expression. Specify multiple expressions using an - :class:`Or` or :class:`MatchFirst`. The default is - :class:`quoted_string`, but if no expressions are to be ignored, then - pass ``None`` for this argument. - - Example:: - - data_type = one_of("void int short long char float double") - decl_data_type = Combine(data_type + Opt(Word('*'))) - ident = Word(alphas+'_', alphanums+'_') - number = pyparsing_common.number - arg = Group(decl_data_type + ident) - LPAR, RPAR = map(Suppress, "()") - - code_body = nested_expr('{', '}', ignore_expr=(quoted_string | c_style_comment)) - - c_function = (decl_data_type("type") - + ident("name") - + LPAR + Opt(delimited_list(arg), [])("args") + RPAR - + code_body("body")) - c_function.ignore(c_style_comment) - - source_code = ''' - int is_odd(int x) { - return (x%2); - } - - int dec_to_hex(char hchar) { - if (hchar >= '0' && hchar <= '9') { - return (ord(hchar)-ord('0')); - } else { - return (10+ord(hchar)-ord('A')); - } - } - ''' - for func in c_function.search_string(source_code): - print("%(name)s (%(type)s) args: %(args)s" % func) - - - prints:: - - is_odd (int) args: [['int', 'x']] - dec_to_hex (int) args: [['char', 'hchar']] - """ - if ignoreExpr != ignore_expr: - ignoreExpr = ignore_expr if ignoreExpr == quoted_string() else ignoreExpr - if opener == closer: - raise ValueError("opening and closing strings cannot be the same") - if content is None: - if isinstance(opener, str_type) and isinstance(closer, str_type): - if len(opener) == 1 and len(closer) == 1: - if ignoreExpr is not None: - content = Combine( - OneOrMore( - ~ignoreExpr - + CharsNotIn( - opener + closer + ParserElement.DEFAULT_WHITE_CHARS, - exact=1, - ) - ) - ).set_parse_action(lambda t: t[0].strip()) - else: - content = empty.copy() + CharsNotIn( - opener + closer + ParserElement.DEFAULT_WHITE_CHARS - ).set_parse_action(lambda t: t[0].strip()) - else: - if ignoreExpr is not None: - content = Combine( - OneOrMore( - ~ignoreExpr - + ~Literal(opener) - + ~Literal(closer) - + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS, exact=1) - ) - ).set_parse_action(lambda t: t[0].strip()) - else: - content = Combine( - OneOrMore( - ~Literal(opener) - + ~Literal(closer) - + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS, exact=1) - ) - ).set_parse_action(lambda t: t[0].strip()) - else: - raise ValueError( - "opening and closing arguments must be strings if no content expression is given" - ) - ret = Forward() - if ignoreExpr is not None: - ret <<= Group( - Suppress(opener) + ZeroOrMore(ignoreExpr | ret | content) + Suppress(closer) - ) - else: - ret <<= Group(Suppress(opener) + ZeroOrMore(ret | content) + Suppress(closer)) - ret.set_name("nested %s%s expression" % (opener, closer)) - return ret - - -def _makeTags(tagStr, xml, suppress_LT=Suppress("<"), suppress_GT=Suppress(">")): - """Internal helper to construct opening and closing tag expressions, given a tag name""" - if isinstance(tagStr, str_type): - resname = tagStr - tagStr = Keyword(tagStr, caseless=not xml) - else: - resname = tagStr.name - - tagAttrName = Word(alphas, alphanums + "_-:") - if xml: - tagAttrValue = dbl_quoted_string.copy().set_parse_action(remove_quotes) - openTag = ( - suppress_LT - + tagStr("tag") - + Dict(ZeroOrMore(Group(tagAttrName + Suppress("=") + tagAttrValue))) - + Opt("/", default=[False])("empty").set_parse_action( - lambda s, l, t: t[0] == "/" - ) - + suppress_GT - ) - else: - tagAttrValue = quoted_string.copy().set_parse_action(remove_quotes) | Word( - printables, exclude_chars=">" - ) - openTag = ( - suppress_LT - + tagStr("tag") - + Dict( - ZeroOrMore( - Group( - tagAttrName.set_parse_action(lambda t: t[0].lower()) - + Opt(Suppress("=") + tagAttrValue) - ) - ) - ) - + Opt("/", default=[False])("empty").set_parse_action( - lambda s, l, t: t[0] == "/" - ) - + suppress_GT - ) - closeTag = Combine(Literal("", adjacent=False) - - openTag.set_name("<%s>" % resname) - # add start results name in parse action now that ungrouped names are not reported at two levels - openTag.add_parse_action( - lambda t: t.__setitem__( - "start" + "".join(resname.replace(":", " ").title().split()), t.copy() - ) - ) - closeTag = closeTag( - "end" + "".join(resname.replace(":", " ").title().split()) - ).set_name("" % resname) - openTag.tag = resname - closeTag.tag = resname - openTag.tag_body = SkipTo(closeTag()) - return openTag, closeTag - - -def make_html_tags( - tag_str: Union[str, ParserElement] -) -> Tuple[ParserElement, ParserElement]: - """Helper to construct opening and closing tag expressions for HTML, - given a tag name. Matches tags in either upper or lower case, - attributes with namespaces and with quoted or unquoted values. - - Example:: - - text = 'More info at the pyparsing wiki page' - # make_html_tags returns pyparsing expressions for the opening and - # closing tags as a 2-tuple - a, a_end = make_html_tags("A") - link_expr = a + SkipTo(a_end)("link_text") + a_end - - for link in link_expr.search_string(text): - # attributes in the tag (like "href" shown here) are - # also accessible as named results - print(link.link_text, '->', link.href) - - prints:: - - pyparsing -> https://github.com/pyparsing/pyparsing/wiki - """ - return _makeTags(tag_str, False) - - -def make_xml_tags( - tag_str: Union[str, ParserElement] -) -> Tuple[ParserElement, ParserElement]: - """Helper to construct opening and closing tag expressions for XML, - given a tag name. Matches tags only in the given upper/lower case. - - Example: similar to :class:`make_html_tags` - """ - return _makeTags(tag_str, True) - - -any_open_tag: ParserElement -any_close_tag: ParserElement -any_open_tag, any_close_tag = make_html_tags( - Word(alphas, alphanums + "_:").set_name("any tag") -) - -_htmlEntityMap = {k.rstrip(";"): v for k, v in html.entities.html5.items()} -common_html_entity = Regex("&(?P" + "|".join(_htmlEntityMap) + ");").set_name( - "common HTML entity" -) - - -def replace_html_entity(t): - """Helper parser action to replace common HTML entities with their special characters""" - return _htmlEntityMap.get(t.entity) - - -class OpAssoc(Enum): - LEFT = 1 - RIGHT = 2 - - -InfixNotationOperatorArgType = Union[ - ParserElement, str, Tuple[Union[ParserElement, str], Union[ParserElement, str]] -] -InfixNotationOperatorSpec = Union[ - Tuple[ - InfixNotationOperatorArgType, - int, - OpAssoc, - typing.Optional[ParseAction], - ], - Tuple[ - InfixNotationOperatorArgType, - int, - OpAssoc, - ], -] - - -def infix_notation( - base_expr: ParserElement, - op_list: List[InfixNotationOperatorSpec], - lpar: Union[str, ParserElement] = Suppress("("), - rpar: Union[str, ParserElement] = Suppress(")"), -) -> ParserElement: - """Helper method for constructing grammars of expressions made up of - operators working in a precedence hierarchy. Operators may be unary - or binary, left- or right-associative. Parse actions can also be - attached to operator expressions. The generated parser will also - recognize the use of parentheses to override operator precedences - (see example below). - - Note: if you define a deep operator list, you may see performance - issues when using infix_notation. See - :class:`ParserElement.enable_packrat` for a mechanism to potentially - improve your parser performance. - - Parameters: - - ``base_expr`` - expression representing the most basic operand to - be used in the expression - - ``op_list`` - list of tuples, one for each operator precedence level - in the expression grammar; each tuple is of the form ``(op_expr, - num_operands, right_left_assoc, (optional)parse_action)``, where: - - - ``op_expr`` is the pyparsing expression for the operator; may also - be a string, which will be converted to a Literal; if ``num_operands`` - is 3, ``op_expr`` is a tuple of two expressions, for the two - operators separating the 3 terms - - ``num_operands`` is the number of terms for this operator (must be 1, - 2, or 3) - - ``right_left_assoc`` is the indicator whether the operator is right - or left associative, using the pyparsing-defined constants - ``OpAssoc.RIGHT`` and ``OpAssoc.LEFT``. - - ``parse_action`` is the parse action to be associated with - expressions matching this operator expression (the parse action - tuple member may be omitted); if the parse action is passed - a tuple or list of functions, this is equivalent to calling - ``set_parse_action(*fn)`` - (:class:`ParserElement.set_parse_action`) - - ``lpar`` - expression for matching left-parentheses; if passed as a - str, then will be parsed as Suppress(lpar). If lpar is passed as - an expression (such as ``Literal('(')``), then it will be kept in - the parsed results, and grouped with them. (default= ``Suppress('(')``) - - ``rpar`` - expression for matching right-parentheses; if passed as a - str, then will be parsed as Suppress(rpar). If rpar is passed as - an expression (such as ``Literal(')')``), then it will be kept in - the parsed results, and grouped with them. (default= ``Suppress(')')``) - - Example:: - - # simple example of four-function arithmetic with ints and - # variable names - integer = pyparsing_common.signed_integer - varname = pyparsing_common.identifier - - arith_expr = infix_notation(integer | varname, - [ - ('-', 1, OpAssoc.RIGHT), - (one_of('* /'), 2, OpAssoc.LEFT), - (one_of('+ -'), 2, OpAssoc.LEFT), - ]) - - arith_expr.run_tests(''' - 5+3*6 - (5+3)*6 - -2--11 - ''', full_dump=False) - - prints:: - - 5+3*6 - [[5, '+', [3, '*', 6]]] - - (5+3)*6 - [[[5, '+', 3], '*', 6]] - - -2--11 - [[['-', 2], '-', ['-', 11]]] - """ - # captive version of FollowedBy that does not do parse actions or capture results names - class _FB(FollowedBy): - def parseImpl(self, instring, loc, doActions=True): - self.expr.try_parse(instring, loc) - return loc, [] - - _FB.__name__ = "FollowedBy>" - - ret = Forward() - if isinstance(lpar, str): - lpar = Suppress(lpar) - if isinstance(rpar, str): - rpar = Suppress(rpar) - - # if lpar and rpar are not suppressed, wrap in group - if not (isinstance(rpar, Suppress) and isinstance(rpar, Suppress)): - lastExpr = base_expr | Group(lpar + ret + rpar) - else: - lastExpr = base_expr | (lpar + ret + rpar) - - for i, operDef in enumerate(op_list): - opExpr, arity, rightLeftAssoc, pa = (operDef + (None,))[:4] - if isinstance(opExpr, str_type): - opExpr = ParserElement._literalStringClass(opExpr) - if arity == 3: - if not isinstance(opExpr, (tuple, list)) or len(opExpr) != 2: - raise ValueError( - "if numterms=3, opExpr must be a tuple or list of two expressions" - ) - opExpr1, opExpr2 = opExpr - term_name = "{}{} term".format(opExpr1, opExpr2) - else: - term_name = "{} term".format(opExpr) - - if not 1 <= arity <= 3: - raise ValueError("operator must be unary (1), binary (2), or ternary (3)") - - if rightLeftAssoc not in (OpAssoc.LEFT, OpAssoc.RIGHT): - raise ValueError("operator must indicate right or left associativity") - - thisExpr: Forward = Forward().set_name(term_name) - if rightLeftAssoc is OpAssoc.LEFT: - if arity == 1: - matchExpr = _FB(lastExpr + opExpr) + Group(lastExpr + opExpr[1, ...]) - elif arity == 2: - if opExpr is not None: - matchExpr = _FB(lastExpr + opExpr + lastExpr) + Group( - lastExpr + (opExpr + lastExpr)[1, ...] - ) - else: - matchExpr = _FB(lastExpr + lastExpr) + Group(lastExpr[2, ...]) - elif arity == 3: - matchExpr = _FB( - lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr - ) + Group(lastExpr + OneOrMore(opExpr1 + lastExpr + opExpr2 + lastExpr)) - elif rightLeftAssoc is OpAssoc.RIGHT: - if arity == 1: - # try to avoid LR with this extra test - if not isinstance(opExpr, Opt): - opExpr = Opt(opExpr) - matchExpr = _FB(opExpr.expr + thisExpr) + Group(opExpr + thisExpr) - elif arity == 2: - if opExpr is not None: - matchExpr = _FB(lastExpr + opExpr + thisExpr) + Group( - lastExpr + (opExpr + thisExpr)[1, ...] - ) - else: - matchExpr = _FB(lastExpr + thisExpr) + Group( - lastExpr + thisExpr[1, ...] - ) - elif arity == 3: - matchExpr = _FB( - lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr - ) + Group(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) - if pa: - if isinstance(pa, (tuple, list)): - matchExpr.set_parse_action(*pa) - else: - matchExpr.set_parse_action(pa) - thisExpr <<= (matchExpr | lastExpr).setName(term_name) - lastExpr = thisExpr - ret <<= lastExpr - return ret - - -def indentedBlock(blockStatementExpr, indentStack, indent=True, backup_stacks=[]): - """ - (DEPRECATED - use IndentedBlock class instead) - Helper method for defining space-delimited indentation blocks, - such as those used to define block statements in Python source code. - - Parameters: - - - ``blockStatementExpr`` - expression defining syntax of statement that - is repeated within the indented block - - ``indentStack`` - list created by caller to manage indentation stack - (multiple ``statementWithIndentedBlock`` expressions within a single - grammar should share a common ``indentStack``) - - ``indent`` - boolean indicating whether block must be indented beyond - the current level; set to ``False`` for block of left-most statements - (default= ``True``) - - A valid block must contain at least one ``blockStatement``. - - (Note that indentedBlock uses internal parse actions which make it - incompatible with packrat parsing.) - - Example:: - - data = ''' - def A(z): - A1 - B = 100 - G = A2 - A2 - A3 - B - def BB(a,b,c): - BB1 - def BBA(): - bba1 - bba2 - bba3 - C - D - def spam(x,y): - def eggs(z): - pass - ''' - - - indentStack = [1] - stmt = Forward() - - identifier = Word(alphas, alphanums) - funcDecl = ("def" + identifier + Group("(" + Opt(delimitedList(identifier)) + ")") + ":") - func_body = indentedBlock(stmt, indentStack) - funcDef = Group(funcDecl + func_body) - - rvalue = Forward() - funcCall = Group(identifier + "(" + Opt(delimitedList(rvalue)) + ")") - rvalue << (funcCall | identifier | Word(nums)) - assignment = Group(identifier + "=" + rvalue) - stmt << (funcDef | assignment | identifier) - - module_body = stmt[1, ...] - - parseTree = module_body.parseString(data) - parseTree.pprint() - - prints:: - - [['def', - 'A', - ['(', 'z', ')'], - ':', - [['A1'], [['B', '=', '100']], [['G', '=', 'A2']], ['A2'], ['A3']]], - 'B', - ['def', - 'BB', - ['(', 'a', 'b', 'c', ')'], - ':', - [['BB1'], [['def', 'BBA', ['(', ')'], ':', [['bba1'], ['bba2'], ['bba3']]]]]], - 'C', - 'D', - ['def', - 'spam', - ['(', 'x', 'y', ')'], - ':', - [[['def', 'eggs', ['(', 'z', ')'], ':', [['pass']]]]]]] - """ - backup_stacks.append(indentStack[:]) - - def reset_stack(): - indentStack[:] = backup_stacks[-1] - - def checkPeerIndent(s, l, t): - if l >= len(s): - return - curCol = col(l, s) - if curCol != indentStack[-1]: - if curCol > indentStack[-1]: - raise ParseException(s, l, "illegal nesting") - raise ParseException(s, l, "not a peer entry") - - def checkSubIndent(s, l, t): - curCol = col(l, s) - if curCol > indentStack[-1]: - indentStack.append(curCol) - else: - raise ParseException(s, l, "not a subentry") - - def checkUnindent(s, l, t): - if l >= len(s): - return - curCol = col(l, s) - if not (indentStack and curCol in indentStack): - raise ParseException(s, l, "not an unindent") - if curCol < indentStack[-1]: - indentStack.pop() - - NL = OneOrMore(LineEnd().set_whitespace_chars("\t ").suppress()) - INDENT = (Empty() + Empty().set_parse_action(checkSubIndent)).set_name("INDENT") - PEER = Empty().set_parse_action(checkPeerIndent).set_name("") - UNDENT = Empty().set_parse_action(checkUnindent).set_name("UNINDENT") - if indent: - smExpr = Group( - Opt(NL) - + INDENT - + OneOrMore(PEER + Group(blockStatementExpr) + Opt(NL)) - + UNDENT - ) - else: - smExpr = Group( - Opt(NL) - + OneOrMore(PEER + Group(blockStatementExpr) + Opt(NL)) - + Opt(UNDENT) - ) - - # add a parse action to remove backup_stack from list of backups - smExpr.add_parse_action( - lambda: backup_stacks.pop(-1) and None if backup_stacks else None - ) - smExpr.set_fail_action(lambda a, b, c, d: reset_stack()) - blockStatementExpr.ignore(_bslash + LineEnd()) - return smExpr.set_name("indented block") - - -# it's easy to get these comment structures wrong - they're very common, so may as well make them available -c_style_comment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + "*/").set_name( - "C style comment" -) -"Comment of the form ``/* ... */``" - -html_comment = Regex(r"").set_name("HTML comment") -"Comment of the form ````" - -rest_of_line = Regex(r".*").leave_whitespace().set_name("rest of line") -dbl_slash_comment = Regex(r"//(?:\\\n|[^\n])*").set_name("// comment") -"Comment of the form ``// ... (to end of line)``" - -cpp_style_comment = Combine( - Regex(r"/\*(?:[^*]|\*(?!/))*") + "*/" | dbl_slash_comment -).set_name("C++ style comment") -"Comment of either form :class:`c_style_comment` or :class:`dbl_slash_comment`" - -java_style_comment = cpp_style_comment -"Same as :class:`cpp_style_comment`" - -python_style_comment = Regex(r"#.*").set_name("Python style comment") -"Comment of the form ``# ... (to end of line)``" - - -# build list of built-in expressions, for future reference if a global default value -# gets updated -_builtin_exprs: List[ParserElement] = [ - v for v in vars().values() if isinstance(v, ParserElement) -] - - -# pre-PEP8 compatible names -delimitedList = delimited_list -countedArray = counted_array -matchPreviousLiteral = match_previous_literal -matchPreviousExpr = match_previous_expr -oneOf = one_of -dictOf = dict_of -originalTextFor = original_text_for -nestedExpr = nested_expr -makeHTMLTags = make_html_tags -makeXMLTags = make_xml_tags -anyOpenTag, anyCloseTag = any_open_tag, any_close_tag -commonHTMLEntity = common_html_entity -replaceHTMLEntity = replace_html_entity -opAssoc = OpAssoc -infixNotation = infix_notation -cStyleComment = c_style_comment -htmlComment = html_comment -restOfLine = rest_of_line -dblSlashComment = dbl_slash_comment -cppStyleComment = cpp_style_comment -javaStyleComment = java_style_comment -pythonStyleComment = python_style_comment diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/results.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/results.py deleted file mode 100755 index 00c9421..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/results.py +++ /dev/null @@ -1,760 +0,0 @@ -# results.py -from collections.abc import MutableMapping, Mapping, MutableSequence, Iterator -import pprint -from weakref import ref as wkref -from typing import Tuple, Any - -str_type: Tuple[type, ...] = (str, bytes) -_generator_type = type((_ for _ in ())) - - -class _ParseResultsWithOffset: - __slots__ = ["tup"] - - def __init__(self, p1, p2): - self.tup = (p1, p2) - - def __getitem__(self, i): - return self.tup[i] - - def __getstate__(self): - return self.tup - - def __setstate__(self, *args): - self.tup = args[0] - - -class ParseResults: - """Structured parse results, to provide multiple means of access to - the parsed data: - - - as a list (``len(results)``) - - by list index (``results[0], results[1]``, etc.) - - by attribute (``results.`` - see :class:`ParserElement.set_results_name`) - - Example:: - - integer = Word(nums) - date_str = (integer.set_results_name("year") + '/' - + integer.set_results_name("month") + '/' - + integer.set_results_name("day")) - # equivalent form: - # date_str = (integer("year") + '/' - # + integer("month") + '/' - # + integer("day")) - - # parse_string returns a ParseResults object - result = date_str.parse_string("1999/12/31") - - def test(s, fn=repr): - print("{} -> {}".format(s, fn(eval(s)))) - test("list(result)") - test("result[0]") - test("result['month']") - test("result.day") - test("'month' in result") - test("'minutes' in result") - test("result.dump()", str) - - prints:: - - list(result) -> ['1999', '/', '12', '/', '31'] - result[0] -> '1999' - result['month'] -> '12' - result.day -> '31' - 'month' in result -> True - 'minutes' in result -> False - result.dump() -> ['1999', '/', '12', '/', '31'] - - day: '31' - - month: '12' - - year: '1999' - """ - - _null_values: Tuple[Any, ...] = (None, [], "", ()) - - __slots__ = [ - "_name", - "_parent", - "_all_names", - "_modal", - "_toklist", - "_tokdict", - "__weakref__", - ] - - class List(list): - """ - Simple wrapper class to distinguish parsed list results that should be preserved - as actual Python lists, instead of being converted to :class:`ParseResults`: - - LBRACK, RBRACK = map(pp.Suppress, "[]") - element = pp.Forward() - item = ppc.integer - element_list = LBRACK + pp.delimited_list(element) + RBRACK - - # add parse actions to convert from ParseResults to actual Python collection types - def as_python_list(t): - return pp.ParseResults.List(t.as_list()) - element_list.add_parse_action(as_python_list) - - element <<= item | element_list - - element.run_tests(''' - 100 - [2,3,4] - [[2, 1],3,4] - [(2, 1),3,4] - (2,3,4) - ''', post_parse=lambda s, r: (r[0], type(r[0]))) - - prints: - - 100 - (100, ) - - [2,3,4] - ([2, 3, 4], ) - - [[2, 1],3,4] - ([[2, 1], 3, 4], ) - - (Used internally by :class:`Group` when `aslist=True`.) - """ - - def __new__(cls, contained=None): - if contained is None: - contained = [] - - if not isinstance(contained, list): - raise TypeError( - "{} may only be constructed with a list," - " not {}".format(cls.__name__, type(contained).__name__) - ) - - return list.__new__(cls) - - def __new__(cls, toklist=None, name=None, **kwargs): - if isinstance(toklist, ParseResults): - return toklist - self = object.__new__(cls) - self._name = None - self._parent = None - self._all_names = set() - - if toklist is None: - self._toklist = [] - elif isinstance(toklist, (list, _generator_type)): - self._toklist = ( - [toklist[:]] - if isinstance(toklist, ParseResults.List) - else list(toklist) - ) - else: - self._toklist = [toklist] - self._tokdict = dict() - return self - - # Performance tuning: we construct a *lot* of these, so keep this - # constructor as small and fast as possible - def __init__( - self, toklist=None, name=None, asList=True, modal=True, isinstance=isinstance - ): - self._modal = modal - if name is not None and name != "": - if isinstance(name, int): - name = str(name) - if not modal: - self._all_names = {name} - self._name = name - if toklist not in self._null_values: - if isinstance(toklist, (str_type, type)): - toklist = [toklist] - if asList: - if isinstance(toklist, ParseResults): - self[name] = _ParseResultsWithOffset( - ParseResults(toklist._toklist), 0 - ) - else: - self[name] = _ParseResultsWithOffset( - ParseResults(toklist[0]), 0 - ) - self[name]._name = name - else: - try: - self[name] = toklist[0] - except (KeyError, TypeError, IndexError): - if toklist is not self: - self[name] = toklist - else: - self._name = name - - def __getitem__(self, i): - if isinstance(i, (int, slice)): - return self._toklist[i] - else: - if i not in self._all_names: - return self._tokdict[i][-1][0] - else: - return ParseResults([v[0] for v in self._tokdict[i]]) - - def __setitem__(self, k, v, isinstance=isinstance): - if isinstance(v, _ParseResultsWithOffset): - self._tokdict[k] = self._tokdict.get(k, list()) + [v] - sub = v[0] - elif isinstance(k, (int, slice)): - self._toklist[k] = v - sub = v - else: - self._tokdict[k] = self._tokdict.get(k, list()) + [ - _ParseResultsWithOffset(v, 0) - ] - sub = v - if isinstance(sub, ParseResults): - sub._parent = wkref(self) - - def __delitem__(self, i): - if isinstance(i, (int, slice)): - mylen = len(self._toklist) - del self._toklist[i] - - # convert int to slice - if isinstance(i, int): - if i < 0: - i += mylen - i = slice(i, i + 1) - # get removed indices - removed = list(range(*i.indices(mylen))) - removed.reverse() - # fixup indices in token dictionary - for name, occurrences in self._tokdict.items(): - for j in removed: - for k, (value, position) in enumerate(occurrences): - occurrences[k] = _ParseResultsWithOffset( - value, position - (position > j) - ) - else: - del self._tokdict[i] - - def __contains__(self, k) -> bool: - return k in self._tokdict - - def __len__(self) -> int: - return len(self._toklist) - - def __bool__(self) -> bool: - return not not (self._toklist or self._tokdict) - - def __iter__(self) -> Iterator: - return iter(self._toklist) - - def __reversed__(self) -> Iterator: - return iter(self._toklist[::-1]) - - def keys(self): - return iter(self._tokdict) - - def values(self): - return (self[k] for k in self.keys()) - - def items(self): - return ((k, self[k]) for k in self.keys()) - - def haskeys(self) -> bool: - """ - Since ``keys()`` returns an iterator, this method is helpful in bypassing - code that looks for the existence of any defined results names.""" - return bool(self._tokdict) - - def pop(self, *args, **kwargs): - """ - Removes and returns item at specified index (default= ``last``). - Supports both ``list`` and ``dict`` semantics for ``pop()``. If - passed no argument or an integer argument, it will use ``list`` - semantics and pop tokens from the list of parsed tokens. If passed - a non-integer argument (most likely a string), it will use ``dict`` - semantics and pop the corresponding value from any defined results - names. A second default return value argument is supported, just as in - ``dict.pop()``. - - Example:: - - numlist = Word(nums)[...] - print(numlist.parse_string("0 123 321")) # -> ['0', '123', '321'] - - def remove_first(tokens): - tokens.pop(0) - numlist.add_parse_action(remove_first) - print(numlist.parse_string("0 123 321")) # -> ['123', '321'] - - label = Word(alphas) - patt = label("LABEL") + Word(nums)[1, ...] - print(patt.parse_string("AAB 123 321").dump()) - - # Use pop() in a parse action to remove named result (note that corresponding value is not - # removed from list form of results) - def remove_LABEL(tokens): - tokens.pop("LABEL") - return tokens - patt.add_parse_action(remove_LABEL) - print(patt.parse_string("AAB 123 321").dump()) - - prints:: - - ['AAB', '123', '321'] - - LABEL: 'AAB' - - ['AAB', '123', '321'] - """ - if not args: - args = [-1] - for k, v in kwargs.items(): - if k == "default": - args = (args[0], v) - else: - raise TypeError( - "pop() got an unexpected keyword argument {!r}".format(k) - ) - if isinstance(args[0], int) or len(args) == 1 or args[0] in self: - index = args[0] - ret = self[index] - del self[index] - return ret - else: - defaultvalue = args[1] - return defaultvalue - - def get(self, key, default_value=None): - """ - Returns named result matching the given key, or if there is no - such name, then returns the given ``default_value`` or ``None`` if no - ``default_value`` is specified. - - Similar to ``dict.get()``. - - Example:: - - integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - result = date_str.parse_string("1999/12/31") - print(result.get("year")) # -> '1999' - print(result.get("hour", "not specified")) # -> 'not specified' - print(result.get("hour")) # -> None - """ - if key in self: - return self[key] - else: - return default_value - - def insert(self, index, ins_string): - """ - Inserts new element at location index in the list of parsed tokens. - - Similar to ``list.insert()``. - - Example:: - - numlist = Word(nums)[...] - print(numlist.parse_string("0 123 321")) # -> ['0', '123', '321'] - - # use a parse action to insert the parse location in the front of the parsed results - def insert_locn(locn, tokens): - tokens.insert(0, locn) - numlist.add_parse_action(insert_locn) - print(numlist.parse_string("0 123 321")) # -> [0, '0', '123', '321'] - """ - self._toklist.insert(index, ins_string) - # fixup indices in token dictionary - for name, occurrences in self._tokdict.items(): - for k, (value, position) in enumerate(occurrences): - occurrences[k] = _ParseResultsWithOffset( - value, position + (position > index) - ) - - def append(self, item): - """ - Add single element to end of ``ParseResults`` list of elements. - - Example:: - - numlist = Word(nums)[...] - print(numlist.parse_string("0 123 321")) # -> ['0', '123', '321'] - - # use a parse action to compute the sum of the parsed integers, and add it to the end - def append_sum(tokens): - tokens.append(sum(map(int, tokens))) - numlist.add_parse_action(append_sum) - print(numlist.parse_string("0 123 321")) # -> ['0', '123', '321', 444] - """ - self._toklist.append(item) - - def extend(self, itemseq): - """ - Add sequence of elements to end of ``ParseResults`` list of elements. - - Example:: - - patt = Word(alphas)[1, ...] - - # use a parse action to append the reverse of the matched strings, to make a palindrome - def make_palindrome(tokens): - tokens.extend(reversed([t[::-1] for t in tokens])) - return ''.join(tokens) - patt.add_parse_action(make_palindrome) - print(patt.parse_string("lskdj sdlkjf lksd")) # -> 'lskdjsdlkjflksddsklfjkldsjdksl' - """ - if isinstance(itemseq, ParseResults): - self.__iadd__(itemseq) - else: - self._toklist.extend(itemseq) - - def clear(self): - """ - Clear all elements and results names. - """ - del self._toklist[:] - self._tokdict.clear() - - def __getattr__(self, name): - try: - return self[name] - except KeyError: - if name.startswith("__"): - raise AttributeError(name) - return "" - - def __add__(self, other) -> "ParseResults": - ret = self.copy() - ret += other - return ret - - def __iadd__(self, other) -> "ParseResults": - if other._tokdict: - offset = len(self._toklist) - addoffset = lambda a: offset if a < 0 else a + offset - otheritems = other._tokdict.items() - otherdictitems = [ - (k, _ParseResultsWithOffset(v[0], addoffset(v[1]))) - for k, vlist in otheritems - for v in vlist - ] - for k, v in otherdictitems: - self[k] = v - if isinstance(v[0], ParseResults): - v[0]._parent = wkref(self) - - self._toklist += other._toklist - self._all_names |= other._all_names - return self - - def __radd__(self, other) -> "ParseResults": - if isinstance(other, int) and other == 0: - # useful for merging many ParseResults using sum() builtin - return self.copy() - else: - # this may raise a TypeError - so be it - return other + self - - def __repr__(self) -> str: - return "{}({!r}, {})".format(type(self).__name__, self._toklist, self.as_dict()) - - def __str__(self) -> str: - return ( - "[" - + ", ".join( - [ - str(i) if isinstance(i, ParseResults) else repr(i) - for i in self._toklist - ] - ) - + "]" - ) - - def _asStringList(self, sep=""): - out = [] - for item in self._toklist: - if out and sep: - out.append(sep) - if isinstance(item, ParseResults): - out += item._asStringList() - else: - out.append(str(item)) - return out - - def as_list(self) -> list: - """ - Returns the parse results as a nested list of matching tokens, all converted to strings. - - Example:: - - patt = Word(alphas)[1, ...] - result = patt.parse_string("sldkj lsdkj sldkj") - # even though the result prints in string-like form, it is actually a pyparsing ParseResults - print(type(result), result) # -> ['sldkj', 'lsdkj', 'sldkj'] - - # Use as_list() to create an actual list - result_list = result.as_list() - print(type(result_list), result_list) # -> ['sldkj', 'lsdkj', 'sldkj'] - """ - return [ - res.as_list() if isinstance(res, ParseResults) else res - for res in self._toklist - ] - - def as_dict(self) -> dict: - """ - Returns the named parse results as a nested dictionary. - - Example:: - - integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - result = date_str.parse_string('12/31/1999') - print(type(result), repr(result)) # -> (['12', '/', '31', '/', '1999'], {'day': [('1999', 4)], 'year': [('12', 0)], 'month': [('31', 2)]}) - - result_dict = result.as_dict() - print(type(result_dict), repr(result_dict)) # -> {'day': '1999', 'year': '12', 'month': '31'} - - # even though a ParseResults supports dict-like access, sometime you just need to have a dict - import json - print(json.dumps(result)) # -> Exception: TypeError: ... is not JSON serializable - print(json.dumps(result.as_dict())) # -> {"month": "31", "day": "1999", "year": "12"} - """ - - def to_item(obj): - if isinstance(obj, ParseResults): - return obj.as_dict() if obj.haskeys() else [to_item(v) for v in obj] - else: - return obj - - return dict((k, to_item(v)) for k, v in self.items()) - - def copy(self) -> "ParseResults": - """ - Returns a new copy of a :class:`ParseResults` object. - """ - ret = ParseResults(self._toklist) - ret._tokdict = self._tokdict.copy() - ret._parent = self._parent - ret._all_names |= self._all_names - ret._name = self._name - return ret - - def get_name(self): - r""" - Returns the results name for this token expression. Useful when several - different expressions might match at a particular location. - - Example:: - - integer = Word(nums) - ssn_expr = Regex(r"\d\d\d-\d\d-\d\d\d\d") - house_number_expr = Suppress('#') + Word(nums, alphanums) - user_data = (Group(house_number_expr)("house_number") - | Group(ssn_expr)("ssn") - | Group(integer)("age")) - user_info = user_data[1, ...] - - result = user_info.parse_string("22 111-22-3333 #221B") - for item in result: - print(item.get_name(), ':', item[0]) - - prints:: - - age : 22 - ssn : 111-22-3333 - house_number : 221B - """ - if self._name: - return self._name - elif self._parent: - par = self._parent() - - def find_in_parent(sub): - return next( - ( - k - for k, vlist in par._tokdict.items() - for v, loc in vlist - if sub is v - ), - None, - ) - - return find_in_parent(self) if par else None - elif ( - len(self) == 1 - and len(self._tokdict) == 1 - and next(iter(self._tokdict.values()))[0][1] in (0, -1) - ): - return next(iter(self._tokdict.keys())) - else: - return None - - def dump(self, indent="", full=True, include_list=True, _depth=0) -> str: - """ - Diagnostic method for listing out the contents of - a :class:`ParseResults`. Accepts an optional ``indent`` argument so - that this string can be embedded in a nested display of other data. - - Example:: - - integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - result = date_str.parse_string('1999/12/31') - print(result.dump()) - - prints:: - - ['1999', '/', '12', '/', '31'] - - day: '31' - - month: '12' - - year: '1999' - """ - out = [] - NL = "\n" - out.append(indent + str(self.as_list()) if include_list else "") - - if full: - if self.haskeys(): - items = sorted((str(k), v) for k, v in self.items()) - for k, v in items: - if out: - out.append(NL) - out.append("{}{}- {}: ".format(indent, (" " * _depth), k)) - if isinstance(v, ParseResults): - if v: - out.append( - v.dump( - indent=indent, - full=full, - include_list=include_list, - _depth=_depth + 1, - ) - ) - else: - out.append(str(v)) - else: - out.append(repr(v)) - if any(isinstance(vv, ParseResults) for vv in self): - v = self - for i, vv in enumerate(v): - if isinstance(vv, ParseResults): - out.append( - "\n{}{}[{}]:\n{}{}{}".format( - indent, - (" " * (_depth)), - i, - indent, - (" " * (_depth + 1)), - vv.dump( - indent=indent, - full=full, - include_list=include_list, - _depth=_depth + 1, - ), - ) - ) - else: - out.append( - "\n%s%s[%d]:\n%s%s%s" - % ( - indent, - (" " * (_depth)), - i, - indent, - (" " * (_depth + 1)), - str(vv), - ) - ) - - return "".join(out) - - def pprint(self, *args, **kwargs): - """ - Pretty-printer for parsed results as a list, using the - `pprint `_ module. - Accepts additional positional or keyword args as defined for - `pprint.pprint `_ . - - Example:: - - ident = Word(alphas, alphanums) - num = Word(nums) - func = Forward() - term = ident | num | Group('(' + func + ')') - func <<= ident + Group(Optional(delimited_list(term))) - result = func.parse_string("fna a,b,(fnb c,d,200),100") - result.pprint(width=40) - - prints:: - - ['fna', - ['a', - 'b', - ['(', 'fnb', ['c', 'd', '200'], ')'], - '100']] - """ - pprint.pprint(self.as_list(), *args, **kwargs) - - # add support for pickle protocol - def __getstate__(self): - return ( - self._toklist, - ( - self._tokdict.copy(), - self._parent is not None and self._parent() or None, - self._all_names, - self._name, - ), - ) - - def __setstate__(self, state): - self._toklist, (self._tokdict, par, inAccumNames, self._name) = state - self._all_names = set(inAccumNames) - if par is not None: - self._parent = wkref(par) - else: - self._parent = None - - def __getnewargs__(self): - return self._toklist, self._name - - def __dir__(self): - return dir(type(self)) + list(self.keys()) - - @classmethod - def from_dict(cls, other, name=None) -> "ParseResults": - """ - Helper classmethod to construct a ``ParseResults`` from a ``dict``, preserving the - name-value relations as results names. If an optional ``name`` argument is - given, a nested ``ParseResults`` will be returned. - """ - - def is_iterable(obj): - try: - iter(obj) - except Exception: - return False - else: - return not isinstance(obj, str_type) - - ret = cls([]) - for k, v in other.items(): - if isinstance(v, Mapping): - ret += cls.from_dict(v, name=k) - else: - ret += cls([v], name=k, asList=is_iterable(v)) - if name is not None: - ret = cls([ret], name=name) - return ret - - asList = as_list - asDict = as_dict - getName = get_name - - -MutableMapping.register(ParseResults) -MutableSequence.register(ParseResults) diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/testing.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/testing.py deleted file mode 100755 index 84a0ef1..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/testing.py +++ /dev/null @@ -1,331 +0,0 @@ -# testing.py - -from contextlib import contextmanager -import typing - -from .core import ( - ParserElement, - ParseException, - Keyword, - __diag__, - __compat__, -) - - -class pyparsing_test: - """ - namespace class for classes useful in writing unit tests - """ - - class reset_pyparsing_context: - """ - Context manager to be used when writing unit tests that modify pyparsing config values: - - packrat parsing - - bounded recursion parsing - - default whitespace characters. - - default keyword characters - - literal string auto-conversion class - - __diag__ settings - - Example:: - - with reset_pyparsing_context(): - # test that literals used to construct a grammar are automatically suppressed - ParserElement.inlineLiteralsUsing(Suppress) - - term = Word(alphas) | Word(nums) - group = Group('(' + term[...] + ')') - - # assert that the '()' characters are not included in the parsed tokens - self.assertParseAndCheckList(group, "(abc 123 def)", ['abc', '123', 'def']) - - # after exiting context manager, literals are converted to Literal expressions again - """ - - def __init__(self): - self._save_context = {} - - def save(self): - self._save_context["default_whitespace"] = ParserElement.DEFAULT_WHITE_CHARS - self._save_context["default_keyword_chars"] = Keyword.DEFAULT_KEYWORD_CHARS - - self._save_context[ - "literal_string_class" - ] = ParserElement._literalStringClass - - self._save_context["verbose_stacktrace"] = ParserElement.verbose_stacktrace - - self._save_context["packrat_enabled"] = ParserElement._packratEnabled - if ParserElement._packratEnabled: - self._save_context[ - "packrat_cache_size" - ] = ParserElement.packrat_cache.size - else: - self._save_context["packrat_cache_size"] = None - self._save_context["packrat_parse"] = ParserElement._parse - self._save_context[ - "recursion_enabled" - ] = ParserElement._left_recursion_enabled - - self._save_context["__diag__"] = { - name: getattr(__diag__, name) for name in __diag__._all_names - } - - self._save_context["__compat__"] = { - "collect_all_And_tokens": __compat__.collect_all_And_tokens - } - - return self - - def restore(self): - # reset pyparsing global state - if ( - ParserElement.DEFAULT_WHITE_CHARS - != self._save_context["default_whitespace"] - ): - ParserElement.set_default_whitespace_chars( - self._save_context["default_whitespace"] - ) - - ParserElement.verbose_stacktrace = self._save_context["verbose_stacktrace"] - - Keyword.DEFAULT_KEYWORD_CHARS = self._save_context["default_keyword_chars"] - ParserElement.inlineLiteralsUsing( - self._save_context["literal_string_class"] - ) - - for name, value in self._save_context["__diag__"].items(): - (__diag__.enable if value else __diag__.disable)(name) - - ParserElement._packratEnabled = False - if self._save_context["packrat_enabled"]: - ParserElement.enable_packrat(self._save_context["packrat_cache_size"]) - else: - ParserElement._parse = self._save_context["packrat_parse"] - ParserElement._left_recursion_enabled = self._save_context[ - "recursion_enabled" - ] - - __compat__.collect_all_And_tokens = self._save_context["__compat__"] - - return self - - def copy(self): - ret = type(self)() - ret._save_context.update(self._save_context) - return ret - - def __enter__(self): - return self.save() - - def __exit__(self, *args): - self.restore() - - class TestParseResultsAsserts: - """ - A mixin class to add parse results assertion methods to normal unittest.TestCase classes. - """ - - def assertParseResultsEquals( - self, result, expected_list=None, expected_dict=None, msg=None - ): - """ - Unit test assertion to compare a :class:`ParseResults` object with an optional ``expected_list``, - and compare any defined results names with an optional ``expected_dict``. - """ - if expected_list is not None: - self.assertEqual(expected_list, result.as_list(), msg=msg) - if expected_dict is not None: - self.assertEqual(expected_dict, result.as_dict(), msg=msg) - - def assertParseAndCheckList( - self, expr, test_string, expected_list, msg=None, verbose=True - ): - """ - Convenience wrapper assert to test a parser element and input string, and assert that - the resulting ``ParseResults.asList()`` is equal to the ``expected_list``. - """ - result = expr.parse_string(test_string, parse_all=True) - if verbose: - print(result.dump()) - else: - print(result.as_list()) - self.assertParseResultsEquals(result, expected_list=expected_list, msg=msg) - - def assertParseAndCheckDict( - self, expr, test_string, expected_dict, msg=None, verbose=True - ): - """ - Convenience wrapper assert to test a parser element and input string, and assert that - the resulting ``ParseResults.asDict()`` is equal to the ``expected_dict``. - """ - result = expr.parse_string(test_string, parseAll=True) - if verbose: - print(result.dump()) - else: - print(result.as_list()) - self.assertParseResultsEquals(result, expected_dict=expected_dict, msg=msg) - - def assertRunTestResults( - self, run_tests_report, expected_parse_results=None, msg=None - ): - """ - Unit test assertion to evaluate output of ``ParserElement.runTests()``. If a list of - list-dict tuples is given as the ``expected_parse_results`` argument, then these are zipped - with the report tuples returned by ``runTests`` and evaluated using ``assertParseResultsEquals``. - Finally, asserts that the overall ``runTests()`` success value is ``True``. - - :param run_tests_report: tuple(bool, [tuple(str, ParseResults or Exception)]) returned from runTests - :param expected_parse_results (optional): [tuple(str, list, dict, Exception)] - """ - run_test_success, run_test_results = run_tests_report - - if expected_parse_results is not None: - merged = [ - (*rpt, expected) - for rpt, expected in zip(run_test_results, expected_parse_results) - ] - for test_string, result, expected in merged: - # expected should be a tuple containing a list and/or a dict or an exception, - # and optional failure message string - # an empty tuple will skip any result validation - fail_msg = next( - (exp for exp in expected if isinstance(exp, str)), None - ) - expected_exception = next( - ( - exp - for exp in expected - if isinstance(exp, type) and issubclass(exp, Exception) - ), - None, - ) - if expected_exception is not None: - with self.assertRaises( - expected_exception=expected_exception, msg=fail_msg or msg - ): - if isinstance(result, Exception): - raise result - else: - expected_list = next( - (exp for exp in expected if isinstance(exp, list)), None - ) - expected_dict = next( - (exp for exp in expected if isinstance(exp, dict)), None - ) - if (expected_list, expected_dict) != (None, None): - self.assertParseResultsEquals( - result, - expected_list=expected_list, - expected_dict=expected_dict, - msg=fail_msg or msg, - ) - else: - # warning here maybe? - print("no validation for {!r}".format(test_string)) - - # do this last, in case some specific test results can be reported instead - self.assertTrue( - run_test_success, msg=msg if msg is not None else "failed runTests" - ) - - @contextmanager - def assertRaisesParseException(self, exc_type=ParseException, msg=None): - with self.assertRaises(exc_type, msg=msg): - yield - - @staticmethod - def with_line_numbers( - s: str, - start_line: typing.Optional[int] = None, - end_line: typing.Optional[int] = None, - expand_tabs: bool = True, - eol_mark: str = "|", - mark_spaces: typing.Optional[str] = None, - mark_control: typing.Optional[str] = None, - ) -> str: - """ - Helpful method for debugging a parser - prints a string with line and column numbers. - (Line and column numbers are 1-based.) - - :param s: tuple(bool, str - string to be printed with line and column numbers - :param start_line: int - (optional) starting line number in s to print (default=1) - :param end_line: int - (optional) ending line number in s to print (default=len(s)) - :param expand_tabs: bool - (optional) expand tabs to spaces, to match the pyparsing default - :param eol_mark: str - (optional) string to mark the end of lines, helps visualize trailing spaces (default="|") - :param mark_spaces: str - (optional) special character to display in place of spaces - :param mark_control: str - (optional) convert non-printing control characters to a placeholding - character; valid values: - - "unicode" - replaces control chars with Unicode symbols, such as "␍" and "␊" - - any single character string - replace control characters with given string - - None (default) - string is displayed as-is - - :return: str - input string with leading line numbers and column number headers - """ - if expand_tabs: - s = s.expandtabs() - if mark_control is not None: - if mark_control == "unicode": - tbl = str.maketrans( - {c: u for c, u in zip(range(0, 33), range(0x2400, 0x2433))} - | {127: 0x2421} - ) - eol_mark = "" - else: - tbl = str.maketrans( - {c: mark_control for c in list(range(0, 32)) + [127]} - ) - s = s.translate(tbl) - if mark_spaces is not None and mark_spaces != " ": - if mark_spaces == "unicode": - tbl = str.maketrans({9: 0x2409, 32: 0x2423}) - s = s.translate(tbl) - else: - s = s.replace(" ", mark_spaces) - if start_line is None: - start_line = 1 - if end_line is None: - end_line = len(s) - end_line = min(end_line, len(s)) - start_line = min(max(1, start_line), end_line) - - if mark_control != "unicode": - s_lines = s.splitlines()[start_line - 1 : end_line] - else: - s_lines = [line + "␊" for line in s.split("␊")[start_line - 1 : end_line]] - if not s_lines: - return "" - - lineno_width = len(str(end_line)) - max_line_len = max(len(line) for line in s_lines) - lead = " " * (lineno_width + 1) - if max_line_len >= 99: - header0 = ( - lead - + "".join( - "{}{}".format(" " * 99, (i + 1) % 100) - for i in range(max(max_line_len // 100, 1)) - ) - + "\n" - ) - else: - header0 = "" - header1 = ( - header0 - + lead - + "".join( - " {}".format((i + 1) % 10) - for i in range(-(-max_line_len // 10)) - ) - + "\n" - ) - header2 = lead + "1234567890" * (-(-max_line_len // 10)) + "\n" - return ( - header1 - + header2 - + "\n".join( - "{:{}d}:{}{}".format(i, lineno_width, line, eol_mark) - for i, line in enumerate(s_lines, start=start_line) - ) - + "\n" - ) diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/unicode.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/unicode.py deleted file mode 100755 index 0652620..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/unicode.py +++ /dev/null @@ -1,352 +0,0 @@ -# unicode.py - -import sys -from itertools import filterfalse -from typing import List, Tuple, Union - - -class _lazyclassproperty: - def __init__(self, fn): - self.fn = fn - self.__doc__ = fn.__doc__ - self.__name__ = fn.__name__ - - def __get__(self, obj, cls): - if cls is None: - cls = type(obj) - if not hasattr(cls, "_intern") or any( - cls._intern is getattr(superclass, "_intern", []) - for superclass in cls.__mro__[1:] - ): - cls._intern = {} - attrname = self.fn.__name__ - if attrname not in cls._intern: - cls._intern[attrname] = self.fn(cls) - return cls._intern[attrname] - - -UnicodeRangeList = List[Union[Tuple[int, int], Tuple[int]]] - - -class unicode_set: - """ - A set of Unicode characters, for language-specific strings for - ``alphas``, ``nums``, ``alphanums``, and ``printables``. - A unicode_set is defined by a list of ranges in the Unicode character - set, in a class attribute ``_ranges``. Ranges can be specified using - 2-tuples or a 1-tuple, such as:: - - _ranges = [ - (0x0020, 0x007e), - (0x00a0, 0x00ff), - (0x0100,), - ] - - Ranges are left- and right-inclusive. A 1-tuple of (x,) is treated as (x, x). - - A unicode set can also be defined using multiple inheritance of other unicode sets:: - - class CJK(Chinese, Japanese, Korean): - pass - """ - - _ranges: UnicodeRangeList = [] - - @_lazyclassproperty - def _chars_for_ranges(cls): - ret = [] - for cc in cls.__mro__: - if cc is unicode_set: - break - for rr in getattr(cc, "_ranges", ()): - ret.extend(range(rr[0], rr[-1] + 1)) - return [chr(c) for c in sorted(set(ret))] - - @_lazyclassproperty - def printables(cls): - "all non-whitespace characters in this range" - return "".join(filterfalse(str.isspace, cls._chars_for_ranges)) - - @_lazyclassproperty - def alphas(cls): - "all alphabetic characters in this range" - return "".join(filter(str.isalpha, cls._chars_for_ranges)) - - @_lazyclassproperty - def nums(cls): - "all numeric digit characters in this range" - return "".join(filter(str.isdigit, cls._chars_for_ranges)) - - @_lazyclassproperty - def alphanums(cls): - "all alphanumeric characters in this range" - return cls.alphas + cls.nums - - @_lazyclassproperty - def identchars(cls): - "all characters in this range that are valid identifier characters, plus underscore '_'" - return "".join( - sorted( - set( - "".join(filter(str.isidentifier, cls._chars_for_ranges)) - + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzªµº" - + "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ" - + "_" - ) - ) - ) - - @_lazyclassproperty - def identbodychars(cls): - """ - all characters in this range that are valid identifier body characters, - plus the digits 0-9 - """ - return "".join( - sorted( - set( - cls.identchars - + "0123456789" - + "".join( - [c for c in cls._chars_for_ranges if ("_" + c).isidentifier()] - ) - ) - ) - ) - - -class pyparsing_unicode(unicode_set): - """ - A namespace class for defining common language unicode_sets. - """ - - # fmt: off - - # define ranges in language character sets - _ranges: UnicodeRangeList = [ - (0x0020, sys.maxunicode), - ] - - class BasicMultilingualPlane(unicode_set): - "Unicode set for the Basic Multilingual Plane" - _ranges: UnicodeRangeList = [ - (0x0020, 0xFFFF), - ] - - class Latin1(unicode_set): - "Unicode set for Latin-1 Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x0020, 0x007E), - (0x00A0, 0x00FF), - ] - - class LatinA(unicode_set): - "Unicode set for Latin-A Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x0100, 0x017F), - ] - - class LatinB(unicode_set): - "Unicode set for Latin-B Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x0180, 0x024F), - ] - - class Greek(unicode_set): - "Unicode set for Greek Unicode Character Ranges" - _ranges: UnicodeRangeList = [ - (0x0342, 0x0345), - (0x0370, 0x0377), - (0x037A, 0x037F), - (0x0384, 0x038A), - (0x038C,), - (0x038E, 0x03A1), - (0x03A3, 0x03E1), - (0x03F0, 0x03FF), - (0x1D26, 0x1D2A), - (0x1D5E,), - (0x1D60,), - (0x1D66, 0x1D6A), - (0x1F00, 0x1F15), - (0x1F18, 0x1F1D), - (0x1F20, 0x1F45), - (0x1F48, 0x1F4D), - (0x1F50, 0x1F57), - (0x1F59,), - (0x1F5B,), - (0x1F5D,), - (0x1F5F, 0x1F7D), - (0x1F80, 0x1FB4), - (0x1FB6, 0x1FC4), - (0x1FC6, 0x1FD3), - (0x1FD6, 0x1FDB), - (0x1FDD, 0x1FEF), - (0x1FF2, 0x1FF4), - (0x1FF6, 0x1FFE), - (0x2129,), - (0x2719, 0x271A), - (0xAB65,), - (0x10140, 0x1018D), - (0x101A0,), - (0x1D200, 0x1D245), - (0x1F7A1, 0x1F7A7), - ] - - class Cyrillic(unicode_set): - "Unicode set for Cyrillic Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x0400, 0x052F), - (0x1C80, 0x1C88), - (0x1D2B,), - (0x1D78,), - (0x2DE0, 0x2DFF), - (0xA640, 0xA672), - (0xA674, 0xA69F), - (0xFE2E, 0xFE2F), - ] - - class Chinese(unicode_set): - "Unicode set for Chinese Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x2E80, 0x2E99), - (0x2E9B, 0x2EF3), - (0x31C0, 0x31E3), - (0x3400, 0x4DB5), - (0x4E00, 0x9FEF), - (0xA700, 0xA707), - (0xF900, 0xFA6D), - (0xFA70, 0xFAD9), - (0x16FE2, 0x16FE3), - (0x1F210, 0x1F212), - (0x1F214, 0x1F23B), - (0x1F240, 0x1F248), - (0x20000, 0x2A6D6), - (0x2A700, 0x2B734), - (0x2B740, 0x2B81D), - (0x2B820, 0x2CEA1), - (0x2CEB0, 0x2EBE0), - (0x2F800, 0x2FA1D), - ] - - class Japanese(unicode_set): - "Unicode set for Japanese Unicode Character Range, combining Kanji, Hiragana, and Katakana ranges" - _ranges: UnicodeRangeList = [] - - class Kanji(unicode_set): - "Unicode set for Kanji Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x4E00, 0x9FBF), - (0x3000, 0x303F), - ] - - class Hiragana(unicode_set): - "Unicode set for Hiragana Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x3041, 0x3096), - (0x3099, 0x30A0), - (0x30FC,), - (0xFF70,), - (0x1B001,), - (0x1B150, 0x1B152), - (0x1F200,), - ] - - class Katakana(unicode_set): - "Unicode set for Katakana Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x3099, 0x309C), - (0x30A0, 0x30FF), - (0x31F0, 0x31FF), - (0x32D0, 0x32FE), - (0xFF65, 0xFF9F), - (0x1B000,), - (0x1B164, 0x1B167), - (0x1F201, 0x1F202), - (0x1F213,), - ] - - class Hangul(unicode_set): - "Unicode set for Hangul (Korean) Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x1100, 0x11FF), - (0x302E, 0x302F), - (0x3131, 0x318E), - (0x3200, 0x321C), - (0x3260, 0x327B), - (0x327E,), - (0xA960, 0xA97C), - (0xAC00, 0xD7A3), - (0xD7B0, 0xD7C6), - (0xD7CB, 0xD7FB), - (0xFFA0, 0xFFBE), - (0xFFC2, 0xFFC7), - (0xFFCA, 0xFFCF), - (0xFFD2, 0xFFD7), - (0xFFDA, 0xFFDC), - ] - - Korean = Hangul - - class CJK(Chinese, Japanese, Hangul): - "Unicode set for combined Chinese, Japanese, and Korean (CJK) Unicode Character Range" - - class Thai(unicode_set): - "Unicode set for Thai Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x0E01, 0x0E3A), - (0x0E3F, 0x0E5B) - ] - - class Arabic(unicode_set): - "Unicode set for Arabic Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x0600, 0x061B), - (0x061E, 0x06FF), - (0x0700, 0x077F), - ] - - class Hebrew(unicode_set): - "Unicode set for Hebrew Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x0591, 0x05C7), - (0x05D0, 0x05EA), - (0x05EF, 0x05F4), - (0xFB1D, 0xFB36), - (0xFB38, 0xFB3C), - (0xFB3E,), - (0xFB40, 0xFB41), - (0xFB43, 0xFB44), - (0xFB46, 0xFB4F), - ] - - class Devanagari(unicode_set): - "Unicode set for Devanagari Unicode Character Range" - _ranges: UnicodeRangeList = [ - (0x0900, 0x097F), - (0xA8E0, 0xA8FF) - ] - - # fmt: on - - -pyparsing_unicode.Japanese._ranges = ( - pyparsing_unicode.Japanese.Kanji._ranges - + pyparsing_unicode.Japanese.Hiragana._ranges - + pyparsing_unicode.Japanese.Katakana._ranges -) - -pyparsing_unicode.BMP = pyparsing_unicode.BasicMultilingualPlane - -# add language identifiers using language Unicode -pyparsing_unicode.العربية = pyparsing_unicode.Arabic -pyparsing_unicode.中文 = pyparsing_unicode.Chinese -pyparsing_unicode.кириллица = pyparsing_unicode.Cyrillic -pyparsing_unicode.Ελληνικά = pyparsing_unicode.Greek -pyparsing_unicode.עִברִית = pyparsing_unicode.Hebrew -pyparsing_unicode.日本語 = pyparsing_unicode.Japanese -pyparsing_unicode.Japanese.漢字 = pyparsing_unicode.Japanese.Kanji -pyparsing_unicode.Japanese.カタカナ = pyparsing_unicode.Japanese.Katakana -pyparsing_unicode.Japanese.ひらがな = pyparsing_unicode.Japanese.Hiragana -pyparsing_unicode.한국어 = pyparsing_unicode.Korean -pyparsing_unicode.ไทย = pyparsing_unicode.Thai -pyparsing_unicode.देवनागरी = pyparsing_unicode.Devanagari diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/util.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/util.py deleted file mode 100755 index 34ce092..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/pyparsing/util.py +++ /dev/null @@ -1,235 +0,0 @@ -# util.py -import warnings -import types -import collections -import itertools -from functools import lru_cache -from typing import List, Union, Iterable - -_bslash = chr(92) - - -class __config_flags: - """Internal class for defining compatibility and debugging flags""" - - _all_names: List[str] = [] - _fixed_names: List[str] = [] - _type_desc = "configuration" - - @classmethod - def _set(cls, dname, value): - if dname in cls._fixed_names: - warnings.warn( - "{}.{} {} is {} and cannot be overridden".format( - cls.__name__, - dname, - cls._type_desc, - str(getattr(cls, dname)).upper(), - ) - ) - return - if dname in cls._all_names: - setattr(cls, dname, value) - else: - raise ValueError("no such {} {!r}".format(cls._type_desc, dname)) - - enable = classmethod(lambda cls, name: cls._set(name, True)) - disable = classmethod(lambda cls, name: cls._set(name, False)) - - -@lru_cache(maxsize=128) -def col(loc: int, strg: str) -> int: - """ - Returns current column within a string, counting newlines as line separators. - The first column is number 1. - - Note: the default parsing behavior is to expand tabs in the input string - before starting the parsing process. See - :class:`ParserElement.parseString` for more - information on parsing strings containing ```` s, and suggested - methods to maintain a consistent view of the parsed string, the parse - location, and line and column positions within the parsed string. - """ - s = strg - return 1 if 0 < loc < len(s) and s[loc - 1] == "\n" else loc - s.rfind("\n", 0, loc) - - -@lru_cache(maxsize=128) -def lineno(loc: int, strg: str) -> int: - """Returns current line number within a string, counting newlines as line separators. - The first line is number 1. - - Note - the default parsing behavior is to expand tabs in the input string - before starting the parsing process. See :class:`ParserElement.parseString` - for more information on parsing strings containing ```` s, and - suggested methods to maintain a consistent view of the parsed string, the - parse location, and line and column positions within the parsed string. - """ - return strg.count("\n", 0, loc) + 1 - - -@lru_cache(maxsize=128) -def line(loc: int, strg: str) -> str: - """ - Returns the line of text containing loc within a string, counting newlines as line separators. - """ - last_cr = strg.rfind("\n", 0, loc) - next_cr = strg.find("\n", loc) - return strg[last_cr + 1 : next_cr] if next_cr >= 0 else strg[last_cr + 1 :] - - -class _UnboundedCache: - def __init__(self): - cache = {} - cache_get = cache.get - self.not_in_cache = not_in_cache = object() - - def get(_, key): - return cache_get(key, not_in_cache) - - def set_(_, key, value): - cache[key] = value - - def clear(_): - cache.clear() - - self.size = None - self.get = types.MethodType(get, self) - self.set = types.MethodType(set_, self) - self.clear = types.MethodType(clear, self) - - -class _FifoCache: - def __init__(self, size): - self.not_in_cache = not_in_cache = object() - cache = collections.OrderedDict() - cache_get = cache.get - - def get(_, key): - return cache_get(key, not_in_cache) - - def set_(_, key, value): - cache[key] = value - while len(cache) > size: - cache.popitem(last=False) - - def clear(_): - cache.clear() - - self.size = size - self.get = types.MethodType(get, self) - self.set = types.MethodType(set_, self) - self.clear = types.MethodType(clear, self) - - -class LRUMemo: - """ - A memoizing mapping that retains `capacity` deleted items - - The memo tracks retained items by their access order; once `capacity` items - are retained, the least recently used item is discarded. - """ - - def __init__(self, capacity): - self._capacity = capacity - self._active = {} - self._memory = collections.OrderedDict() - - def __getitem__(self, key): - try: - return self._active[key] - except KeyError: - self._memory.move_to_end(key) - return self._memory[key] - - def __setitem__(self, key, value): - self._memory.pop(key, None) - self._active[key] = value - - def __delitem__(self, key): - try: - value = self._active.pop(key) - except KeyError: - pass - else: - while len(self._memory) >= self._capacity: - self._memory.popitem(last=False) - self._memory[key] = value - - def clear(self): - self._active.clear() - self._memory.clear() - - -class UnboundedMemo(dict): - """ - A memoizing mapping that retains all deleted items - """ - - def __delitem__(self, key): - pass - - -def _escape_regex_range_chars(s: str) -> str: - # escape these chars: ^-[] - for c in r"\^-[]": - s = s.replace(c, _bslash + c) - s = s.replace("\n", r"\n") - s = s.replace("\t", r"\t") - return str(s) - - -def _collapse_string_to_ranges( - s: Union[str, Iterable[str]], re_escape: bool = True -) -> str: - def is_consecutive(c): - c_int = ord(c) - is_consecutive.prev, prev = c_int, is_consecutive.prev - if c_int - prev > 1: - is_consecutive.value = next(is_consecutive.counter) - return is_consecutive.value - - is_consecutive.prev = 0 - is_consecutive.counter = itertools.count() - is_consecutive.value = -1 - - def escape_re_range_char(c): - return "\\" + c if c in r"\^-][" else c - - def no_escape_re_range_char(c): - return c - - if not re_escape: - escape_re_range_char = no_escape_re_range_char - - ret = [] - s = "".join(sorted(set(s))) - if len(s) > 3: - for _, chars in itertools.groupby(s, key=is_consecutive): - first = last = next(chars) - last = collections.deque( - itertools.chain(iter([last]), chars), maxlen=1 - ).pop() - if first == last: - ret.append(escape_re_range_char(first)) - else: - sep = "" if ord(last) == ord(first) + 1 else "-" - ret.append( - "{}{}{}".format( - escape_re_range_char(first), sep, escape_re_range_char(last) - ) - ) - else: - ret = [escape_re_range_char(c) for c in s] - - return "".join(ret) - - -def _flatten(ll: list) -> list: - ret = [] - for i in ll: - if isinstance(i, list): - ret.extend(_flatten(i)) - else: - ret.append(i) - return ret diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__init__.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__init__.py deleted file mode 100755 index 4c6ec97..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: MIT -# SPDX-FileCopyrightText: 2021 Taneli Hukkinen -# Licensed to PSF under a Contributor Agreement. - -__all__ = ("loads", "load", "TOMLDecodeError") -__version__ = "2.0.1" # DO NOT EDIT THIS LINE MANUALLY. LET bump2version UTILITY DO IT - -from ._parser import TOMLDecodeError, load, loads - -# Pretend this exception was created here. -TOMLDecodeError.__module__ = __name__ diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index 841df83..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/_parser.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/_parser.cpython-311.pyc deleted file mode 100755 index b35a8ad..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/_parser.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/_re.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/_re.cpython-311.pyc deleted file mode 100755 index 5911fdb..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/_re.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/_types.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/_types.cpython-311.pyc deleted file mode 100755 index 4320003..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/__pycache__/_types.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/_parser.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/_parser.py deleted file mode 100755 index f1bb0aa..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/_parser.py +++ /dev/null @@ -1,691 +0,0 @@ -# SPDX-License-Identifier: MIT -# SPDX-FileCopyrightText: 2021 Taneli Hukkinen -# Licensed to PSF under a Contributor Agreement. - -from __future__ import annotations - -from collections.abc import Iterable -import string -from types import MappingProxyType -from typing import Any, BinaryIO, NamedTuple - -from ._re import ( - RE_DATETIME, - RE_LOCALTIME, - RE_NUMBER, - match_to_datetime, - match_to_localtime, - match_to_number, -) -from ._types import Key, ParseFloat, Pos - -ASCII_CTRL = frozenset(chr(i) for i in range(32)) | frozenset(chr(127)) - -# Neither of these sets include quotation mark or backslash. They are -# currently handled as separate cases in the parser functions. -ILLEGAL_BASIC_STR_CHARS = ASCII_CTRL - frozenset("\t") -ILLEGAL_MULTILINE_BASIC_STR_CHARS = ASCII_CTRL - frozenset("\t\n") - -ILLEGAL_LITERAL_STR_CHARS = ILLEGAL_BASIC_STR_CHARS -ILLEGAL_MULTILINE_LITERAL_STR_CHARS = ILLEGAL_MULTILINE_BASIC_STR_CHARS - -ILLEGAL_COMMENT_CHARS = ILLEGAL_BASIC_STR_CHARS - -TOML_WS = frozenset(" \t") -TOML_WS_AND_NEWLINE = TOML_WS | frozenset("\n") -BARE_KEY_CHARS = frozenset(string.ascii_letters + string.digits + "-_") -KEY_INITIAL_CHARS = BARE_KEY_CHARS | frozenset("\"'") -HEXDIGIT_CHARS = frozenset(string.hexdigits) - -BASIC_STR_ESCAPE_REPLACEMENTS = MappingProxyType( - { - "\\b": "\u0008", # backspace - "\\t": "\u0009", # tab - "\\n": "\u000A", # linefeed - "\\f": "\u000C", # form feed - "\\r": "\u000D", # carriage return - '\\"': "\u0022", # quote - "\\\\": "\u005C", # backslash - } -) - - -class TOMLDecodeError(ValueError): - """An error raised if a document is not valid TOML.""" - - -def load(__fp: BinaryIO, *, parse_float: ParseFloat = float) -> dict[str, Any]: - """Parse TOML from a binary file object.""" - b = __fp.read() - try: - s = b.decode() - except AttributeError: - raise TypeError( - "File must be opened in binary mode, e.g. use `open('foo.toml', 'rb')`" - ) from None - return loads(s, parse_float=parse_float) - - -def loads(__s: str, *, parse_float: ParseFloat = float) -> dict[str, Any]: # noqa: C901 - """Parse TOML from a string.""" - - # The spec allows converting "\r\n" to "\n", even in string - # literals. Let's do so to simplify parsing. - src = __s.replace("\r\n", "\n") - pos = 0 - out = Output(NestedDict(), Flags()) - header: Key = () - parse_float = make_safe_parse_float(parse_float) - - # Parse one statement at a time - # (typically means one line in TOML source) - while True: - # 1. Skip line leading whitespace - pos = skip_chars(src, pos, TOML_WS) - - # 2. Parse rules. Expect one of the following: - # - end of file - # - end of line - # - comment - # - key/value pair - # - append dict to list (and move to its namespace) - # - create dict (and move to its namespace) - # Skip trailing whitespace when applicable. - try: - char = src[pos] - except IndexError: - break - if char == "\n": - pos += 1 - continue - if char in KEY_INITIAL_CHARS: - pos = key_value_rule(src, pos, out, header, parse_float) - pos = skip_chars(src, pos, TOML_WS) - elif char == "[": - try: - second_char: str | None = src[pos + 1] - except IndexError: - second_char = None - out.flags.finalize_pending() - if second_char == "[": - pos, header = create_list_rule(src, pos, out) - else: - pos, header = create_dict_rule(src, pos, out) - pos = skip_chars(src, pos, TOML_WS) - elif char != "#": - raise suffixed_err(src, pos, "Invalid statement") - - # 3. Skip comment - pos = skip_comment(src, pos) - - # 4. Expect end of line or end of file - try: - char = src[pos] - except IndexError: - break - if char != "\n": - raise suffixed_err( - src, pos, "Expected newline or end of document after a statement" - ) - pos += 1 - - return out.data.dict - - -class Flags: - """Flags that map to parsed keys/namespaces.""" - - # Marks an immutable namespace (inline array or inline table). - FROZEN = 0 - # Marks a nest that has been explicitly created and can no longer - # be opened using the "[table]" syntax. - EXPLICIT_NEST = 1 - - def __init__(self) -> None: - self._flags: dict[str, dict] = {} - self._pending_flags: set[tuple[Key, int]] = set() - - def add_pending(self, key: Key, flag: int) -> None: - self._pending_flags.add((key, flag)) - - def finalize_pending(self) -> None: - for key, flag in self._pending_flags: - self.set(key, flag, recursive=False) - self._pending_flags.clear() - - def unset_all(self, key: Key) -> None: - cont = self._flags - for k in key[:-1]: - if k not in cont: - return - cont = cont[k]["nested"] - cont.pop(key[-1], None) - - def set(self, key: Key, flag: int, *, recursive: bool) -> None: # noqa: A003 - cont = self._flags - key_parent, key_stem = key[:-1], key[-1] - for k in key_parent: - if k not in cont: - cont[k] = {"flags": set(), "recursive_flags": set(), "nested": {}} - cont = cont[k]["nested"] - if key_stem not in cont: - cont[key_stem] = {"flags": set(), "recursive_flags": set(), "nested": {}} - cont[key_stem]["recursive_flags" if recursive else "flags"].add(flag) - - def is_(self, key: Key, flag: int) -> bool: - if not key: - return False # document root has no flags - cont = self._flags - for k in key[:-1]: - if k not in cont: - return False - inner_cont = cont[k] - if flag in inner_cont["recursive_flags"]: - return True - cont = inner_cont["nested"] - key_stem = key[-1] - if key_stem in cont: - cont = cont[key_stem] - return flag in cont["flags"] or flag in cont["recursive_flags"] - return False - - -class NestedDict: - def __init__(self) -> None: - # The parsed content of the TOML document - self.dict: dict[str, Any] = {} - - def get_or_create_nest( - self, - key: Key, - *, - access_lists: bool = True, - ) -> dict: - cont: Any = self.dict - for k in key: - if k not in cont: - cont[k] = {} - cont = cont[k] - if access_lists and isinstance(cont, list): - cont = cont[-1] - if not isinstance(cont, dict): - raise KeyError("There is no nest behind this key") - return cont - - def append_nest_to_list(self, key: Key) -> None: - cont = self.get_or_create_nest(key[:-1]) - last_key = key[-1] - if last_key in cont: - list_ = cont[last_key] - if not isinstance(list_, list): - raise KeyError("An object other than list found behind this key") - list_.append({}) - else: - cont[last_key] = [{}] - - -class Output(NamedTuple): - data: NestedDict - flags: Flags - - -def skip_chars(src: str, pos: Pos, chars: Iterable[str]) -> Pos: - try: - while src[pos] in chars: - pos += 1 - except IndexError: - pass - return pos - - -def skip_until( - src: str, - pos: Pos, - expect: str, - *, - error_on: frozenset[str], - error_on_eof: bool, -) -> Pos: - try: - new_pos = src.index(expect, pos) - except ValueError: - new_pos = len(src) - if error_on_eof: - raise suffixed_err(src, new_pos, f"Expected {expect!r}") from None - - if not error_on.isdisjoint(src[pos:new_pos]): - while src[pos] not in error_on: - pos += 1 - raise suffixed_err(src, pos, f"Found invalid character {src[pos]!r}") - return new_pos - - -def skip_comment(src: str, pos: Pos) -> Pos: - try: - char: str | None = src[pos] - except IndexError: - char = None - if char == "#": - return skip_until( - src, pos + 1, "\n", error_on=ILLEGAL_COMMENT_CHARS, error_on_eof=False - ) - return pos - - -def skip_comments_and_array_ws(src: str, pos: Pos) -> Pos: - while True: - pos_before_skip = pos - pos = skip_chars(src, pos, TOML_WS_AND_NEWLINE) - pos = skip_comment(src, pos) - if pos == pos_before_skip: - return pos - - -def create_dict_rule(src: str, pos: Pos, out: Output) -> tuple[Pos, Key]: - pos += 1 # Skip "[" - pos = skip_chars(src, pos, TOML_WS) - pos, key = parse_key(src, pos) - - if out.flags.is_(key, Flags.EXPLICIT_NEST) or out.flags.is_(key, Flags.FROZEN): - raise suffixed_err(src, pos, f"Cannot declare {key} twice") - out.flags.set(key, Flags.EXPLICIT_NEST, recursive=False) - try: - out.data.get_or_create_nest(key) - except KeyError: - raise suffixed_err(src, pos, "Cannot overwrite a value") from None - - if not src.startswith("]", pos): - raise suffixed_err(src, pos, "Expected ']' at the end of a table declaration") - return pos + 1, key - - -def create_list_rule(src: str, pos: Pos, out: Output) -> tuple[Pos, Key]: - pos += 2 # Skip "[[" - pos = skip_chars(src, pos, TOML_WS) - pos, key = parse_key(src, pos) - - if out.flags.is_(key, Flags.FROZEN): - raise suffixed_err(src, pos, f"Cannot mutate immutable namespace {key}") - # Free the namespace now that it points to another empty list item... - out.flags.unset_all(key) - # ...but this key precisely is still prohibited from table declaration - out.flags.set(key, Flags.EXPLICIT_NEST, recursive=False) - try: - out.data.append_nest_to_list(key) - except KeyError: - raise suffixed_err(src, pos, "Cannot overwrite a value") from None - - if not src.startswith("]]", pos): - raise suffixed_err(src, pos, "Expected ']]' at the end of an array declaration") - return pos + 2, key - - -def key_value_rule( - src: str, pos: Pos, out: Output, header: Key, parse_float: ParseFloat -) -> Pos: - pos, key, value = parse_key_value_pair(src, pos, parse_float) - key_parent, key_stem = key[:-1], key[-1] - abs_key_parent = header + key_parent - - relative_path_cont_keys = (header + key[:i] for i in range(1, len(key))) - for cont_key in relative_path_cont_keys: - # Check that dotted key syntax does not redefine an existing table - if out.flags.is_(cont_key, Flags.EXPLICIT_NEST): - raise suffixed_err(src, pos, f"Cannot redefine namespace {cont_key}") - # Containers in the relative path can't be opened with the table syntax or - # dotted key/value syntax in following table sections. - out.flags.add_pending(cont_key, Flags.EXPLICIT_NEST) - - if out.flags.is_(abs_key_parent, Flags.FROZEN): - raise suffixed_err( - src, pos, f"Cannot mutate immutable namespace {abs_key_parent}" - ) - - try: - nest = out.data.get_or_create_nest(abs_key_parent) - except KeyError: - raise suffixed_err(src, pos, "Cannot overwrite a value") from None - if key_stem in nest: - raise suffixed_err(src, pos, "Cannot overwrite a value") - # Mark inline table and array namespaces recursively immutable - if isinstance(value, (dict, list)): - out.flags.set(header + key, Flags.FROZEN, recursive=True) - nest[key_stem] = value - return pos - - -def parse_key_value_pair( - src: str, pos: Pos, parse_float: ParseFloat -) -> tuple[Pos, Key, Any]: - pos, key = parse_key(src, pos) - try: - char: str | None = src[pos] - except IndexError: - char = None - if char != "=": - raise suffixed_err(src, pos, "Expected '=' after a key in a key/value pair") - pos += 1 - pos = skip_chars(src, pos, TOML_WS) - pos, value = parse_value(src, pos, parse_float) - return pos, key, value - - -def parse_key(src: str, pos: Pos) -> tuple[Pos, Key]: - pos, key_part = parse_key_part(src, pos) - key: Key = (key_part,) - pos = skip_chars(src, pos, TOML_WS) - while True: - try: - char: str | None = src[pos] - except IndexError: - char = None - if char != ".": - return pos, key - pos += 1 - pos = skip_chars(src, pos, TOML_WS) - pos, key_part = parse_key_part(src, pos) - key += (key_part,) - pos = skip_chars(src, pos, TOML_WS) - - -def parse_key_part(src: str, pos: Pos) -> tuple[Pos, str]: - try: - char: str | None = src[pos] - except IndexError: - char = None - if char in BARE_KEY_CHARS: - start_pos = pos - pos = skip_chars(src, pos, BARE_KEY_CHARS) - return pos, src[start_pos:pos] - if char == "'": - return parse_literal_str(src, pos) - if char == '"': - return parse_one_line_basic_str(src, pos) - raise suffixed_err(src, pos, "Invalid initial character for a key part") - - -def parse_one_line_basic_str(src: str, pos: Pos) -> tuple[Pos, str]: - pos += 1 - return parse_basic_str(src, pos, multiline=False) - - -def parse_array(src: str, pos: Pos, parse_float: ParseFloat) -> tuple[Pos, list]: - pos += 1 - array: list = [] - - pos = skip_comments_and_array_ws(src, pos) - if src.startswith("]", pos): - return pos + 1, array - while True: - pos, val = parse_value(src, pos, parse_float) - array.append(val) - pos = skip_comments_and_array_ws(src, pos) - - c = src[pos : pos + 1] - if c == "]": - return pos + 1, array - if c != ",": - raise suffixed_err(src, pos, "Unclosed array") - pos += 1 - - pos = skip_comments_and_array_ws(src, pos) - if src.startswith("]", pos): - return pos + 1, array - - -def parse_inline_table(src: str, pos: Pos, parse_float: ParseFloat) -> tuple[Pos, dict]: - pos += 1 - nested_dict = NestedDict() - flags = Flags() - - pos = skip_chars(src, pos, TOML_WS) - if src.startswith("}", pos): - return pos + 1, nested_dict.dict - while True: - pos, key, value = parse_key_value_pair(src, pos, parse_float) - key_parent, key_stem = key[:-1], key[-1] - if flags.is_(key, Flags.FROZEN): - raise suffixed_err(src, pos, f"Cannot mutate immutable namespace {key}") - try: - nest = nested_dict.get_or_create_nest(key_parent, access_lists=False) - except KeyError: - raise suffixed_err(src, pos, "Cannot overwrite a value") from None - if key_stem in nest: - raise suffixed_err(src, pos, f"Duplicate inline table key {key_stem!r}") - nest[key_stem] = value - pos = skip_chars(src, pos, TOML_WS) - c = src[pos : pos + 1] - if c == "}": - return pos + 1, nested_dict.dict - if c != ",": - raise suffixed_err(src, pos, "Unclosed inline table") - if isinstance(value, (dict, list)): - flags.set(key, Flags.FROZEN, recursive=True) - pos += 1 - pos = skip_chars(src, pos, TOML_WS) - - -def parse_basic_str_escape( - src: str, pos: Pos, *, multiline: bool = False -) -> tuple[Pos, str]: - escape_id = src[pos : pos + 2] - pos += 2 - if multiline and escape_id in {"\\ ", "\\\t", "\\\n"}: - # Skip whitespace until next non-whitespace character or end of - # the doc. Error if non-whitespace is found before newline. - if escape_id != "\\\n": - pos = skip_chars(src, pos, TOML_WS) - try: - char = src[pos] - except IndexError: - return pos, "" - if char != "\n": - raise suffixed_err(src, pos, "Unescaped '\\' in a string") - pos += 1 - pos = skip_chars(src, pos, TOML_WS_AND_NEWLINE) - return pos, "" - if escape_id == "\\u": - return parse_hex_char(src, pos, 4) - if escape_id == "\\U": - return parse_hex_char(src, pos, 8) - try: - return pos, BASIC_STR_ESCAPE_REPLACEMENTS[escape_id] - except KeyError: - raise suffixed_err(src, pos, "Unescaped '\\' in a string") from None - - -def parse_basic_str_escape_multiline(src: str, pos: Pos) -> tuple[Pos, str]: - return parse_basic_str_escape(src, pos, multiline=True) - - -def parse_hex_char(src: str, pos: Pos, hex_len: int) -> tuple[Pos, str]: - hex_str = src[pos : pos + hex_len] - if len(hex_str) != hex_len or not HEXDIGIT_CHARS.issuperset(hex_str): - raise suffixed_err(src, pos, "Invalid hex value") - pos += hex_len - hex_int = int(hex_str, 16) - if not is_unicode_scalar_value(hex_int): - raise suffixed_err(src, pos, "Escaped character is not a Unicode scalar value") - return pos, chr(hex_int) - - -def parse_literal_str(src: str, pos: Pos) -> tuple[Pos, str]: - pos += 1 # Skip starting apostrophe - start_pos = pos - pos = skip_until( - src, pos, "'", error_on=ILLEGAL_LITERAL_STR_CHARS, error_on_eof=True - ) - return pos + 1, src[start_pos:pos] # Skip ending apostrophe - - -def parse_multiline_str(src: str, pos: Pos, *, literal: bool) -> tuple[Pos, str]: - pos += 3 - if src.startswith("\n", pos): - pos += 1 - - if literal: - delim = "'" - end_pos = skip_until( - src, - pos, - "'''", - error_on=ILLEGAL_MULTILINE_LITERAL_STR_CHARS, - error_on_eof=True, - ) - result = src[pos:end_pos] - pos = end_pos + 3 - else: - delim = '"' - pos, result = parse_basic_str(src, pos, multiline=True) - - # Add at maximum two extra apostrophes/quotes if the end sequence - # is 4 or 5 chars long instead of just 3. - if not src.startswith(delim, pos): - return pos, result - pos += 1 - if not src.startswith(delim, pos): - return pos, result + delim - pos += 1 - return pos, result + (delim * 2) - - -def parse_basic_str(src: str, pos: Pos, *, multiline: bool) -> tuple[Pos, str]: - if multiline: - error_on = ILLEGAL_MULTILINE_BASIC_STR_CHARS - parse_escapes = parse_basic_str_escape_multiline - else: - error_on = ILLEGAL_BASIC_STR_CHARS - parse_escapes = parse_basic_str_escape - result = "" - start_pos = pos - while True: - try: - char = src[pos] - except IndexError: - raise suffixed_err(src, pos, "Unterminated string") from None - if char == '"': - if not multiline: - return pos + 1, result + src[start_pos:pos] - if src.startswith('"""', pos): - return pos + 3, result + src[start_pos:pos] - pos += 1 - continue - if char == "\\": - result += src[start_pos:pos] - pos, parsed_escape = parse_escapes(src, pos) - result += parsed_escape - start_pos = pos - continue - if char in error_on: - raise suffixed_err(src, pos, f"Illegal character {char!r}") - pos += 1 - - -def parse_value( # noqa: C901 - src: str, pos: Pos, parse_float: ParseFloat -) -> tuple[Pos, Any]: - try: - char: str | None = src[pos] - except IndexError: - char = None - - # IMPORTANT: order conditions based on speed of checking and likelihood - - # Basic strings - if char == '"': - if src.startswith('"""', pos): - return parse_multiline_str(src, pos, literal=False) - return parse_one_line_basic_str(src, pos) - - # Literal strings - if char == "'": - if src.startswith("'''", pos): - return parse_multiline_str(src, pos, literal=True) - return parse_literal_str(src, pos) - - # Booleans - if char == "t": - if src.startswith("true", pos): - return pos + 4, True - if char == "f": - if src.startswith("false", pos): - return pos + 5, False - - # Arrays - if char == "[": - return parse_array(src, pos, parse_float) - - # Inline tables - if char == "{": - return parse_inline_table(src, pos, parse_float) - - # Dates and times - datetime_match = RE_DATETIME.match(src, pos) - if datetime_match: - try: - datetime_obj = match_to_datetime(datetime_match) - except ValueError as e: - raise suffixed_err(src, pos, "Invalid date or datetime") from e - return datetime_match.end(), datetime_obj - localtime_match = RE_LOCALTIME.match(src, pos) - if localtime_match: - return localtime_match.end(), match_to_localtime(localtime_match) - - # Integers and "normal" floats. - # The regex will greedily match any type starting with a decimal - # char, so needs to be located after handling of dates and times. - number_match = RE_NUMBER.match(src, pos) - if number_match: - return number_match.end(), match_to_number(number_match, parse_float) - - # Special floats - first_three = src[pos : pos + 3] - if first_three in {"inf", "nan"}: - return pos + 3, parse_float(first_three) - first_four = src[pos : pos + 4] - if first_four in {"-inf", "+inf", "-nan", "+nan"}: - return pos + 4, parse_float(first_four) - - raise suffixed_err(src, pos, "Invalid value") - - -def suffixed_err(src: str, pos: Pos, msg: str) -> TOMLDecodeError: - """Return a `TOMLDecodeError` where error message is suffixed with - coordinates in source.""" - - def coord_repr(src: str, pos: Pos) -> str: - if pos >= len(src): - return "end of document" - line = src.count("\n", 0, pos) + 1 - if line == 1: - column = pos + 1 - else: - column = pos - src.rindex("\n", 0, pos) - return f"line {line}, column {column}" - - return TOMLDecodeError(f"{msg} (at {coord_repr(src, pos)})") - - -def is_unicode_scalar_value(codepoint: int) -> bool: - return (0 <= codepoint <= 55295) or (57344 <= codepoint <= 1114111) - - -def make_safe_parse_float(parse_float: ParseFloat) -> ParseFloat: - """A decorator to make `parse_float` safe. - - `parse_float` must not return dicts or lists, because these types - would be mixed with parsed TOML tables and arrays, thus confusing - the parser. The returned decorated callable raises `ValueError` - instead of returning illegal types. - """ - # The default `float` callable never returns illegal types. Optimize it. - if parse_float is float: # type: ignore[comparison-overlap] - return float - - def safe_parse_float(float_str: str) -> Any: - float_value = parse_float(float_str) - if isinstance(float_value, (dict, list)): - raise ValueError("parse_float must not return dicts or lists") - return float_value - - return safe_parse_float diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/_re.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/_re.py deleted file mode 100755 index 994bb74..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/_re.py +++ /dev/null @@ -1,107 +0,0 @@ -# SPDX-License-Identifier: MIT -# SPDX-FileCopyrightText: 2021 Taneli Hukkinen -# Licensed to PSF under a Contributor Agreement. - -from __future__ import annotations - -from datetime import date, datetime, time, timedelta, timezone, tzinfo -from functools import lru_cache -import re -from typing import Any - -from ._types import ParseFloat - -# E.g. -# - 00:32:00.999999 -# - 00:32:00 -_TIME_RE_STR = r"([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(?:\.([0-9]{1,6})[0-9]*)?" - -RE_NUMBER = re.compile( - r""" -0 -(?: - x[0-9A-Fa-f](?:_?[0-9A-Fa-f])* # hex - | - b[01](?:_?[01])* # bin - | - o[0-7](?:_?[0-7])* # oct -) -| -[+-]?(?:0|[1-9](?:_?[0-9])*) # dec, integer part -(?P - (?:\.[0-9](?:_?[0-9])*)? # optional fractional part - (?:[eE][+-]?[0-9](?:_?[0-9])*)? # optional exponent part -) -""", - flags=re.VERBOSE, -) -RE_LOCALTIME = re.compile(_TIME_RE_STR) -RE_DATETIME = re.compile( - rf""" -([0-9]{{4}})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01]) # date, e.g. 1988-10-27 -(?: - [Tt ] - {_TIME_RE_STR} - (?:([Zz])|([+-])([01][0-9]|2[0-3]):([0-5][0-9]))? # optional time offset -)? -""", - flags=re.VERBOSE, -) - - -def match_to_datetime(match: re.Match) -> datetime | date: - """Convert a `RE_DATETIME` match to `datetime.datetime` or `datetime.date`. - - Raises ValueError if the match does not correspond to a valid date - or datetime. - """ - ( - year_str, - month_str, - day_str, - hour_str, - minute_str, - sec_str, - micros_str, - zulu_time, - offset_sign_str, - offset_hour_str, - offset_minute_str, - ) = match.groups() - year, month, day = int(year_str), int(month_str), int(day_str) - if hour_str is None: - return date(year, month, day) - hour, minute, sec = int(hour_str), int(minute_str), int(sec_str) - micros = int(micros_str.ljust(6, "0")) if micros_str else 0 - if offset_sign_str: - tz: tzinfo | None = cached_tz( - offset_hour_str, offset_minute_str, offset_sign_str - ) - elif zulu_time: - tz = timezone.utc - else: # local date-time - tz = None - return datetime(year, month, day, hour, minute, sec, micros, tzinfo=tz) - - -@lru_cache(maxsize=None) -def cached_tz(hour_str: str, minute_str: str, sign_str: str) -> timezone: - sign = 1 if sign_str == "+" else -1 - return timezone( - timedelta( - hours=sign * int(hour_str), - minutes=sign * int(minute_str), - ) - ) - - -def match_to_localtime(match: re.Match) -> time: - hour_str, minute_str, sec_str, micros_str = match.groups() - micros = int(micros_str.ljust(6, "0")) if micros_str else 0 - return time(int(hour_str), int(minute_str), int(sec_str), micros) - - -def match_to_number(match: re.Match, parse_float: ParseFloat) -> Any: - if match.group("floatpart"): - return parse_float(match.group()) - return int(match.group(), 0) diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/_types.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/_types.py deleted file mode 100755 index d949412..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/tomli/_types.py +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: MIT -# SPDX-FileCopyrightText: 2021 Taneli Hukkinen -# Licensed to PSF under a Contributor Agreement. - -from typing import Any, Callable, Tuple - -# Type annotations -ParseFloat = Callable[[str], Any] -Key = Tuple[str, ...] -Pos = int diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/typing_extensions.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/typing_extensions.py deleted file mode 100755 index 9f1c7aa..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/typing_extensions.py +++ /dev/null @@ -1,2296 +0,0 @@ -import abc -import collections -import collections.abc -import operator -import sys -import typing - -# After PEP 560, internal typing API was substantially reworked. -# This is especially important for Protocol class which uses internal APIs -# quite extensively. -PEP_560 = sys.version_info[:3] >= (3, 7, 0) - -if PEP_560: - GenericMeta = type -else: - # 3.6 - from typing import GenericMeta, _type_vars # noqa - -# The two functions below are copies of typing internal helpers. -# They are needed by _ProtocolMeta - - -def _no_slots_copy(dct): - dict_copy = dict(dct) - if '__slots__' in dict_copy: - for slot in dict_copy['__slots__']: - dict_copy.pop(slot, None) - return dict_copy - - -def _check_generic(cls, parameters): - if not cls.__parameters__: - raise TypeError(f"{cls} is not a generic class") - alen = len(parameters) - elen = len(cls.__parameters__) - if alen != elen: - raise TypeError(f"Too {'many' if alen > elen else 'few'} arguments for {cls};" - f" actual {alen}, expected {elen}") - - -# Please keep __all__ alphabetized within each category. -__all__ = [ - # Super-special typing primitives. - 'ClassVar', - 'Concatenate', - 'Final', - 'ParamSpec', - 'Self', - 'Type', - - # ABCs (from collections.abc). - 'Awaitable', - 'AsyncIterator', - 'AsyncIterable', - 'Coroutine', - 'AsyncGenerator', - 'AsyncContextManager', - 'ChainMap', - - # Concrete collection types. - 'ContextManager', - 'Counter', - 'Deque', - 'DefaultDict', - 'OrderedDict', - 'TypedDict', - - # Structural checks, a.k.a. protocols. - 'SupportsIndex', - - # One-off things. - 'Annotated', - 'final', - 'IntVar', - 'Literal', - 'NewType', - 'overload', - 'Protocol', - 'runtime', - 'runtime_checkable', - 'Text', - 'TypeAlias', - 'TypeGuard', - 'TYPE_CHECKING', -] - -if PEP_560: - __all__.extend(["get_args", "get_origin", "get_type_hints"]) - -# 3.6.2+ -if hasattr(typing, 'NoReturn'): - NoReturn = typing.NoReturn -# 3.6.0-3.6.1 -else: - class _NoReturn(typing._FinalTypingBase, _root=True): - """Special type indicating functions that never return. - Example:: - - from typing import NoReturn - - def stop() -> NoReturn: - raise Exception('no way') - - This type is invalid in other positions, e.g., ``List[NoReturn]`` - will fail in static type checkers. - """ - __slots__ = () - - def __instancecheck__(self, obj): - raise TypeError("NoReturn cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("NoReturn cannot be used with issubclass().") - - NoReturn = _NoReturn(_root=True) - -# Some unconstrained type variables. These are used by the container types. -# (These are not for export.) -T = typing.TypeVar('T') # Any type. -KT = typing.TypeVar('KT') # Key type. -VT = typing.TypeVar('VT') # Value type. -T_co = typing.TypeVar('T_co', covariant=True) # Any type covariant containers. -T_contra = typing.TypeVar('T_contra', contravariant=True) # Ditto contravariant. - -ClassVar = typing.ClassVar - -# On older versions of typing there is an internal class named "Final". -# 3.8+ -if hasattr(typing, 'Final') and sys.version_info[:2] >= (3, 7): - Final = typing.Final -# 3.7 -elif sys.version_info[:2] >= (3, 7): - class _FinalForm(typing._SpecialForm, _root=True): - - def __repr__(self): - return 'typing_extensions.' + self._name - - def __getitem__(self, parameters): - item = typing._type_check(parameters, - f'{self._name} accepts only single type') - return typing._GenericAlias(self, (item,)) - - Final = _FinalForm('Final', - doc="""A special typing construct to indicate that a name - cannot be re-assigned or overridden in a subclass. - For example: - - MAX_SIZE: Final = 9000 - MAX_SIZE += 1 # Error reported by type checker - - class Connection: - TIMEOUT: Final[int] = 10 - class FastConnector(Connection): - TIMEOUT = 1 # Error reported by type checker - - There is no runtime checking of these properties.""") -# 3.6 -else: - class _Final(typing._FinalTypingBase, _root=True): - """A special typing construct to indicate that a name - cannot be re-assigned or overridden in a subclass. - For example: - - MAX_SIZE: Final = 9000 - MAX_SIZE += 1 # Error reported by type checker - - class Connection: - TIMEOUT: Final[int] = 10 - class FastConnector(Connection): - TIMEOUT = 1 # Error reported by type checker - - There is no runtime checking of these properties. - """ - - __slots__ = ('__type__',) - - def __init__(self, tp=None, **kwds): - self.__type__ = tp - - def __getitem__(self, item): - cls = type(self) - if self.__type__ is None: - return cls(typing._type_check(item, - f'{cls.__name__[1:]} accepts only single type.'), - _root=True) - raise TypeError(f'{cls.__name__[1:]} cannot be further subscripted') - - def _eval_type(self, globalns, localns): - new_tp = typing._eval_type(self.__type__, globalns, localns) - if new_tp == self.__type__: - return self - return type(self)(new_tp, _root=True) - - def __repr__(self): - r = super().__repr__() - if self.__type__ is not None: - r += f'[{typing._type_repr(self.__type__)}]' - return r - - def __hash__(self): - return hash((type(self).__name__, self.__type__)) - - def __eq__(self, other): - if not isinstance(other, _Final): - return NotImplemented - if self.__type__ is not None: - return self.__type__ == other.__type__ - return self is other - - Final = _Final(_root=True) - - -# 3.8+ -if hasattr(typing, 'final'): - final = typing.final -# 3.6-3.7 -else: - def final(f): - """This decorator can be used to indicate to type checkers that - the decorated method cannot be overridden, and decorated class - cannot be subclassed. For example: - - class Base: - @final - def done(self) -> None: - ... - class Sub(Base): - def done(self) -> None: # Error reported by type checker - ... - @final - class Leaf: - ... - class Other(Leaf): # Error reported by type checker - ... - - There is no runtime checking of these properties. - """ - return f - - -def IntVar(name): - return typing.TypeVar(name) - - -# 3.8+: -if hasattr(typing, 'Literal'): - Literal = typing.Literal -# 3.7: -elif sys.version_info[:2] >= (3, 7): - class _LiteralForm(typing._SpecialForm, _root=True): - - def __repr__(self): - return 'typing_extensions.' + self._name - - def __getitem__(self, parameters): - return typing._GenericAlias(self, parameters) - - Literal = _LiteralForm('Literal', - doc="""A type that can be used to indicate to type checkers - that the corresponding value has a value literally equivalent - to the provided parameter. For example: - - var: Literal[4] = 4 - - The type checker understands that 'var' is literally equal to - the value 4 and no other value. - - Literal[...] cannot be subclassed. There is no runtime - checking verifying that the parameter is actually a value - instead of a type.""") -# 3.6: -else: - class _Literal(typing._FinalTypingBase, _root=True): - """A type that can be used to indicate to type checkers that the - corresponding value has a value literally equivalent to the - provided parameter. For example: - - var: Literal[4] = 4 - - The type checker understands that 'var' is literally equal to the - value 4 and no other value. - - Literal[...] cannot be subclassed. There is no runtime checking - verifying that the parameter is actually a value instead of a type. - """ - - __slots__ = ('__values__',) - - def __init__(self, values=None, **kwds): - self.__values__ = values - - def __getitem__(self, values): - cls = type(self) - if self.__values__ is None: - if not isinstance(values, tuple): - values = (values,) - return cls(values, _root=True) - raise TypeError(f'{cls.__name__[1:]} cannot be further subscripted') - - def _eval_type(self, globalns, localns): - return self - - def __repr__(self): - r = super().__repr__() - if self.__values__ is not None: - r += f'[{", ".join(map(typing._type_repr, self.__values__))}]' - return r - - def __hash__(self): - return hash((type(self).__name__, self.__values__)) - - def __eq__(self, other): - if not isinstance(other, _Literal): - return NotImplemented - if self.__values__ is not None: - return self.__values__ == other.__values__ - return self is other - - Literal = _Literal(_root=True) - - -_overload_dummy = typing._overload_dummy # noqa -overload = typing.overload - - -# This is not a real generic class. Don't use outside annotations. -Type = typing.Type - -# Various ABCs mimicking those in collections.abc. -# A few are simply re-exported for completeness. - - -class _ExtensionsGenericMeta(GenericMeta): - def __subclasscheck__(self, subclass): - """This mimics a more modern GenericMeta.__subclasscheck__() logic - (that does not have problems with recursion) to work around interactions - between collections, typing, and typing_extensions on older - versions of Python, see https://github.com/python/typing/issues/501. - """ - if self.__origin__ is not None: - if sys._getframe(1).f_globals['__name__'] not in ['abc', 'functools']: - raise TypeError("Parameterized generics cannot be used with class " - "or instance checks") - return False - if not self.__extra__: - return super().__subclasscheck__(subclass) - res = self.__extra__.__subclasshook__(subclass) - if res is not NotImplemented: - return res - if self.__extra__ in subclass.__mro__: - return True - for scls in self.__extra__.__subclasses__(): - if isinstance(scls, GenericMeta): - continue - if issubclass(subclass, scls): - return True - return False - - -Awaitable = typing.Awaitable -Coroutine = typing.Coroutine -AsyncIterable = typing.AsyncIterable -AsyncIterator = typing.AsyncIterator - -# 3.6.1+ -if hasattr(typing, 'Deque'): - Deque = typing.Deque -# 3.6.0 -else: - class Deque(collections.deque, typing.MutableSequence[T], - metaclass=_ExtensionsGenericMeta, - extra=collections.deque): - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is Deque: - return collections.deque(*args, **kwds) - return typing._generic_new(collections.deque, cls, *args, **kwds) - -ContextManager = typing.ContextManager -# 3.6.2+ -if hasattr(typing, 'AsyncContextManager'): - AsyncContextManager = typing.AsyncContextManager -# 3.6.0-3.6.1 -else: - from _collections_abc import _check_methods as _check_methods_in_mro # noqa - - class AsyncContextManager(typing.Generic[T_co]): - __slots__ = () - - async def __aenter__(self): - return self - - @abc.abstractmethod - async def __aexit__(self, exc_type, exc_value, traceback): - return None - - @classmethod - def __subclasshook__(cls, C): - if cls is AsyncContextManager: - return _check_methods_in_mro(C, "__aenter__", "__aexit__") - return NotImplemented - -DefaultDict = typing.DefaultDict - -# 3.7.2+ -if hasattr(typing, 'OrderedDict'): - OrderedDict = typing.OrderedDict -# 3.7.0-3.7.2 -elif (3, 7, 0) <= sys.version_info[:3] < (3, 7, 2): - OrderedDict = typing._alias(collections.OrderedDict, (KT, VT)) -# 3.6 -else: - class OrderedDict(collections.OrderedDict, typing.MutableMapping[KT, VT], - metaclass=_ExtensionsGenericMeta, - extra=collections.OrderedDict): - - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is OrderedDict: - return collections.OrderedDict(*args, **kwds) - return typing._generic_new(collections.OrderedDict, cls, *args, **kwds) - -# 3.6.2+ -if hasattr(typing, 'Counter'): - Counter = typing.Counter -# 3.6.0-3.6.1 -else: - class Counter(collections.Counter, - typing.Dict[T, int], - metaclass=_ExtensionsGenericMeta, extra=collections.Counter): - - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is Counter: - return collections.Counter(*args, **kwds) - return typing._generic_new(collections.Counter, cls, *args, **kwds) - -# 3.6.1+ -if hasattr(typing, 'ChainMap'): - ChainMap = typing.ChainMap -elif hasattr(collections, 'ChainMap'): - class ChainMap(collections.ChainMap, typing.MutableMapping[KT, VT], - metaclass=_ExtensionsGenericMeta, - extra=collections.ChainMap): - - __slots__ = () - - def __new__(cls, *args, **kwds): - if cls._gorg is ChainMap: - return collections.ChainMap(*args, **kwds) - return typing._generic_new(collections.ChainMap, cls, *args, **kwds) - -# 3.6.1+ -if hasattr(typing, 'AsyncGenerator'): - AsyncGenerator = typing.AsyncGenerator -# 3.6.0 -else: - class AsyncGenerator(AsyncIterator[T_co], typing.Generic[T_co, T_contra], - metaclass=_ExtensionsGenericMeta, - extra=collections.abc.AsyncGenerator): - __slots__ = () - -NewType = typing.NewType -Text = typing.Text -TYPE_CHECKING = typing.TYPE_CHECKING - - -def _gorg(cls): - """This function exists for compatibility with old typing versions.""" - assert isinstance(cls, GenericMeta) - if hasattr(cls, '_gorg'): - return cls._gorg - while cls.__origin__ is not None: - cls = cls.__origin__ - return cls - - -_PROTO_WHITELIST = ['Callable', 'Awaitable', - 'Iterable', 'Iterator', 'AsyncIterable', 'AsyncIterator', - 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', - 'ContextManager', 'AsyncContextManager'] - - -def _get_protocol_attrs(cls): - attrs = set() - for base in cls.__mro__[:-1]: # without object - if base.__name__ in ('Protocol', 'Generic'): - continue - annotations = getattr(base, '__annotations__', {}) - for attr in list(base.__dict__.keys()) + list(annotations.keys()): - if (not attr.startswith('_abc_') and attr not in ( - '__abstractmethods__', '__annotations__', '__weakref__', - '_is_protocol', '_is_runtime_protocol', '__dict__', - '__args__', '__slots__', - '__next_in_mro__', '__parameters__', '__origin__', - '__orig_bases__', '__extra__', '__tree_hash__', - '__doc__', '__subclasshook__', '__init__', '__new__', - '__module__', '_MutableMapping__marker', '_gorg')): - attrs.add(attr) - return attrs - - -def _is_callable_members_only(cls): - return all(callable(getattr(cls, attr, None)) for attr in _get_protocol_attrs(cls)) - - -# 3.8+ -if hasattr(typing, 'Protocol'): - Protocol = typing.Protocol -# 3.7 -elif PEP_560: - from typing import _collect_type_vars # noqa - - def _no_init(self, *args, **kwargs): - if type(self)._is_protocol: - raise TypeError('Protocols cannot be instantiated') - - class _ProtocolMeta(abc.ABCMeta): - # This metaclass is a bit unfortunate and exists only because of the lack - # of __instancehook__. - def __instancecheck__(cls, instance): - # We need this method for situations where attributes are - # assigned in __init__. - if ((not getattr(cls, '_is_protocol', False) or - _is_callable_members_only(cls)) and - issubclass(instance.__class__, cls)): - return True - if cls._is_protocol: - if all(hasattr(instance, attr) and - (not callable(getattr(cls, attr, None)) or - getattr(instance, attr) is not None) - for attr in _get_protocol_attrs(cls)): - return True - return super().__instancecheck__(instance) - - class Protocol(metaclass=_ProtocolMeta): - # There is quite a lot of overlapping code with typing.Generic. - # Unfortunately it is hard to avoid this while these live in two different - # modules. The duplicated code will be removed when Protocol is moved to typing. - """Base class for protocol classes. Protocol classes are defined as:: - - class Proto(Protocol): - def meth(self) -> int: - ... - - Such classes are primarily used with static type checkers that recognize - structural subtyping (static duck-typing), for example:: - - class C: - def meth(self) -> int: - return 0 - - def func(x: Proto) -> int: - return x.meth() - - func(C()) # Passes static type check - - See PEP 544 for details. Protocol classes decorated with - @typing_extensions.runtime act as simple-minded runtime protocol that checks - only the presence of given attributes, ignoring their type signatures. - - Protocol classes can be generic, they are defined as:: - - class GenProto(Protocol[T]): - def meth(self) -> T: - ... - """ - __slots__ = () - _is_protocol = True - - def __new__(cls, *args, **kwds): - if cls is Protocol: - raise TypeError("Type Protocol cannot be instantiated; " - "it can only be used as a base class") - return super().__new__(cls) - - @typing._tp_cache - def __class_getitem__(cls, params): - if not isinstance(params, tuple): - params = (params,) - if not params and cls is not typing.Tuple: - raise TypeError( - f"Parameter list to {cls.__qualname__}[...] cannot be empty") - msg = "Parameters to generic types must be types." - params = tuple(typing._type_check(p, msg) for p in params) # noqa - if cls is Protocol: - # Generic can only be subscripted with unique type variables. - if not all(isinstance(p, typing.TypeVar) for p in params): - i = 0 - while isinstance(params[i], typing.TypeVar): - i += 1 - raise TypeError( - "Parameters to Protocol[...] must all be type variables." - f" Parameter {i + 1} is {params[i]}") - if len(set(params)) != len(params): - raise TypeError( - "Parameters to Protocol[...] must all be unique") - else: - # Subscripting a regular Generic subclass. - _check_generic(cls, params) - return typing._GenericAlias(cls, params) - - def __init_subclass__(cls, *args, **kwargs): - tvars = [] - if '__orig_bases__' in cls.__dict__: - error = typing.Generic in cls.__orig_bases__ - else: - error = typing.Generic in cls.__bases__ - if error: - raise TypeError("Cannot inherit from plain Generic") - if '__orig_bases__' in cls.__dict__: - tvars = _collect_type_vars(cls.__orig_bases__) - # Look for Generic[T1, ..., Tn] or Protocol[T1, ..., Tn]. - # If found, tvars must be a subset of it. - # If not found, tvars is it. - # Also check for and reject plain Generic, - # and reject multiple Generic[...] and/or Protocol[...]. - gvars = None - for base in cls.__orig_bases__: - if (isinstance(base, typing._GenericAlias) and - base.__origin__ in (typing.Generic, Protocol)): - # for error messages - the_base = base.__origin__.__name__ - if gvars is not None: - raise TypeError( - "Cannot inherit from Generic[...]" - " and/or Protocol[...] multiple types.") - gvars = base.__parameters__ - if gvars is None: - gvars = tvars - else: - tvarset = set(tvars) - gvarset = set(gvars) - if not tvarset <= gvarset: - s_vars = ', '.join(str(t) for t in tvars if t not in gvarset) - s_args = ', '.join(str(g) for g in gvars) - raise TypeError(f"Some type variables ({s_vars}) are" - f" not listed in {the_base}[{s_args}]") - tvars = gvars - cls.__parameters__ = tuple(tvars) - - # Determine if this is a protocol or a concrete subclass. - if not cls.__dict__.get('_is_protocol', None): - cls._is_protocol = any(b is Protocol for b in cls.__bases__) - - # Set (or override) the protocol subclass hook. - def _proto_hook(other): - if not cls.__dict__.get('_is_protocol', None): - return NotImplemented - if not getattr(cls, '_is_runtime_protocol', False): - if sys._getframe(2).f_globals['__name__'] in ['abc', 'functools']: - return NotImplemented - raise TypeError("Instance and class checks can only be used with" - " @runtime protocols") - if not _is_callable_members_only(cls): - if sys._getframe(2).f_globals['__name__'] in ['abc', 'functools']: - return NotImplemented - raise TypeError("Protocols with non-method members" - " don't support issubclass()") - if not isinstance(other, type): - # Same error as for issubclass(1, int) - raise TypeError('issubclass() arg 1 must be a class') - for attr in _get_protocol_attrs(cls): - for base in other.__mro__: - if attr in base.__dict__: - if base.__dict__[attr] is None: - return NotImplemented - break - annotations = getattr(base, '__annotations__', {}) - if (isinstance(annotations, typing.Mapping) and - attr in annotations and - isinstance(other, _ProtocolMeta) and - other._is_protocol): - break - else: - return NotImplemented - return True - if '__subclasshook__' not in cls.__dict__: - cls.__subclasshook__ = _proto_hook - - # We have nothing more to do for non-protocols. - if not cls._is_protocol: - return - - # Check consistency of bases. - for base in cls.__bases__: - if not (base in (object, typing.Generic) or - base.__module__ == 'collections.abc' and - base.__name__ in _PROTO_WHITELIST or - isinstance(base, _ProtocolMeta) and base._is_protocol): - raise TypeError('Protocols can only inherit from other' - f' protocols, got {repr(base)}') - cls.__init__ = _no_init -# 3.6 -else: - from typing import _next_in_mro, _type_check # noqa - - def _no_init(self, *args, **kwargs): - if type(self)._is_protocol: - raise TypeError('Protocols cannot be instantiated') - - class _ProtocolMeta(GenericMeta): - """Internal metaclass for Protocol. - - This exists so Protocol classes can be generic without deriving - from Generic. - """ - def __new__(cls, name, bases, namespace, - tvars=None, args=None, origin=None, extra=None, orig_bases=None): - # This is just a version copied from GenericMeta.__new__ that - # includes "Protocol" special treatment. (Comments removed for brevity.) - assert extra is None # Protocols should not have extra - if tvars is not None: - assert origin is not None - assert all(isinstance(t, typing.TypeVar) for t in tvars), tvars - else: - tvars = _type_vars(bases) - gvars = None - for base in bases: - if base is typing.Generic: - raise TypeError("Cannot inherit from plain Generic") - if (isinstance(base, GenericMeta) and - base.__origin__ in (typing.Generic, Protocol)): - if gvars is not None: - raise TypeError( - "Cannot inherit from Generic[...] or" - " Protocol[...] multiple times.") - gvars = base.__parameters__ - if gvars is None: - gvars = tvars - else: - tvarset = set(tvars) - gvarset = set(gvars) - if not tvarset <= gvarset: - s_vars = ", ".join(str(t) for t in tvars if t not in gvarset) - s_args = ", ".join(str(g) for g in gvars) - cls_name = "Generic" if any(b.__origin__ is typing.Generic - for b in bases) else "Protocol" - raise TypeError(f"Some type variables ({s_vars}) are" - f" not listed in {cls_name}[{s_args}]") - tvars = gvars - - initial_bases = bases - if (extra is not None and type(extra) is abc.ABCMeta and - extra not in bases): - bases = (extra,) + bases - bases = tuple(_gorg(b) if isinstance(b, GenericMeta) else b - for b in bases) - if any(isinstance(b, GenericMeta) and b is not typing.Generic for b in bases): - bases = tuple(b for b in bases if b is not typing.Generic) - namespace.update({'__origin__': origin, '__extra__': extra}) - self = super(GenericMeta, cls).__new__(cls, name, bases, namespace, - _root=True) - super(GenericMeta, self).__setattr__('_gorg', - self if not origin else - _gorg(origin)) - self.__parameters__ = tvars - self.__args__ = tuple(... if a is typing._TypingEllipsis else - () if a is typing._TypingEmpty else - a for a in args) if args else None - self.__next_in_mro__ = _next_in_mro(self) - if orig_bases is None: - self.__orig_bases__ = initial_bases - elif origin is not None: - self._abc_registry = origin._abc_registry - self._abc_cache = origin._abc_cache - if hasattr(self, '_subs_tree'): - self.__tree_hash__ = (hash(self._subs_tree()) if origin else - super(GenericMeta, self).__hash__()) - return self - - def __init__(cls, *args, **kwargs): - super().__init__(*args, **kwargs) - if not cls.__dict__.get('_is_protocol', None): - cls._is_protocol = any(b is Protocol or - isinstance(b, _ProtocolMeta) and - b.__origin__ is Protocol - for b in cls.__bases__) - if cls._is_protocol: - for base in cls.__mro__[1:]: - if not (base in (object, typing.Generic) or - base.__module__ == 'collections.abc' and - base.__name__ in _PROTO_WHITELIST or - isinstance(base, typing.TypingMeta) and base._is_protocol or - isinstance(base, GenericMeta) and - base.__origin__ is typing.Generic): - raise TypeError(f'Protocols can only inherit from other' - f' protocols, got {repr(base)}') - - cls.__init__ = _no_init - - def _proto_hook(other): - if not cls.__dict__.get('_is_protocol', None): - return NotImplemented - if not isinstance(other, type): - # Same error as for issubclass(1, int) - raise TypeError('issubclass() arg 1 must be a class') - for attr in _get_protocol_attrs(cls): - for base in other.__mro__: - if attr in base.__dict__: - if base.__dict__[attr] is None: - return NotImplemented - break - annotations = getattr(base, '__annotations__', {}) - if (isinstance(annotations, typing.Mapping) and - attr in annotations and - isinstance(other, _ProtocolMeta) and - other._is_protocol): - break - else: - return NotImplemented - return True - if '__subclasshook__' not in cls.__dict__: - cls.__subclasshook__ = _proto_hook - - def __instancecheck__(self, instance): - # We need this method for situations where attributes are - # assigned in __init__. - if ((not getattr(self, '_is_protocol', False) or - _is_callable_members_only(self)) and - issubclass(instance.__class__, self)): - return True - if self._is_protocol: - if all(hasattr(instance, attr) and - (not callable(getattr(self, attr, None)) or - getattr(instance, attr) is not None) - for attr in _get_protocol_attrs(self)): - return True - return super(GenericMeta, self).__instancecheck__(instance) - - def __subclasscheck__(self, cls): - if self.__origin__ is not None: - if sys._getframe(1).f_globals['__name__'] not in ['abc', 'functools']: - raise TypeError("Parameterized generics cannot be used with class " - "or instance checks") - return False - if (self.__dict__.get('_is_protocol', None) and - not self.__dict__.get('_is_runtime_protocol', None)): - if sys._getframe(1).f_globals['__name__'] in ['abc', - 'functools', - 'typing']: - return False - raise TypeError("Instance and class checks can only be used with" - " @runtime protocols") - if (self.__dict__.get('_is_runtime_protocol', None) and - not _is_callable_members_only(self)): - if sys._getframe(1).f_globals['__name__'] in ['abc', - 'functools', - 'typing']: - return super(GenericMeta, self).__subclasscheck__(cls) - raise TypeError("Protocols with non-method members" - " don't support issubclass()") - return super(GenericMeta, self).__subclasscheck__(cls) - - @typing._tp_cache - def __getitem__(self, params): - # We also need to copy this from GenericMeta.__getitem__ to get - # special treatment of "Protocol". (Comments removed for brevity.) - if not isinstance(params, tuple): - params = (params,) - if not params and _gorg(self) is not typing.Tuple: - raise TypeError( - f"Parameter list to {self.__qualname__}[...] cannot be empty") - msg = "Parameters to generic types must be types." - params = tuple(_type_check(p, msg) for p in params) - if self in (typing.Generic, Protocol): - if not all(isinstance(p, typing.TypeVar) for p in params): - raise TypeError( - f"Parameters to {repr(self)}[...] must all be type variables") - if len(set(params)) != len(params): - raise TypeError( - f"Parameters to {repr(self)}[...] must all be unique") - tvars = params - args = params - elif self in (typing.Tuple, typing.Callable): - tvars = _type_vars(params) - args = params - elif self.__origin__ in (typing.Generic, Protocol): - raise TypeError(f"Cannot subscript already-subscripted {repr(self)}") - else: - _check_generic(self, params) - tvars = _type_vars(params) - args = params - - prepend = (self,) if self.__origin__ is None else () - return self.__class__(self.__name__, - prepend + self.__bases__, - _no_slots_copy(self.__dict__), - tvars=tvars, - args=args, - origin=self, - extra=self.__extra__, - orig_bases=self.__orig_bases__) - - class Protocol(metaclass=_ProtocolMeta): - """Base class for protocol classes. Protocol classes are defined as:: - - class Proto(Protocol): - def meth(self) -> int: - ... - - Such classes are primarily used with static type checkers that recognize - structural subtyping (static duck-typing), for example:: - - class C: - def meth(self) -> int: - return 0 - - def func(x: Proto) -> int: - return x.meth() - - func(C()) # Passes static type check - - See PEP 544 for details. Protocol classes decorated with - @typing_extensions.runtime act as simple-minded runtime protocol that checks - only the presence of given attributes, ignoring their type signatures. - - Protocol classes can be generic, they are defined as:: - - class GenProto(Protocol[T]): - def meth(self) -> T: - ... - """ - __slots__ = () - _is_protocol = True - - def __new__(cls, *args, **kwds): - if _gorg(cls) is Protocol: - raise TypeError("Type Protocol cannot be instantiated; " - "it can be used only as a base class") - return typing._generic_new(cls.__next_in_mro__, cls, *args, **kwds) - - -# 3.8+ -if hasattr(typing, 'runtime_checkable'): - runtime_checkable = typing.runtime_checkable -# 3.6-3.7 -else: - def runtime_checkable(cls): - """Mark a protocol class as a runtime protocol, so that it - can be used with isinstance() and issubclass(). Raise TypeError - if applied to a non-protocol class. - - This allows a simple-minded structural check very similar to the - one-offs in collections.abc such as Hashable. - """ - if not isinstance(cls, _ProtocolMeta) or not cls._is_protocol: - raise TypeError('@runtime_checkable can be only applied to protocol classes,' - f' got {cls!r}') - cls._is_runtime_protocol = True - return cls - - -# Exists for backwards compatibility. -runtime = runtime_checkable - - -# 3.8+ -if hasattr(typing, 'SupportsIndex'): - SupportsIndex = typing.SupportsIndex -# 3.6-3.7 -else: - @runtime_checkable - class SupportsIndex(Protocol): - __slots__ = () - - @abc.abstractmethod - def __index__(self) -> int: - pass - - -if sys.version_info >= (3, 9, 2): - # The standard library TypedDict in Python 3.8 does not store runtime information - # about which (if any) keys are optional. See https://bugs.python.org/issue38834 - # The standard library TypedDict in Python 3.9.0/1 does not honour the "total" - # keyword with old-style TypedDict(). See https://bugs.python.org/issue42059 - TypedDict = typing.TypedDict -else: - def _check_fails(cls, other): - try: - if sys._getframe(1).f_globals['__name__'] not in ['abc', - 'functools', - 'typing']: - # Typed dicts are only for static structural subtyping. - raise TypeError('TypedDict does not support instance and class checks') - except (AttributeError, ValueError): - pass - return False - - def _dict_new(*args, **kwargs): - if not args: - raise TypeError('TypedDict.__new__(): not enough arguments') - _, args = args[0], args[1:] # allow the "cls" keyword be passed - return dict(*args, **kwargs) - - _dict_new.__text_signature__ = '($cls, _typename, _fields=None, /, **kwargs)' - - def _typeddict_new(*args, total=True, **kwargs): - if not args: - raise TypeError('TypedDict.__new__(): not enough arguments') - _, args = args[0], args[1:] # allow the "cls" keyword be passed - if args: - typename, args = args[0], args[1:] # allow the "_typename" keyword be passed - elif '_typename' in kwargs: - typename = kwargs.pop('_typename') - import warnings - warnings.warn("Passing '_typename' as keyword argument is deprecated", - DeprecationWarning, stacklevel=2) - else: - raise TypeError("TypedDict.__new__() missing 1 required positional " - "argument: '_typename'") - if args: - try: - fields, = args # allow the "_fields" keyword be passed - except ValueError: - raise TypeError('TypedDict.__new__() takes from 2 to 3 ' - f'positional arguments but {len(args) + 2} ' - 'were given') - elif '_fields' in kwargs and len(kwargs) == 1: - fields = kwargs.pop('_fields') - import warnings - warnings.warn("Passing '_fields' as keyword argument is deprecated", - DeprecationWarning, stacklevel=2) - else: - fields = None - - if fields is None: - fields = kwargs - elif kwargs: - raise TypeError("TypedDict takes either a dict or keyword arguments," - " but not both") - - ns = {'__annotations__': dict(fields)} - try: - # Setting correct module is necessary to make typed dict classes pickleable. - ns['__module__'] = sys._getframe(1).f_globals.get('__name__', '__main__') - except (AttributeError, ValueError): - pass - - return _TypedDictMeta(typename, (), ns, total=total) - - _typeddict_new.__text_signature__ = ('($cls, _typename, _fields=None,' - ' /, *, total=True, **kwargs)') - - class _TypedDictMeta(type): - def __init__(cls, name, bases, ns, total=True): - super().__init__(name, bases, ns) - - def __new__(cls, name, bases, ns, total=True): - # Create new typed dict class object. - # This method is called directly when TypedDict is subclassed, - # or via _typeddict_new when TypedDict is instantiated. This way - # TypedDict supports all three syntaxes described in its docstring. - # Subclasses and instances of TypedDict return actual dictionaries - # via _dict_new. - ns['__new__'] = _typeddict_new if name == 'TypedDict' else _dict_new - tp_dict = super().__new__(cls, name, (dict,), ns) - - annotations = {} - own_annotations = ns.get('__annotations__', {}) - own_annotation_keys = set(own_annotations.keys()) - msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type" - own_annotations = { - n: typing._type_check(tp, msg) for n, tp in own_annotations.items() - } - required_keys = set() - optional_keys = set() - - for base in bases: - annotations.update(base.__dict__.get('__annotations__', {})) - required_keys.update(base.__dict__.get('__required_keys__', ())) - optional_keys.update(base.__dict__.get('__optional_keys__', ())) - - annotations.update(own_annotations) - if total: - required_keys.update(own_annotation_keys) - else: - optional_keys.update(own_annotation_keys) - - tp_dict.__annotations__ = annotations - tp_dict.__required_keys__ = frozenset(required_keys) - tp_dict.__optional_keys__ = frozenset(optional_keys) - if not hasattr(tp_dict, '__total__'): - tp_dict.__total__ = total - return tp_dict - - __instancecheck__ = __subclasscheck__ = _check_fails - - TypedDict = _TypedDictMeta('TypedDict', (dict,), {}) - TypedDict.__module__ = __name__ - TypedDict.__doc__ = \ - """A simple typed name space. At runtime it is equivalent to a plain dict. - - TypedDict creates a dictionary type that expects all of its - instances to have a certain set of keys, with each key - associated with a value of a consistent type. This expectation - is not checked at runtime but is only enforced by type checkers. - Usage:: - - class Point2D(TypedDict): - x: int - y: int - label: str - - a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK - b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check - - assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first') - - The type info can be accessed via the Point2D.__annotations__ dict, and - the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets. - TypedDict supports two additional equivalent forms:: - - Point2D = TypedDict('Point2D', x=int, y=int, label=str) - Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str}) - - The class syntax is only supported in Python 3.6+, while two other - syntax forms work for Python 2.7 and 3.2+ - """ - - -# Python 3.9+ has PEP 593 (Annotated and modified get_type_hints) -if hasattr(typing, 'Annotated'): - Annotated = typing.Annotated - get_type_hints = typing.get_type_hints - # Not exported and not a public API, but needed for get_origin() and get_args() - # to work. - _AnnotatedAlias = typing._AnnotatedAlias -# 3.7-3.8 -elif PEP_560: - class _AnnotatedAlias(typing._GenericAlias, _root=True): - """Runtime representation of an annotated type. - - At its core 'Annotated[t, dec1, dec2, ...]' is an alias for the type 't' - with extra annotations. The alias behaves like a normal typing alias, - instantiating is the same as instantiating the underlying type, binding - it to types is also the same. - """ - def __init__(self, origin, metadata): - if isinstance(origin, _AnnotatedAlias): - metadata = origin.__metadata__ + metadata - origin = origin.__origin__ - super().__init__(origin, origin) - self.__metadata__ = metadata - - def copy_with(self, params): - assert len(params) == 1 - new_type = params[0] - return _AnnotatedAlias(new_type, self.__metadata__) - - def __repr__(self): - return (f"typing_extensions.Annotated[{typing._type_repr(self.__origin__)}, " - f"{', '.join(repr(a) for a in self.__metadata__)}]") - - def __reduce__(self): - return operator.getitem, ( - Annotated, (self.__origin__,) + self.__metadata__ - ) - - def __eq__(self, other): - if not isinstance(other, _AnnotatedAlias): - return NotImplemented - if self.__origin__ != other.__origin__: - return False - return self.__metadata__ == other.__metadata__ - - def __hash__(self): - return hash((self.__origin__, self.__metadata__)) - - class Annotated: - """Add context specific metadata to a type. - - Example: Annotated[int, runtime_check.Unsigned] indicates to the - hypothetical runtime_check module that this type is an unsigned int. - Every other consumer of this type can ignore this metadata and treat - this type as int. - - The first argument to Annotated must be a valid type (and will be in - the __origin__ field), the remaining arguments are kept as a tuple in - the __extra__ field. - - Details: - - - It's an error to call `Annotated` with less than two arguments. - - Nested Annotated are flattened:: - - Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] - - - Instantiating an annotated type is equivalent to instantiating the - underlying type:: - - Annotated[C, Ann1](5) == C(5) - - - Annotated can be used as a generic type alias:: - - Optimized = Annotated[T, runtime.Optimize()] - Optimized[int] == Annotated[int, runtime.Optimize()] - - OptimizedList = Annotated[List[T], runtime.Optimize()] - OptimizedList[int] == Annotated[List[int], runtime.Optimize()] - """ - - __slots__ = () - - def __new__(cls, *args, **kwargs): - raise TypeError("Type Annotated cannot be instantiated.") - - @typing._tp_cache - def __class_getitem__(cls, params): - if not isinstance(params, tuple) or len(params) < 2: - raise TypeError("Annotated[...] should be used " - "with at least two arguments (a type and an " - "annotation).") - msg = "Annotated[t, ...]: t must be a type." - origin = typing._type_check(params[0], msg) - metadata = tuple(params[1:]) - return _AnnotatedAlias(origin, metadata) - - def __init_subclass__(cls, *args, **kwargs): - raise TypeError( - f"Cannot subclass {cls.__module__}.Annotated" - ) - - def _strip_annotations(t): - """Strips the annotations from a given type. - """ - if isinstance(t, _AnnotatedAlias): - return _strip_annotations(t.__origin__) - if isinstance(t, typing._GenericAlias): - stripped_args = tuple(_strip_annotations(a) for a in t.__args__) - if stripped_args == t.__args__: - return t - res = t.copy_with(stripped_args) - res._special = t._special - return res - return t - - def get_type_hints(obj, globalns=None, localns=None, include_extras=False): - """Return type hints for an object. - - This is often the same as obj.__annotations__, but it handles - forward references encoded as string literals, adds Optional[t] if a - default value equal to None is set and recursively replaces all - 'Annotated[T, ...]' with 'T' (unless 'include_extras=True'). - - The argument may be a module, class, method, or function. The annotations - are returned as a dictionary. For classes, annotations include also - inherited members. - - TypeError is raised if the argument is not of a type that can contain - annotations, and an empty dictionary is returned if no annotations are - present. - - BEWARE -- the behavior of globalns and localns is counterintuitive - (unless you are familiar with how eval() and exec() work). The - search order is locals first, then globals. - - - If no dict arguments are passed, an attempt is made to use the - globals from obj (or the respective module's globals for classes), - and these are also used as the locals. If the object does not appear - to have globals, an empty dictionary is used. - - - If one dict argument is passed, it is used for both globals and - locals. - - - If two dict arguments are passed, they specify globals and - locals, respectively. - """ - hint = typing.get_type_hints(obj, globalns=globalns, localns=localns) - if include_extras: - return hint - return {k: _strip_annotations(t) for k, t in hint.items()} -# 3.6 -else: - - def _is_dunder(name): - """Returns True if name is a __dunder_variable_name__.""" - return len(name) > 4 and name.startswith('__') and name.endswith('__') - - # Prior to Python 3.7 types did not have `copy_with`. A lot of the equality - # checks, argument expansion etc. are done on the _subs_tre. As a result we - # can't provide a get_type_hints function that strips out annotations. - - class AnnotatedMeta(typing.GenericMeta): - """Metaclass for Annotated""" - - def __new__(cls, name, bases, namespace, **kwargs): - if any(b is not object for b in bases): - raise TypeError("Cannot subclass " + str(Annotated)) - return super().__new__(cls, name, bases, namespace, **kwargs) - - @property - def __metadata__(self): - return self._subs_tree()[2] - - def _tree_repr(self, tree): - cls, origin, metadata = tree - if not isinstance(origin, tuple): - tp_repr = typing._type_repr(origin) - else: - tp_repr = origin[0]._tree_repr(origin) - metadata_reprs = ", ".join(repr(arg) for arg in metadata) - return f'{cls}[{tp_repr}, {metadata_reprs}]' - - def _subs_tree(self, tvars=None, args=None): # noqa - if self is Annotated: - return Annotated - res = super()._subs_tree(tvars=tvars, args=args) - # Flatten nested Annotated - if isinstance(res[1], tuple) and res[1][0] is Annotated: - sub_tp = res[1][1] - sub_annot = res[1][2] - return (Annotated, sub_tp, sub_annot + res[2]) - return res - - def _get_cons(self): - """Return the class used to create instance of this type.""" - if self.__origin__ is None: - raise TypeError("Cannot get the underlying type of a " - "non-specialized Annotated type.") - tree = self._subs_tree() - while isinstance(tree, tuple) and tree[0] is Annotated: - tree = tree[1] - if isinstance(tree, tuple): - return tree[0] - else: - return tree - - @typing._tp_cache - def __getitem__(self, params): - if not isinstance(params, tuple): - params = (params,) - if self.__origin__ is not None: # specializing an instantiated type - return super().__getitem__(params) - elif not isinstance(params, tuple) or len(params) < 2: - raise TypeError("Annotated[...] should be instantiated " - "with at least two arguments (a type and an " - "annotation).") - else: - msg = "Annotated[t, ...]: t must be a type." - tp = typing._type_check(params[0], msg) - metadata = tuple(params[1:]) - return self.__class__( - self.__name__, - self.__bases__, - _no_slots_copy(self.__dict__), - tvars=_type_vars((tp,)), - # Metadata is a tuple so it won't be touched by _replace_args et al. - args=(tp, metadata), - origin=self, - ) - - def __call__(self, *args, **kwargs): - cons = self._get_cons() - result = cons(*args, **kwargs) - try: - result.__orig_class__ = self - except AttributeError: - pass - return result - - def __getattr__(self, attr): - # For simplicity we just don't relay all dunder names - if self.__origin__ is not None and not _is_dunder(attr): - return getattr(self._get_cons(), attr) - raise AttributeError(attr) - - def __setattr__(self, attr, value): - if _is_dunder(attr) or attr.startswith('_abc_'): - super().__setattr__(attr, value) - elif self.__origin__ is None: - raise AttributeError(attr) - else: - setattr(self._get_cons(), attr, value) - - def __instancecheck__(self, obj): - raise TypeError("Annotated cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("Annotated cannot be used with issubclass().") - - class Annotated(metaclass=AnnotatedMeta): - """Add context specific metadata to a type. - - Example: Annotated[int, runtime_check.Unsigned] indicates to the - hypothetical runtime_check module that this type is an unsigned int. - Every other consumer of this type can ignore this metadata and treat - this type as int. - - The first argument to Annotated must be a valid type, the remaining - arguments are kept as a tuple in the __metadata__ field. - - Details: - - - It's an error to call `Annotated` with less than two arguments. - - Nested Annotated are flattened:: - - Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] - - - Instantiating an annotated type is equivalent to instantiating the - underlying type:: - - Annotated[C, Ann1](5) == C(5) - - - Annotated can be used as a generic type alias:: - - Optimized = Annotated[T, runtime.Optimize()] - Optimized[int] == Annotated[int, runtime.Optimize()] - - OptimizedList = Annotated[List[T], runtime.Optimize()] - OptimizedList[int] == Annotated[List[int], runtime.Optimize()] - """ - -# Python 3.8 has get_origin() and get_args() but those implementations aren't -# Annotated-aware, so we can't use those. Python 3.9's versions don't support -# ParamSpecArgs and ParamSpecKwargs, so only Python 3.10's versions will do. -if sys.version_info[:2] >= (3, 10): - get_origin = typing.get_origin - get_args = typing.get_args -# 3.7-3.9 -elif PEP_560: - try: - # 3.9+ - from typing import _BaseGenericAlias - except ImportError: - _BaseGenericAlias = typing._GenericAlias - try: - # 3.9+ - from typing import GenericAlias - except ImportError: - GenericAlias = typing._GenericAlias - - def get_origin(tp): - """Get the unsubscripted version of a type. - - This supports generic types, Callable, Tuple, Union, Literal, Final, ClassVar - and Annotated. Return None for unsupported types. Examples:: - - get_origin(Literal[42]) is Literal - get_origin(int) is None - get_origin(ClassVar[int]) is ClassVar - get_origin(Generic) is Generic - get_origin(Generic[T]) is Generic - get_origin(Union[T, int]) is Union - get_origin(List[Tuple[T, T]][int]) == list - get_origin(P.args) is P - """ - if isinstance(tp, _AnnotatedAlias): - return Annotated - if isinstance(tp, (typing._GenericAlias, GenericAlias, _BaseGenericAlias, - ParamSpecArgs, ParamSpecKwargs)): - return tp.__origin__ - if tp is typing.Generic: - return typing.Generic - return None - - def get_args(tp): - """Get type arguments with all substitutions performed. - - For unions, basic simplifications used by Union constructor are performed. - Examples:: - get_args(Dict[str, int]) == (str, int) - get_args(int) == () - get_args(Union[int, Union[T, int], str][int]) == (int, str) - get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int]) - get_args(Callable[[], T][int]) == ([], int) - """ - if isinstance(tp, _AnnotatedAlias): - return (tp.__origin__,) + tp.__metadata__ - if isinstance(tp, (typing._GenericAlias, GenericAlias)): - if getattr(tp, "_special", False): - return () - res = tp.__args__ - if get_origin(tp) is collections.abc.Callable and res[0] is not Ellipsis: - res = (list(res[:-1]), res[-1]) - return res - return () - - -# 3.10+ -if hasattr(typing, 'TypeAlias'): - TypeAlias = typing.TypeAlias -# 3.9 -elif sys.version_info[:2] >= (3, 9): - class _TypeAliasForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - @_TypeAliasForm - def TypeAlias(self, parameters): - """Special marker indicating that an assignment should - be recognized as a proper type alias definition by type - checkers. - - For example:: - - Predicate: TypeAlias = Callable[..., bool] - - It's invalid when used anywhere except as in the example above. - """ - raise TypeError(f"{self} is not subscriptable") -# 3.7-3.8 -elif sys.version_info[:2] >= (3, 7): - class _TypeAliasForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - TypeAlias = _TypeAliasForm('TypeAlias', - doc="""Special marker indicating that an assignment should - be recognized as a proper type alias definition by type - checkers. - - For example:: - - Predicate: TypeAlias = Callable[..., bool] - - It's invalid when used anywhere except as in the example - above.""") -# 3.6 -else: - class _TypeAliasMeta(typing.TypingMeta): - """Metaclass for TypeAlias""" - - def __repr__(self): - return 'typing_extensions.TypeAlias' - - class _TypeAliasBase(typing._FinalTypingBase, metaclass=_TypeAliasMeta, _root=True): - """Special marker indicating that an assignment should - be recognized as a proper type alias definition by type - checkers. - - For example:: - - Predicate: TypeAlias = Callable[..., bool] - - It's invalid when used anywhere except as in the example above. - """ - __slots__ = () - - def __instancecheck__(self, obj): - raise TypeError("TypeAlias cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("TypeAlias cannot be used with issubclass().") - - def __repr__(self): - return 'typing_extensions.TypeAlias' - - TypeAlias = _TypeAliasBase(_root=True) - - -# Python 3.10+ has PEP 612 -if hasattr(typing, 'ParamSpecArgs'): - ParamSpecArgs = typing.ParamSpecArgs - ParamSpecKwargs = typing.ParamSpecKwargs -# 3.6-3.9 -else: - class _Immutable: - """Mixin to indicate that object should not be copied.""" - __slots__ = () - - def __copy__(self): - return self - - def __deepcopy__(self, memo): - return self - - class ParamSpecArgs(_Immutable): - """The args for a ParamSpec object. - - Given a ParamSpec object P, P.args is an instance of ParamSpecArgs. - - ParamSpecArgs objects have a reference back to their ParamSpec: - - P.args.__origin__ is P - - This type is meant for runtime introspection and has no special meaning to - static type checkers. - """ - def __init__(self, origin): - self.__origin__ = origin - - def __repr__(self): - return f"{self.__origin__.__name__}.args" - - class ParamSpecKwargs(_Immutable): - """The kwargs for a ParamSpec object. - - Given a ParamSpec object P, P.kwargs is an instance of ParamSpecKwargs. - - ParamSpecKwargs objects have a reference back to their ParamSpec: - - P.kwargs.__origin__ is P - - This type is meant for runtime introspection and has no special meaning to - static type checkers. - """ - def __init__(self, origin): - self.__origin__ = origin - - def __repr__(self): - return f"{self.__origin__.__name__}.kwargs" - -# 3.10+ -if hasattr(typing, 'ParamSpec'): - ParamSpec = typing.ParamSpec -# 3.6-3.9 -else: - - # Inherits from list as a workaround for Callable checks in Python < 3.9.2. - class ParamSpec(list): - """Parameter specification variable. - - Usage:: - - P = ParamSpec('P') - - Parameter specification variables exist primarily for the benefit of static - type checkers. They are used to forward the parameter types of one - callable to another callable, a pattern commonly found in higher order - functions and decorators. They are only valid when used in ``Concatenate``, - or s the first argument to ``Callable``. In Python 3.10 and higher, - they are also supported in user-defined Generics at runtime. - See class Generic for more information on generic types. An - example for annotating a decorator:: - - T = TypeVar('T') - P = ParamSpec('P') - - def add_logging(f: Callable[P, T]) -> Callable[P, T]: - '''A type-safe decorator to add logging to a function.''' - def inner(*args: P.args, **kwargs: P.kwargs) -> T: - logging.info(f'{f.__name__} was called') - return f(*args, **kwargs) - return inner - - @add_logging - def add_two(x: float, y: float) -> float: - '''Add two numbers together.''' - return x + y - - Parameter specification variables defined with covariant=True or - contravariant=True can be used to declare covariant or contravariant - generic types. These keyword arguments are valid, but their actual semantics - are yet to be decided. See PEP 612 for details. - - Parameter specification variables can be introspected. e.g.: - - P.__name__ == 'T' - P.__bound__ == None - P.__covariant__ == False - P.__contravariant__ == False - - Note that only parameter specification variables defined in global scope can - be pickled. - """ - - # Trick Generic __parameters__. - __class__ = typing.TypeVar - - @property - def args(self): - return ParamSpecArgs(self) - - @property - def kwargs(self): - return ParamSpecKwargs(self) - - def __init__(self, name, *, bound=None, covariant=False, contravariant=False): - super().__init__([self]) - self.__name__ = name - self.__covariant__ = bool(covariant) - self.__contravariant__ = bool(contravariant) - if bound: - self.__bound__ = typing._type_check(bound, 'Bound must be a type.') - else: - self.__bound__ = None - - # for pickling: - try: - def_mod = sys._getframe(1).f_globals.get('__name__', '__main__') - except (AttributeError, ValueError): - def_mod = None - if def_mod != 'typing_extensions': - self.__module__ = def_mod - - def __repr__(self): - if self.__covariant__: - prefix = '+' - elif self.__contravariant__: - prefix = '-' - else: - prefix = '~' - return prefix + self.__name__ - - def __hash__(self): - return object.__hash__(self) - - def __eq__(self, other): - return self is other - - def __reduce__(self): - return self.__name__ - - # Hack to get typing._type_check to pass. - def __call__(self, *args, **kwargs): - pass - - if not PEP_560: - # Only needed in 3.6. - def _get_type_vars(self, tvars): - if self not in tvars: - tvars.append(self) - - -# 3.6-3.9 -if not hasattr(typing, 'Concatenate'): - # Inherits from list as a workaround for Callable checks in Python < 3.9.2. - class _ConcatenateGenericAlias(list): - - # Trick Generic into looking into this for __parameters__. - if PEP_560: - __class__ = typing._GenericAlias - else: - __class__ = typing._TypingBase - - # Flag in 3.8. - _special = False - # Attribute in 3.6 and earlier. - _gorg = typing.Generic - - def __init__(self, origin, args): - super().__init__(args) - self.__origin__ = origin - self.__args__ = args - - def __repr__(self): - _type_repr = typing._type_repr - return (f'{_type_repr(self.__origin__)}' - f'[{", ".join(_type_repr(arg) for arg in self.__args__)}]') - - def __hash__(self): - return hash((self.__origin__, self.__args__)) - - # Hack to get typing._type_check to pass in Generic. - def __call__(self, *args, **kwargs): - pass - - @property - def __parameters__(self): - return tuple( - tp for tp in self.__args__ if isinstance(tp, (typing.TypeVar, ParamSpec)) - ) - - if not PEP_560: - # Only required in 3.6. - def _get_type_vars(self, tvars): - if self.__origin__ and self.__parameters__: - typing._get_type_vars(self.__parameters__, tvars) - - -# 3.6-3.9 -@typing._tp_cache -def _concatenate_getitem(self, parameters): - if parameters == (): - raise TypeError("Cannot take a Concatenate of no types.") - if not isinstance(parameters, tuple): - parameters = (parameters,) - if not isinstance(parameters[-1], ParamSpec): - raise TypeError("The last parameter to Concatenate should be a " - "ParamSpec variable.") - msg = "Concatenate[arg, ...]: each arg must be a type." - parameters = tuple(typing._type_check(p, msg) for p in parameters) - return _ConcatenateGenericAlias(self, parameters) - - -# 3.10+ -if hasattr(typing, 'Concatenate'): - Concatenate = typing.Concatenate - _ConcatenateGenericAlias = typing._ConcatenateGenericAlias # noqa -# 3.9 -elif sys.version_info[:2] >= (3, 9): - @_TypeAliasForm - def Concatenate(self, parameters): - """Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a - higher order function which adds, removes or transforms parameters of a - callable. - - For example:: - - Callable[Concatenate[int, P], int] - - See PEP 612 for detailed information. - """ - return _concatenate_getitem(self, parameters) -# 3.7-8 -elif sys.version_info[:2] >= (3, 7): - class _ConcatenateForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - def __getitem__(self, parameters): - return _concatenate_getitem(self, parameters) - - Concatenate = _ConcatenateForm( - 'Concatenate', - doc="""Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a - higher order function which adds, removes or transforms parameters of a - callable. - - For example:: - - Callable[Concatenate[int, P], int] - - See PEP 612 for detailed information. - """) -# 3.6 -else: - class _ConcatenateAliasMeta(typing.TypingMeta): - """Metaclass for Concatenate.""" - - def __repr__(self): - return 'typing_extensions.Concatenate' - - class _ConcatenateAliasBase(typing._FinalTypingBase, - metaclass=_ConcatenateAliasMeta, - _root=True): - """Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a - higher order function which adds, removes or transforms parameters of a - callable. - - For example:: - - Callable[Concatenate[int, P], int] - - See PEP 612 for detailed information. - """ - __slots__ = () - - def __instancecheck__(self, obj): - raise TypeError("Concatenate cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError("Concatenate cannot be used with issubclass().") - - def __repr__(self): - return 'typing_extensions.Concatenate' - - def __getitem__(self, parameters): - return _concatenate_getitem(self, parameters) - - Concatenate = _ConcatenateAliasBase(_root=True) - -# 3.10+ -if hasattr(typing, 'TypeGuard'): - TypeGuard = typing.TypeGuard -# 3.9 -elif sys.version_info[:2] >= (3, 9): - class _TypeGuardForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - @_TypeGuardForm - def TypeGuard(self, parameters): - """Special typing form used to annotate the return type of a user-defined - type guard function. ``TypeGuard`` only accepts a single type argument. - At runtime, functions marked this way should return a boolean. - - ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static - type checkers to determine a more precise type of an expression within a - program's code flow. Usually type narrowing is done by analyzing - conditional code flow and applying the narrowing to a block of code. The - conditional expression here is sometimes referred to as a "type guard". - - Sometimes it would be convenient to use a user-defined boolean function - as a type guard. Such a function should use ``TypeGuard[...]`` as its - return type to alert static type checkers to this intention. - - Using ``-> TypeGuard`` tells the static type checker that for a given - function: - - 1. The return value is a boolean. - 2. If the return value is ``True``, the type of its argument - is the type inside ``TypeGuard``. - - For example:: - - def is_str(val: Union[str, float]): - # "isinstance" type guard - if isinstance(val, str): - # Type of ``val`` is narrowed to ``str`` - ... - else: - # Else, type of ``val`` is narrowed to ``float``. - ... - - Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower - form of ``TypeA`` (it can even be a wider form) and this may lead to - type-unsafe results. The main reason is to allow for things like - narrowing ``List[object]`` to ``List[str]`` even though the latter is not - a subtype of the former, since ``List`` is invariant. The responsibility of - writing type-safe type guards is left to the user. - - ``TypeGuard`` also works with type variables. For more information, see - PEP 647 (User-Defined Type Guards). - """ - item = typing._type_check(parameters, f'{self} accepts only single type.') - return typing._GenericAlias(self, (item,)) -# 3.7-3.8 -elif sys.version_info[:2] >= (3, 7): - class _TypeGuardForm(typing._SpecialForm, _root=True): - - def __repr__(self): - return 'typing_extensions.' + self._name - - def __getitem__(self, parameters): - item = typing._type_check(parameters, - f'{self._name} accepts only a single type') - return typing._GenericAlias(self, (item,)) - - TypeGuard = _TypeGuardForm( - 'TypeGuard', - doc="""Special typing form used to annotate the return type of a user-defined - type guard function. ``TypeGuard`` only accepts a single type argument. - At runtime, functions marked this way should return a boolean. - - ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static - type checkers to determine a more precise type of an expression within a - program's code flow. Usually type narrowing is done by analyzing - conditional code flow and applying the narrowing to a block of code. The - conditional expression here is sometimes referred to as a "type guard". - - Sometimes it would be convenient to use a user-defined boolean function - as a type guard. Such a function should use ``TypeGuard[...]`` as its - return type to alert static type checkers to this intention. - - Using ``-> TypeGuard`` tells the static type checker that for a given - function: - - 1. The return value is a boolean. - 2. If the return value is ``True``, the type of its argument - is the type inside ``TypeGuard``. - - For example:: - - def is_str(val: Union[str, float]): - # "isinstance" type guard - if isinstance(val, str): - # Type of ``val`` is narrowed to ``str`` - ... - else: - # Else, type of ``val`` is narrowed to ``float``. - ... - - Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower - form of ``TypeA`` (it can even be a wider form) and this may lead to - type-unsafe results. The main reason is to allow for things like - narrowing ``List[object]`` to ``List[str]`` even though the latter is not - a subtype of the former, since ``List`` is invariant. The responsibility of - writing type-safe type guards is left to the user. - - ``TypeGuard`` also works with type variables. For more information, see - PEP 647 (User-Defined Type Guards). - """) -# 3.6 -else: - class _TypeGuard(typing._FinalTypingBase, _root=True): - """Special typing form used to annotate the return type of a user-defined - type guard function. ``TypeGuard`` only accepts a single type argument. - At runtime, functions marked this way should return a boolean. - - ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static - type checkers to determine a more precise type of an expression within a - program's code flow. Usually type narrowing is done by analyzing - conditional code flow and applying the narrowing to a block of code. The - conditional expression here is sometimes referred to as a "type guard". - - Sometimes it would be convenient to use a user-defined boolean function - as a type guard. Such a function should use ``TypeGuard[...]`` as its - return type to alert static type checkers to this intention. - - Using ``-> TypeGuard`` tells the static type checker that for a given - function: - - 1. The return value is a boolean. - 2. If the return value is ``True``, the type of its argument - is the type inside ``TypeGuard``. - - For example:: - - def is_str(val: Union[str, float]): - # "isinstance" type guard - if isinstance(val, str): - # Type of ``val`` is narrowed to ``str`` - ... - else: - # Else, type of ``val`` is narrowed to ``float``. - ... - - Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower - form of ``TypeA`` (it can even be a wider form) and this may lead to - type-unsafe results. The main reason is to allow for things like - narrowing ``List[object]`` to ``List[str]`` even though the latter is not - a subtype of the former, since ``List`` is invariant. The responsibility of - writing type-safe type guards is left to the user. - - ``TypeGuard`` also works with type variables. For more information, see - PEP 647 (User-Defined Type Guards). - """ - - __slots__ = ('__type__',) - - def __init__(self, tp=None, **kwds): - self.__type__ = tp - - def __getitem__(self, item): - cls = type(self) - if self.__type__ is None: - return cls(typing._type_check(item, - f'{cls.__name__[1:]} accepts only a single type.'), - _root=True) - raise TypeError(f'{cls.__name__[1:]} cannot be further subscripted') - - def _eval_type(self, globalns, localns): - new_tp = typing._eval_type(self.__type__, globalns, localns) - if new_tp == self.__type__: - return self - return type(self)(new_tp, _root=True) - - def __repr__(self): - r = super().__repr__() - if self.__type__ is not None: - r += f'[{typing._type_repr(self.__type__)}]' - return r - - def __hash__(self): - return hash((type(self).__name__, self.__type__)) - - def __eq__(self, other): - if not isinstance(other, _TypeGuard): - return NotImplemented - if self.__type__ is not None: - return self.__type__ == other.__type__ - return self is other - - TypeGuard = _TypeGuard(_root=True) - -if hasattr(typing, "Self"): - Self = typing.Self -elif sys.version_info[:2] >= (3, 7): - # Vendored from cpython typing._SpecialFrom - class _SpecialForm(typing._Final, _root=True): - __slots__ = ('_name', '__doc__', '_getitem') - - def __init__(self, getitem): - self._getitem = getitem - self._name = getitem.__name__ - self.__doc__ = getitem.__doc__ - - def __getattr__(self, item): - if item in {'__name__', '__qualname__'}: - return self._name - - raise AttributeError(item) - - def __mro_entries__(self, bases): - raise TypeError(f"Cannot subclass {self!r}") - - def __repr__(self): - return f'typing_extensions.{self._name}' - - def __reduce__(self): - return self._name - - def __call__(self, *args, **kwds): - raise TypeError(f"Cannot instantiate {self!r}") - - def __or__(self, other): - return typing.Union[self, other] - - def __ror__(self, other): - return typing.Union[other, self] - - def __instancecheck__(self, obj): - raise TypeError(f"{self} cannot be used with isinstance()") - - def __subclasscheck__(self, cls): - raise TypeError(f"{self} cannot be used with issubclass()") - - @typing._tp_cache - def __getitem__(self, parameters): - return self._getitem(self, parameters) - - @_SpecialForm - def Self(self, params): - """Used to spell the type of "self" in classes. - - Example:: - - from typing import Self - - class ReturnsSelf: - def parse(self, data: bytes) -> Self: - ... - return self - - """ - - raise TypeError(f"{self} is not subscriptable") -else: - class _Self(typing._FinalTypingBase, _root=True): - """Used to spell the type of "self" in classes. - - Example:: - - from typing import Self - - class ReturnsSelf: - def parse(self, data: bytes) -> Self: - ... - return self - - """ - - __slots__ = () - - def __instancecheck__(self, obj): - raise TypeError(f"{self} cannot be used with isinstance().") - - def __subclasscheck__(self, cls): - raise TypeError(f"{self} cannot be used with issubclass().") - - Self = _Self(_root=True) - - -if hasattr(typing, 'Required'): - Required = typing.Required - NotRequired = typing.NotRequired -elif sys.version_info[:2] >= (3, 9): - class _ExtensionsSpecialForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - @_ExtensionsSpecialForm - def Required(self, parameters): - """A special typing construct to mark a key of a total=False TypedDict - as required. For example: - - class Movie(TypedDict, total=False): - title: Required[str] - year: int - - m = Movie( - title='The Matrix', # typechecker error if key is omitted - year=1999, - ) - - There is no runtime checking that a required key is actually provided - when instantiating a related TypedDict. - """ - item = typing._type_check(parameters, f'{self._name} accepts only single type') - return typing._GenericAlias(self, (item,)) - - @_ExtensionsSpecialForm - def NotRequired(self, parameters): - """A special typing construct to mark a key of a TypedDict as - potentially missing. For example: - - class Movie(TypedDict): - title: str - year: NotRequired[int] - - m = Movie( - title='The Matrix', # typechecker error if key is omitted - year=1999, - ) - """ - item = typing._type_check(parameters, f'{self._name} accepts only single type') - return typing._GenericAlias(self, (item,)) - -elif sys.version_info[:2] >= (3, 7): - class _RequiredForm(typing._SpecialForm, _root=True): - def __repr__(self): - return 'typing_extensions.' + self._name - - def __getitem__(self, parameters): - item = typing._type_check(parameters, - '{} accepts only single type'.format(self._name)) - return typing._GenericAlias(self, (item,)) - - Required = _RequiredForm( - 'Required', - doc="""A special typing construct to mark a key of a total=False TypedDict - as required. For example: - - class Movie(TypedDict, total=False): - title: Required[str] - year: int - - m = Movie( - title='The Matrix', # typechecker error if key is omitted - year=1999, - ) - - There is no runtime checking that a required key is actually provided - when instantiating a related TypedDict. - """) - NotRequired = _RequiredForm( - 'NotRequired', - doc="""A special typing construct to mark a key of a TypedDict as - potentially missing. For example: - - class Movie(TypedDict): - title: str - year: NotRequired[int] - - m = Movie( - title='The Matrix', # typechecker error if key is omitted - year=1999, - ) - """) -else: - # NOTE: Modeled after _Final's implementation when _FinalTypingBase available - class _MaybeRequired(typing._FinalTypingBase, _root=True): - __slots__ = ('__type__',) - - def __init__(self, tp=None, **kwds): - self.__type__ = tp - - def __getitem__(self, item): - cls = type(self) - if self.__type__ is None: - return cls(typing._type_check(item, - '{} accepts only single type.'.format(cls.__name__[1:])), - _root=True) - raise TypeError('{} cannot be further subscripted' - .format(cls.__name__[1:])) - - def _eval_type(self, globalns, localns): - new_tp = typing._eval_type(self.__type__, globalns, localns) - if new_tp == self.__type__: - return self - return type(self)(new_tp, _root=True) - - def __repr__(self): - r = super().__repr__() - if self.__type__ is not None: - r += '[{}]'.format(typing._type_repr(self.__type__)) - return r - - def __hash__(self): - return hash((type(self).__name__, self.__type__)) - - def __eq__(self, other): - if not isinstance(other, type(self)): - return NotImplemented - if self.__type__ is not None: - return self.__type__ == other.__type__ - return self is other - - class _Required(_MaybeRequired, _root=True): - """A special typing construct to mark a key of a total=False TypedDict - as required. For example: - - class Movie(TypedDict, total=False): - title: Required[str] - year: int - - m = Movie( - title='The Matrix', # typechecker error if key is omitted - year=1999, - ) - - There is no runtime checking that a required key is actually provided - when instantiating a related TypedDict. - """ - - class _NotRequired(_MaybeRequired, _root=True): - """A special typing construct to mark a key of a TypedDict as - potentially missing. For example: - - class Movie(TypedDict): - title: str - year: NotRequired[int] - - m = Movie( - title='The Matrix', # typechecker error if key is omitted - year=1999, - ) - """ - - Required = _Required(_root=True) - NotRequired = _NotRequired(_root=True) diff --git a/venv/lib/python3.11/site-packages/setuptools/_vendor/zipp.py b/venv/lib/python3.11/site-packages/setuptools/_vendor/zipp.py deleted file mode 100755 index 26b723c..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/_vendor/zipp.py +++ /dev/null @@ -1,329 +0,0 @@ -import io -import posixpath -import zipfile -import itertools -import contextlib -import sys -import pathlib - -if sys.version_info < (3, 7): - from collections import OrderedDict -else: - OrderedDict = dict - - -__all__ = ['Path'] - - -def _parents(path): - """ - Given a path with elements separated by - posixpath.sep, generate all parents of that path. - - >>> list(_parents('b/d')) - ['b'] - >>> list(_parents('/b/d/')) - ['/b'] - >>> list(_parents('b/d/f/')) - ['b/d', 'b'] - >>> list(_parents('b')) - [] - >>> list(_parents('')) - [] - """ - return itertools.islice(_ancestry(path), 1, None) - - -def _ancestry(path): - """ - Given a path with elements separated by - posixpath.sep, generate all elements of that path - - >>> list(_ancestry('b/d')) - ['b/d', 'b'] - >>> list(_ancestry('/b/d/')) - ['/b/d', '/b'] - >>> list(_ancestry('b/d/f/')) - ['b/d/f', 'b/d', 'b'] - >>> list(_ancestry('b')) - ['b'] - >>> list(_ancestry('')) - [] - """ - path = path.rstrip(posixpath.sep) - while path and path != posixpath.sep: - yield path - path, tail = posixpath.split(path) - - -_dedupe = OrderedDict.fromkeys -"""Deduplicate an iterable in original order""" - - -def _difference(minuend, subtrahend): - """ - Return items in minuend not in subtrahend, retaining order - with O(1) lookup. - """ - return itertools.filterfalse(set(subtrahend).__contains__, minuend) - - -class CompleteDirs(zipfile.ZipFile): - """ - A ZipFile subclass that ensures that implied directories - are always included in the namelist. - """ - - @staticmethod - def _implied_dirs(names): - parents = itertools.chain.from_iterable(map(_parents, names)) - as_dirs = (p + posixpath.sep for p in parents) - return _dedupe(_difference(as_dirs, names)) - - def namelist(self): - names = super(CompleteDirs, self).namelist() - return names + list(self._implied_dirs(names)) - - def _name_set(self): - return set(self.namelist()) - - def resolve_dir(self, name): - """ - If the name represents a directory, return that name - as a directory (with the trailing slash). - """ - names = self._name_set() - dirname = name + '/' - dir_match = name not in names and dirname in names - return dirname if dir_match else name - - @classmethod - def make(cls, source): - """ - Given a source (filename or zipfile), return an - appropriate CompleteDirs subclass. - """ - if isinstance(source, CompleteDirs): - return source - - if not isinstance(source, zipfile.ZipFile): - return cls(_pathlib_compat(source)) - - # Only allow for FastLookup when supplied zipfile is read-only - if 'r' not in source.mode: - cls = CompleteDirs - - source.__class__ = cls - return source - - -class FastLookup(CompleteDirs): - """ - ZipFile subclass to ensure implicit - dirs exist and are resolved rapidly. - """ - - def namelist(self): - with contextlib.suppress(AttributeError): - return self.__names - self.__names = super(FastLookup, self).namelist() - return self.__names - - def _name_set(self): - with contextlib.suppress(AttributeError): - return self.__lookup - self.__lookup = super(FastLookup, self)._name_set() - return self.__lookup - - -def _pathlib_compat(path): - """ - For path-like objects, convert to a filename for compatibility - on Python 3.6.1 and earlier. - """ - try: - return path.__fspath__() - except AttributeError: - return str(path) - - -class Path: - """ - A pathlib-compatible interface for zip files. - - Consider a zip file with this structure:: - - . - ├── a.txt - └── b - ├── c.txt - └── d - └── e.txt - - >>> data = io.BytesIO() - >>> zf = zipfile.ZipFile(data, 'w') - >>> zf.writestr('a.txt', 'content of a') - >>> zf.writestr('b/c.txt', 'content of c') - >>> zf.writestr('b/d/e.txt', 'content of e') - >>> zf.filename = 'mem/abcde.zip' - - Path accepts the zipfile object itself or a filename - - >>> root = Path(zf) - - From there, several path operations are available. - - Directory iteration (including the zip file itself): - - >>> a, b = root.iterdir() - >>> a - Path('mem/abcde.zip', 'a.txt') - >>> b - Path('mem/abcde.zip', 'b/') - - name property: - - >>> b.name - 'b' - - join with divide operator: - - >>> c = b / 'c.txt' - >>> c - Path('mem/abcde.zip', 'b/c.txt') - >>> c.name - 'c.txt' - - Read text: - - >>> c.read_text() - 'content of c' - - existence: - - >>> c.exists() - True - >>> (b / 'missing.txt').exists() - False - - Coercion to string: - - >>> import os - >>> str(c).replace(os.sep, posixpath.sep) - 'mem/abcde.zip/b/c.txt' - - At the root, ``name``, ``filename``, and ``parent`` - resolve to the zipfile. Note these attributes are not - valid and will raise a ``ValueError`` if the zipfile - has no filename. - - >>> root.name - 'abcde.zip' - >>> str(root.filename).replace(os.sep, posixpath.sep) - 'mem/abcde.zip' - >>> str(root.parent) - 'mem' - """ - - __repr = "{self.__class__.__name__}({self.root.filename!r}, {self.at!r})" - - def __init__(self, root, at=""): - """ - Construct a Path from a ZipFile or filename. - - Note: When the source is an existing ZipFile object, - its type (__class__) will be mutated to a - specialized type. If the caller wishes to retain the - original type, the caller should either create a - separate ZipFile object or pass a filename. - """ - self.root = FastLookup.make(root) - self.at = at - - def open(self, mode='r', *args, pwd=None, **kwargs): - """ - Open this entry as text or binary following the semantics - of ``pathlib.Path.open()`` by passing arguments through - to io.TextIOWrapper(). - """ - if self.is_dir(): - raise IsADirectoryError(self) - zip_mode = mode[0] - if not self.exists() and zip_mode == 'r': - raise FileNotFoundError(self) - stream = self.root.open(self.at, zip_mode, pwd=pwd) - if 'b' in mode: - if args or kwargs: - raise ValueError("encoding args invalid for binary operation") - return stream - return io.TextIOWrapper(stream, *args, **kwargs) - - @property - def name(self): - return pathlib.Path(self.at).name or self.filename.name - - @property - def suffix(self): - return pathlib.Path(self.at).suffix or self.filename.suffix - - @property - def suffixes(self): - return pathlib.Path(self.at).suffixes or self.filename.suffixes - - @property - def stem(self): - return pathlib.Path(self.at).stem or self.filename.stem - - @property - def filename(self): - return pathlib.Path(self.root.filename).joinpath(self.at) - - def read_text(self, *args, **kwargs): - with self.open('r', *args, **kwargs) as strm: - return strm.read() - - def read_bytes(self): - with self.open('rb') as strm: - return strm.read() - - def _is_child(self, path): - return posixpath.dirname(path.at.rstrip("/")) == self.at.rstrip("/") - - def _next(self, at): - return self.__class__(self.root, at) - - def is_dir(self): - return not self.at or self.at.endswith("/") - - def is_file(self): - return self.exists() and not self.is_dir() - - def exists(self): - return self.at in self.root._name_set() - - def iterdir(self): - if not self.is_dir(): - raise ValueError("Can't listdir a file") - subs = map(self._next, self.root.namelist()) - return filter(self._is_child, subs) - - def __str__(self): - return posixpath.join(self.root.filename, self.at) - - def __repr__(self): - return self.__repr.format(self=self) - - def joinpath(self, *other): - next = posixpath.join(self.at, *map(_pathlib_compat, other)) - return self._next(self.root.resolve_dir(next)) - - __truediv__ = joinpath - - @property - def parent(self): - if not self.at: - return self.filename.parent - parent_at = posixpath.dirname(self.at.rstrip('/')) - if parent_at: - parent_at += '/' - return self._next(parent_at) diff --git a/venv/lib/python3.11/site-packages/setuptools/archive_util.py b/venv/lib/python3.11/site-packages/setuptools/archive_util.py deleted file mode 100755 index d8e10c1..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/archive_util.py +++ /dev/null @@ -1,213 +0,0 @@ -"""Utilities for extracting common archive formats""" - -import zipfile -import tarfile -import os -import shutil -import posixpath -import contextlib -from distutils.errors import DistutilsError - -from ._path import ensure_directory - -__all__ = [ - "unpack_archive", "unpack_zipfile", "unpack_tarfile", "default_filter", - "UnrecognizedFormat", "extraction_drivers", "unpack_directory", -] - - -class UnrecognizedFormat(DistutilsError): - """Couldn't recognize the archive type""" - - -def default_filter(src, dst): - """The default progress/filter callback; returns True for all files""" - return dst - - -def unpack_archive( - filename, extract_dir, progress_filter=default_filter, - drivers=None): - """Unpack `filename` to `extract_dir`, or raise ``UnrecognizedFormat`` - - `progress_filter` is a function taking two arguments: a source path - internal to the archive ('/'-separated), and a filesystem path where it - will be extracted. The callback must return the desired extract path - (which may be the same as the one passed in), or else ``None`` to skip - that file or directory. The callback can thus be used to report on the - progress of the extraction, as well as to filter the items extracted or - alter their extraction paths. - - `drivers`, if supplied, must be a non-empty sequence of functions with the - same signature as this function (minus the `drivers` argument), that raise - ``UnrecognizedFormat`` if they do not support extracting the designated - archive type. The `drivers` are tried in sequence until one is found that - does not raise an error, or until all are exhausted (in which case - ``UnrecognizedFormat`` is raised). If you do not supply a sequence of - drivers, the module's ``extraction_drivers`` constant will be used, which - means that ``unpack_zipfile`` and ``unpack_tarfile`` will be tried, in that - order. - """ - for driver in drivers or extraction_drivers: - try: - driver(filename, extract_dir, progress_filter) - except UnrecognizedFormat: - continue - else: - return - else: - raise UnrecognizedFormat( - "Not a recognized archive type: %s" % filename - ) - - -def unpack_directory(filename, extract_dir, progress_filter=default_filter): - """"Unpack" a directory, using the same interface as for archives - - Raises ``UnrecognizedFormat`` if `filename` is not a directory - """ - if not os.path.isdir(filename): - raise UnrecognizedFormat("%s is not a directory" % filename) - - paths = { - filename: ('', extract_dir), - } - for base, dirs, files in os.walk(filename): - src, dst = paths[base] - for d in dirs: - paths[os.path.join(base, d)] = src + d + '/', os.path.join(dst, d) - for f in files: - target = os.path.join(dst, f) - target = progress_filter(src + f, target) - if not target: - # skip non-files - continue - ensure_directory(target) - f = os.path.join(base, f) - shutil.copyfile(f, target) - shutil.copystat(f, target) - - -def unpack_zipfile(filename, extract_dir, progress_filter=default_filter): - """Unpack zip `filename` to `extract_dir` - - Raises ``UnrecognizedFormat`` if `filename` is not a zipfile (as determined - by ``zipfile.is_zipfile()``). See ``unpack_archive()`` for an explanation - of the `progress_filter` argument. - """ - - if not zipfile.is_zipfile(filename): - raise UnrecognizedFormat("%s is not a zip file" % (filename,)) - - with zipfile.ZipFile(filename) as z: - _unpack_zipfile_obj(z, extract_dir, progress_filter) - - -def _unpack_zipfile_obj(zipfile_obj, extract_dir, progress_filter=default_filter): - """Internal/private API used by other parts of setuptools. - Similar to ``unpack_zipfile``, but receives an already opened :obj:`zipfile.ZipFile` - object instead of a filename. - """ - for info in zipfile_obj.infolist(): - name = info.filename - - # don't extract absolute paths or ones with .. in them - if name.startswith('/') or '..' in name.split('/'): - continue - - target = os.path.join(extract_dir, *name.split('/')) - target = progress_filter(name, target) - if not target: - continue - if name.endswith('/'): - # directory - ensure_directory(target) - else: - # file - ensure_directory(target) - data = zipfile_obj.read(info.filename) - with open(target, 'wb') as f: - f.write(data) - unix_attributes = info.external_attr >> 16 - if unix_attributes: - os.chmod(target, unix_attributes) - - -def _resolve_tar_file_or_dir(tar_obj, tar_member_obj): - """Resolve any links and extract link targets as normal files.""" - while tar_member_obj is not None and ( - tar_member_obj.islnk() or tar_member_obj.issym()): - linkpath = tar_member_obj.linkname - if tar_member_obj.issym(): - base = posixpath.dirname(tar_member_obj.name) - linkpath = posixpath.join(base, linkpath) - linkpath = posixpath.normpath(linkpath) - tar_member_obj = tar_obj._getmember(linkpath) - - is_file_or_dir = ( - tar_member_obj is not None and - (tar_member_obj.isfile() or tar_member_obj.isdir()) - ) - if is_file_or_dir: - return tar_member_obj - - raise LookupError('Got unknown file type') - - -def _iter_open_tar(tar_obj, extract_dir, progress_filter): - """Emit member-destination pairs from a tar archive.""" - # don't do any chowning! - tar_obj.chown = lambda *args: None - - with contextlib.closing(tar_obj): - for member in tar_obj: - name = member.name - # don't extract absolute paths or ones with .. in them - if name.startswith('/') or '..' in name.split('/'): - continue - - prelim_dst = os.path.join(extract_dir, *name.split('/')) - - try: - member = _resolve_tar_file_or_dir(tar_obj, member) - except LookupError: - continue - - final_dst = progress_filter(name, prelim_dst) - if not final_dst: - continue - - if final_dst.endswith(os.sep): - final_dst = final_dst[:-1] - - yield member, final_dst - - -def unpack_tarfile(filename, extract_dir, progress_filter=default_filter): - """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir` - - Raises ``UnrecognizedFormat`` if `filename` is not a tarfile (as determined - by ``tarfile.open()``). See ``unpack_archive()`` for an explanation - of the `progress_filter` argument. - """ - try: - tarobj = tarfile.open(filename) - except tarfile.TarError as e: - raise UnrecognizedFormat( - "%s is not a compressed or uncompressed tar file" % (filename,) - ) from e - - for member, final_dst in _iter_open_tar( - tarobj, extract_dir, progress_filter, - ): - try: - # XXX Ugh - tarobj._extract_member(member, final_dst) - except tarfile.ExtractError: - # chown/chmod/mkfifo/mknode/makedev failed - pass - - return True - - -extraction_drivers = unpack_directory, unpack_zipfile, unpack_tarfile diff --git a/venv/lib/python3.11/site-packages/setuptools/build_meta.py b/venv/lib/python3.11/site-packages/setuptools/build_meta.py deleted file mode 100755 index 1fb4c3b..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/build_meta.py +++ /dev/null @@ -1,512 +0,0 @@ -"""A PEP 517 interface to setuptools - -Previously, when a user or a command line tool (let's call it a "frontend") -needed to make a request of setuptools to take a certain action, for -example, generating a list of installation requirements, the frontend would -would call "setup.py egg_info" or "setup.py bdist_wheel" on the command line. - -PEP 517 defines a different method of interfacing with setuptools. Rather -than calling "setup.py" directly, the frontend should: - - 1. Set the current directory to the directory with a setup.py file - 2. Import this module into a safe python interpreter (one in which - setuptools can potentially set global variables or crash hard). - 3. Call one of the functions defined in PEP 517. - -What each function does is defined in PEP 517. However, here is a "casual" -definition of the functions (this definition should not be relied on for -bug reports or API stability): - - - `build_wheel`: build a wheel in the folder and return the basename - - `get_requires_for_build_wheel`: get the `setup_requires` to build - - `prepare_metadata_for_build_wheel`: get the `install_requires` - - `build_sdist`: build an sdist in the folder and return the basename - - `get_requires_for_build_sdist`: get the `setup_requires` to build - -Again, this is not a formal definition! Just a "taste" of the module. -""" - -import io -import os -import shlex -import sys -import tokenize -import shutil -import contextlib -import tempfile -import warnings -from pathlib import Path -from typing import Dict, Iterator, List, Optional, Union - -import setuptools -import distutils -from . import errors -from ._path import same_path -from ._reqs import parse_strings -from ._deprecation_warning import SetuptoolsDeprecationWarning -from distutils.util import strtobool - - -__all__ = ['get_requires_for_build_sdist', - 'get_requires_for_build_wheel', - 'prepare_metadata_for_build_wheel', - 'build_wheel', - 'build_sdist', - 'get_requires_for_build_editable', - 'prepare_metadata_for_build_editable', - 'build_editable', - '__legacy__', - 'SetupRequirementsError'] - -SETUPTOOLS_ENABLE_FEATURES = os.getenv("SETUPTOOLS_ENABLE_FEATURES", "").lower() -LEGACY_EDITABLE = "legacy-editable" in SETUPTOOLS_ENABLE_FEATURES.replace("_", "-") - - -class SetupRequirementsError(BaseException): - def __init__(self, specifiers): - self.specifiers = specifiers - - -class Distribution(setuptools.dist.Distribution): - def fetch_build_eggs(self, specifiers): - specifier_list = list(parse_strings(specifiers)) - - raise SetupRequirementsError(specifier_list) - - @classmethod - @contextlib.contextmanager - def patch(cls): - """ - Replace - distutils.dist.Distribution with this class - for the duration of this context. - """ - orig = distutils.core.Distribution - distutils.core.Distribution = cls - try: - yield - finally: - distutils.core.Distribution = orig - - -@contextlib.contextmanager -def no_install_setup_requires(): - """Temporarily disable installing setup_requires - - Under PEP 517, the backend reports build dependencies to the frontend, - and the frontend is responsible for ensuring they're installed. - So setuptools (acting as a backend) should not try to install them. - """ - orig = setuptools._install_setup_requires - setuptools._install_setup_requires = lambda attrs: None - try: - yield - finally: - setuptools._install_setup_requires = orig - - -def _get_immediate_subdirectories(a_dir): - return [name for name in os.listdir(a_dir) - if os.path.isdir(os.path.join(a_dir, name))] - - -def _file_with_extension(directory, extension): - matching = ( - f for f in os.listdir(directory) - if f.endswith(extension) - ) - try: - file, = matching - except ValueError: - raise ValueError( - 'No distribution was found. Ensure that `setup.py` ' - 'is not empty and that it calls `setup()`.') - return file - - -def _open_setup_script(setup_script): - if not os.path.exists(setup_script): - # Supply a default setup.py - return io.StringIO(u"from setuptools import setup; setup()") - - return getattr(tokenize, 'open', open)(setup_script) - - -@contextlib.contextmanager -def suppress_known_deprecation(): - with warnings.catch_warnings(): - warnings.filterwarnings('ignore', 'setup.py install is deprecated') - yield - - -_ConfigSettings = Optional[Dict[str, Union[str, List[str], None]]] -""" -Currently the user can run:: - - pip install -e . --config-settings key=value - python -m build -C--key=value -C key=value - -- pip will pass both key and value as strings and overwriting repeated keys - (pypa/pip#11059). -- build will accumulate values associated with repeated keys in a list. - It will also accept keys with no associated value. - This means that an option passed by build can be ``str | list[str] | None``. -- PEP 517 specifies that ``config_settings`` is an optional dict. -""" - - -class _ConfigSettingsTranslator: - """Translate ``config_settings`` into distutils-style command arguments. - Only a limited number of options is currently supported. - """ - # See pypa/setuptools#1928 pypa/setuptools#2491 - - def _get_config(self, key: str, config_settings: _ConfigSettings) -> List[str]: - """ - Get the value of a specific key in ``config_settings`` as a list of strings. - - >>> fn = _ConfigSettingsTranslator()._get_config - >>> fn("--global-option", None) - [] - >>> fn("--global-option", {}) - [] - >>> fn("--global-option", {'--global-option': 'foo'}) - ['foo'] - >>> fn("--global-option", {'--global-option': ['foo']}) - ['foo'] - >>> fn("--global-option", {'--global-option': 'foo'}) - ['foo'] - >>> fn("--global-option", {'--global-option': 'foo bar'}) - ['foo', 'bar'] - """ - cfg = config_settings or {} - opts = cfg.get(key) or [] - return shlex.split(opts) if isinstance(opts, str) else opts - - def _valid_global_options(self): - """Global options accepted by setuptools (e.g. quiet or verbose).""" - options = (opt[:2] for opt in setuptools.dist.Distribution.global_options) - return {flag for long_and_short in options for flag in long_and_short if flag} - - def _global_args(self, config_settings: _ConfigSettings) -> Iterator[str]: - """ - Let the user specify ``verbose`` or ``quiet`` + escape hatch via - ``--global-option``. - Note: ``-v``, ``-vv``, ``-vvv`` have similar effects in setuptools, - so we just have to cover the basic scenario ``-v``. - - >>> fn = _ConfigSettingsTranslator()._global_args - >>> list(fn(None)) - [] - >>> list(fn({"verbose": "False"})) - ['-q'] - >>> list(fn({"verbose": "1"})) - ['-v'] - >>> list(fn({"--verbose": None})) - ['-v'] - >>> list(fn({"verbose": "true", "--global-option": "-q --no-user-cfg"})) - ['-v', '-q', '--no-user-cfg'] - >>> list(fn({"--quiet": None})) - ['-q'] - """ - cfg = config_settings or {} - falsey = {"false", "no", "0", "off"} - if "verbose" in cfg or "--verbose" in cfg: - level = str(cfg.get("verbose") or cfg.get("--verbose") or "1") - yield ("-q" if level.lower() in falsey else "-v") - if "quiet" in cfg or "--quiet" in cfg: - level = str(cfg.get("quiet") or cfg.get("--quiet") or "1") - yield ("-v" if level.lower() in falsey else "-q") - - valid = self._valid_global_options() - args = self._get_config("--global-option", config_settings) - yield from (arg for arg in args if arg.strip("-") in valid) - - def __dist_info_args(self, config_settings: _ConfigSettings) -> Iterator[str]: - """ - The ``dist_info`` command accepts ``tag-date`` and ``tag-build``. - - .. warning:: - We cannot use this yet as it requires the ``sdist`` and ``bdist_wheel`` - commands run in ``build_sdist`` and ``build_wheel`` to re-use the egg-info - directory created in ``prepare_metadata_for_build_wheel``. - - >>> fn = _ConfigSettingsTranslator()._ConfigSettingsTranslator__dist_info_args - >>> list(fn(None)) - [] - >>> list(fn({"tag-date": "False"})) - ['--no-date'] - >>> list(fn({"tag-date": None})) - ['--no-date'] - >>> list(fn({"tag-date": "true", "tag-build": ".a"})) - ['--tag-date', '--tag-build', '.a'] - """ - cfg = config_settings or {} - if "tag-date" in cfg: - val = strtobool(str(cfg["tag-date"] or "false")) - yield ("--tag-date" if val else "--no-date") - if "tag-build" in cfg: - yield from ["--tag-build", str(cfg["tag-build"])] - - def _editable_args(self, config_settings: _ConfigSettings) -> Iterator[str]: - """ - The ``editable_wheel`` command accepts ``editable-mode=strict``. - - >>> fn = _ConfigSettingsTranslator()._editable_args - >>> list(fn(None)) - [] - >>> list(fn({"editable-mode": "strict"})) - ['--mode', 'strict'] - """ - cfg = config_settings or {} - mode = cfg.get("editable-mode") or cfg.get("editable_mode") - if not mode: - return - yield from ["--mode", str(mode)] - - def _arbitrary_args(self, config_settings: _ConfigSettings) -> Iterator[str]: - """ - Users may expect to pass arbitrary lists of arguments to a command - via "--global-option" (example provided in PEP 517 of a "escape hatch"). - - >>> fn = _ConfigSettingsTranslator()._arbitrary_args - >>> list(fn(None)) - [] - >>> list(fn({})) - [] - >>> list(fn({'--build-option': 'foo'})) - ['foo'] - >>> list(fn({'--build-option': ['foo']})) - ['foo'] - >>> list(fn({'--build-option': 'foo'})) - ['foo'] - >>> list(fn({'--build-option': 'foo bar'})) - ['foo', 'bar'] - >>> warnings.simplefilter('error', SetuptoolsDeprecationWarning) - >>> list(fn({'--global-option': 'foo'})) # doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - SetuptoolsDeprecationWarning: ...arguments given via `--global-option`... - """ - args = self._get_config("--global-option", config_settings) - global_opts = self._valid_global_options() - bad_args = [] - - for arg in args: - if arg.strip("-") not in global_opts: - bad_args.append(arg) - yield arg - - yield from self._get_config("--build-option", config_settings) - - if bad_args: - msg = f""" - The arguments {bad_args!r} were given via `--global-option`. - Please use `--build-option` instead, - `--global-option` is reserved to flags like `--verbose` or `--quiet`. - """ - warnings.warn(msg, SetuptoolsDeprecationWarning) - - -class _BuildMetaBackend(_ConfigSettingsTranslator): - def _get_build_requires(self, config_settings, requirements): - sys.argv = [ - *sys.argv[:1], - *self._global_args(config_settings), - "egg_info", - *self._arbitrary_args(config_settings), - ] - try: - with Distribution.patch(): - self.run_setup() - except SetupRequirementsError as e: - requirements += e.specifiers - - return requirements - - def run_setup(self, setup_script='setup.py'): - # Note that we can reuse our build directory between calls - # Correctness comes first, then optimization later - __file__ = setup_script - __name__ = '__main__' - - with _open_setup_script(__file__) as f: - code = f.read().replace(r'\r\n', r'\n') - - exec(code, locals()) - - def get_requires_for_build_wheel(self, config_settings=None): - return self._get_build_requires(config_settings, requirements=['wheel']) - - def get_requires_for_build_sdist(self, config_settings=None): - return self._get_build_requires(config_settings, requirements=[]) - - def _bubble_up_info_directory(self, metadata_directory: str, suffix: str) -> str: - """ - PEP 517 requires that the .dist-info directory be placed in the - metadata_directory. To comply, we MUST copy the directory to the root. - - Returns the basename of the info directory, e.g. `proj-0.0.0.dist-info`. - """ - info_dir = self._find_info_directory(metadata_directory, suffix) - if not same_path(info_dir.parent, metadata_directory): - shutil.move(str(info_dir), metadata_directory) - # PEP 517 allow other files and dirs to exist in metadata_directory - return info_dir.name - - def _find_info_directory(self, metadata_directory: str, suffix: str) -> Path: - for parent, dirs, _ in os.walk(metadata_directory): - candidates = [f for f in dirs if f.endswith(suffix)] - - if len(candidates) != 0 or len(dirs) != 1: - assert len(candidates) == 1, f"Multiple {suffix} directories found" - return Path(parent, candidates[0]) - - msg = f"No {suffix} directory found in {metadata_directory}" - raise errors.InternalError(msg) - - def prepare_metadata_for_build_wheel(self, metadata_directory, - config_settings=None): - sys.argv = [ - *sys.argv[:1], - *self._global_args(config_settings), - "dist_info", - "--output-dir", metadata_directory, - "--keep-egg-info", - ] - with no_install_setup_requires(): - self.run_setup() - - self._bubble_up_info_directory(metadata_directory, ".egg-info") - return self._bubble_up_info_directory(metadata_directory, ".dist-info") - - def _build_with_temp_dir(self, setup_command, result_extension, - result_directory, config_settings): - result_directory = os.path.abspath(result_directory) - - # Build in a temporary directory, then copy to the target. - os.makedirs(result_directory, exist_ok=True) - temp_opts = {"prefix": ".tmp-", "dir": result_directory} - with tempfile.TemporaryDirectory(**temp_opts) as tmp_dist_dir: - sys.argv = [ - *sys.argv[:1], - *self._global_args(config_settings), - *setup_command, - "--dist-dir", tmp_dist_dir, - *self._arbitrary_args(config_settings), - ] - with no_install_setup_requires(): - self.run_setup() - - result_basename = _file_with_extension( - tmp_dist_dir, result_extension) - result_path = os.path.join(result_directory, result_basename) - if os.path.exists(result_path): - # os.rename will fail overwriting on non-Unix. - os.remove(result_path) - os.rename(os.path.join(tmp_dist_dir, result_basename), result_path) - - return result_basename - - def build_wheel(self, wheel_directory, config_settings=None, - metadata_directory=None): - with suppress_known_deprecation(): - return self._build_with_temp_dir(['bdist_wheel'], '.whl', - wheel_directory, config_settings) - - def build_sdist(self, sdist_directory, config_settings=None): - return self._build_with_temp_dir(['sdist', '--formats', 'gztar'], - '.tar.gz', sdist_directory, - config_settings) - - def _get_dist_info_dir(self, metadata_directory: Optional[str]) -> Optional[str]: - if not metadata_directory: - return None - dist_info_candidates = list(Path(metadata_directory).glob("*.dist-info")) - assert len(dist_info_candidates) <= 1 - return str(dist_info_candidates[0]) if dist_info_candidates else None - - if not LEGACY_EDITABLE: - - # PEP660 hooks: - # build_editable - # get_requires_for_build_editable - # prepare_metadata_for_build_editable - def build_editable( - self, wheel_directory, config_settings=None, metadata_directory=None - ): - # XXX can or should we hide our editable_wheel command normally? - info_dir = self._get_dist_info_dir(metadata_directory) - opts = ["--dist-info-dir", info_dir] if info_dir else [] - cmd = ["editable_wheel", *opts, *self._editable_args(config_settings)] - with suppress_known_deprecation(): - return self._build_with_temp_dir( - cmd, ".whl", wheel_directory, config_settings - ) - - def get_requires_for_build_editable(self, config_settings=None): - return self.get_requires_for_build_wheel(config_settings) - - def prepare_metadata_for_build_editable(self, metadata_directory, - config_settings=None): - return self.prepare_metadata_for_build_wheel( - metadata_directory, config_settings - ) - - -class _BuildMetaLegacyBackend(_BuildMetaBackend): - """Compatibility backend for setuptools - - This is a version of setuptools.build_meta that endeavors - to maintain backwards - compatibility with pre-PEP 517 modes of invocation. It - exists as a temporary - bridge between the old packaging mechanism and the new - packaging mechanism, - and will eventually be removed. - """ - def run_setup(self, setup_script='setup.py'): - # In order to maintain compatibility with scripts assuming that - # the setup.py script is in a directory on the PYTHONPATH, inject - # '' into sys.path. (pypa/setuptools#1642) - sys_path = list(sys.path) # Save the original path - - script_dir = os.path.dirname(os.path.abspath(setup_script)) - if script_dir not in sys.path: - sys.path.insert(0, script_dir) - - # Some setup.py scripts (e.g. in pygame and numpy) use sys.argv[0] to - # get the directory of the source code. They expect it to refer to the - # setup.py script. - sys_argv_0 = sys.argv[0] - sys.argv[0] = setup_script - - try: - super(_BuildMetaLegacyBackend, - self).run_setup(setup_script=setup_script) - finally: - # While PEP 517 frontends should be calling each hook in a fresh - # subprocess according to the standard (and thus it should not be - # strictly necessary to restore the old sys.path), we'll restore - # the original path so that the path manipulation does not persist - # within the hook after run_setup is called. - sys.path[:] = sys_path - sys.argv[0] = sys_argv_0 - - -# The primary backend -_BACKEND = _BuildMetaBackend() - -get_requires_for_build_wheel = _BACKEND.get_requires_for_build_wheel -get_requires_for_build_sdist = _BACKEND.get_requires_for_build_sdist -prepare_metadata_for_build_wheel = _BACKEND.prepare_metadata_for_build_wheel -build_wheel = _BACKEND.build_wheel -build_sdist = _BACKEND.build_sdist - -if not LEGACY_EDITABLE: - get_requires_for_build_editable = _BACKEND.get_requires_for_build_editable - prepare_metadata_for_build_editable = _BACKEND.prepare_metadata_for_build_editable - build_editable = _BACKEND.build_editable - - -# The legacy backend -__legacy__ = _BuildMetaLegacyBackend() diff --git a/venv/lib/python3.11/site-packages/setuptools/cli-32.exe b/venv/lib/python3.11/site-packages/setuptools/cli-32.exe deleted file mode 100755 index b1487b7..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/cli-32.exe and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/cli-64.exe b/venv/lib/python3.11/site-packages/setuptools/cli-64.exe deleted file mode 100755 index 675e6bf..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/cli-64.exe and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/cli-arm64.exe b/venv/lib/python3.11/site-packages/setuptools/cli-arm64.exe deleted file mode 100755 index 7a87ce4..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/cli-arm64.exe and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/cli.exe b/venv/lib/python3.11/site-packages/setuptools/cli.exe deleted file mode 100755 index b1487b7..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/cli.exe and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__init__.py b/venv/lib/python3.11/site-packages/setuptools/command/__init__.py deleted file mode 100755 index 5acd768..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -from distutils.command.bdist import bdist -import sys - -if 'egg' not in bdist.format_commands: - try: - bdist.format_commands['egg'] = ('bdist_egg', "Python .egg file") - except TypeError: - # For backward compatibility with older distutils (stdlib) - bdist.format_command['egg'] = ('bdist_egg', "Python .egg file") - bdist.format_commands.append('egg') - -del bdist, sys diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index 8e1c461..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/alias.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/alias.cpython-311.pyc deleted file mode 100755 index 5f70bcd..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/alias.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/bdist_egg.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/bdist_egg.cpython-311.pyc deleted file mode 100755 index a516a11..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/bdist_egg.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/bdist_rpm.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/bdist_rpm.cpython-311.pyc deleted file mode 100755 index 33962ab..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/bdist_rpm.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/build.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/build.cpython-311.pyc deleted file mode 100755 index 2d194b1..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/build.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/build_clib.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/build_clib.cpython-311.pyc deleted file mode 100755 index 63a0163..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/build_clib.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/build_ext.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/build_ext.cpython-311.pyc deleted file mode 100755 index b91b53e..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/build_ext.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/build_py.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/build_py.cpython-311.pyc deleted file mode 100755 index e733cd6..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/build_py.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/develop.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/develop.cpython-311.pyc deleted file mode 100755 index 228a27f..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/develop.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/dist_info.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/dist_info.cpython-311.pyc deleted file mode 100755 index c0149f2..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/dist_info.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/easy_install.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/easy_install.cpython-311.pyc deleted file mode 100755 index fc68381..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/easy_install.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/editable_wheel.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/editable_wheel.cpython-311.pyc deleted file mode 100755 index 70b9b70..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/editable_wheel.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/egg_info.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/egg_info.cpython-311.pyc deleted file mode 100755 index 5a9e4ac..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/egg_info.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/install.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/install.cpython-311.pyc deleted file mode 100755 index 6d932dd..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/install.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/install_egg_info.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/install_egg_info.cpython-311.pyc deleted file mode 100755 index 8bb5fa1..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/install_egg_info.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/install_lib.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/install_lib.cpython-311.pyc deleted file mode 100755 index 98be08b..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/install_lib.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/install_scripts.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/install_scripts.cpython-311.pyc deleted file mode 100755 index b64b42d..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/install_scripts.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/py36compat.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/py36compat.cpython-311.pyc deleted file mode 100755 index 59c4872..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/py36compat.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/register.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/register.cpython-311.pyc deleted file mode 100755 index 50aa3e0..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/register.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/rotate.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/rotate.cpython-311.pyc deleted file mode 100755 index 5f4d083..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/rotate.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/saveopts.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/saveopts.cpython-311.pyc deleted file mode 100755 index 5f1f106..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/saveopts.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/sdist.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/sdist.cpython-311.pyc deleted file mode 100755 index c95532c..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/sdist.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/setopt.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/setopt.cpython-311.pyc deleted file mode 100755 index fb27e21..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/setopt.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/test.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/test.cpython-311.pyc deleted file mode 100755 index 7544506..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/test.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/upload.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/upload.cpython-311.pyc deleted file mode 100755 index 8416a71..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/upload.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/upload_docs.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/upload_docs.cpython-311.pyc deleted file mode 100755 index 781ab4e..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/command/__pycache__/upload_docs.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/alias.py b/venv/lib/python3.11/site-packages/setuptools/command/alias.py deleted file mode 100755 index 452a924..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/alias.py +++ /dev/null @@ -1,78 +0,0 @@ -from distutils.errors import DistutilsOptionError - -from setuptools.command.setopt import edit_config, option_base, config_file - - -def shquote(arg): - """Quote an argument for later parsing by shlex.split()""" - for c in '"', "'", "\\", "#": - if c in arg: - return repr(arg) - if arg.split() != [arg]: - return repr(arg) - return arg - - -class alias(option_base): - """Define a shortcut that invokes one or more commands""" - - description = "define a shortcut to invoke one or more commands" - command_consumes_arguments = True - - user_options = [ - ('remove', 'r', 'remove (unset) the alias'), - ] + option_base.user_options - - boolean_options = option_base.boolean_options + ['remove'] - - def initialize_options(self): - option_base.initialize_options(self) - self.args = None - self.remove = None - - def finalize_options(self): - option_base.finalize_options(self) - if self.remove and len(self.args) != 1: - raise DistutilsOptionError( - "Must specify exactly one argument (the alias name) when " - "using --remove" - ) - - def run(self): - aliases = self.distribution.get_option_dict('aliases') - - if not self.args: - print("Command Aliases") - print("---------------") - for alias in aliases: - print("setup.py alias", format_alias(alias, aliases)) - return - - elif len(self.args) == 1: - alias, = self.args - if self.remove: - command = None - elif alias in aliases: - print("setup.py alias", format_alias(alias, aliases)) - return - else: - print("No alias definition found for %r" % alias) - return - else: - alias = self.args[0] - command = ' '.join(map(shquote, self.args[1:])) - - edit_config(self.filename, {'aliases': {alias: command}}, self.dry_run) - - -def format_alias(name, aliases): - source, command = aliases[name] - if source == config_file('global'): - source = '--global-config ' - elif source == config_file('user'): - source = '--user-config ' - elif source == config_file('local'): - source = '' - else: - source = '--filename=%r' % source - return source + name + ' ' + command diff --git a/venv/lib/python3.11/site-packages/setuptools/command/bdist_egg.py b/venv/lib/python3.11/site-packages/setuptools/command/bdist_egg.py deleted file mode 100755 index 11a1c6b..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/bdist_egg.py +++ /dev/null @@ -1,457 +0,0 @@ -"""setuptools.command.bdist_egg - -Build .egg distributions""" - -from distutils.dir_util import remove_tree, mkpath -from distutils import log -from types import CodeType -import sys -import os -import re -import textwrap -import marshal - -from pkg_resources import get_build_platform, Distribution -from setuptools.extension import Library -from setuptools import Command -from .._path import ensure_directory - -from sysconfig import get_path, get_python_version - - -def _get_purelib(): - return get_path("purelib") - - -def strip_module(filename): - if '.' in filename: - filename = os.path.splitext(filename)[0] - if filename.endswith('module'): - filename = filename[:-6] - return filename - - -def sorted_walk(dir): - """Do os.walk in a reproducible way, - independent of indeterministic filesystem readdir order - """ - for base, dirs, files in os.walk(dir): - dirs.sort() - files.sort() - yield base, dirs, files - - -def write_stub(resource, pyfile): - _stub_template = textwrap.dedent(""" - def __bootstrap__(): - global __bootstrap__, __loader__, __file__ - import sys, pkg_resources, importlib.util - __file__ = pkg_resources.resource_filename(__name__, %r) - __loader__ = None; del __bootstrap__, __loader__ - spec = importlib.util.spec_from_file_location(__name__,__file__) - mod = importlib.util.module_from_spec(spec) - spec.loader.exec_module(mod) - __bootstrap__() - """).lstrip() - with open(pyfile, 'w') as f: - f.write(_stub_template % resource) - - -class bdist_egg(Command): - description = "create an \"egg\" distribution" - - user_options = [ - ('bdist-dir=', 'b', - "temporary directory for creating the distribution"), - ('plat-name=', 'p', "platform name to embed in generated filenames " - "(default: %s)" % get_build_platform()), - ('exclude-source-files', None, - "remove all .py files from the generated egg"), - ('keep-temp', 'k', - "keep the pseudo-installation tree around after " + - "creating the distribution archive"), - ('dist-dir=', 'd', - "directory to put final built distributions in"), - ('skip-build', None, - "skip rebuilding everything (for testing/debugging)"), - ] - - boolean_options = [ - 'keep-temp', 'skip-build', 'exclude-source-files' - ] - - def initialize_options(self): - self.bdist_dir = None - self.plat_name = None - self.keep_temp = 0 - self.dist_dir = None - self.skip_build = 0 - self.egg_output = None - self.exclude_source_files = None - - def finalize_options(self): - ei_cmd = self.ei_cmd = self.get_finalized_command("egg_info") - self.egg_info = ei_cmd.egg_info - - if self.bdist_dir is None: - bdist_base = self.get_finalized_command('bdist').bdist_base - self.bdist_dir = os.path.join(bdist_base, 'egg') - - if self.plat_name is None: - self.plat_name = get_build_platform() - - self.set_undefined_options('bdist', ('dist_dir', 'dist_dir')) - - if self.egg_output is None: - - # Compute filename of the output egg - basename = Distribution( - None, None, ei_cmd.egg_name, ei_cmd.egg_version, - get_python_version(), - self.distribution.has_ext_modules() and self.plat_name - ).egg_name() - - self.egg_output = os.path.join(self.dist_dir, basename + '.egg') - - def do_install_data(self): - # Hack for packages that install data to install's --install-lib - self.get_finalized_command('install').install_lib = self.bdist_dir - - site_packages = os.path.normcase(os.path.realpath(_get_purelib())) - old, self.distribution.data_files = self.distribution.data_files, [] - - for item in old: - if isinstance(item, tuple) and len(item) == 2: - if os.path.isabs(item[0]): - realpath = os.path.realpath(item[0]) - normalized = os.path.normcase(realpath) - if normalized == site_packages or normalized.startswith( - site_packages + os.sep - ): - item = realpath[len(site_packages) + 1:], item[1] - # XXX else: raise ??? - self.distribution.data_files.append(item) - - try: - log.info("installing package data to %s", self.bdist_dir) - self.call_command('install_data', force=0, root=None) - finally: - self.distribution.data_files = old - - def get_outputs(self): - return [self.egg_output] - - def call_command(self, cmdname, **kw): - """Invoke reinitialized command `cmdname` with keyword args""" - for dirname in INSTALL_DIRECTORY_ATTRS: - kw.setdefault(dirname, self.bdist_dir) - kw.setdefault('skip_build', self.skip_build) - kw.setdefault('dry_run', self.dry_run) - cmd = self.reinitialize_command(cmdname, **kw) - self.run_command(cmdname) - return cmd - - def run(self): # noqa: C901 # is too complex (14) # FIXME - # Generate metadata first - self.run_command("egg_info") - # We run install_lib before install_data, because some data hacks - # pull their data path from the install_lib command. - log.info("installing library code to %s", self.bdist_dir) - instcmd = self.get_finalized_command('install') - old_root = instcmd.root - instcmd.root = None - if self.distribution.has_c_libraries() and not self.skip_build: - self.run_command('build_clib') - cmd = self.call_command('install_lib', warn_dir=0) - instcmd.root = old_root - - all_outputs, ext_outputs = self.get_ext_outputs() - self.stubs = [] - to_compile = [] - for (p, ext_name) in enumerate(ext_outputs): - filename, ext = os.path.splitext(ext_name) - pyfile = os.path.join(self.bdist_dir, strip_module(filename) + - '.py') - self.stubs.append(pyfile) - log.info("creating stub loader for %s", ext_name) - if not self.dry_run: - write_stub(os.path.basename(ext_name), pyfile) - to_compile.append(pyfile) - ext_outputs[p] = ext_name.replace(os.sep, '/') - - if to_compile: - cmd.byte_compile(to_compile) - if self.distribution.data_files: - self.do_install_data() - - # Make the EGG-INFO directory - archive_root = self.bdist_dir - egg_info = os.path.join(archive_root, 'EGG-INFO') - self.mkpath(egg_info) - if self.distribution.scripts: - script_dir = os.path.join(egg_info, 'scripts') - log.info("installing scripts to %s", script_dir) - self.call_command('install_scripts', install_dir=script_dir, - no_ep=1) - - self.copy_metadata_to(egg_info) - native_libs = os.path.join(egg_info, "native_libs.txt") - if all_outputs: - log.info("writing %s", native_libs) - if not self.dry_run: - ensure_directory(native_libs) - libs_file = open(native_libs, 'wt') - libs_file.write('\n'.join(all_outputs)) - libs_file.write('\n') - libs_file.close() - elif os.path.isfile(native_libs): - log.info("removing %s", native_libs) - if not self.dry_run: - os.unlink(native_libs) - - write_safety_flag( - os.path.join(archive_root, 'EGG-INFO'), self.zip_safe() - ) - - if os.path.exists(os.path.join(self.egg_info, 'depends.txt')): - log.warn( - "WARNING: 'depends.txt' will not be used by setuptools 0.6!\n" - "Use the install_requires/extras_require setup() args instead." - ) - - if self.exclude_source_files: - self.zap_pyfiles() - - # Make the archive - make_zipfile(self.egg_output, archive_root, verbose=self.verbose, - dry_run=self.dry_run, mode=self.gen_header()) - if not self.keep_temp: - remove_tree(self.bdist_dir, dry_run=self.dry_run) - - # Add to 'Distribution.dist_files' so that the "upload" command works - getattr(self.distribution, 'dist_files', []).append( - ('bdist_egg', get_python_version(), self.egg_output)) - - def zap_pyfiles(self): - log.info("Removing .py files from temporary directory") - for base, dirs, files in walk_egg(self.bdist_dir): - for name in files: - path = os.path.join(base, name) - - if name.endswith('.py'): - log.debug("Deleting %s", path) - os.unlink(path) - - if base.endswith('__pycache__'): - path_old = path - - pattern = r'(?P.+)\.(?P[^.]+)\.pyc' - m = re.match(pattern, name) - path_new = os.path.join( - base, os.pardir, m.group('name') + '.pyc') - log.info( - "Renaming file from [%s] to [%s]" - % (path_old, path_new)) - try: - os.remove(path_new) - except OSError: - pass - os.rename(path_old, path_new) - - def zip_safe(self): - safe = getattr(self.distribution, 'zip_safe', None) - if safe is not None: - return safe - log.warn("zip_safe flag not set; analyzing archive contents...") - return analyze_egg(self.bdist_dir, self.stubs) - - def gen_header(self): - return 'w' - - def copy_metadata_to(self, target_dir): - "Copy metadata (egg info) to the target_dir" - # normalize the path (so that a forward-slash in egg_info will - # match using startswith below) - norm_egg_info = os.path.normpath(self.egg_info) - prefix = os.path.join(norm_egg_info, '') - for path in self.ei_cmd.filelist.files: - if path.startswith(prefix): - target = os.path.join(target_dir, path[len(prefix):]) - ensure_directory(target) - self.copy_file(path, target) - - def get_ext_outputs(self): - """Get a list of relative paths to C extensions in the output distro""" - - all_outputs = [] - ext_outputs = [] - - paths = {self.bdist_dir: ''} - for base, dirs, files in sorted_walk(self.bdist_dir): - for filename in files: - if os.path.splitext(filename)[1].lower() in NATIVE_EXTENSIONS: - all_outputs.append(paths[base] + filename) - for filename in dirs: - paths[os.path.join(base, filename)] = (paths[base] + - filename + '/') - - if self.distribution.has_ext_modules(): - build_cmd = self.get_finalized_command('build_ext') - for ext in build_cmd.extensions: - if isinstance(ext, Library): - continue - fullname = build_cmd.get_ext_fullname(ext.name) - filename = build_cmd.get_ext_filename(fullname) - if not os.path.basename(filename).startswith('dl-'): - if os.path.exists(os.path.join(self.bdist_dir, filename)): - ext_outputs.append(filename) - - return all_outputs, ext_outputs - - -NATIVE_EXTENSIONS = dict.fromkeys('.dll .so .dylib .pyd'.split()) - - -def walk_egg(egg_dir): - """Walk an unpacked egg's contents, skipping the metadata directory""" - walker = sorted_walk(egg_dir) - base, dirs, files = next(walker) - if 'EGG-INFO' in dirs: - dirs.remove('EGG-INFO') - yield base, dirs, files - for bdf in walker: - yield bdf - - -def analyze_egg(egg_dir, stubs): - # check for existing flag in EGG-INFO - for flag, fn in safety_flags.items(): - if os.path.exists(os.path.join(egg_dir, 'EGG-INFO', fn)): - return flag - if not can_scan(): - return False - safe = True - for base, dirs, files in walk_egg(egg_dir): - for name in files: - if name.endswith('.py') or name.endswith('.pyw'): - continue - elif name.endswith('.pyc') or name.endswith('.pyo'): - # always scan, even if we already know we're not safe - safe = scan_module(egg_dir, base, name, stubs) and safe - return safe - - -def write_safety_flag(egg_dir, safe): - # Write or remove zip safety flag file(s) - for flag, fn in safety_flags.items(): - fn = os.path.join(egg_dir, fn) - if os.path.exists(fn): - if safe is None or bool(safe) != flag: - os.unlink(fn) - elif safe is not None and bool(safe) == flag: - f = open(fn, 'wt') - f.write('\n') - f.close() - - -safety_flags = { - True: 'zip-safe', - False: 'not-zip-safe', -} - - -def scan_module(egg_dir, base, name, stubs): - """Check whether module possibly uses unsafe-for-zipfile stuff""" - - filename = os.path.join(base, name) - if filename[:-1] in stubs: - return True # Extension module - pkg = base[len(egg_dir) + 1:].replace(os.sep, '.') - module = pkg + (pkg and '.' or '') + os.path.splitext(name)[0] - if sys.version_info < (3, 7): - skip = 12 # skip magic & date & file size - else: - skip = 16 # skip magic & reserved? & date & file size - f = open(filename, 'rb') - f.read(skip) - code = marshal.load(f) - f.close() - safe = True - symbols = dict.fromkeys(iter_symbols(code)) - for bad in ['__file__', '__path__']: - if bad in symbols: - log.warn("%s: module references %s", module, bad) - safe = False - if 'inspect' in symbols: - for bad in [ - 'getsource', 'getabsfile', 'getsourcefile', 'getfile' - 'getsourcelines', 'findsource', 'getcomments', 'getframeinfo', - 'getinnerframes', 'getouterframes', 'stack', 'trace' - ]: - if bad in symbols: - log.warn("%s: module MAY be using inspect.%s", module, bad) - safe = False - return safe - - -def iter_symbols(code): - """Yield names and strings used by `code` and its nested code objects""" - for name in code.co_names: - yield name - for const in code.co_consts: - if isinstance(const, str): - yield const - elif isinstance(const, CodeType): - for name in iter_symbols(const): - yield name - - -def can_scan(): - if not sys.platform.startswith('java') and sys.platform != 'cli': - # CPython, PyPy, etc. - return True - log.warn("Unable to analyze compiled code on this platform.") - log.warn("Please ask the author to include a 'zip_safe'" - " setting (either True or False) in the package's setup.py") - - -# Attribute names of options for commands that might need to be convinced to -# install to the egg build directory - -INSTALL_DIRECTORY_ATTRS = [ - 'install_lib', 'install_dir', 'install_data', 'install_base' -] - - -def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=True, - mode='w'): - """Create a zip file from all the files under 'base_dir'. The output - zip file will be named 'base_dir' + ".zip". Uses either the "zipfile" - Python module (if available) or the InfoZIP "zip" utility (if installed - and found on the default search path). If neither tool is available, - raises DistutilsExecError. Returns the name of the output zip file. - """ - import zipfile - - mkpath(os.path.dirname(zip_filename), dry_run=dry_run) - log.info("creating '%s' and adding '%s' to it", zip_filename, base_dir) - - def visit(z, dirname, names): - for name in names: - path = os.path.normpath(os.path.join(dirname, name)) - if os.path.isfile(path): - p = path[len(base_dir) + 1:] - if not dry_run: - z.write(path, p) - log.debug("adding '%s'", p) - - compression = zipfile.ZIP_DEFLATED if compress else zipfile.ZIP_STORED - if not dry_run: - z = zipfile.ZipFile(zip_filename, mode, compression=compression) - for dirname, dirs, files in sorted_walk(base_dir): - visit(z, dirname, files) - z.close() - else: - for dirname, dirs, files in sorted_walk(base_dir): - visit(None, dirname, files) - return zip_filename diff --git a/venv/lib/python3.11/site-packages/setuptools/command/bdist_rpm.py b/venv/lib/python3.11/site-packages/setuptools/command/bdist_rpm.py deleted file mode 100755 index 98bf5de..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/bdist_rpm.py +++ /dev/null @@ -1,40 +0,0 @@ -import distutils.command.bdist_rpm as orig -import warnings - -from setuptools import SetuptoolsDeprecationWarning - - -class bdist_rpm(orig.bdist_rpm): - """ - Override the default bdist_rpm behavior to do the following: - - 1. Run egg_info to ensure the name and version are properly calculated. - 2. Always run 'install' using --single-version-externally-managed to - disable eggs in RPM distributions. - """ - - def run(self): - warnings.warn( - "bdist_rpm is deprecated and will be removed in a future " - "version. Use bdist_wheel (wheel packages) instead.", - SetuptoolsDeprecationWarning, - ) - - # ensure distro name is up-to-date - self.run_command('egg_info') - - orig.bdist_rpm.run(self) - - def _make_spec_file(self): - spec = orig.bdist_rpm._make_spec_file(self) - spec = [ - line.replace( - "setup.py install ", - "setup.py install --single-version-externally-managed " - ).replace( - "%setup", - "%setup -n %{name}-%{unmangled_version}" - ) - for line in spec - ] - return spec diff --git a/venv/lib/python3.11/site-packages/setuptools/command/build.py b/venv/lib/python3.11/site-packages/setuptools/command/build.py deleted file mode 100755 index fa3c99e..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/build.py +++ /dev/null @@ -1,146 +0,0 @@ -import sys -import warnings -from typing import TYPE_CHECKING, List, Dict -from distutils.command.build import build as _build - -from setuptools import SetuptoolsDeprecationWarning - -if sys.version_info >= (3, 8): - from typing import Protocol -elif TYPE_CHECKING: - from typing_extensions import Protocol -else: - from abc import ABC as Protocol - - -_ORIGINAL_SUBCOMMANDS = {"build_py", "build_clib", "build_ext", "build_scripts"} - - -class build(_build): - # copy to avoid sharing the object with parent class - sub_commands = _build.sub_commands[:] - - def get_sub_commands(self): - subcommands = {cmd[0] for cmd in _build.sub_commands} - if subcommands - _ORIGINAL_SUBCOMMANDS: - msg = """ - It seems that you are using `distutils.command.build` to add - new subcommands. Using `distutils` directly is considered deprecated, - please use `setuptools.command.build`. - """ - warnings.warn(msg, SetuptoolsDeprecationWarning) - self.sub_commands = _build.sub_commands - return super().get_sub_commands() - - -class SubCommand(Protocol): - """In order to support editable installations (see :pep:`660`) all - build subcommands **SHOULD** implement this protocol. They also **MUST** inherit - from ``setuptools.Command``. - - When creating an :pep:`editable wheel <660>`, ``setuptools`` will try to evaluate - custom ``build`` subcommands using the following procedure: - - 1. ``setuptools`` will set the ``editable_mode`` attribute to ``True`` - 2. ``setuptools`` will execute the ``run()`` command. - - .. important:: - Subcommands **SHOULD** take advantage of ``editable_mode=True`` to adequate - its behaviour or perform optimisations. - - For example, if a subcommand doesn't need to generate an extra file and - all it does is to copy a source file into the build directory, - ``run()`` **SHOULD** simply "early return". - - Similarly, if the subcommand creates files that would be placed alongside - Python files in the final distribution, during an editable install - the command **SHOULD** generate these files "in place" (i.e. write them to - the original source directory, instead of using the build directory). - Note that ``get_output_mapping()`` should reflect that and include mappings - for "in place" builds accordingly. - - 3. ``setuptools`` use any knowledge it can derive from the return values of - ``get_outputs()`` and ``get_output_mapping()`` to create an editable wheel. - When relevant ``setuptools`` **MAY** attempt to use file links based on the value - of ``get_output_mapping()``. Alternatively, ``setuptools`` **MAY** attempt to use - :doc:`import hooks ` to redirect any attempt to import - to the directory with the original source code and other files built in place. - - Please note that custom sub-commands **SHOULD NOT** rely on ``run()`` being - executed (or not) to provide correct return values for ``get_outputs()``, - ``get_output_mapping()`` or ``get_source_files()``. The ``get_*`` methods should - work independently of ``run()``. - """ - - editable_mode: bool = False - """Boolean flag that will be set to ``True`` when setuptools is used for an - editable installation (see :pep:`660`). - Implementations **SHOULD** explicitly set the default value of this attribute to - ``False``. - When subcommands run, they can use this flag to perform optimizations or change - their behaviour accordingly. - """ - - build_lib: str - """String representing the directory where the build artifacts should be stored, - e.g. ``build/lib``. - For example, if a distribution wants to provide a Python module named ``pkg.mod``, - then a corresponding file should be written to ``{build_lib}/package/module.py``. - A way of thinking about this is that the files saved under ``build_lib`` - would be eventually copied to one of the directories in :obj:`site.PREFIXES` - upon installation. - - A command that produces platform-independent files (e.g. compiling text templates - into Python functions), **CAN** initialize ``build_lib`` by copying its value from - the ``build_py`` command. On the other hand, a command that produces - platform-specific files **CAN** initialize ``build_lib`` by copying its value from - the ``build_ext`` command. In general this is done inside the ``finalize_options`` - method with the help of the ``set_undefined_options`` command:: - - def finalize_options(self): - self.set_undefined_options("build_py", ("build_lib", "build_lib")) - ... - """ - - def initialize_options(self): - """(Required by the original :class:`setuptools.Command` interface)""" - - def finalize_options(self): - """(Required by the original :class:`setuptools.Command` interface)""" - - def run(self): - """(Required by the original :class:`setuptools.Command` interface)""" - - def get_source_files(self) -> List[str]: - """ - Return a list of all files that are used by the command to create the expected - outputs. - For example, if your build command transpiles Java files into Python, you should - list here all the Java files. - The primary purpose of this function is to help populating the ``sdist`` - with all the files necessary to build the distribution. - All files should be strings relative to the project root directory. - """ - - def get_outputs(self) -> List[str]: - """ - Return a list of files intended for distribution as they would have been - produced by the build. - These files should be strings in the form of - ``"{build_lib}/destination/file/path"``. - - .. note:: - The return value of ``get_output()`` should include all files used as keys - in ``get_output_mapping()`` plus files that are generated during the build - and don't correspond to any source file already present in the project. - """ - - def get_output_mapping(self) -> Dict[str, str]: - """ - Return a mapping between destination files as they would be produced by the - build (dict keys) into the respective existing (source) files (dict values). - Existing (source) files should be represented as strings relative to the project - root directory. - Destination files should be strings in the form of - ``"{build_lib}/destination/file/path"``. - """ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/build_clib.py b/venv/lib/python3.11/site-packages/setuptools/command/build_clib.py deleted file mode 100755 index 09483e6..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/build_clib.py +++ /dev/null @@ -1,101 +0,0 @@ -import distutils.command.build_clib as orig -from distutils.errors import DistutilsSetupError -from distutils import log -from setuptools.dep_util import newer_pairwise_group - - -class build_clib(orig.build_clib): - """ - Override the default build_clib behaviour to do the following: - - 1. Implement a rudimentary timestamp-based dependency system - so 'compile()' doesn't run every time. - 2. Add more keys to the 'build_info' dictionary: - * obj_deps - specify dependencies for each object compiled. - this should be a dictionary mapping a key - with the source filename to a list of - dependencies. Use an empty string for global - dependencies. - * cflags - specify a list of additional flags to pass to - the compiler. - """ - - def build_libraries(self, libraries): - for (lib_name, build_info) in libraries: - sources = build_info.get('sources') - if sources is None or not isinstance(sources, (list, tuple)): - raise DistutilsSetupError( - "in 'libraries' option (library '%s'), " - "'sources' must be present and must be " - "a list of source filenames" % lib_name) - sources = sorted(list(sources)) - - log.info("building '%s' library", lib_name) - - # Make sure everything is the correct type. - # obj_deps should be a dictionary of keys as sources - # and a list/tuple of files that are its dependencies. - obj_deps = build_info.get('obj_deps', dict()) - if not isinstance(obj_deps, dict): - raise DistutilsSetupError( - "in 'libraries' option (library '%s'), " - "'obj_deps' must be a dictionary of " - "type 'source: list'" % lib_name) - dependencies = [] - - # Get the global dependencies that are specified by the '' key. - # These will go into every source's dependency list. - global_deps = obj_deps.get('', list()) - if not isinstance(global_deps, (list, tuple)): - raise DistutilsSetupError( - "in 'libraries' option (library '%s'), " - "'obj_deps' must be a dictionary of " - "type 'source: list'" % lib_name) - - # Build the list to be used by newer_pairwise_group - # each source will be auto-added to its dependencies. - for source in sources: - src_deps = [source] - src_deps.extend(global_deps) - extra_deps = obj_deps.get(source, list()) - if not isinstance(extra_deps, (list, tuple)): - raise DistutilsSetupError( - "in 'libraries' option (library '%s'), " - "'obj_deps' must be a dictionary of " - "type 'source: list'" % lib_name) - src_deps.extend(extra_deps) - dependencies.append(src_deps) - - expected_objects = self.compiler.object_filenames( - sources, - output_dir=self.build_temp, - ) - - if ( - newer_pairwise_group(dependencies, expected_objects) - != ([], []) - ): - # First, compile the source code to object files in the library - # directory. (This should probably change to putting object - # files in a temporary build directory.) - macros = build_info.get('macros') - include_dirs = build_info.get('include_dirs') - cflags = build_info.get('cflags') - self.compiler.compile( - sources, - output_dir=self.build_temp, - macros=macros, - include_dirs=include_dirs, - extra_postargs=cflags, - debug=self.debug - ) - - # Now "link" the object files together into a static library. - # (On Unix at least, this isn't really linking -- it just - # builds an archive. Whatever.) - self.compiler.create_static_lib( - expected_objects, - lib_name, - output_dir=self.build_clib, - debug=self.debug - ) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/build_ext.py b/venv/lib/python3.11/site-packages/setuptools/command/build_ext.py deleted file mode 100755 index cbfe3ec..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/build_ext.py +++ /dev/null @@ -1,383 +0,0 @@ -import os -import sys -import itertools -from importlib.machinery import EXTENSION_SUFFIXES -from importlib.util import cache_from_source as _compiled_file_name -from typing import Dict, Iterator, List, Tuple - -from distutils.command.build_ext import build_ext as _du_build_ext -from distutils.ccompiler import new_compiler -from distutils.sysconfig import customize_compiler, get_config_var -from distutils import log - -from setuptools.errors import BaseError -from setuptools.extension import Extension, Library - -try: - # Attempt to use Cython for building extensions, if available - from Cython.Distutils.build_ext import build_ext as _build_ext - # Additionally, assert that the compiler module will load - # also. Ref #1229. - __import__('Cython.Compiler.Main') -except ImportError: - _build_ext = _du_build_ext - -# make sure _config_vars is initialized -get_config_var("LDSHARED") -from distutils.sysconfig import _config_vars as _CONFIG_VARS # noqa - - -def _customize_compiler_for_shlib(compiler): - if sys.platform == "darwin": - # building .dylib requires additional compiler flags on OSX; here we - # temporarily substitute the pyconfig.h variables so that distutils' - # 'customize_compiler' uses them before we build the shared libraries. - tmp = _CONFIG_VARS.copy() - try: - # XXX Help! I don't have any idea whether these are right... - _CONFIG_VARS['LDSHARED'] = ( - "gcc -Wl,-x -dynamiclib -undefined dynamic_lookup") - _CONFIG_VARS['CCSHARED'] = " -dynamiclib" - _CONFIG_VARS['SO'] = ".dylib" - customize_compiler(compiler) - finally: - _CONFIG_VARS.clear() - _CONFIG_VARS.update(tmp) - else: - customize_compiler(compiler) - - -have_rtld = False -use_stubs = False -libtype = 'shared' - -if sys.platform == "darwin": - use_stubs = True -elif os.name != 'nt': - try: - import dl - use_stubs = have_rtld = hasattr(dl, 'RTLD_NOW') - except ImportError: - pass - - -def if_dl(s): - return s if have_rtld else '' - - -def get_abi3_suffix(): - """Return the file extension for an abi3-compliant Extension()""" - for suffix in EXTENSION_SUFFIXES: - if '.abi3' in suffix: # Unix - return suffix - elif suffix == '.pyd': # Windows - return suffix - - -class build_ext(_build_ext): - editable_mode: bool = False - inplace: bool = False - - def run(self): - """Build extensions in build directory, then copy if --inplace""" - old_inplace, self.inplace = self.inplace, 0 - _build_ext.run(self) - self.inplace = old_inplace - if old_inplace: - self.copy_extensions_to_source() - - def _get_inplace_equivalent(self, build_py, ext: Extension) -> Tuple[str, str]: - fullname = self.get_ext_fullname(ext.name) - filename = self.get_ext_filename(fullname) - modpath = fullname.split('.') - package = '.'.join(modpath[:-1]) - package_dir = build_py.get_package_dir(package) - inplace_file = os.path.join(package_dir, os.path.basename(filename)) - regular_file = os.path.join(self.build_lib, filename) - return (inplace_file, regular_file) - - def copy_extensions_to_source(self): - build_py = self.get_finalized_command('build_py') - for ext in self.extensions: - inplace_file, regular_file = self._get_inplace_equivalent(build_py, ext) - - # Always copy, even if source is older than destination, to ensure - # that the right extensions for the current Python/platform are - # used. - if os.path.exists(regular_file) or not ext.optional: - self.copy_file(regular_file, inplace_file, level=self.verbose) - - if ext._needs_stub: - inplace_stub = self._get_equivalent_stub(ext, inplace_file) - self._write_stub_file(inplace_stub, ext, compile=True) - # Always compile stub and remove the original (leave the cache behind) - # (this behaviour was observed in previous iterations of the code) - - def _get_equivalent_stub(self, ext: Extension, output_file: str) -> str: - dir_ = os.path.dirname(output_file) - _, _, name = ext.name.rpartition(".") - return f"{os.path.join(dir_, name)}.py" - - def _get_output_mapping(self) -> Iterator[Tuple[str, str]]: - if not self.inplace: - return - - build_py = self.get_finalized_command('build_py') - opt = self.get_finalized_command('install_lib').optimize or "" - - for ext in self.extensions: - inplace_file, regular_file = self._get_inplace_equivalent(build_py, ext) - yield (regular_file, inplace_file) - - if ext._needs_stub: - # This version of `build_ext` always builds artifacts in another dir, - # when "inplace=True" is given it just copies them back. - # This is done in the `copy_extensions_to_source` function, which - # always compile stub files via `_compile_and_remove_stub`. - # At the end of the process, a `.pyc` stub file is created without the - # corresponding `.py`. - - inplace_stub = self._get_equivalent_stub(ext, inplace_file) - regular_stub = self._get_equivalent_stub(ext, regular_file) - inplace_cache = _compiled_file_name(inplace_stub, optimization=opt) - output_cache = _compiled_file_name(regular_stub, optimization=opt) - yield (output_cache, inplace_cache) - - def get_ext_filename(self, fullname): - so_ext = os.getenv('SETUPTOOLS_EXT_SUFFIX') - if so_ext: - filename = os.path.join(*fullname.split('.')) + so_ext - else: - filename = _build_ext.get_ext_filename(self, fullname) - so_ext = get_config_var('EXT_SUFFIX') - - if fullname in self.ext_map: - ext = self.ext_map[fullname] - use_abi3 = getattr(ext, 'py_limited_api') and get_abi3_suffix() - if use_abi3: - filename = filename[:-len(so_ext)] - so_ext = get_abi3_suffix() - filename = filename + so_ext - if isinstance(ext, Library): - fn, ext = os.path.splitext(filename) - return self.shlib_compiler.library_filename(fn, libtype) - elif use_stubs and ext._links_to_dynamic: - d, fn = os.path.split(filename) - return os.path.join(d, 'dl-' + fn) - return filename - - def initialize_options(self): - _build_ext.initialize_options(self) - self.shlib_compiler = None - self.shlibs = [] - self.ext_map = {} - self.editable_mode = False - - def finalize_options(self): - _build_ext.finalize_options(self) - self.extensions = self.extensions or [] - self.check_extensions_list(self.extensions) - self.shlibs = [ext for ext in self.extensions - if isinstance(ext, Library)] - if self.shlibs: - self.setup_shlib_compiler() - for ext in self.extensions: - ext._full_name = self.get_ext_fullname(ext.name) - for ext in self.extensions: - fullname = ext._full_name - self.ext_map[fullname] = ext - - # distutils 3.1 will also ask for module names - # XXX what to do with conflicts? - self.ext_map[fullname.split('.')[-1]] = ext - - ltd = self.shlibs and self.links_to_dynamic(ext) or False - ns = ltd and use_stubs and not isinstance(ext, Library) - ext._links_to_dynamic = ltd - ext._needs_stub = ns - filename = ext._file_name = self.get_ext_filename(fullname) - libdir = os.path.dirname(os.path.join(self.build_lib, filename)) - if ltd and libdir not in ext.library_dirs: - ext.library_dirs.append(libdir) - if ltd and use_stubs and os.curdir not in ext.runtime_library_dirs: - ext.runtime_library_dirs.append(os.curdir) - - if self.editable_mode: - self.inplace = True - - def setup_shlib_compiler(self): - compiler = self.shlib_compiler = new_compiler( - compiler=self.compiler, dry_run=self.dry_run, force=self.force - ) - _customize_compiler_for_shlib(compiler) - - if self.include_dirs is not None: - compiler.set_include_dirs(self.include_dirs) - if self.define is not None: - # 'define' option is a list of (name,value) tuples - for (name, value) in self.define: - compiler.define_macro(name, value) - if self.undef is not None: - for macro in self.undef: - compiler.undefine_macro(macro) - if self.libraries is not None: - compiler.set_libraries(self.libraries) - if self.library_dirs is not None: - compiler.set_library_dirs(self.library_dirs) - if self.rpath is not None: - compiler.set_runtime_library_dirs(self.rpath) - if self.link_objects is not None: - compiler.set_link_objects(self.link_objects) - - # hack so distutils' build_extension() builds a library instead - compiler.link_shared_object = link_shared_object.__get__(compiler) - - def get_export_symbols(self, ext): - if isinstance(ext, Library): - return ext.export_symbols - return _build_ext.get_export_symbols(self, ext) - - def build_extension(self, ext): - ext._convert_pyx_sources_to_lang() - _compiler = self.compiler - try: - if isinstance(ext, Library): - self.compiler = self.shlib_compiler - _build_ext.build_extension(self, ext) - if ext._needs_stub: - build_lib = self.get_finalized_command('build_py').build_lib - self.write_stub(build_lib, ext) - finally: - self.compiler = _compiler - - def links_to_dynamic(self, ext): - """Return true if 'ext' links to a dynamic lib in the same package""" - # XXX this should check to ensure the lib is actually being built - # XXX as dynamic, and not just using a locally-found version or a - # XXX static-compiled version - libnames = dict.fromkeys([lib._full_name for lib in self.shlibs]) - pkg = '.'.join(ext._full_name.split('.')[:-1] + ['']) - return any(pkg + libname in libnames for libname in ext.libraries) - - def get_outputs(self) -> List[str]: - if self.inplace: - return list(self.get_output_mapping().keys()) - return sorted(_build_ext.get_outputs(self) + self.__get_stubs_outputs()) - - def get_output_mapping(self) -> Dict[str, str]: - """See :class:`setuptools.commands.build.SubCommand`""" - mapping = self._get_output_mapping() - return dict(sorted(mapping, key=lambda x: x[0])) - - def __get_stubs_outputs(self): - # assemble the base name for each extension that needs a stub - ns_ext_bases = ( - os.path.join(self.build_lib, *ext._full_name.split('.')) - for ext in self.extensions - if ext._needs_stub - ) - # pair each base with the extension - pairs = itertools.product(ns_ext_bases, self.__get_output_extensions()) - return list(base + fnext for base, fnext in pairs) - - def __get_output_extensions(self): - yield '.py' - yield '.pyc' - if self.get_finalized_command('build_py').optimize: - yield '.pyo' - - def write_stub(self, output_dir, ext, compile=False): - stub_file = os.path.join(output_dir, *ext._full_name.split('.')) + '.py' - self._write_stub_file(stub_file, ext, compile) - - def _write_stub_file(self, stub_file: str, ext: Extension, compile=False): - log.info("writing stub loader for %s to %s", ext._full_name, stub_file) - if compile and os.path.exists(stub_file): - raise BaseError(stub_file + " already exists! Please delete.") - if not self.dry_run: - f = open(stub_file, 'w') - f.write( - '\n'.join([ - "def __bootstrap__():", - " global __bootstrap__, __file__, __loader__", - " import sys, os, pkg_resources, importlib.util" + - if_dl(", dl"), - " __file__ = pkg_resources.resource_filename" - "(__name__,%r)" - % os.path.basename(ext._file_name), - " del __bootstrap__", - " if '__loader__' in globals():", - " del __loader__", - if_dl(" old_flags = sys.getdlopenflags()"), - " old_dir = os.getcwd()", - " try:", - " os.chdir(os.path.dirname(__file__))", - if_dl(" sys.setdlopenflags(dl.RTLD_NOW)"), - " spec = importlib.util.spec_from_file_location(", - " __name__, __file__)", - " mod = importlib.util.module_from_spec(spec)", - " spec.loader.exec_module(mod)", - " finally:", - if_dl(" sys.setdlopenflags(old_flags)"), - " os.chdir(old_dir)", - "__bootstrap__()", - "" # terminal \n - ]) - ) - f.close() - if compile: - self._compile_and_remove_stub(stub_file) - - def _compile_and_remove_stub(self, stub_file: str): - from distutils.util import byte_compile - - byte_compile([stub_file], optimize=0, - force=True, dry_run=self.dry_run) - optimize = self.get_finalized_command('install_lib').optimize - if optimize > 0: - byte_compile([stub_file], optimize=optimize, - force=True, dry_run=self.dry_run) - if os.path.exists(stub_file) and not self.dry_run: - os.unlink(stub_file) - - -if use_stubs or os.name == 'nt': - # Build shared libraries - # - def link_shared_object( - self, objects, output_libname, output_dir=None, libraries=None, - library_dirs=None, runtime_library_dirs=None, export_symbols=None, - debug=0, extra_preargs=None, extra_postargs=None, build_temp=None, - target_lang=None): - self.link( - self.SHARED_LIBRARY, objects, output_libname, - output_dir, libraries, library_dirs, runtime_library_dirs, - export_symbols, debug, extra_preargs, extra_postargs, - build_temp, target_lang - ) -else: - # Build static libraries everywhere else - libtype = 'static' - - def link_shared_object( - self, objects, output_libname, output_dir=None, libraries=None, - library_dirs=None, runtime_library_dirs=None, export_symbols=None, - debug=0, extra_preargs=None, extra_postargs=None, build_temp=None, - target_lang=None): - # XXX we need to either disallow these attrs on Library instances, - # or warn/abort here if set, or something... - # libraries=None, library_dirs=None, runtime_library_dirs=None, - # export_symbols=None, extra_preargs=None, extra_postargs=None, - # build_temp=None - - assert output_dir is None # distutils build_ext doesn't pass this - output_dir, filename = os.path.split(output_libname) - basename, ext = os.path.splitext(filename) - if self.library_filename("x").startswith('lib'): - # strip 'lib' prefix; this is kludgy if some platform uses - # a different prefix - basename = basename[3:] - - self.create_static_lib( - objects, basename, output_dir, debug, target_lang - ) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/build_py.py b/venv/lib/python3.11/site-packages/setuptools/command/build_py.py deleted file mode 100755 index ec06274..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/build_py.py +++ /dev/null @@ -1,368 +0,0 @@ -from functools import partial -from glob import glob -from distutils.util import convert_path -import distutils.command.build_py as orig -import os -import fnmatch -import textwrap -import io -import distutils.errors -import itertools -import stat -import warnings -from pathlib import Path -from typing import Dict, Iterable, Iterator, List, Optional, Tuple - -from setuptools._deprecation_warning import SetuptoolsDeprecationWarning -from setuptools.extern.more_itertools import unique_everseen - - -def make_writable(target): - os.chmod(target, os.stat(target).st_mode | stat.S_IWRITE) - - -class build_py(orig.build_py): - """Enhanced 'build_py' command that includes data files with packages - - The data files are specified via a 'package_data' argument to 'setup()'. - See 'setuptools.dist.Distribution' for more details. - - Also, this version of the 'build_py' command allows you to specify both - 'py_modules' and 'packages' in the same setup operation. - """ - editable_mode: bool = False - existing_egg_info_dir: Optional[str] = None #: Private API, internal use only. - - def finalize_options(self): - orig.build_py.finalize_options(self) - self.package_data = self.distribution.package_data - self.exclude_package_data = self.distribution.exclude_package_data or {} - if 'data_files' in self.__dict__: - del self.__dict__['data_files'] - self.__updated_files = [] - - def copy_file(self, infile, outfile, preserve_mode=1, preserve_times=1, - link=None, level=1): - # Overwrite base class to allow using links - if link: - infile = str(Path(infile).resolve()) - outfile = str(Path(outfile).resolve()) - return super().copy_file(infile, outfile, preserve_mode, preserve_times, - link, level) - - def run(self): - """Build modules, packages, and copy data files to build directory""" - if not (self.py_modules or self.packages) or self.editable_mode: - return - - if self.py_modules: - self.build_modules() - - if self.packages: - self.build_packages() - self.build_package_data() - - # Only compile actual .py files, using our base class' idea of what our - # output files are. - self.byte_compile(orig.build_py.get_outputs(self, include_bytecode=0)) - - def __getattr__(self, attr): - "lazily compute data files" - if attr == 'data_files': - self.data_files = self._get_data_files() - return self.data_files - return orig.build_py.__getattr__(self, attr) - - def build_module(self, module, module_file, package): - outfile, copied = orig.build_py.build_module(self, module, module_file, package) - if copied: - self.__updated_files.append(outfile) - return outfile, copied - - def _get_data_files(self): - """Generate list of '(package,src_dir,build_dir,filenames)' tuples""" - self.analyze_manifest() - return list(map(self._get_pkg_data_files, self.packages or ())) - - def get_data_files_without_manifest(self): - """ - Generate list of ``(package,src_dir,build_dir,filenames)`` tuples, - but without triggering any attempt to analyze or build the manifest. - """ - # Prevent eventual errors from unset `manifest_files` - # (that would otherwise be set by `analyze_manifest`) - self.__dict__.setdefault('manifest_files', {}) - return list(map(self._get_pkg_data_files, self.packages or ())) - - def _get_pkg_data_files(self, package): - # Locate package source directory - src_dir = self.get_package_dir(package) - - # Compute package build directory - build_dir = os.path.join(*([self.build_lib] + package.split('.'))) - - # Strip directory from globbed filenames - filenames = [ - os.path.relpath(file, src_dir) - for file in self.find_data_files(package, src_dir) - ] - return package, src_dir, build_dir, filenames - - def find_data_files(self, package, src_dir): - """Return filenames for package's data files in 'src_dir'""" - patterns = self._get_platform_patterns( - self.package_data, - package, - src_dir, - ) - globs_expanded = map(partial(glob, recursive=True), patterns) - # flatten the expanded globs into an iterable of matches - globs_matches = itertools.chain.from_iterable(globs_expanded) - glob_files = filter(os.path.isfile, globs_matches) - files = itertools.chain( - self.manifest_files.get(package, []), - glob_files, - ) - return self.exclude_data_files(package, src_dir, files) - - def get_outputs(self, include_bytecode=1) -> List[str]: - """See :class:`setuptools.commands.build.SubCommand`""" - if self.editable_mode: - return list(self.get_output_mapping().keys()) - return super().get_outputs(include_bytecode) - - def get_output_mapping(self) -> Dict[str, str]: - """See :class:`setuptools.commands.build.SubCommand`""" - mapping = itertools.chain( - self._get_package_data_output_mapping(), - self._get_module_mapping(), - ) - return dict(sorted(mapping, key=lambda x: x[0])) - - def _get_module_mapping(self) -> Iterator[Tuple[str, str]]: - """Iterate over all modules producing (dest, src) pairs.""" - for (package, module, module_file) in self.find_all_modules(): - package = package.split('.') - filename = self.get_module_outfile(self.build_lib, package, module) - yield (filename, module_file) - - def _get_package_data_output_mapping(self) -> Iterator[Tuple[str, str]]: - """Iterate over package data producing (dest, src) pairs.""" - for package, src_dir, build_dir, filenames in self.data_files: - for filename in filenames: - target = os.path.join(build_dir, filename) - srcfile = os.path.join(src_dir, filename) - yield (target, srcfile) - - def build_package_data(self): - """Copy data files into build directory""" - for target, srcfile in self._get_package_data_output_mapping(): - self.mkpath(os.path.dirname(target)) - _outf, _copied = self.copy_file(srcfile, target) - make_writable(target) - - def analyze_manifest(self): - self.manifest_files = mf = {} - if not self.distribution.include_package_data: - return - src_dirs = {} - for package in self.packages or (): - # Locate package source directory - src_dirs[assert_relative(self.get_package_dir(package))] = package - - if ( - getattr(self, 'existing_egg_info_dir', None) - and Path(self.existing_egg_info_dir, "SOURCES.txt").exists() - ): - egg_info_dir = self.existing_egg_info_dir - manifest = Path(egg_info_dir, "SOURCES.txt") - files = manifest.read_text(encoding="utf-8").splitlines() - else: - self.run_command('egg_info') - ei_cmd = self.get_finalized_command('egg_info') - egg_info_dir = ei_cmd.egg_info - files = ei_cmd.filelist.files - - check = _IncludePackageDataAbuse() - for path in self._filter_build_files(files, egg_info_dir): - d, f = os.path.split(assert_relative(path)) - prev = None - oldf = f - while d and d != prev and d not in src_dirs: - prev = d - d, df = os.path.split(d) - f = os.path.join(df, f) - if d in src_dirs: - if f == oldf: - if check.is_module(f): - continue # it's a module, not data - else: - importable = check.importable_subpackage(src_dirs[d], f) - if importable: - check.warn(importable) - mf.setdefault(src_dirs[d], []).append(path) - - def _filter_build_files(self, files: Iterable[str], egg_info: str) -> Iterator[str]: - """ - ``build_meta`` may try to create egg_info outside of the project directory, - and this can be problematic for certain plugins (reported in issue #3500). - - Extensions might also include between their sources files created on the - ``build_lib`` and ``build_temp`` directories. - - This function should filter this case of invalid files out. - """ - build = self.get_finalized_command("build") - build_dirs = (egg_info, self.build_lib, build.build_temp, build.build_base) - norm_dirs = [os.path.normpath(p) for p in build_dirs if p] - - for file in files: - norm_path = os.path.normpath(file) - if not os.path.isabs(file) or all(d not in norm_path for d in norm_dirs): - yield file - - def get_data_files(self): - pass # Lazily compute data files in _get_data_files() function. - - def check_package(self, package, package_dir): - """Check namespace packages' __init__ for declare_namespace""" - try: - return self.packages_checked[package] - except KeyError: - pass - - init_py = orig.build_py.check_package(self, package, package_dir) - self.packages_checked[package] = init_py - - if not init_py or not self.distribution.namespace_packages: - return init_py - - for pkg in self.distribution.namespace_packages: - if pkg == package or pkg.startswith(package + '.'): - break - else: - return init_py - - with io.open(init_py, 'rb') as f: - contents = f.read() - if b'declare_namespace' not in contents: - raise distutils.errors.DistutilsError( - "Namespace package problem: %s is a namespace package, but " - "its\n__init__.py does not call declare_namespace()! Please " - 'fix it.\n(See the setuptools manual under ' - '"Namespace Packages" for details.)\n"' % (package,) - ) - return init_py - - def initialize_options(self): - self.packages_checked = {} - orig.build_py.initialize_options(self) - self.editable_mode = False - self.existing_egg_info_dir = None - - def get_package_dir(self, package): - res = orig.build_py.get_package_dir(self, package) - if self.distribution.src_root is not None: - return os.path.join(self.distribution.src_root, res) - return res - - def exclude_data_files(self, package, src_dir, files): - """Filter filenames for package's data files in 'src_dir'""" - files = list(files) - patterns = self._get_platform_patterns( - self.exclude_package_data, - package, - src_dir, - ) - match_groups = (fnmatch.filter(files, pattern) for pattern in patterns) - # flatten the groups of matches into an iterable of matches - matches = itertools.chain.from_iterable(match_groups) - bad = set(matches) - keepers = (fn for fn in files if fn not in bad) - # ditch dupes - return list(unique_everseen(keepers)) - - @staticmethod - def _get_platform_patterns(spec, package, src_dir): - """ - yield platform-specific path patterns (suitable for glob - or fn_match) from a glob-based spec (such as - self.package_data or self.exclude_package_data) - matching package in src_dir. - """ - raw_patterns = itertools.chain( - spec.get('', []), - spec.get(package, []), - ) - return ( - # Each pattern has to be converted to a platform-specific path - os.path.join(src_dir, convert_path(pattern)) - for pattern in raw_patterns - ) - - -def assert_relative(path): - if not os.path.isabs(path): - return path - from distutils.errors import DistutilsSetupError - - msg = ( - textwrap.dedent( - """ - Error: setup script specifies an absolute path: - - %s - - setup() arguments must *always* be /-separated paths relative to the - setup.py directory, *never* absolute paths. - """ - ).lstrip() - % path - ) - raise DistutilsSetupError(msg) - - -class _IncludePackageDataAbuse: - """Inform users that package or module is included as 'data file'""" - - MESSAGE = """\ - Installing {importable!r} as data is deprecated, please list it in `packages`. - !!\n\n - ############################ - # Package would be ignored # - ############################ - Python recognizes {importable!r} as an importable package, - but it is not listed in the `packages` configuration of setuptools. - - {importable!r} has been automatically added to the distribution only - because it may contain data files, but this behavior is likely to change - in future versions of setuptools (and therefore is considered deprecated). - - Please make sure that {importable!r} is included as a package by using - the `packages` configuration field or the proper discovery methods - (for example by using `find_namespace_packages(...)`/`find_namespace:` - instead of `find_packages(...)`/`find:`). - - You can read more about "package discovery" and "data files" on setuptools - documentation page. - \n\n!! - """ - - def __init__(self): - self._already_warned = set() - - def is_module(self, file): - return file.endswith(".py") and file[:-len(".py")].isidentifier() - - def importable_subpackage(self, parent, file): - pkg = Path(file).parent - parts = list(itertools.takewhile(str.isidentifier, pkg.parts)) - if parts: - return ".".join([parent, *parts]) - return None - - def warn(self, importable): - if importable not in self._already_warned: - msg = textwrap.dedent(self.MESSAGE).format(importable=importable) - warnings.warn(msg, SetuptoolsDeprecationWarning, stacklevel=2) - self._already_warned.add(importable) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/develop.py b/venv/lib/python3.11/site-packages/setuptools/command/develop.py deleted file mode 100755 index 24fb0a7..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/develop.py +++ /dev/null @@ -1,193 +0,0 @@ -from distutils.util import convert_path -from distutils import log -from distutils.errors import DistutilsError, DistutilsOptionError -import os -import glob -import io - -import pkg_resources -from setuptools.command.easy_install import easy_install -from setuptools import namespaces -import setuptools - - -class develop(namespaces.DevelopInstaller, easy_install): - """Set up package for development""" - - description = "install package in 'development mode'" - - user_options = easy_install.user_options + [ - ("uninstall", "u", "Uninstall this source package"), - ("egg-path=", None, "Set the path to be used in the .egg-link file"), - ] - - boolean_options = easy_install.boolean_options + ['uninstall'] - - command_consumes_arguments = False # override base - - def run(self): - if self.uninstall: - self.multi_version = True - self.uninstall_link() - self.uninstall_namespaces() - else: - self.install_for_development() - self.warn_deprecated_options() - - def initialize_options(self): - self.uninstall = None - self.egg_path = None - easy_install.initialize_options(self) - self.setup_path = None - self.always_copy_from = '.' # always copy eggs installed in curdir - - def finalize_options(self): - ei = self.get_finalized_command("egg_info") - if ei.broken_egg_info: - template = "Please rename %r to %r before using 'develop'" - args = ei.egg_info, ei.broken_egg_info - raise DistutilsError(template % args) - self.args = [ei.egg_name] - - easy_install.finalize_options(self) - self.expand_basedirs() - self.expand_dirs() - # pick up setup-dir .egg files only: no .egg-info - self.package_index.scan(glob.glob('*.egg')) - - egg_link_fn = ei.egg_name + '.egg-link' - self.egg_link = os.path.join(self.install_dir, egg_link_fn) - self.egg_base = ei.egg_base - if self.egg_path is None: - self.egg_path = os.path.abspath(ei.egg_base) - - target = pkg_resources.normalize_path(self.egg_base) - egg_path = pkg_resources.normalize_path( - os.path.join(self.install_dir, self.egg_path) - ) - if egg_path != target: - raise DistutilsOptionError( - "--egg-path must be a relative path from the install" - " directory to " + target - ) - - # Make a distribution for the package's source - self.dist = pkg_resources.Distribution( - target, - pkg_resources.PathMetadata(target, os.path.abspath(ei.egg_info)), - project_name=ei.egg_name, - ) - - self.setup_path = self._resolve_setup_path( - self.egg_base, - self.install_dir, - self.egg_path, - ) - - @staticmethod - def _resolve_setup_path(egg_base, install_dir, egg_path): - """ - Generate a path from egg_base back to '.' where the - setup script resides and ensure that path points to the - setup path from $install_dir/$egg_path. - """ - path_to_setup = egg_base.replace(os.sep, '/').rstrip('/') - if path_to_setup != os.curdir: - path_to_setup = '../' * (path_to_setup.count('/') + 1) - resolved = pkg_resources.normalize_path( - os.path.join(install_dir, egg_path, path_to_setup) - ) - if resolved != pkg_resources.normalize_path(os.curdir): - raise DistutilsOptionError( - "Can't get a consistent path to setup script from" - " installation directory", - resolved, - pkg_resources.normalize_path(os.curdir), - ) - return path_to_setup - - def install_for_development(self): - self.run_command('egg_info') - - # Build extensions in-place - self.reinitialize_command('build_ext', inplace=1) - self.run_command('build_ext') - - if setuptools.bootstrap_install_from: - self.easy_install(setuptools.bootstrap_install_from) - setuptools.bootstrap_install_from = None - - self.install_namespaces() - - # create an .egg-link in the installation dir, pointing to our egg - log.info("Creating %s (link to %s)", self.egg_link, self.egg_base) - if not self.dry_run: - with open(self.egg_link, "w") as f: - f.write(self.egg_path + "\n" + self.setup_path) - # postprocess the installed distro, fixing up .pth, installing scripts, - # and handling requirements - self.process_distribution(None, self.dist, not self.no_deps) - - def uninstall_link(self): - if os.path.exists(self.egg_link): - log.info("Removing %s (link to %s)", self.egg_link, self.egg_base) - egg_link_file = open(self.egg_link) - contents = [line.rstrip() for line in egg_link_file] - egg_link_file.close() - if contents not in ([self.egg_path], [self.egg_path, self.setup_path]): - log.warn("Link points to %s: uninstall aborted", contents) - return - if not self.dry_run: - os.unlink(self.egg_link) - if not self.dry_run: - self.update_pth(self.dist) # remove any .pth link to us - if self.distribution.scripts: - # XXX should also check for entry point scripts! - log.warn("Note: you must uninstall or replace scripts manually!") - - def install_egg_scripts(self, dist): - if dist is not self.dist: - # Installing a dependency, so fall back to normal behavior - return easy_install.install_egg_scripts(self, dist) - - # create wrapper scripts in the script dir, pointing to dist.scripts - - # new-style... - self.install_wrapper_scripts(dist) - - # ...and old-style - for script_name in self.distribution.scripts or []: - script_path = os.path.abspath(convert_path(script_name)) - script_name = os.path.basename(script_path) - with io.open(script_path) as strm: - script_text = strm.read() - self.install_script(dist, script_name, script_text, script_path) - - def install_wrapper_scripts(self, dist): - dist = VersionlessRequirement(dist) - return easy_install.install_wrapper_scripts(self, dist) - - -class VersionlessRequirement: - """ - Adapt a pkg_resources.Distribution to simply return the project - name as the 'requirement' so that scripts will work across - multiple versions. - - >>> from pkg_resources import Distribution - >>> dist = Distribution(project_name='foo', version='1.0') - >>> str(dist.as_requirement()) - 'foo==1.0' - >>> adapted_dist = VersionlessRequirement(dist) - >>> str(adapted_dist.as_requirement()) - 'foo' - """ - - def __init__(self, dist): - self.__dist = dist - - def __getattr__(self, name): - return getattr(self.__dist, name) - - def as_requirement(self): - return self.project_name diff --git a/venv/lib/python3.11/site-packages/setuptools/command/dist_info.py b/venv/lib/python3.11/site-packages/setuptools/command/dist_info.py deleted file mode 100755 index 0685c94..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/dist_info.py +++ /dev/null @@ -1,142 +0,0 @@ -""" -Create a dist_info directory -As defined in the wheel specification -""" - -import os -import re -import shutil -import sys -import warnings -from contextlib import contextmanager -from inspect import cleandoc -from pathlib import Path - -from distutils.core import Command -from distutils import log -from setuptools.extern import packaging -from setuptools._deprecation_warning import SetuptoolsDeprecationWarning - - -class dist_info(Command): - - description = 'create a .dist-info directory' - - user_options = [ - ('egg-base=', 'e', "directory containing .egg-info directories" - " (default: top of the source tree)" - " DEPRECATED: use --output-dir."), - ('output-dir=', 'o', "directory inside of which the .dist-info will be" - "created (default: top of the source tree)"), - ('tag-date', 'd', "Add date stamp (e.g. 20050528) to version number"), - ('tag-build=', 'b', "Specify explicit tag to add to version number"), - ('no-date', 'D', "Don't include date stamp [default]"), - ('keep-egg-info', None, "*TRANSITIONAL* will be removed in the future"), - ] - - boolean_options = ['tag-date', 'keep-egg-info'] - negative_opt = {'no-date': 'tag-date'} - - def initialize_options(self): - self.egg_base = None - self.output_dir = None - self.name = None - self.dist_info_dir = None - self.tag_date = None - self.tag_build = None - self.keep_egg_info = False - - def finalize_options(self): - if self.egg_base: - msg = "--egg-base is deprecated for dist_info command. Use --output-dir." - warnings.warn(msg, SetuptoolsDeprecationWarning) - self.output_dir = self.egg_base or self.output_dir - - dist = self.distribution - project_dir = dist.src_root or os.curdir - self.output_dir = Path(self.output_dir or project_dir) - - egg_info = self.reinitialize_command("egg_info") - egg_info.egg_base = str(self.output_dir) - - if self.tag_date: - egg_info.tag_date = self.tag_date - else: - self.tag_date = egg_info.tag_date - - if self.tag_build: - egg_info.tag_build = self.tag_build - else: - self.tag_build = egg_info.tag_build - - egg_info.finalize_options() - self.egg_info = egg_info - - name = _safe(dist.get_name()) - version = _version(dist.get_version()) - self.name = f"{name}-{version}" - self.dist_info_dir = os.path.join(self.output_dir, f"{self.name}.dist-info") - - @contextmanager - def _maybe_bkp_dir(self, dir_path: str, requires_bkp: bool): - if requires_bkp: - bkp_name = f"{dir_path}.__bkp__" - _rm(bkp_name, ignore_errors=True) - _copy(dir_path, bkp_name, dirs_exist_ok=True, symlinks=True) - try: - yield - finally: - _rm(dir_path, ignore_errors=True) - shutil.move(bkp_name, dir_path) - else: - yield - - def run(self): - self.output_dir.mkdir(parents=True, exist_ok=True) - self.egg_info.run() - egg_info_dir = self.egg_info.egg_info - assert os.path.isdir(egg_info_dir), ".egg-info dir should have been created" - - log.info("creating '{}'".format(os.path.abspath(self.dist_info_dir))) - bdist_wheel = self.get_finalized_command('bdist_wheel') - - # TODO: if bdist_wheel if merged into setuptools, just add "keep_egg_info" there - with self._maybe_bkp_dir(egg_info_dir, self.keep_egg_info): - bdist_wheel.egg2dist(egg_info_dir, self.dist_info_dir) - - -def _safe(component: str) -> str: - """Escape a component used to form a wheel name according to PEP 491""" - return re.sub(r"[^\w\d.]+", "_", component) - - -def _version(version: str) -> str: - """Convert an arbitrary string to a version string.""" - v = version.replace(' ', '.') - try: - return str(packaging.version.Version(v)).replace("-", "_") - except packaging.version.InvalidVersion: - msg = f"""Invalid version: {version!r}. - !!\n\n - ################### - # Invalid version # - ################### - {version!r} is not valid according to PEP 440.\n - Please make sure specify a valid version for your package. - Also note that future releases of setuptools may halt the build process - if an invalid version is given. - \n\n!! - """ - warnings.warn(cleandoc(msg)) - return _safe(v).strip("_") - - -def _rm(dir_name, **opts): - if os.path.isdir(dir_name): - shutil.rmtree(dir_name, **opts) - - -def _copy(src, dst, **opts): - if sys.version_info < (3, 8): - opts.pop("dirs_exist_ok", None) - shutil.copytree(src, dst, **opts) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/easy_install.py b/venv/lib/python3.11/site-packages/setuptools/command/easy_install.py deleted file mode 100755 index f4b67b5..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/easy_install.py +++ /dev/null @@ -1,2366 +0,0 @@ -""" -Easy Install ------------- - -A tool for doing automatic download/extract/build of distutils-based Python -packages. For detailed documentation, see the accompanying EasyInstall.txt -file, or visit the `EasyInstall home page`__. - -__ https://setuptools.pypa.io/en/latest/deprecated/easy_install.html - -""" - -from glob import glob -from distutils.util import get_platform -from distutils.util import convert_path, subst_vars -from distutils.errors import ( - DistutilsArgError, DistutilsOptionError, - DistutilsError, DistutilsPlatformError, -) -from distutils import log, dir_util -from distutils.command.build_scripts import first_line_re -from distutils.spawn import find_executable -from distutils.command import install -import sys -import os -import zipimport -import shutil -import tempfile -import zipfile -import re -import stat -import random -import textwrap -import warnings -import site -import struct -import contextlib -import subprocess -import shlex -import io -import configparser -import sysconfig - - -from sysconfig import get_path - -from setuptools import SetuptoolsDeprecationWarning - -from setuptools import Command -from setuptools.sandbox import run_setup -from setuptools.command import setopt -from setuptools.archive_util import unpack_archive -from setuptools.package_index import ( - PackageIndex, parse_requirement_arg, URL_SCHEME, -) -from setuptools.command import bdist_egg, egg_info -from setuptools.wheel import Wheel -from pkg_resources import ( - normalize_path, resource_string, - get_distribution, find_distributions, Environment, Requirement, - Distribution, PathMetadata, EggMetadata, WorkingSet, DistributionNotFound, - VersionConflict, DEVELOP_DIST, -) -import pkg_resources -from .._path import ensure_directory -from ..extern.jaraco.text import yield_lines - - -# Turn on PEP440Warnings -warnings.filterwarnings("default", category=pkg_resources.PEP440Warning) - -__all__ = [ - 'easy_install', 'PthDistributions', 'extract_wininst_cfg', - 'get_exe_prefixes', -] - - -def is_64bit(): - return struct.calcsize("P") == 8 - - -def _to_bytes(s): - return s.encode('utf8') - - -def isascii(s): - try: - s.encode('ascii') - return True - except UnicodeError: - return False - - -def _one_liner(text): - return textwrap.dedent(text).strip().replace('\n', '; ') - - -class easy_install(Command): - """Manage a download/build/install process""" - description = "Find/get/install Python packages" - command_consumes_arguments = True - - user_options = [ - ('prefix=', None, "installation prefix"), - ("zip-ok", "z", "install package as a zipfile"), - ("multi-version", "m", "make apps have to require() a version"), - ("upgrade", "U", "force upgrade (searches PyPI for latest versions)"), - ("install-dir=", "d", "install package to DIR"), - ("script-dir=", "s", "install scripts to DIR"), - ("exclude-scripts", "x", "Don't install scripts"), - ("always-copy", "a", "Copy all needed packages to install dir"), - ("index-url=", "i", "base URL of Python Package Index"), - ("find-links=", "f", "additional URL(s) to search for packages"), - ("build-directory=", "b", - "download/extract/build in DIR; keep the results"), - ('optimize=', 'O', - "also compile with optimization: -O1 for \"python -O\", " - "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), - ('record=', None, - "filename in which to record list of installed files"), - ('always-unzip', 'Z', "don't install as a zipfile, no matter what"), - ('site-dirs=', 'S', "list of directories where .pth files work"), - ('editable', 'e', "Install specified packages in editable form"), - ('no-deps', 'N', "don't install dependencies"), - ('allow-hosts=', 'H', "pattern(s) that hostnames must match"), - ('local-snapshots-ok', 'l', - "allow building eggs from local checkouts"), - ('version', None, "print version information and exit"), - ('install-layout=', None, "installation layout to choose (known values: deb)"), - ('force-installation-into-system-dir', '0', "force installation into /usr"), - ('no-find-links', None, - "Don't load find-links defined in packages being installed"), - ('user', None, "install in user site-package '%s'" % site.USER_SITE) - ] - boolean_options = [ - 'zip-ok', 'multi-version', 'exclude-scripts', 'upgrade', 'always-copy', - 'editable', - 'no-deps', 'local-snapshots-ok', 'version', 'force-installation-into-system-dir' - 'user' - ] - - negative_opt = {'always-unzip': 'zip-ok'} - create_index = PackageIndex - - def initialize_options(self): - warnings.warn( - "easy_install command is deprecated. " - "Use build and pip and other standards-based tools.", - EasyInstallDeprecationWarning, - ) - - # the --user option seems to be an opt-in one, - # so the default should be False. - self.user = 0 - self.zip_ok = self.local_snapshots_ok = None - self.install_dir = self.script_dir = self.exclude_scripts = None - self.index_url = None - self.find_links = None - self.build_directory = None - self.args = None - self.optimize = self.record = None - self.upgrade = self.always_copy = self.multi_version = None - self.editable = self.no_deps = self.allow_hosts = None - self.root = self.prefix = self.no_report = None - self.version = None - self.install_purelib = None # for pure module distributions - self.install_platlib = None # non-pure (dists w/ extensions) - self.install_headers = None # for C/C++ headers - self.install_lib = None # set to either purelib or platlib - self.install_scripts = None - self.install_data = None - self.install_base = None - self.install_platbase = None - self.install_userbase = site.USER_BASE - self.install_usersite = site.USER_SITE - self.no_find_links = None - - # Options not specifiable via command line - self.package_index = None - self.pth_file = self.always_copy_from = None - self.site_dirs = None - self.installed_projects = {} - # enable custom installation, known values: deb - self.install_layout = None - self.force_installation_into_system_dir = None - self.multiarch = None - - # Always read easy_install options, even if we are subclassed, or have - # an independent instance created. This ensures that defaults will - # always come from the standard configuration file(s)' "easy_install" - # section, even if this is a "develop" or "install" command, or some - # other embedding. - self._dry_run = None - self.verbose = self.distribution.verbose - self.distribution._set_command_options( - self, self.distribution.get_option_dict('easy_install') - ) - - def delete_blockers(self, blockers): - extant_blockers = ( - filename for filename in blockers - if os.path.exists(filename) or os.path.islink(filename) - ) - list(map(self._delete_path, extant_blockers)) - - def _delete_path(self, path): - log.info("Deleting %s", path) - if self.dry_run: - return - - is_tree = os.path.isdir(path) and not os.path.islink(path) - remover = rmtree if is_tree else os.unlink - remover(path) - - @staticmethod - def _render_version(): - """ - Render the Setuptools version and installation details, then exit. - """ - ver = '{}.{}'.format(*sys.version_info) - dist = get_distribution('setuptools') - tmpl = 'setuptools {dist.version} from {dist.location} (Python {ver})' - print(tmpl.format(**locals())) - raise SystemExit() - - def finalize_options(self): # noqa: C901 # is too complex (25) # FIXME - self.version and self._render_version() - - py_version = sys.version.split()[0] - - self.config_vars = dict(sysconfig.get_config_vars()) - - self.config_vars.update({ - 'dist_name': self.distribution.get_name(), - 'dist_version': self.distribution.get_version(), - 'dist_fullname': self.distribution.get_fullname(), - 'py_version': py_version, - 'py_version_short': f'{sys.version_info.major}.{sys.version_info.minor}', - 'py_version_nodot': f'{sys.version_info.major}{sys.version_info.minor}', - 'sys_prefix': self.config_vars['prefix'], - 'sys_exec_prefix': self.config_vars['exec_prefix'], - # Only python 3.2+ has abiflags - 'abiflags': getattr(sys, 'abiflags', ''), - 'platlibdir': getattr(sys, 'platlibdir', 'lib'), - }) - with contextlib.suppress(AttributeError): - # only for distutils outside stdlib - self.config_vars.update({ - 'implementation_lower': install._get_implementation().lower(), - 'implementation': install._get_implementation(), - }) - - # pypa/distutils#113 Python 3.9 compat - self.config_vars.setdefault( - 'py_version_nodot_plat', - getattr(sys, 'windir', '').replace('.', ''), - ) - - self.config_vars['userbase'] = self.install_userbase - self.config_vars['usersite'] = self.install_usersite - if self.user and not site.ENABLE_USER_SITE: - log.warn("WARNING: The user site-packages directory is disabled.") - - self._fix_install_dir_for_user_site() - - self.expand_basedirs() - self.expand_dirs() - - if self.install_layout: - if not self.install_layout.lower() in ['deb']: - raise DistutilsOptionError("unknown value for --install-layout") - self.install_layout = self.install_layout.lower() - - if sys.version_info[:2] >= (3, 3): - self.multiarch = sysconfig.get_config_var('MULTIARCH') - - self._expand( - 'install_dir', 'script_dir', 'build_directory', - 'site_dirs', - ) - # If a non-default installation directory was specified, default the - # script directory to match it. - if self.script_dir is None: - self.script_dir = self.install_dir - - if self.no_find_links is None: - self.no_find_links = False - - # Let install_dir get set by install_lib command, which in turn - # gets its info from the install command, and takes into account - # --prefix and --home and all that other crud. - self.set_undefined_options( - 'install_lib', ('install_dir', 'install_dir') - ) - # Likewise, set default script_dir from 'install_scripts.install_dir' - self.set_undefined_options( - 'install_scripts', ('install_dir', 'script_dir') - ) - - if self.user and self.install_purelib: - self.install_dir = self.install_purelib - self.script_dir = self.install_scripts - - if self.prefix == '/usr' and not self.force_installation_into_system_dir: - raise DistutilsOptionError("""installation into /usr - -Trying to install into the system managed parts of the file system. Please -consider to install to another location, or use the option ---force-installation-into-system-dir to overwrite this warning. -""") - - # default --record from the install command - self.set_undefined_options('install', ('record', 'record')) - self.all_site_dirs = get_site_dirs() - self.all_site_dirs.extend(self._process_site_dirs(self.site_dirs)) - - if not self.editable: - self.check_site_dir() - default_index = os.getenv("__EASYINSTALL_INDEX", "https://pypi.org/simple/") - # ^ Private API for testing purposes only - self.index_url = self.index_url or default_index - self.shadow_path = self.all_site_dirs[:] - for path_item in self.install_dir, normalize_path(self.script_dir): - if path_item not in self.shadow_path: - self.shadow_path.insert(0, path_item) - - if self.allow_hosts is not None: - hosts = [s.strip() for s in self.allow_hosts.split(',')] - else: - hosts = ['*'] - if self.package_index is None: - self.package_index = self.create_index( - self.index_url, search_path=self.shadow_path, hosts=hosts, - ) - self.local_index = Environment(self.shadow_path + sys.path) - - if self.find_links is not None: - if isinstance(self.find_links, str): - self.find_links = self.find_links.split() - else: - self.find_links = [] - if self.local_snapshots_ok: - self.package_index.scan_egg_links(self.shadow_path + sys.path) - if not self.no_find_links: - self.package_index.add_find_links(self.find_links) - self.set_undefined_options('install_lib', ('optimize', 'optimize')) - self.optimize = self._validate_optimize(self.optimize) - - if self.editable and not self.build_directory: - raise DistutilsArgError( - "Must specify a build directory (-b) when using --editable" - ) - if not self.args: - raise DistutilsArgError( - "No urls, filenames, or requirements specified (see --help)") - - self.outputs = [] - - @staticmethod - def _process_site_dirs(site_dirs): - if site_dirs is None: - return - - normpath = map(normalize_path, sys.path) - site_dirs = [ - os.path.expanduser(s.strip()) for s in - site_dirs.split(',') - ] - for d in site_dirs: - if not os.path.isdir(d): - log.warn("%s (in --site-dirs) does not exist", d) - elif normalize_path(d) not in normpath: - raise DistutilsOptionError( - d + " (in --site-dirs) is not on sys.path" - ) - else: - yield normalize_path(d) - - @staticmethod - def _validate_optimize(value): - try: - value = int(value) - if value not in range(3): - raise ValueError - except ValueError as e: - raise DistutilsOptionError( - "--optimize must be 0, 1, or 2" - ) from e - - return value - - def _fix_install_dir_for_user_site(self): - """ - Fix the install_dir if "--user" was used. - """ - if not self.user: - return - - self.create_home_path() - if self.install_userbase is None: - msg = "User base directory is not specified" - raise DistutilsPlatformError(msg) - self.install_base = self.install_platbase = self.install_userbase - scheme_name = f'{os.name}_user' - self.select_scheme(scheme_name) - - def _expand_attrs(self, attrs): - for attr in attrs: - val = getattr(self, attr) - if val is not None: - if os.name == 'posix' or os.name == 'nt': - val = os.path.expanduser(val) - val = subst_vars(val, self.config_vars) - setattr(self, attr, val) - - def expand_basedirs(self): - """Calls `os.path.expanduser` on install_base, install_platbase and - root.""" - self._expand_attrs(['install_base', 'install_platbase', 'root']) - - def expand_dirs(self): - """Calls `os.path.expanduser` on install dirs.""" - dirs = [ - 'install_purelib', - 'install_platlib', - 'install_lib', - 'install_headers', - 'install_scripts', - 'install_data', - ] - self._expand_attrs(dirs) - - def run(self, show_deprecation=True): - if show_deprecation: - self.announce( - "WARNING: The easy_install command is deprecated " - "and will be removed in a future version.", - log.WARN, - ) - if self.verbose != self.distribution.verbose: - log.set_verbosity(self.verbose) - try: - for spec in self.args: - self.easy_install(spec, not self.no_deps) - if self.record: - outputs = list(sorted(self.outputs)) - if self.root: # strip any package prefix - root_len = len(self.root) - for counter in range(len(outputs)): - outputs[counter] = outputs[counter][root_len:] - from distutils import file_util - - self.execute( - file_util.write_file, (self.record, outputs), - "writing list of installed files to '%s'" % - self.record - ) - self.warn_deprecated_options() - finally: - log.set_verbosity(self.distribution.verbose) - - def pseudo_tempname(self): - """Return a pseudo-tempname base in the install directory. - This code is intentionally naive; if a malicious party can write to - the target directory you're already in deep doodoo. - """ - try: - pid = os.getpid() - except Exception: - pid = random.randint(0, sys.maxsize) - return os.path.join(self.install_dir, "test-easy-install-%s" % pid) - - def warn_deprecated_options(self): - pass - - def check_site_dir(self): # noqa: C901 # is too complex (12) # FIXME - """Verify that self.install_dir is .pth-capable dir, if needed""" - - instdir = normalize_path(self.install_dir) - pth_file = os.path.join(instdir, 'easy-install.pth') - - if not os.path.exists(instdir): - try: - os.makedirs(instdir) - except (OSError, IOError): - self.cant_write_to_target() - - # Is it a configured, PYTHONPATH, implicit, or explicit site dir? - is_site_dir = instdir in self.all_site_dirs - - if not is_site_dir and not self.multi_version: - # No? Then directly test whether it does .pth file processing - is_site_dir = self.check_pth_processing() - else: - # make sure we can write to target dir - testfile = self.pseudo_tempname() + '.write-test' - test_exists = os.path.exists(testfile) - try: - if test_exists: - os.unlink(testfile) - open(testfile, 'w').close() - os.unlink(testfile) - except (OSError, IOError): - self.cant_write_to_target() - - if not is_site_dir and not self.multi_version: - # Can't install non-multi to non-site dir with easy_install - pythonpath = os.environ.get('PYTHONPATH', '') - log.warn(self.__no_default_msg, self.install_dir, pythonpath) - - if is_site_dir: - if self.pth_file is None: - self.pth_file = PthDistributions(pth_file, self.all_site_dirs) - else: - self.pth_file = None - - if self.multi_version and not os.path.exists(pth_file): - self.pth_file = None # don't create a .pth file - self.install_dir = instdir - - __cant_write_msg = textwrap.dedent(""" - can't create or remove files in install directory - - The following error occurred while trying to add or remove files in the - installation directory: - - %s - - The installation directory you specified (via --install-dir, --prefix, or - the distutils default setting) was: - - %s - """).lstrip() # noqa - - __not_exists_id = textwrap.dedent(""" - This directory does not currently exist. Please create it and try again, or - choose a different installation directory (using the -d or --install-dir - option). - """).lstrip() # noqa - - __access_msg = textwrap.dedent(""" - Perhaps your account does not have write access to this directory? If the - installation directory is a system-owned directory, you may need to sign in - as the administrator or "root" account. If you do not have administrative - access to this machine, you may wish to choose a different installation - directory, preferably one that is listed in your PYTHONPATH environment - variable. - - For information on other options, you may wish to consult the - documentation at: - - https://setuptools.pypa.io/en/latest/deprecated/easy_install.html - - Please make the appropriate changes for your system and try again. - """).lstrip() # noqa - - def cant_write_to_target(self): - msg = self.__cant_write_msg % (sys.exc_info()[1], self.install_dir,) - - if not os.path.exists(self.install_dir): - msg += '\n' + self.__not_exists_id - else: - msg += '\n' + self.__access_msg - raise DistutilsError(msg) - - def check_pth_processing(self): - """Empirically verify whether .pth files are supported in inst. dir""" - instdir = self.install_dir - log.info("Checking .pth file support in %s", instdir) - pth_file = self.pseudo_tempname() + ".pth" - ok_file = pth_file + '.ok' - ok_exists = os.path.exists(ok_file) - tmpl = _one_liner(""" - import os - f = open({ok_file!r}, 'w') - f.write('OK') - f.close() - """) + '\n' - try: - if ok_exists: - os.unlink(ok_file) - dirname = os.path.dirname(ok_file) - os.makedirs(dirname, exist_ok=True) - f = open(pth_file, 'w') - except (OSError, IOError): - self.cant_write_to_target() - else: - try: - f.write(tmpl.format(**locals())) - f.close() - f = None - executable = sys.executable - if os.name == 'nt': - dirname, basename = os.path.split(executable) - alt = os.path.join(dirname, 'pythonw.exe') - use_alt = ( - basename.lower() == 'python.exe' and - os.path.exists(alt) - ) - if use_alt: - # use pythonw.exe to avoid opening a console window - executable = alt - - from distutils.spawn import spawn - - spawn([executable, '-E', '-c', 'pass'], 0) - - if os.path.exists(ok_file): - log.info( - "TEST PASSED: %s appears to support .pth files", - instdir - ) - return True - finally: - if f: - f.close() - if os.path.exists(ok_file): - os.unlink(ok_file) - if os.path.exists(pth_file): - os.unlink(pth_file) - if not self.multi_version: - log.warn("TEST FAILED: %s does NOT support .pth files", instdir) - return False - - def install_egg_scripts(self, dist): - """Write all the scripts for `dist`, unless scripts are excluded""" - if not self.exclude_scripts and dist.metadata_isdir('scripts'): - for script_name in dist.metadata_listdir('scripts'): - if dist.metadata_isdir('scripts/' + script_name): - # The "script" is a directory, likely a Python 3 - # __pycache__ directory, so skip it. - continue - self.install_script( - dist, script_name, - dist.get_metadata('scripts/' + script_name) - ) - self.install_wrapper_scripts(dist) - - def add_output(self, path): - if os.path.isdir(path): - for base, dirs, files in os.walk(path): - for filename in files: - self.outputs.append(os.path.join(base, filename)) - else: - self.outputs.append(path) - - def not_editable(self, spec): - if self.editable: - raise DistutilsArgError( - "Invalid argument %r: you can't use filenames or URLs " - "with --editable (except via the --find-links option)." - % (spec,) - ) - - def check_editable(self, spec): - if not self.editable: - return - - if os.path.exists(os.path.join(self.build_directory, spec.key)): - raise DistutilsArgError( - "%r already exists in %s; can't do a checkout there" % - (spec.key, self.build_directory) - ) - - @contextlib.contextmanager - def _tmpdir(self): - tmpdir = tempfile.mkdtemp(prefix=u"easy_install-") - try: - # cast to str as workaround for #709 and #710 and #712 - yield str(tmpdir) - finally: - os.path.exists(tmpdir) and rmtree(tmpdir) - - def easy_install(self, spec, deps=False): - with self._tmpdir() as tmpdir: - if not isinstance(spec, Requirement): - if URL_SCHEME(spec): - # It's a url, download it to tmpdir and process - self.not_editable(spec) - dl = self.package_index.download(spec, tmpdir) - return self.install_item(None, dl, tmpdir, deps, True) - - elif os.path.exists(spec): - # Existing file or directory, just process it directly - self.not_editable(spec) - return self.install_item(None, spec, tmpdir, deps, True) - else: - spec = parse_requirement_arg(spec) - - self.check_editable(spec) - dist = self.package_index.fetch_distribution( - spec, tmpdir, self.upgrade, self.editable, - not self.always_copy, self.local_index - ) - if dist is None: - msg = "Could not find suitable distribution for %r" % spec - if self.always_copy: - msg += " (--always-copy skips system and development eggs)" - raise DistutilsError(msg) - elif dist.precedence == DEVELOP_DIST: - # .egg-info dists don't need installing, just process deps - self.process_distribution(spec, dist, deps, "Using") - return dist - else: - return self.install_item(spec, dist.location, tmpdir, deps) - - def install_item(self, spec, download, tmpdir, deps, install_needed=False): - - # Installation is also needed if file in tmpdir or is not an egg - install_needed = install_needed or self.always_copy - install_needed = install_needed or os.path.dirname(download) == tmpdir - install_needed = install_needed or not download.endswith('.egg') - install_needed = install_needed or ( - self.always_copy_from is not None and - os.path.dirname(normalize_path(download)) == - normalize_path(self.always_copy_from) - ) - - if spec and not install_needed: - # at this point, we know it's a local .egg, we just don't know if - # it's already installed. - for dist in self.local_index[spec.project_name]: - if dist.location == download: - break - else: - install_needed = True # it's not in the local index - - log.info("Processing %s", os.path.basename(download)) - - if install_needed: - dists = self.install_eggs(spec, download, tmpdir) - for dist in dists: - self.process_distribution(spec, dist, deps) - else: - dists = [self.egg_distribution(download)] - self.process_distribution(spec, dists[0], deps, "Using") - - if spec is not None: - for dist in dists: - if dist in spec: - return dist - - def select_scheme(self, name): - try: - install._select_scheme(self, name) - except AttributeError: - # stdlib distutils - install.install.select_scheme(self, name.replace('posix', 'unix')) - - # FIXME: 'easy_install.process_distribution' is too complex (12) - def process_distribution( # noqa: C901 - self, requirement, dist, deps=True, *info, - ): - self.update_pth(dist) - self.package_index.add(dist) - if dist in self.local_index[dist.key]: - self.local_index.remove(dist) - self.local_index.add(dist) - self.install_egg_scripts(dist) - self.installed_projects[dist.key] = dist - log.info(self.installation_report(requirement, dist, *info)) - if (dist.has_metadata('dependency_links.txt') and - not self.no_find_links): - self.package_index.add_find_links( - dist.get_metadata_lines('dependency_links.txt') - ) - if not deps and not self.always_copy: - return - elif requirement is not None and dist.key != requirement.key: - log.warn("Skipping dependencies for %s", dist) - return # XXX this is not the distribution we were looking for - elif requirement is None or dist not in requirement: - # if we wound up with a different version, resolve what we've got - distreq = dist.as_requirement() - requirement = Requirement(str(distreq)) - log.info("Processing dependencies for %s", requirement) - try: - distros = WorkingSet([]).resolve( - [requirement], self.local_index, self.easy_install - ) - except DistributionNotFound as e: - raise DistutilsError(str(e)) from e - except VersionConflict as e: - raise DistutilsError(e.report()) from e - if self.always_copy or self.always_copy_from: - # Force all the relevant distros to be copied or activated - for dist in distros: - if dist.key not in self.installed_projects: - self.easy_install(dist.as_requirement()) - log.info("Finished processing dependencies for %s", requirement) - - def should_unzip(self, dist): - if self.zip_ok is not None: - return not self.zip_ok - if dist.has_metadata('not-zip-safe'): - return True - if not dist.has_metadata('zip-safe'): - return True - return False - - def maybe_move(self, spec, dist_filename, setup_base): - dst = os.path.join(self.build_directory, spec.key) - if os.path.exists(dst): - msg = ( - "%r already exists in %s; build directory %s will not be kept" - ) - log.warn(msg, spec.key, self.build_directory, setup_base) - return setup_base - if os.path.isdir(dist_filename): - setup_base = dist_filename - else: - if os.path.dirname(dist_filename) == setup_base: - os.unlink(dist_filename) # get it out of the tmp dir - contents = os.listdir(setup_base) - if len(contents) == 1: - dist_filename = os.path.join(setup_base, contents[0]) - if os.path.isdir(dist_filename): - # if the only thing there is a directory, move it instead - setup_base = dist_filename - ensure_directory(dst) - shutil.move(setup_base, dst) - return dst - - def install_wrapper_scripts(self, dist): - if self.exclude_scripts: - return - for args in ScriptWriter.best().get_args(dist): - self.write_script(*args) - - def install_script(self, dist, script_name, script_text, dev_path=None): - """Generate a legacy script wrapper and install it""" - spec = str(dist.as_requirement()) - is_script = is_python_script(script_text, script_name) - - if is_script: - body = self._load_template(dev_path) % locals() - script_text = ScriptWriter.get_header(script_text) + body - self.write_script(script_name, _to_bytes(script_text), 'b') - - @staticmethod - def _load_template(dev_path): - """ - There are a couple of template scripts in the package. This - function loads one of them and prepares it for use. - """ - # See https://github.com/pypa/setuptools/issues/134 for info - # on script file naming and downstream issues with SVR4 - name = 'script.tmpl' - if dev_path: - name = name.replace('.tmpl', ' (dev).tmpl') - - raw_bytes = resource_string('setuptools', name) - return raw_bytes.decode('utf-8') - - def write_script(self, script_name, contents, mode="t", blockers=()): - """Write an executable file to the scripts directory""" - self.delete_blockers( # clean up old .py/.pyw w/o a script - [os.path.join(self.script_dir, x) for x in blockers] - ) - log.info("Installing %s script to %s", script_name, self.script_dir) - target = os.path.join(self.script_dir, script_name) - self.add_output(target) - - if self.dry_run: - return - - mask = current_umask() - ensure_directory(target) - if os.path.exists(target): - os.unlink(target) - with open(target, "w" + mode) as f: - f.write(contents) - chmod(target, 0o777 - mask) - - def install_eggs(self, spec, dist_filename, tmpdir): - # .egg dirs or files are already built, so just return them - installer_map = { - '.egg': self.install_egg, - '.exe': self.install_exe, - '.whl': self.install_wheel, - } - try: - install_dist = installer_map[ - dist_filename.lower()[-4:] - ] - except KeyError: - pass - else: - return [install_dist(dist_filename, tmpdir)] - - # Anything else, try to extract and build - setup_base = tmpdir - if os.path.isfile(dist_filename) and not dist_filename.endswith('.py'): - unpack_archive(dist_filename, tmpdir, self.unpack_progress) - elif os.path.isdir(dist_filename): - setup_base = os.path.abspath(dist_filename) - - if (setup_base.startswith(tmpdir) # something we downloaded - and self.build_directory and spec is not None): - setup_base = self.maybe_move(spec, dist_filename, setup_base) - - # Find the setup.py file - setup_script = os.path.join(setup_base, 'setup.py') - - if not os.path.exists(setup_script): - setups = glob(os.path.join(setup_base, '*', 'setup.py')) - if not setups: - raise DistutilsError( - "Couldn't find a setup script in %s" % - os.path.abspath(dist_filename) - ) - if len(setups) > 1: - raise DistutilsError( - "Multiple setup scripts in %s" % - os.path.abspath(dist_filename) - ) - setup_script = setups[0] - - # Now run it, and return the result - if self.editable: - log.info(self.report_editable(spec, setup_script)) - return [] - else: - return self.build_and_install(setup_script, setup_base) - - def egg_distribution(self, egg_path): - if os.path.isdir(egg_path): - metadata = PathMetadata(egg_path, os.path.join(egg_path, - 'EGG-INFO')) - else: - metadata = EggMetadata(zipimport.zipimporter(egg_path)) - return Distribution.from_filename(egg_path, metadata=metadata) - - # FIXME: 'easy_install.install_egg' is too complex (11) - def install_egg(self, egg_path, tmpdir): # noqa: C901 - destination = os.path.join( - self.install_dir, - os.path.basename(egg_path), - ) - destination = os.path.abspath(destination) - if not self.dry_run: - ensure_directory(destination) - - dist = self.egg_distribution(egg_path) - if not ( - os.path.exists(destination) and os.path.samefile(egg_path, destination) - ): - if os.path.isdir(destination) and not os.path.islink(destination): - dir_util.remove_tree(destination, dry_run=self.dry_run) - elif os.path.exists(destination): - self.execute( - os.unlink, - (destination,), - "Removing " + destination, - ) - try: - new_dist_is_zipped = False - if os.path.isdir(egg_path): - if egg_path.startswith(tmpdir): - f, m = shutil.move, "Moving" - else: - f, m = shutil.copytree, "Copying" - elif self.should_unzip(dist): - self.mkpath(destination) - f, m = self.unpack_and_compile, "Extracting" - else: - new_dist_is_zipped = True - if egg_path.startswith(tmpdir): - f, m = shutil.move, "Moving" - else: - f, m = shutil.copy2, "Copying" - self.execute( - f, - (egg_path, destination), - (m + " %s to %s") % ( - os.path.basename(egg_path), - os.path.dirname(destination) - ), - ) - update_dist_caches( - destination, - fix_zipimporter_caches=new_dist_is_zipped, - ) - except Exception: - update_dist_caches(destination, fix_zipimporter_caches=False) - raise - - self.add_output(destination) - return self.egg_distribution(destination) - - def install_exe(self, dist_filename, tmpdir): - # See if it's valid, get data - cfg = extract_wininst_cfg(dist_filename) - if cfg is None: - raise DistutilsError( - "%s is not a valid distutils Windows .exe" % dist_filename - ) - # Create a dummy distribution object until we build the real distro - dist = Distribution( - None, - project_name=cfg.get('metadata', 'name'), - version=cfg.get('metadata', 'version'), platform=get_platform(), - ) - - # Convert the .exe to an unpacked egg - egg_path = os.path.join(tmpdir, dist.egg_name() + '.egg') - dist.location = egg_path - egg_tmp = egg_path + '.tmp' - _egg_info = os.path.join(egg_tmp, 'EGG-INFO') - pkg_inf = os.path.join(_egg_info, 'PKG-INFO') - ensure_directory(pkg_inf) # make sure EGG-INFO dir exists - dist._provider = PathMetadata(egg_tmp, _egg_info) # XXX - self.exe_to_egg(dist_filename, egg_tmp) - - # Write EGG-INFO/PKG-INFO - if not os.path.exists(pkg_inf): - f = open(pkg_inf, 'w') - f.write('Metadata-Version: 1.0\n') - for k, v in cfg.items('metadata'): - if k != 'target_version': - f.write('%s: %s\n' % (k.replace('_', '-').title(), v)) - f.close() - script_dir = os.path.join(_egg_info, 'scripts') - # delete entry-point scripts to avoid duping - self.delete_blockers([ - os.path.join(script_dir, args[0]) - for args in ScriptWriter.get_args(dist) - ]) - # Build .egg file from tmpdir - bdist_egg.make_zipfile( - egg_path, egg_tmp, verbose=self.verbose, dry_run=self.dry_run, - ) - # install the .egg - return self.install_egg(egg_path, tmpdir) - - # FIXME: 'easy_install.exe_to_egg' is too complex (12) - def exe_to_egg(self, dist_filename, egg_tmp): # noqa: C901 - """Extract a bdist_wininst to the directories an egg would use""" - # Check for .pth file and set up prefix translations - prefixes = get_exe_prefixes(dist_filename) - to_compile = [] - native_libs = [] - top_level = {} - - def process(src, dst): - s = src.lower() - for old, new in prefixes: - if s.startswith(old): - src = new + src[len(old):] - parts = src.split('/') - dst = os.path.join(egg_tmp, *parts) - dl = dst.lower() - if dl.endswith('.pyd') or dl.endswith('.dll'): - parts[-1] = bdist_egg.strip_module(parts[-1]) - top_level[os.path.splitext(parts[0])[0]] = 1 - native_libs.append(src) - elif dl.endswith('.py') and old != 'SCRIPTS/': - top_level[os.path.splitext(parts[0])[0]] = 1 - to_compile.append(dst) - return dst - if not src.endswith('.pth'): - log.warn("WARNING: can't process %s", src) - return None - - # extract, tracking .pyd/.dll->native_libs and .py -> to_compile - unpack_archive(dist_filename, egg_tmp, process) - stubs = [] - for res in native_libs: - if res.lower().endswith('.pyd'): # create stubs for .pyd's - parts = res.split('/') - resource = parts[-1] - parts[-1] = bdist_egg.strip_module(parts[-1]) + '.py' - pyfile = os.path.join(egg_tmp, *parts) - to_compile.append(pyfile) - stubs.append(pyfile) - bdist_egg.write_stub(resource, pyfile) - self.byte_compile(to_compile) # compile .py's - bdist_egg.write_safety_flag( - os.path.join(egg_tmp, 'EGG-INFO'), - bdist_egg.analyze_egg(egg_tmp, stubs)) # write zip-safety flag - - for name in 'top_level', 'native_libs': - if locals()[name]: - txt = os.path.join(egg_tmp, 'EGG-INFO', name + '.txt') - if not os.path.exists(txt): - f = open(txt, 'w') - f.write('\n'.join(locals()[name]) + '\n') - f.close() - - def install_wheel(self, wheel_path, tmpdir): - wheel = Wheel(wheel_path) - assert wheel.is_compatible() - destination = os.path.join(self.install_dir, wheel.egg_name()) - destination = os.path.abspath(destination) - if not self.dry_run: - ensure_directory(destination) - if os.path.isdir(destination) and not os.path.islink(destination): - dir_util.remove_tree(destination, dry_run=self.dry_run) - elif os.path.exists(destination): - self.execute( - os.unlink, - (destination,), - "Removing " + destination, - ) - try: - self.execute( - wheel.install_as_egg, - (destination,), - ("Installing %s to %s") % ( - os.path.basename(wheel_path), - os.path.dirname(destination) - ), - ) - finally: - update_dist_caches(destination, fix_zipimporter_caches=False) - self.add_output(destination) - return self.egg_distribution(destination) - - __mv_warning = textwrap.dedent(""" - Because this distribution was installed --multi-version, before you can - import modules from this package in an application, you will need to - 'import pkg_resources' and then use a 'require()' call similar to one of - these examples, in order to select the desired version: - - pkg_resources.require("%(name)s") # latest installed version - pkg_resources.require("%(name)s==%(version)s") # this exact version - pkg_resources.require("%(name)s>=%(version)s") # this version or higher - """).lstrip() # noqa - - __id_warning = textwrap.dedent(""" - Note also that the installation directory must be on sys.path at runtime for - this to work. (e.g. by being the application's script directory, by being on - PYTHONPATH, or by being added to sys.path by your code.) - """) # noqa - - def installation_report(self, req, dist, what="Installed"): - """Helpful installation message for display to package users""" - msg = "\n%(what)s %(eggloc)s%(extras)s" - if self.multi_version and not self.no_report: - msg += '\n' + self.__mv_warning - if self.install_dir not in map(normalize_path, sys.path): - msg += '\n' + self.__id_warning - - eggloc = dist.location - name = dist.project_name - version = dist.version - extras = '' # TODO: self.report_extras(req, dist) - return msg % locals() - - __editable_msg = textwrap.dedent(""" - Extracted editable version of %(spec)s to %(dirname)s - - If it uses setuptools in its setup script, you can activate it in - "development" mode by going to that directory and running:: - - %(python)s setup.py develop - - See the setuptools documentation for the "develop" command for more info. - """).lstrip() # noqa - - def report_editable(self, spec, setup_script): - dirname = os.path.dirname(setup_script) - python = sys.executable - return '\n' + self.__editable_msg % locals() - - def run_setup(self, setup_script, setup_base, args): - sys.modules.setdefault('distutils.command.bdist_egg', bdist_egg) - sys.modules.setdefault('distutils.command.egg_info', egg_info) - - args = list(args) - if self.verbose > 2: - v = 'v' * (self.verbose - 1) - args.insert(0, '-' + v) - elif self.verbose < 2: - args.insert(0, '-q') - if self.dry_run: - args.insert(0, '-n') - log.info( - "Running %s %s", setup_script[len(setup_base) + 1:], ' '.join(args) - ) - try: - run_setup(setup_script, args) - except SystemExit as v: - raise DistutilsError( - "Setup script exited with %s" % (v.args[0],) - ) from v - - def build_and_install(self, setup_script, setup_base): - args = ['bdist_egg', '--dist-dir'] - - dist_dir = tempfile.mkdtemp( - prefix='egg-dist-tmp-', dir=os.path.dirname(setup_script) - ) - try: - self._set_fetcher_options(os.path.dirname(setup_script)) - args.append(dist_dir) - - self.run_setup(setup_script, setup_base, args) - all_eggs = Environment([dist_dir]) - eggs = [] - for key in all_eggs: - for dist in all_eggs[key]: - eggs.append(self.install_egg(dist.location, setup_base)) - if not eggs and not self.dry_run: - log.warn("No eggs found in %s (setup script problem?)", - dist_dir) - return eggs - finally: - rmtree(dist_dir) - log.set_verbosity(self.verbose) # restore our log verbosity - - def _set_fetcher_options(self, base): - """ - When easy_install is about to run bdist_egg on a source dist, that - source dist might have 'setup_requires' directives, requiring - additional fetching. Ensure the fetcher options given to easy_install - are available to that command as well. - """ - # find the fetch options from easy_install and write them out - # to the setup.cfg file. - ei_opts = self.distribution.get_option_dict('easy_install').copy() - fetch_directives = ( - 'find_links', 'site_dirs', 'index_url', 'optimize', 'allow_hosts', - ) - fetch_options = {} - for key, val in ei_opts.items(): - if key not in fetch_directives: - continue - fetch_options[key] = val[1] - # create a settings dictionary suitable for `edit_config` - settings = dict(easy_install=fetch_options) - cfg_filename = os.path.join(base, 'setup.cfg') - setopt.edit_config(cfg_filename, settings) - - def update_pth(self, dist): # noqa: C901 # is too complex (11) # FIXME - if self.pth_file is None: - return - - for d in self.pth_file[dist.key]: # drop old entries - if not self.multi_version and d.location == dist.location: - continue - - log.info("Removing %s from easy-install.pth file", d) - self.pth_file.remove(d) - if d.location in self.shadow_path: - self.shadow_path.remove(d.location) - - if not self.multi_version: - if dist.location in self.pth_file.paths: - log.info( - "%s is already the active version in easy-install.pth", - dist, - ) - else: - log.info("Adding %s to easy-install.pth file", dist) - self.pth_file.add(dist) # add new entry - if dist.location not in self.shadow_path: - self.shadow_path.append(dist.location) - - if self.dry_run: - return - - self.pth_file.save() - - if dist.key != 'setuptools': - return - - # Ensure that setuptools itself never becomes unavailable! - # XXX should this check for latest version? - filename = os.path.join(self.install_dir, 'setuptools.pth') - if os.path.islink(filename): - os.unlink(filename) - with open(filename, 'wt') as f: - f.write(self.pth_file.make_relative(dist.location) + '\n') - - def unpack_progress(self, src, dst): - # Progress filter for unpacking - log.debug("Unpacking %s to %s", src, dst) - return dst # only unpack-and-compile skips files for dry run - - def unpack_and_compile(self, egg_path, destination): - to_compile = [] - to_chmod = [] - - def pf(src, dst): - if dst.endswith('.py') and not src.startswith('EGG-INFO/'): - to_compile.append(dst) - elif dst.endswith('.dll') or dst.endswith('.so'): - to_chmod.append(dst) - self.unpack_progress(src, dst) - return not self.dry_run and dst or None - - unpack_archive(egg_path, destination, pf) - self.byte_compile(to_compile) - if not self.dry_run: - for f in to_chmod: - mode = ((os.stat(f)[stat.ST_MODE]) | 0o555) & 0o7755 - chmod(f, mode) - - def byte_compile(self, to_compile): - if sys.dont_write_bytecode: - return - - from distutils.util import byte_compile - - try: - # try to make the byte compile messages quieter - log.set_verbosity(self.verbose - 1) - - byte_compile(to_compile, optimize=0, force=1, dry_run=self.dry_run) - if self.optimize: - byte_compile( - to_compile, optimize=self.optimize, force=1, - dry_run=self.dry_run, - ) - finally: - log.set_verbosity(self.verbose) # restore original verbosity - - __no_default_msg = textwrap.dedent(""" - bad install directory or PYTHONPATH - - You are attempting to install a package to a directory that is not - on PYTHONPATH and which Python does not read ".pth" files from. The - installation directory you specified (via --install-dir, --prefix, or - the distutils default setting) was: - - %s - - and your PYTHONPATH environment variable currently contains: - - %r - - Here are some of your options for correcting the problem: - - * You can choose a different installation directory, i.e., one that is - on PYTHONPATH or supports .pth files - - * You can add the installation directory to the PYTHONPATH environment - variable. (It must then also be on PYTHONPATH whenever you run - Python and want to use the package(s) you are installing.) - - * You can set up the installation directory to support ".pth" files by - using one of the approaches described here: - - https://setuptools.pypa.io/en/latest/deprecated/easy_install.html#custom-installation-locations - - - Please make the appropriate changes for your system and try again. - """).strip() - - def create_home_path(self): - """Create directories under ~.""" - if not self.user: - return - home = convert_path(os.path.expanduser("~")) - for path in only_strs(self.config_vars.values()): - if path.startswith(home) and not os.path.isdir(path): - self.debug_print("os.makedirs('%s', 0o700)" % path) - os.makedirs(path, 0o700) - - if sys.version[:3] in ('2.3', '2.4', '2.5') or 'real_prefix' in sys.__dict__: - sitedir_name = 'site-packages' - else: - sitedir_name = 'dist-packages' - - INSTALL_SCHEMES = dict( - posix=dict( - install_dir='$base/lib/python$py_version_short/site-packages', - script_dir='$base/bin', - ), - unix_local = dict( - install_dir = '$base/local/lib/python$py_version_short/%s' % sitedir_name, - script_dir = '$base/local/bin', - ), - posix_local = dict( - install_dir = '$base/local/lib/python$py_version_short/%s' % sitedir_name, - script_dir = '$base/local/bin', - ), - deb_system = dict( - install_dir = '$base/lib/python3/%s' % sitedir_name, - script_dir = '$base/bin', - ), - ) - - DEFAULT_SCHEME = dict( - install_dir='$base/Lib/site-packages', - script_dir='$base/Scripts', - ) - - def _expand(self, *attrs): - config_vars = self.get_finalized_command('install').config_vars - - if self.prefix or self.install_layout: - if self.install_layout and self.install_layout in ['deb']: - scheme_name = "deb_system" - self.prefix = '/usr' - elif self.prefix or 'real_prefix' in sys.__dict__: - scheme_name = os.name - else: - scheme_name = "posix_local" - # Set default install_dir/scripts from --prefix - config_vars = dict(config_vars) - config_vars['base'] = self.prefix - scheme = self.INSTALL_SCHEMES.get(scheme_name,self.DEFAULT_SCHEME) - for attr, val in scheme.items(): - if getattr(self, attr, None) is None: - setattr(self, attr, val) - - from distutils.util import subst_vars - - for attr in attrs: - val = getattr(self, attr) - if val is not None: - val = subst_vars(val, config_vars) - if os.name == 'posix': - val = os.path.expanduser(val) - setattr(self, attr, val) - - -def _pythonpath(): - items = os.environ.get('PYTHONPATH', '').split(os.pathsep) - return filter(None, items) - - -def get_site_dirs(): - """ - Return a list of 'site' dirs - """ - - sitedirs = [] - - # start with PYTHONPATH - sitedirs.extend(_pythonpath()) - - prefixes = [sys.prefix] - if sys.exec_prefix != sys.prefix: - prefixes.append(sys.exec_prefix) - for prefix in prefixes: - if not prefix: - continue - - if sys.platform in ('os2emx', 'riscos'): - sitedirs.append(os.path.join(prefix, "Lib", "site-packages")) - elif os.sep == '/': - sitedirs.extend([ - os.path.join( - prefix, - "local/lib", - "python" + sys.version[:3], - "dist-packages", - ), - os.path.join( - prefix, - "lib", - "python{}.{}".format(*sys.version_info), - "dist-packages", - ), - os.path.join(prefix, "lib", "site-python"), - ]) - else: - sitedirs.extend([ - prefix, - os.path.join(prefix, "lib", "site-packages"), - ]) - if sys.platform != 'darwin': - continue - - # for framework builds *only* we add the standard Apple - # locations. Currently only per-user, but /Library and - # /Network/Library could be added too - if 'Python.framework' not in prefix: - continue - - home = os.environ.get('HOME') - if not home: - continue - - home_sp = os.path.join( - home, - 'Library', - 'Python', - '{}.{}'.format(*sys.version_info), - 'site-packages', - ) - sitedirs.append(home_sp) - lib_paths = get_path('purelib'), get_path('platlib') - - sitedirs.extend(s for s in lib_paths if s not in sitedirs) - - if site.ENABLE_USER_SITE: - sitedirs.append(site.USER_SITE) - - with contextlib.suppress(AttributeError): - sitedirs.extend(site.getsitepackages()) - - sitedirs = list(map(normalize_path, sitedirs)) - - return sitedirs - - -def expand_paths(inputs): # noqa: C901 # is too complex (11) # FIXME - """Yield sys.path directories that might contain "old-style" packages""" - - seen = {} - - for dirname in inputs: - dirname = normalize_path(dirname) - if dirname in seen: - continue - - seen[dirname] = 1 - if not os.path.isdir(dirname): - continue - - files = os.listdir(dirname) - yield dirname, files - - for name in files: - if not name.endswith('.pth'): - # We only care about the .pth files - continue - if name in ('easy-install.pth', 'setuptools.pth'): - # Ignore .pth files that we control - continue - - # Read the .pth file - f = open(os.path.join(dirname, name)) - lines = list(yield_lines(f)) - f.close() - - # Yield existing non-dupe, non-import directory lines from it - for line in lines: - if line.startswith("import"): - continue - - line = normalize_path(line.rstrip()) - if line in seen: - continue - - seen[line] = 1 - if not os.path.isdir(line): - continue - - yield line, os.listdir(line) - - -def extract_wininst_cfg(dist_filename): - """Extract configuration data from a bdist_wininst .exe - - Returns a configparser.RawConfigParser, or None - """ - f = open(dist_filename, 'rb') - try: - endrec = zipfile._EndRecData(f) - if endrec is None: - return None - - prepended = (endrec[9] - endrec[5]) - endrec[6] - if prepended < 12: # no wininst data here - return None - f.seek(prepended - 12) - - tag, cfglen, bmlen = struct.unpack("egg path translations for a given .exe file""" - - prefixes = [ - ('PURELIB/', ''), - ('PLATLIB/pywin32_system32', ''), - ('PLATLIB/', ''), - ('SCRIPTS/', 'EGG-INFO/scripts/'), - ('DATA/lib/site-packages', ''), - ] - z = zipfile.ZipFile(exe_filename) - try: - for info in z.infolist(): - name = info.filename - parts = name.split('/') - if len(parts) == 3 and parts[2] == 'PKG-INFO': - if parts[1].endswith('.egg-info'): - prefixes.insert(0, ('/'.join(parts[:2]), 'EGG-INFO/')) - break - if len(parts) != 2 or not name.endswith('.pth'): - continue - if name.endswith('-nspkg.pth'): - continue - if parts[0].upper() in ('PURELIB', 'PLATLIB'): - contents = z.read(name).decode() - for pth in yield_lines(contents): - pth = pth.strip().replace('\\', '/') - if not pth.startswith('import'): - prefixes.append((('%s/%s/' % (parts[0], pth)), '')) - finally: - z.close() - prefixes = [(x.lower(), y) for x, y in prefixes] - prefixes.sort() - prefixes.reverse() - return prefixes - - -class PthDistributions(Environment): - """A .pth file with Distribution paths in it""" - - dirty = False - - def __init__(self, filename, sitedirs=()): - self.filename = filename - self.sitedirs = list(map(normalize_path, sitedirs)) - self.basedir = normalize_path(os.path.dirname(self.filename)) - self._load() - super().__init__([], None, None) - for path in yield_lines(self.paths): - list(map(self.add, find_distributions(path, True))) - - def _load(self): - self.paths = [] - saw_import = False - seen = dict.fromkeys(self.sitedirs) - if os.path.isfile(self.filename): - f = open(self.filename, 'rt') - for line in f: - if line.startswith('import'): - saw_import = True - continue - path = line.rstrip() - self.paths.append(path) - if not path.strip() or path.strip().startswith('#'): - continue - # skip non-existent paths, in case somebody deleted a package - # manually, and duplicate paths as well - path = self.paths[-1] = normalize_path( - os.path.join(self.basedir, path) - ) - if not os.path.exists(path) or path in seen: - self.paths.pop() # skip it - self.dirty = True # we cleaned up, so we're dirty now :) - continue - seen[path] = 1 - f.close() - - if self.paths and not saw_import: - self.dirty = True # ensure anything we touch has import wrappers - while self.paths and not self.paths[-1].strip(): - self.paths.pop() - - def save(self): - """Write changed .pth file back to disk""" - if not self.dirty: - return - - rel_paths = list(map(self.make_relative, self.paths)) - if rel_paths: - log.debug("Saving %s", self.filename) - lines = self._wrap_lines(rel_paths) - data = '\n'.join(lines) + '\n' - - if os.path.islink(self.filename): - os.unlink(self.filename) - with open(self.filename, 'wt') as f: - f.write(data) - - elif os.path.exists(self.filename): - log.debug("Deleting empty %s", self.filename) - os.unlink(self.filename) - - self.dirty = False - - @staticmethod - def _wrap_lines(lines): - return lines - - def add(self, dist): - """Add `dist` to the distribution map""" - new_path = ( - dist.location not in self.paths and ( - dist.location not in self.sitedirs or - # account for '.' being in PYTHONPATH - dist.location == os.getcwd() - ) - ) - if new_path: - self.paths.append(dist.location) - self.dirty = True - super().add(dist) - - def remove(self, dist): - """Remove `dist` from the distribution map""" - while dist.location in self.paths: - self.paths.remove(dist.location) - self.dirty = True - super().remove(dist) - - def make_relative(self, path): - npath, last = os.path.split(normalize_path(path)) - baselen = len(self.basedir) - parts = [last] - sep = os.altsep == '/' and '/' or os.sep - while len(npath) >= baselen: - if npath == self.basedir: - parts.append(os.curdir) - parts.reverse() - return sep.join(parts) - npath, last = os.path.split(npath) - parts.append(last) - else: - return path - - -class RewritePthDistributions(PthDistributions): - @classmethod - def _wrap_lines(cls, lines): - yield cls.prelude - for line in lines: - yield line - yield cls.postlude - - prelude = _one_liner(""" - import sys - sys.__plen = len(sys.path) - """) - postlude = _one_liner(""" - import sys - new = sys.path[sys.__plen:] - del sys.path[sys.__plen:] - p = getattr(sys, '__egginsert', 0) - sys.path[p:p] = new - sys.__egginsert = p + len(new) - """) - - -if os.environ.get('SETUPTOOLS_SYS_PATH_TECHNIQUE', 'raw') == 'rewrite': - PthDistributions = RewritePthDistributions - - -def _first_line_re(): - """ - Return a regular expression based on first_line_re suitable for matching - strings. - """ - if isinstance(first_line_re.pattern, str): - return first_line_re - - # first_line_re in Python >=3.1.4 and >=3.2.1 is a bytes pattern. - return re.compile(first_line_re.pattern.decode()) - - -def auto_chmod(func, arg, exc): - if func in [os.unlink, os.remove] and os.name == 'nt': - chmod(arg, stat.S_IWRITE) - return func(arg) - et, ev, _ = sys.exc_info() - # TODO: This code doesn't make sense. What is it trying to do? - raise (ev[0], ev[1] + (" %s %s" % (func, arg))) - - -def update_dist_caches(dist_path, fix_zipimporter_caches): - """ - Fix any globally cached `dist_path` related data - - `dist_path` should be a path of a newly installed egg distribution (zipped - or unzipped). - - sys.path_importer_cache contains finder objects that have been cached when - importing data from the original distribution. Any such finders need to be - cleared since the replacement distribution might be packaged differently, - e.g. a zipped egg distribution might get replaced with an unzipped egg - folder or vice versa. Having the old finders cached may then cause Python - to attempt loading modules from the replacement distribution using an - incorrect loader. - - zipimport.zipimporter objects are Python loaders charged with importing - data packaged inside zip archives. If stale loaders referencing the - original distribution, are left behind, they can fail to load modules from - the replacement distribution. E.g. if an old zipimport.zipimporter instance - is used to load data from a new zipped egg archive, it may cause the - operation to attempt to locate the requested data in the wrong location - - one indicated by the original distribution's zip archive directory - information. Such an operation may then fail outright, e.g. report having - read a 'bad local file header', or even worse, it may fail silently & - return invalid data. - - zipimport._zip_directory_cache contains cached zip archive directory - information for all existing zipimport.zipimporter instances and all such - instances connected to the same archive share the same cached directory - information. - - If asked, and the underlying Python implementation allows it, we can fix - all existing zipimport.zipimporter instances instead of having to track - them down and remove them one by one, by updating their shared cached zip - archive directory information. This, of course, assumes that the - replacement distribution is packaged as a zipped egg. - - If not asked to fix existing zipimport.zipimporter instances, we still do - our best to clear any remaining zipimport.zipimporter related cached data - that might somehow later get used when attempting to load data from the new - distribution and thus cause such load operations to fail. Note that when - tracking down such remaining stale data, we can not catch every conceivable - usage from here, and we clear only those that we know of and have found to - cause problems if left alive. Any remaining caches should be updated by - whomever is in charge of maintaining them, i.e. they should be ready to - handle us replacing their zip archives with new distributions at runtime. - - """ - # There are several other known sources of stale zipimport.zipimporter - # instances that we do not clear here, but might if ever given a reason to - # do so: - # * Global setuptools pkg_resources.working_set (a.k.a. 'master working - # set') may contain distributions which may in turn contain their - # zipimport.zipimporter loaders. - # * Several zipimport.zipimporter loaders held by local variables further - # up the function call stack when running the setuptools installation. - # * Already loaded modules may have their __loader__ attribute set to the - # exact loader instance used when importing them. Python 3.4 docs state - # that this information is intended mostly for introspection and so is - # not expected to cause us problems. - normalized_path = normalize_path(dist_path) - _uncache(normalized_path, sys.path_importer_cache) - if fix_zipimporter_caches: - _replace_zip_directory_cache_data(normalized_path) - else: - # Here, even though we do not want to fix existing and now stale - # zipimporter cache information, we still want to remove it. Related to - # Python's zip archive directory information cache, we clear each of - # its stale entries in two phases: - # 1. Clear the entry so attempting to access zip archive information - # via any existing stale zipimport.zipimporter instances fails. - # 2. Remove the entry from the cache so any newly constructed - # zipimport.zipimporter instances do not end up using old stale - # zip archive directory information. - # This whole stale data removal step does not seem strictly necessary, - # but has been left in because it was done before we started replacing - # the zip archive directory information cache content if possible, and - # there are no relevant unit tests that we can depend on to tell us if - # this is really needed. - _remove_and_clear_zip_directory_cache_data(normalized_path) - - -def _collect_zipimporter_cache_entries(normalized_path, cache): - """ - Return zipimporter cache entry keys related to a given normalized path. - - Alternative path spellings (e.g. those using different character case or - those using alternative path separators) related to the same path are - included. Any sub-path entries are included as well, i.e. those - corresponding to zip archives embedded in other zip archives. - - """ - result = [] - prefix_len = len(normalized_path) - for p in cache: - np = normalize_path(p) - if (np.startswith(normalized_path) and - np[prefix_len:prefix_len + 1] in (os.sep, '')): - result.append(p) - return result - - -def _update_zipimporter_cache(normalized_path, cache, updater=None): - """ - Update zipimporter cache data for a given normalized path. - - Any sub-path entries are processed as well, i.e. those corresponding to zip - archives embedded in other zip archives. - - Given updater is a callable taking a cache entry key and the original entry - (after already removing the entry from the cache), and expected to update - the entry and possibly return a new one to be inserted in its place. - Returning None indicates that the entry should not be replaced with a new - one. If no updater is given, the cache entries are simply removed without - any additional processing, the same as if the updater simply returned None. - - """ - for p in _collect_zipimporter_cache_entries(normalized_path, cache): - # N.B. pypy's custom zipimport._zip_directory_cache implementation does - # not support the complete dict interface: - # * Does not support item assignment, thus not allowing this function - # to be used only for removing existing cache entries. - # * Does not support the dict.pop() method, forcing us to use the - # get/del patterns instead. For more detailed information see the - # following links: - # https://github.com/pypa/setuptools/issues/202#issuecomment-202913420 - # http://bit.ly/2h9itJX - old_entry = cache[p] - del cache[p] - new_entry = updater and updater(p, old_entry) - if new_entry is not None: - cache[p] = new_entry - - -def _uncache(normalized_path, cache): - _update_zipimporter_cache(normalized_path, cache) - - -def _remove_and_clear_zip_directory_cache_data(normalized_path): - def clear_and_remove_cached_zip_archive_directory_data(path, old_entry): - old_entry.clear() - - _update_zipimporter_cache( - normalized_path, zipimport._zip_directory_cache, - updater=clear_and_remove_cached_zip_archive_directory_data) - - -# PyPy Python implementation does not allow directly writing to the -# zipimport._zip_directory_cache and so prevents us from attempting to correct -# its content. The best we can do there is clear the problematic cache content -# and have PyPy repopulate it as needed. The downside is that if there are any -# stale zipimport.zipimporter instances laying around, attempting to use them -# will fail due to not having its zip archive directory information available -# instead of being automatically corrected to use the new correct zip archive -# directory information. -if '__pypy__' in sys.builtin_module_names: - _replace_zip_directory_cache_data = \ - _remove_and_clear_zip_directory_cache_data -else: - - def _replace_zip_directory_cache_data(normalized_path): - def replace_cached_zip_archive_directory_data(path, old_entry): - # N.B. In theory, we could load the zip directory information just - # once for all updated path spellings, and then copy it locally and - # update its contained path strings to contain the correct - # spelling, but that seems like a way too invasive move (this cache - # structure is not officially documented anywhere and could in - # theory change with new Python releases) for no significant - # benefit. - old_entry.clear() - zipimport.zipimporter(path) - old_entry.update(zipimport._zip_directory_cache[path]) - return old_entry - - _update_zipimporter_cache( - normalized_path, zipimport._zip_directory_cache, - updater=replace_cached_zip_archive_directory_data) - - -def is_python(text, filename=''): - "Is this string a valid Python script?" - try: - compile(text, filename, 'exec') - except (SyntaxError, TypeError): - return False - else: - return True - - -def is_sh(executable): - """Determine if the specified executable is a .sh (contains a #! line)""" - try: - with io.open(executable, encoding='latin-1') as fp: - magic = fp.read(2) - except (OSError, IOError): - return executable - return magic == '#!' - - -def nt_quote_arg(arg): - """Quote a command line argument according to Windows parsing rules""" - return subprocess.list2cmdline([arg]) - - -def is_python_script(script_text, filename): - """Is this text, as a whole, a Python script? (as opposed to shell/bat/etc. - """ - if filename.endswith('.py') or filename.endswith('.pyw'): - return True # extension says it's Python - if is_python(script_text, filename): - return True # it's syntactically valid Python - if script_text.startswith('#!'): - # It begins with a '#!' line, so check if 'python' is in it somewhere - return 'python' in script_text.splitlines()[0].lower() - - return False # Not any Python I can recognize - - -try: - from os import chmod as _chmod -except ImportError: - # Jython compatibility - def _chmod(*args): - pass - - -def chmod(path, mode): - log.debug("changing mode of %s to %o", path, mode) - try: - _chmod(path, mode) - except os.error as e: - log.debug("chmod failed: %s", e) - - -class CommandSpec(list): - """ - A command spec for a #! header, specified as a list of arguments akin to - those passed to Popen. - """ - - options = [] - split_args = dict() - - @classmethod - def best(cls): - """ - Choose the best CommandSpec class based on environmental conditions. - """ - return cls - - @classmethod - def _sys_executable(cls): - _default = os.path.normpath(sys.executable) - return os.environ.get('__PYVENV_LAUNCHER__', _default) - - @classmethod - def from_param(cls, param): - """ - Construct a CommandSpec from a parameter to build_scripts, which may - be None. - """ - if isinstance(param, cls): - return param - if isinstance(param, list): - return cls(param) - if param is None: - return cls.from_environment() - # otherwise, assume it's a string. - return cls.from_string(param) - - @classmethod - def from_environment(cls): - return cls([cls._sys_executable()]) - - @classmethod - def from_string(cls, string): - """ - Construct a command spec from a simple string representing a command - line parseable by shlex.split. - """ - items = shlex.split(string, **cls.split_args) - return cls(items) - - def install_options(self, script_text): - self.options = shlex.split(self._extract_options(script_text)) - cmdline = subprocess.list2cmdline(self) - if not isascii(cmdline): - self.options[:0] = ['-x'] - - @staticmethod - def _extract_options(orig_script): - """ - Extract any options from the first line of the script. - """ - first = (orig_script + '\n').splitlines()[0] - match = _first_line_re().match(first) - options = match.group(1) or '' if match else '' - return options.strip() - - def as_header(self): - return self._render(self + list(self.options)) - - @staticmethod - def _strip_quotes(item): - _QUOTES = '"\'' - for q in _QUOTES: - if item.startswith(q) and item.endswith(q): - return item[1:-1] - return item - - @staticmethod - def _render(items): - cmdline = subprocess.list2cmdline( - CommandSpec._strip_quotes(item.strip()) for item in items) - return '#!' + cmdline + '\n' - - -# For pbr compat; will be removed in a future version. -sys_executable = CommandSpec._sys_executable() - - -class WindowsCommandSpec(CommandSpec): - split_args = dict(posix=False) - - -class ScriptWriter: - """ - Encapsulates behavior around writing entry point scripts for console and - gui apps. - """ - - template = textwrap.dedent(r""" - # EASY-INSTALL-ENTRY-SCRIPT: %(spec)r,%(group)r,%(name)r - import re - import sys - - # for compatibility with easy_install; see #2198 - __requires__ = %(spec)r - - try: - from importlib.metadata import distribution - except ImportError: - try: - from importlib_metadata import distribution - except ImportError: - from pkg_resources import load_entry_point - - - def importlib_load_entry_point(spec, group, name): - dist_name, _, _ = spec.partition('==') - matches = ( - entry_point - for entry_point in distribution(dist_name).entry_points - if entry_point.group == group and entry_point.name == name - ) - return next(matches).load() - - - globals().setdefault('load_entry_point', importlib_load_entry_point) - - - if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) - sys.exit(load_entry_point(%(spec)r, %(group)r, %(name)r)()) - """).lstrip() - - command_spec_class = CommandSpec - - @classmethod - def get_script_args(cls, dist, executable=None, wininst=False): - # for backward compatibility - warnings.warn("Use get_args", EasyInstallDeprecationWarning) - writer = (WindowsScriptWriter if wininst else ScriptWriter).best() - header = cls.get_script_header("", executable, wininst) - return writer.get_args(dist, header) - - @classmethod - def get_script_header(cls, script_text, executable=None, wininst=False): - # for backward compatibility - warnings.warn( - "Use get_header", EasyInstallDeprecationWarning, stacklevel=2) - if wininst: - executable = "python.exe" - return cls.get_header(script_text, executable) - - @classmethod - def get_args(cls, dist, header=None): - """ - Yield write_script() argument tuples for a distribution's - console_scripts and gui_scripts entry points. - """ - if header is None: - header = cls.get_header() - spec = str(dist.as_requirement()) - for type_ in 'console', 'gui': - group = type_ + '_scripts' - for name, ep in dist.get_entry_map(group).items(): - cls._ensure_safe_name(name) - script_text = cls.template % locals() - args = cls._get_script_args(type_, name, header, script_text) - for res in args: - yield res - - @staticmethod - def _ensure_safe_name(name): - """ - Prevent paths in *_scripts entry point names. - """ - has_path_sep = re.search(r'[\\/]', name) - if has_path_sep: - raise ValueError("Path separators not allowed in script names") - - @classmethod - def get_writer(cls, force_windows): - # for backward compatibility - warnings.warn("Use best", EasyInstallDeprecationWarning) - return WindowsScriptWriter.best() if force_windows else cls.best() - - @classmethod - def best(cls): - """ - Select the best ScriptWriter for this environment. - """ - if sys.platform == 'win32' or (os.name == 'java' and os._name == 'nt'): - return WindowsScriptWriter.best() - else: - return cls - - @classmethod - def _get_script_args(cls, type_, name, header, script_text): - # Simply write the stub with no extension. - yield (name, header + script_text) - - @classmethod - def get_header(cls, script_text="", executable=None): - """Create a #! line, getting options (if any) from script_text""" - cmd = cls.command_spec_class.best().from_param(executable) - cmd.install_options(script_text) - return cmd.as_header() - - -class WindowsScriptWriter(ScriptWriter): - command_spec_class = WindowsCommandSpec - - @classmethod - def get_writer(cls): - # for backward compatibility - warnings.warn("Use best", EasyInstallDeprecationWarning) - return cls.best() - - @classmethod - def best(cls): - """ - Select the best ScriptWriter suitable for Windows - """ - writer_lookup = dict( - executable=WindowsExecutableLauncherWriter, - natural=cls, - ) - # for compatibility, use the executable launcher by default - launcher = os.environ.get('SETUPTOOLS_LAUNCHER', 'executable') - return writer_lookup[launcher] - - @classmethod - def _get_script_args(cls, type_, name, header, script_text): - "For Windows, add a .py extension" - ext = dict(console='.pya', gui='.pyw')[type_] - if ext not in os.environ['PATHEXT'].lower().split(';'): - msg = ( - "{ext} not listed in PATHEXT; scripts will not be " - "recognized as executables." - ).format(**locals()) - warnings.warn(msg, UserWarning) - old = ['.pya', '.py', '-script.py', '.pyc', '.pyo', '.pyw', '.exe'] - old.remove(ext) - header = cls._adjust_header(type_, header) - blockers = [name + x for x in old] - yield name + ext, header + script_text, 't', blockers - - @classmethod - def _adjust_header(cls, type_, orig_header): - """ - Make sure 'pythonw' is used for gui and 'python' is used for - console (regardless of what sys.executable is). - """ - pattern = 'pythonw.exe' - repl = 'python.exe' - if type_ == 'gui': - pattern, repl = repl, pattern - pattern_ob = re.compile(re.escape(pattern), re.IGNORECASE) - new_header = pattern_ob.sub(string=orig_header, repl=repl) - return new_header if cls._use_header(new_header) else orig_header - - @staticmethod - def _use_header(new_header): - """ - Should _adjust_header use the replaced header? - - On non-windows systems, always use. On - Windows systems, only use the replaced header if it resolves - to an executable on the system. - """ - clean_header = new_header[2:-1].strip('"') - return sys.platform != 'win32' or find_executable(clean_header) - - -class WindowsExecutableLauncherWriter(WindowsScriptWriter): - @classmethod - def _get_script_args(cls, type_, name, header, script_text): - """ - For Windows, add a .py extension and an .exe launcher - """ - if type_ == 'gui': - launcher_type = 'gui' - ext = '-script.pyw' - old = ['.pyw'] - else: - launcher_type = 'cli' - ext = '-script.py' - old = ['.py', '.pyc', '.pyo'] - hdr = cls._adjust_header(type_, header) - blockers = [name + x for x in old] - yield (name + ext, hdr + script_text, 't', blockers) - yield ( - name + '.exe', get_win_launcher(launcher_type), - 'b' # write in binary mode - ) - if not is_64bit(): - # install a manifest for the launcher to prevent Windows - # from detecting it as an installer (which it will for - # launchers like easy_install.exe). Consider only - # adding a manifest for launchers detected as installers. - # See Distribute #143 for details. - m_name = name + '.exe.manifest' - yield (m_name, load_launcher_manifest(name), 't') - - -# for backward-compatibility -get_script_args = ScriptWriter.get_script_args -get_script_header = ScriptWriter.get_script_header - - -def get_win_launcher(type): - """ - Load the Windows launcher (executable) suitable for launching a script. - - `type` should be either 'cli' or 'gui' - - Returns the executable as a byte string. - """ - launcher_fn = '%s.exe' % type - if is_64bit(): - if get_platform() == "win-arm64": - launcher_fn = launcher_fn.replace(".", "-arm64.") - else: - launcher_fn = launcher_fn.replace(".", "-64.") - else: - launcher_fn = launcher_fn.replace(".", "-32.") - return resource_string('setuptools', launcher_fn) - - -def load_launcher_manifest(name): - manifest = pkg_resources.resource_string(__name__, 'launcher manifest.xml') - return manifest.decode('utf-8') % vars() - - -def rmtree(path, ignore_errors=False, onerror=auto_chmod): - return shutil.rmtree(path, ignore_errors, onerror) - - -def current_umask(): - tmp = os.umask(0o022) - os.umask(tmp) - return tmp - - -def only_strs(values): - """ - Exclude non-str values. Ref #3063. - """ - return filter(lambda val: isinstance(val, str), values) - - -class EasyInstallDeprecationWarning(SetuptoolsDeprecationWarning): - """ - Warning for EasyInstall deprecations, bypassing suppression. - """ diff --git a/venv/lib/python3.11/site-packages/setuptools/command/editable_wheel.py b/venv/lib/python3.11/site-packages/setuptools/command/editable_wheel.py deleted file mode 100755 index d60cfbe..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/editable_wheel.py +++ /dev/null @@ -1,844 +0,0 @@ -""" -Create a wheel that, when installed, will make the source package 'editable' -(add it to the interpreter's path, including metadata) per PEP 660. Replaces -'setup.py develop'. - -.. note:: - One of the mechanisms briefly mentioned in PEP 660 to implement editable installs is - to create a separated directory inside ``build`` and use a .pth file to point to that - directory. In the context of this file such directory is referred as - *auxiliary build directory* or ``auxiliary_dir``. -""" - -import logging -import os -import re -import shutil -import sys -import traceback -import warnings -from contextlib import suppress -from enum import Enum -from inspect import cleandoc -from itertools import chain -from pathlib import Path -from tempfile import TemporaryDirectory -from typing import ( - TYPE_CHECKING, - Dict, - Iterable, - Iterator, - List, - Mapping, - Optional, - Tuple, - TypeVar, - Union, -) - -from setuptools import Command, SetuptoolsDeprecationWarning, errors, namespaces -from setuptools.command.build_py import build_py as build_py_cls -from setuptools.discovery import find_package_path -from setuptools.dist import Distribution - -if TYPE_CHECKING: - from wheel.wheelfile import WheelFile # noqa - -if sys.version_info >= (3, 8): - from typing import Protocol -elif TYPE_CHECKING: - from typing_extensions import Protocol -else: - from abc import ABC as Protocol - -_Path = Union[str, Path] -_P = TypeVar("_P", bound=_Path) -_logger = logging.getLogger(__name__) - - -class _EditableMode(Enum): - """ - Possible editable installation modes: - `lenient` (new files automatically added to the package - DEFAULT); - `strict` (requires a new installation when files are added/removed); or - `compat` (attempts to emulate `python setup.py develop` - DEPRECATED). - """ - - STRICT = "strict" - LENIENT = "lenient" - COMPAT = "compat" # TODO: Remove `compat` after Dec/2022. - - @classmethod - def convert(cls, mode: Optional[str]) -> "_EditableMode": - if not mode: - return _EditableMode.LENIENT # default - - _mode = mode.upper() - if _mode not in _EditableMode.__members__: - raise errors.OptionError(f"Invalid editable mode: {mode!r}. Try: 'strict'.") - - if _mode == "COMPAT": - msg = """ - The 'compat' editable mode is transitional and will be removed - in future versions of `setuptools`. - Please adapt your code accordingly to use either the 'strict' or the - 'lenient' modes. - - For more information, please check: - https://setuptools.pypa.io/en/latest/userguide/development_mode.html - """ - warnings.warn(msg, SetuptoolsDeprecationWarning) - - return _EditableMode[_mode] - - -_STRICT_WARNING = """ -New or renamed files may not be automatically picked up without a new installation. -""" - -_LENIENT_WARNING = """ -Options like `package-data`, `include/exclude-package-data` or -`packages.find.exclude/include` may have no effect. -""" - - -class editable_wheel(Command): - """Build 'editable' wheel for development. - (This command is reserved for internal use of setuptools). - """ - - description = "create a PEP 660 'editable' wheel" - - user_options = [ - ("dist-dir=", "d", "directory to put final built distributions in"), - ("dist-info-dir=", "I", "path to a pre-build .dist-info directory"), - ("mode=", None, cleandoc(_EditableMode.__doc__ or "")), - ] - - def initialize_options(self): - self.dist_dir = None - self.dist_info_dir = None - self.project_dir = None - self.mode = None - - def finalize_options(self): - dist = self.distribution - self.project_dir = dist.src_root or os.curdir - self.package_dir = dist.package_dir or {} - self.dist_dir = Path(self.dist_dir or os.path.join(self.project_dir, "dist")) - - def run(self): - try: - self.dist_dir.mkdir(exist_ok=True) - self._ensure_dist_info() - - # Add missing dist_info files - self.reinitialize_command("bdist_wheel") - bdist_wheel = self.get_finalized_command("bdist_wheel") - bdist_wheel.write_wheelfile(self.dist_info_dir) - - self._create_wheel_file(bdist_wheel) - except Exception as ex: - traceback.print_exc() - msg = """ - Support for editable installs via PEP 660 was recently introduced - in `setuptools`. If you are seeing this error, please report to: - - https://github.com/pypa/setuptools/issues - - Meanwhile you can try the legacy behavior by setting an - environment variable and trying to install again: - - SETUPTOOLS_ENABLE_FEATURES="legacy-editable" - """ - raise errors.InternalError(cleandoc(msg)) from ex - - def _ensure_dist_info(self): - if self.dist_info_dir is None: - dist_info = self.reinitialize_command("dist_info") - dist_info.output_dir = self.dist_dir - dist_info.ensure_finalized() - dist_info.run() - self.dist_info_dir = dist_info.dist_info_dir - else: - assert str(self.dist_info_dir).endswith(".dist-info") - assert Path(self.dist_info_dir, "METADATA").exists() - - def _install_namespaces(self, installation_dir, pth_prefix): - # XXX: Only required to support the deprecated namespace practice - dist = self.distribution - if not dist.namespace_packages: - return - - src_root = Path(self.project_dir, self.package_dir.get("", ".")).resolve() - installer = _NamespaceInstaller(dist, installation_dir, pth_prefix, src_root) - installer.install_namespaces() - - def _find_egg_info_dir(self) -> Optional[str]: - parent_dir = Path(self.dist_info_dir).parent if self.dist_info_dir else Path() - candidates = map(str, parent_dir.glob("*.egg-info")) - return next(candidates, None) - - def _configure_build( - self, name: str, unpacked_wheel: _Path, build_lib: _Path, tmp_dir: _Path - ): - """Configure commands to behave in the following ways: - - - Build commands can write to ``build_lib`` if they really want to... - (but this folder is expected to be ignored and modules are expected to live - in the project directory...) - - Binary extensions should be built in-place (editable_mode = True) - - Data/header/script files are not part of the "editable" specification - so they are written directly to the unpacked_wheel directory. - """ - # Non-editable files (data, headers, scripts) are written directly to the - # unpacked_wheel - - dist = self.distribution - wheel = str(unpacked_wheel) - build_lib = str(build_lib) - data = str(Path(unpacked_wheel, f"{name}.data", "data")) - headers = str(Path(unpacked_wheel, f"{name}.data", "headers")) - scripts = str(Path(unpacked_wheel, f"{name}.data", "scripts")) - - # egg-info may be generated again to create a manifest (used for package data) - egg_info = dist.reinitialize_command("egg_info", reinit_subcommands=True) - egg_info.egg_base = str(tmp_dir) - egg_info.ignore_egg_info_in_manifest = True - - build = dist.reinitialize_command("build", reinit_subcommands=True) - install = dist.reinitialize_command("install", reinit_subcommands=True) - - build.build_platlib = build.build_purelib = build.build_lib = build_lib - install.install_purelib = install.install_platlib = install.install_lib = wheel - install.install_scripts = build.build_scripts = scripts - install.install_headers = headers - install.install_data = data - - install_scripts = dist.get_command_obj("install_scripts") - install_scripts.no_ep = True - - build.build_temp = str(tmp_dir) - - build_py = dist.get_command_obj("build_py") - build_py.compile = False - build_py.existing_egg_info_dir = self._find_egg_info_dir() - - self._set_editable_mode() - - build.ensure_finalized() - install.ensure_finalized() - - def _set_editable_mode(self): - """Set the ``editable_mode`` flag in the build sub-commands""" - dist = self.distribution - build = dist.get_command_obj("build") - for cmd_name in build.get_sub_commands(): - cmd = dist.get_command_obj(cmd_name) - if hasattr(cmd, "editable_mode"): - cmd.editable_mode = True - elif hasattr(cmd, "inplace"): - cmd.inplace = True # backward compatibility with distutils - - def _collect_build_outputs(self) -> Tuple[List[str], Dict[str, str]]: - files: List[str] = [] - mapping: Dict[str, str] = {} - build = self.get_finalized_command("build") - - for cmd_name in build.get_sub_commands(): - cmd = self.get_finalized_command(cmd_name) - if hasattr(cmd, "get_outputs"): - files.extend(cmd.get_outputs() or []) - if hasattr(cmd, "get_output_mapping"): - mapping.update(cmd.get_output_mapping() or {}) - - return files, mapping - - def _run_build_commands( - self, dist_name: str, unpacked_wheel: _Path, build_lib: _Path, tmp_dir: _Path - ) -> Tuple[List[str], Dict[str, str]]: - self._configure_build(dist_name, unpacked_wheel, build_lib, tmp_dir) - self._run_build_subcommands() - files, mapping = self._collect_build_outputs() - self._run_install("headers") - self._run_install("scripts") - self._run_install("data") - return files, mapping - - def _run_build_subcommands(self): - """ - Issue #3501 indicates that some plugins/customizations might rely on: - - 1. ``build_py`` not running - 2. ``build_py`` always copying files to ``build_lib`` - - However both these assumptions may be false in editable_wheel. - This method implements a temporary workaround to support the ecosystem - while the implementations catch up. - """ - # TODO: Once plugins/customisations had the chance to catch up, replace - # `self._run_build_subcommands()` with `self.run_command("build")`. - # Also remove _safely_run, TestCustomBuildPy. Suggested date: Aug/2023. - build: Command = self.get_finalized_command("build") - for name in build.get_sub_commands(): - cmd = self.get_finalized_command(name) - if name == "build_py" and type(cmd) != build_py_cls: - self._safely_run(name) - else: - self.run_command(name) - - def _safely_run(self, cmd_name: str): - try: - return self.run_command(cmd_name) - except Exception: - msg = f"""{traceback.format_exc()}\n - If you are seeing this warning it is very likely that a setuptools - plugin or customization overrides the `{cmd_name}` command, without - taking into consideration how editable installs run build steps - starting from v64.0.0. - - Plugin authors and developers relying on custom build steps are encouraged - to update their `{cmd_name}` implementation considering the information in - https://setuptools.pypa.io/en/latest/userguide/extension.html - about editable installs. - - For the time being `setuptools` will silence this error and ignore - the faulty command, but this behaviour will change in future versions.\n - """ - warnings.warn(msg, SetuptoolsDeprecationWarning, stacklevel=2) - - def _create_wheel_file(self, bdist_wheel): - from wheel.wheelfile import WheelFile - - dist_info = self.get_finalized_command("dist_info") - dist_name = dist_info.name - tag = "-".join(bdist_wheel.get_tag()) - build_tag = "0.editable" # According to PEP 427 needs to start with digit - archive_name = f"{dist_name}-{build_tag}-{tag}.whl" - wheel_path = Path(self.dist_dir, archive_name) - if wheel_path.exists(): - wheel_path.unlink() - - unpacked_wheel = TemporaryDirectory(suffix=archive_name) - build_lib = TemporaryDirectory(suffix=".build-lib") - build_tmp = TemporaryDirectory(suffix=".build-temp") - - with unpacked_wheel as unpacked, build_lib as lib, build_tmp as tmp: - unpacked_dist_info = Path(unpacked, Path(self.dist_info_dir).name) - shutil.copytree(self.dist_info_dir, unpacked_dist_info) - self._install_namespaces(unpacked, dist_info.name) - files, mapping = self._run_build_commands(dist_name, unpacked, lib, tmp) - strategy = self._select_strategy(dist_name, tag, lib) - with strategy, WheelFile(wheel_path, "w") as wheel_obj: - strategy(wheel_obj, files, mapping) - wheel_obj.write_files(unpacked) - - return wheel_path - - def _run_install(self, category: str): - has_category = getattr(self.distribution, f"has_{category}", None) - if has_category and has_category(): - _logger.info(f"Installing {category} as non editable") - self.run_command(f"install_{category}") - - def _select_strategy( - self, - name: str, - tag: str, - build_lib: _Path, - ) -> "EditableStrategy": - """Decides which strategy to use to implement an editable installation.""" - build_name = f"__editable__.{name}-{tag}" - project_dir = Path(self.project_dir) - mode = _EditableMode.convert(self.mode) - - if mode is _EditableMode.STRICT: - auxiliary_dir = _empty_dir(Path(self.project_dir, "build", build_name)) - return _LinkTree(self.distribution, name, auxiliary_dir, build_lib) - - packages = _find_packages(self.distribution) - has_simple_layout = _simple_layout(packages, self.package_dir, project_dir) - is_compat_mode = mode is _EditableMode.COMPAT - if set(self.package_dir) == {""} and has_simple_layout or is_compat_mode: - # src-layout(ish) is relatively safe for a simple pth file - src_dir = self.package_dir.get("", ".") - return _StaticPth(self.distribution, name, [Path(project_dir, src_dir)]) - - # Use a MetaPathFinder to avoid adding accidental top-level packages/modules - return _TopLevelFinder(self.distribution, name) - - -class EditableStrategy(Protocol): - def __call__(self, wheel: "WheelFile", files: List[str], mapping: Dict[str, str]): - ... - - def __enter__(self): - ... - - def __exit__(self, _exc_type, _exc_value, _traceback): - ... - - -class _StaticPth: - def __init__(self, dist: Distribution, name: str, path_entries: List[Path]): - self.dist = dist - self.name = name - self.path_entries = path_entries - - def __call__(self, wheel: "WheelFile", files: List[str], mapping: Dict[str, str]): - entries = "\n".join((str(p.resolve()) for p in self.path_entries)) - contents = bytes(f"{entries}\n", "utf-8") - wheel.writestr(f"__editable__.{self.name}.pth", contents) - - def __enter__(self): - msg = f""" - Editable install will be performed using .pth file to extend `sys.path` with: - {list(map(os.fspath, self.path_entries))!r} - """ - _logger.warning(msg + _LENIENT_WARNING) - return self - - def __exit__(self, _exc_type, _exc_value, _traceback): - ... - - -class _LinkTree(_StaticPth): - """ - Creates a ``.pth`` file that points to a link tree in the ``auxiliary_dir``. - - This strategy will only link files (not dirs), so it can be implemented in - any OS, even if that means using hardlinks instead of symlinks. - - By collocating ``auxiliary_dir`` and the original source code, limitations - with hardlinks should be avoided. - """ - def __init__( - self, dist: Distribution, - name: str, - auxiliary_dir: _Path, - build_lib: _Path, - ): - self.auxiliary_dir = Path(auxiliary_dir) - self.build_lib = Path(build_lib).resolve() - self._file = dist.get_command_obj("build_py").copy_file - super().__init__(dist, name, [self.auxiliary_dir]) - - def __call__(self, wheel: "WheelFile", files: List[str], mapping: Dict[str, str]): - self._create_links(files, mapping) - super().__call__(wheel, files, mapping) - - def _normalize_output(self, file: str) -> Optional[str]: - # Files relative to build_lib will be normalized to None - with suppress(ValueError): - path = Path(file).resolve().relative_to(self.build_lib) - return str(path).replace(os.sep, '/') - return None - - def _create_file(self, relative_output: str, src_file: str, link=None): - dest = self.auxiliary_dir / relative_output - if not dest.parent.is_dir(): - dest.parent.mkdir(parents=True) - self._file(src_file, dest, link=link) - - def _create_links(self, outputs, output_mapping): - self.auxiliary_dir.mkdir(parents=True, exist_ok=True) - link_type = "sym" if _can_symlink_files(self.auxiliary_dir) else "hard" - mappings = { - self._normalize_output(k): v - for k, v in output_mapping.items() - } - mappings.pop(None, None) # remove files that are not relative to build_lib - - for output in outputs: - relative = self._normalize_output(output) - if relative and relative not in mappings: - self._create_file(relative, output) - - for relative, src in mappings.items(): - self._create_file(relative, src, link=link_type) - - def __enter__(self): - msg = "Strict editable install will be performed using a link tree.\n" - _logger.warning(msg + _STRICT_WARNING) - return self - - def __exit__(self, _exc_type, _exc_value, _traceback): - msg = f"""\n - Strict editable installation performed using the auxiliary directory: - {self.auxiliary_dir} - - Please be careful to not remove this directory, otherwise you might not be able - to import/use your package. - """ - warnings.warn(msg, InformationOnly) - - -class _TopLevelFinder: - def __init__(self, dist: Distribution, name: str): - self.dist = dist - self.name = name - - def __call__(self, wheel: "WheelFile", files: List[str], mapping: Dict[str, str]): - src_root = self.dist.src_root or os.curdir - top_level = chain(_find_packages(self.dist), _find_top_level_modules(self.dist)) - package_dir = self.dist.package_dir or {} - roots = _find_package_roots(top_level, package_dir, src_root) - - namespaces_: Dict[str, List[str]] = dict(chain( - _find_namespaces(self.dist.packages or [], roots), - ((ns, []) for ns in _find_virtual_namespaces(roots)), - )) - - name = f"__editable__.{self.name}.finder" - finder = _make_identifier(name) - content = bytes(_finder_template(name, roots, namespaces_), "utf-8") - wheel.writestr(f"{finder}.py", content) - - content = bytes(f"import {finder}; {finder}.install()", "utf-8") - wheel.writestr(f"__editable__.{self.name}.pth", content) - - def __enter__(self): - msg = "Editable install will be performed using a meta path finder.\n" - _logger.warning(msg + _LENIENT_WARNING) - return self - - def __exit__(self, _exc_type, _exc_value, _traceback): - msg = """\n - Please be careful with folders in your working directory with the same - name as your package as they may take precedence during imports. - """ - warnings.warn(msg, InformationOnly) - - -def _can_symlink_files(base_dir: Path) -> bool: - with TemporaryDirectory(dir=str(base_dir.resolve())) as tmp: - path1, path2 = Path(tmp, "file1.txt"), Path(tmp, "file2.txt") - path1.write_text("file1", encoding="utf-8") - with suppress(AttributeError, NotImplementedError, OSError): - os.symlink(path1, path2) - if path2.is_symlink() and path2.read_text(encoding="utf-8") == "file1": - return True - - try: - os.link(path1, path2) # Ensure hard links can be created - except Exception as ex: - msg = ( - "File system does not seem to support either symlinks or hard links. " - "Strict editable installs require one of them to be supported." - ) - raise LinksNotSupported(msg) from ex - return False - - -def _simple_layout( - packages: Iterable[str], package_dir: Dict[str, str], project_dir: Path -) -> bool: - """Return ``True`` if: - - all packages are contained by the same parent directory, **and** - - all packages become importable if the parent directory is added to ``sys.path``. - - >>> _simple_layout(['a'], {"": "src"}, "/tmp/myproj") - True - >>> _simple_layout(['a', 'a.b'], {"": "src"}, "/tmp/myproj") - True - >>> _simple_layout(['a', 'a.b'], {}, "/tmp/myproj") - True - >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"": "src"}, "/tmp/myproj") - True - >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"a": "a", "b": "b"}, ".") - True - >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"a": "_a", "b": "_b"}, ".") - False - >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"a": "_a"}, "/tmp/myproj") - False - >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"a.a1.a2": "_a2"}, ".") - False - >>> _simple_layout(['a', 'a.b'], {"": "src", "a.b": "_ab"}, "/tmp/myproj") - False - >>> # Special cases, no packages yet: - >>> _simple_layout([], {"": "src"}, "/tmp/myproj") - True - >>> _simple_layout([], {"a": "_a", "": "src"}, "/tmp/myproj") - False - """ - layout = { - pkg: find_package_path(pkg, package_dir, project_dir) - for pkg in packages - } - if not layout: - return set(package_dir) in ({}, {""}) - parent = os.path.commonpath([_parent_path(k, v) for k, v in layout.items()]) - return all( - _normalize_path(Path(parent, *key.split('.'))) == _normalize_path(value) - for key, value in layout.items() - ) - - -def _parent_path(pkg, pkg_path): - """Infer the parent path containing a package, that if added to ``sys.path`` would - allow importing that package. - When ``pkg`` is directly mapped into a directory with a different name, return its - own path. - >>> _parent_path("a", "src/a") - 'src' - >>> _parent_path("b", "src/c") - 'src/c' - """ - parent = pkg_path[:-len(pkg)] if pkg_path.endswith(pkg) else pkg_path - return parent.rstrip("/" + os.sep) - - -def _find_packages(dist: Distribution) -> Iterator[str]: - yield from iter(dist.packages or []) - - py_modules = dist.py_modules or [] - nested_modules = [mod for mod in py_modules if "." in mod] - if dist.ext_package: - yield dist.ext_package - else: - ext_modules = dist.ext_modules or [] - nested_modules += [x.name for x in ext_modules if "." in x.name] - - for module in nested_modules: - package, _, _ = module.rpartition(".") - yield package - - -def _find_top_level_modules(dist: Distribution) -> Iterator[str]: - py_modules = dist.py_modules or [] - yield from (mod for mod in py_modules if "." not in mod) - - if not dist.ext_package: - ext_modules = dist.ext_modules or [] - yield from (x.name for x in ext_modules if "." not in x.name) - - -def _find_package_roots( - packages: Iterable[str], - package_dir: Mapping[str, str], - src_root: _Path, -) -> Dict[str, str]: - pkg_roots: Dict[str, str] = { - pkg: _absolute_root(find_package_path(pkg, package_dir, src_root)) - for pkg in sorted(packages) - } - - return _remove_nested(pkg_roots) - - -def _absolute_root(path: _Path) -> str: - """Works for packages and top-level modules""" - path_ = Path(path) - parent = path_.parent - - if path_.exists(): - return str(path_.resolve()) - else: - return str(parent.resolve() / path_.name) - - -def _find_virtual_namespaces(pkg_roots: Dict[str, str]) -> Iterator[str]: - """By carefully designing ``package_dir``, it is possible to implement the logical - structure of PEP 420 in a package without the corresponding directories. - - Moreover a parent package can be purposefully/accidentally skipped in the discovery - phase (e.g. ``find_packages(include=["mypkg.*"])``, when ``mypkg.foo`` is included - by ``mypkg`` itself is not). - We consider this case to also be a virtual namespace (ignoring the original - directory) to emulate a non-editable installation. - - This function will try to find these kinds of namespaces. - """ - for pkg in pkg_roots: - if "." not in pkg: - continue - parts = pkg.split(".") - for i in range(len(parts) - 1, 0, -1): - partial_name = ".".join(parts[:i]) - path = Path(find_package_path(partial_name, pkg_roots, "")) - if not path.exists() or partial_name not in pkg_roots: - # partial_name not in pkg_roots ==> purposefully/accidentally skipped - yield partial_name - - -def _find_namespaces( - packages: List[str], pkg_roots: Dict[str, str] -) -> Iterator[Tuple[str, List[str]]]: - for pkg in packages: - path = find_package_path(pkg, pkg_roots, "") - if Path(path).exists() and not Path(path, "__init__.py").exists(): - yield (pkg, [path]) - - -def _remove_nested(pkg_roots: Dict[str, str]) -> Dict[str, str]: - output = dict(pkg_roots.copy()) - - for pkg, path in reversed(list(pkg_roots.items())): - if any( - pkg != other and _is_nested(pkg, path, other, other_path) - for other, other_path in pkg_roots.items() - ): - output.pop(pkg) - - return output - - -def _is_nested(pkg: str, pkg_path: str, parent: str, parent_path: str) -> bool: - """ - Return ``True`` if ``pkg`` is nested inside ``parent`` both logically and in the - file system. - >>> _is_nested("a.b", "path/a/b", "a", "path/a") - True - >>> _is_nested("a.b", "path/a/b", "a", "otherpath/a") - False - >>> _is_nested("a.b", "path/a/b", "c", "path/c") - False - >>> _is_nested("a.a", "path/a/a", "a", "path/a") - True - >>> _is_nested("b.a", "path/b/a", "a", "path/a") - False - """ - norm_pkg_path = _normalize_path(pkg_path) - rest = pkg.replace(parent, "", 1).strip(".").split(".") - return ( - pkg.startswith(parent) - and norm_pkg_path == _normalize_path(Path(parent_path, *rest)) - ) - - -def _normalize_path(filename: _Path) -> str: - """Normalize a file/dir name for comparison purposes""" - # See pkg_resources.normalize_path - file = os.path.abspath(filename) if sys.platform == 'cygwin' else filename - return os.path.normcase(os.path.realpath(os.path.normpath(file))) - - -def _empty_dir(dir_: _P) -> _P: - """Create a directory ensured to be empty. Existing files may be removed.""" - shutil.rmtree(dir_, ignore_errors=True) - os.makedirs(dir_) - return dir_ - - -def _make_identifier(name: str) -> str: - """Make a string safe to be used as Python identifier. - >>> _make_identifier("12abc") - '_12abc' - >>> _make_identifier("__editable__.myns.pkg-78.9.3_local") - '__editable___myns_pkg_78_9_3_local' - """ - safe = re.sub(r'\W|^(?=\d)', '_', name) - assert safe.isidentifier() - return safe - - -class _NamespaceInstaller(namespaces.Installer): - def __init__(self, distribution, installation_dir, editable_name, src_root): - self.distribution = distribution - self.src_root = src_root - self.installation_dir = installation_dir - self.editable_name = editable_name - self.outputs = [] - self.dry_run = False - - def _get_target(self): - """Installation target.""" - return os.path.join(self.installation_dir, self.editable_name) - - def _get_root(self): - """Where the modules/packages should be loaded from.""" - return repr(str(self.src_root)) - - -_FINDER_TEMPLATE = """\ -import sys -from importlib.machinery import ModuleSpec -from importlib.machinery import all_suffixes as module_suffixes -from importlib.util import spec_from_file_location -from itertools import chain -from pathlib import Path - -MAPPING = {mapping!r} -NAMESPACES = {namespaces!r} -PATH_PLACEHOLDER = {name!r} + ".__path_hook__" - - -class _EditableFinder: # MetaPathFinder - @classmethod - def find_spec(cls, fullname, path=None, target=None): - for pkg, pkg_path in reversed(list(MAPPING.items())): - if fullname == pkg or fullname.startswith(f"{{pkg}}."): - rest = fullname.replace(pkg, "", 1).strip(".").split(".") - return cls._find_spec(fullname, Path(pkg_path, *rest)) - - return None - - @classmethod - def _find_spec(cls, fullname, candidate_path): - init = candidate_path / "__init__.py" - candidates = (candidate_path.with_suffix(x) for x in module_suffixes()) - for candidate in chain([init], candidates): - if candidate.exists(): - return spec_from_file_location(fullname, candidate) - - -class _EditableNamespaceFinder: # PathEntryFinder - @classmethod - def _path_hook(cls, path): - if path == PATH_PLACEHOLDER: - return cls - raise ImportError - - @classmethod - def _paths(cls, fullname): - # Ensure __path__ is not empty for the spec to be considered a namespace. - return NAMESPACES[fullname] or MAPPING.get(fullname) or [PATH_PLACEHOLDER] - - @classmethod - def find_spec(cls, fullname, target=None): - if fullname in NAMESPACES: - spec = ModuleSpec(fullname, None, is_package=True) - spec.submodule_search_locations = cls._paths(fullname) - return spec - return None - - @classmethod - def find_module(cls, fullname): - return None - - -def install(): - if not any(finder == _EditableFinder for finder in sys.meta_path): - sys.meta_path.append(_EditableFinder) - - if not NAMESPACES: - return - - if not any(hook == _EditableNamespaceFinder._path_hook for hook in sys.path_hooks): - # PathEntryFinder is needed to create NamespaceSpec without private APIS - sys.path_hooks.append(_EditableNamespaceFinder._path_hook) - if PATH_PLACEHOLDER not in sys.path: - sys.path.append(PATH_PLACEHOLDER) # Used just to trigger the path hook -""" - - -def _finder_template( - name: str, mapping: Mapping[str, str], namespaces: Dict[str, List[str]] -) -> str: - """Create a string containing the code for the``MetaPathFinder`` and - ``PathEntryFinder``. - """ - mapping = dict(sorted(mapping.items(), key=lambda p: p[0])) - return _FINDER_TEMPLATE.format(name=name, mapping=mapping, namespaces=namespaces) - - -class InformationOnly(UserWarning): - """Currently there is no clear way of displaying messages to the users - that use the setuptools backend directly via ``pip``. - The only thing that might work is a warning, although it is not the - most appropriate tool for the job... - """ - - -class LinksNotSupported(errors.FileError): - """File system does not seem to support either symlinks or hard links.""" diff --git a/venv/lib/python3.11/site-packages/setuptools/command/egg_info.py b/venv/lib/python3.11/site-packages/setuptools/command/egg_info.py deleted file mode 100755 index 257afc3..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/egg_info.py +++ /dev/null @@ -1,775 +0,0 @@ -"""setuptools.command.egg_info - -Create a distribution's .egg-info directory and contents""" - -from distutils.filelist import FileList as _FileList -from distutils.errors import DistutilsInternalError -from distutils.util import convert_path -from distutils import log -import distutils.errors -import distutils.filelist -import functools -import os -import re -import sys -import io -import warnings -import time -import collections - -from .._importlib import metadata -from .. import _entry_points - -from setuptools import Command -from setuptools.command.sdist import sdist -from setuptools.command.sdist import walk_revctrl -from setuptools.command.setopt import edit_config -from setuptools.command import bdist_egg -from pkg_resources import ( - Requirement, safe_name, parse_version, - safe_version, to_filename) -import setuptools.unicode_utils as unicode_utils -from setuptools.glob import glob - -from setuptools.extern import packaging -from setuptools.extern.jaraco.text import yield_lines -from setuptools import SetuptoolsDeprecationWarning - - -def translate_pattern(glob): # noqa: C901 # is too complex (14) # FIXME - """ - Translate a file path glob like '*.txt' in to a regular expression. - This differs from fnmatch.translate which allows wildcards to match - directory separators. It also knows about '**/' which matches any number of - directories. - """ - pat = '' - - # This will split on '/' within [character classes]. This is deliberate. - chunks = glob.split(os.path.sep) - - sep = re.escape(os.sep) - valid_char = '[^%s]' % (sep,) - - for c, chunk in enumerate(chunks): - last_chunk = c == len(chunks) - 1 - - # Chunks that are a literal ** are globstars. They match anything. - if chunk == '**': - if last_chunk: - # Match anything if this is the last component - pat += '.*' - else: - # Match '(name/)*' - pat += '(?:%s+%s)*' % (valid_char, sep) - continue # Break here as the whole path component has been handled - - # Find any special characters in the remainder - i = 0 - chunk_len = len(chunk) - while i < chunk_len: - char = chunk[i] - if char == '*': - # Match any number of name characters - pat += valid_char + '*' - elif char == '?': - # Match a name character - pat += valid_char - elif char == '[': - # Character class - inner_i = i + 1 - # Skip initial !/] chars - if inner_i < chunk_len and chunk[inner_i] == '!': - inner_i = inner_i + 1 - if inner_i < chunk_len and chunk[inner_i] == ']': - inner_i = inner_i + 1 - - # Loop till the closing ] is found - while inner_i < chunk_len and chunk[inner_i] != ']': - inner_i = inner_i + 1 - - if inner_i >= chunk_len: - # Got to the end of the string without finding a closing ] - # Do not treat this as a matching group, but as a literal [ - pat += re.escape(char) - else: - # Grab the insides of the [brackets] - inner = chunk[i + 1:inner_i] - char_class = '' - - # Class negation - if inner[0] == '!': - char_class = '^' - inner = inner[1:] - - char_class += re.escape(inner) - pat += '[%s]' % (char_class,) - - # Skip to the end ] - i = inner_i - else: - pat += re.escape(char) - i += 1 - - # Join each chunk with the dir separator - if not last_chunk: - pat += sep - - pat += r'\Z' - return re.compile(pat, flags=re.MULTILINE | re.DOTALL) - - -class InfoCommon: - tag_build = None - tag_date = None - - @property - def name(self): - return safe_name(self.distribution.get_name()) - - def tagged_version(self): - return safe_version(self._maybe_tag(self.distribution.get_version())) - - def _maybe_tag(self, version): - """ - egg_info may be called more than once for a distribution, - in which case the version string already contains all tags. - """ - return ( - version if self.vtags and self._already_tagged(version) - else version + self.vtags - ) - - def _already_tagged(self, version: str) -> bool: - # Depending on their format, tags may change with version normalization. - # So in addition the regular tags, we have to search for the normalized ones. - return version.endswith(self.vtags) or version.endswith(self._safe_tags()) - - def _safe_tags(self) -> str: - # To implement this we can rely on `safe_version` pretending to be version 0 - # followed by tags. Then we simply discard the starting 0 (fake version number) - return safe_version(f"0{self.vtags}")[1:] - - def tags(self) -> str: - version = '' - if self.tag_build: - version += self.tag_build - if self.tag_date: - version += time.strftime("%Y%m%d") - return version - vtags = property(tags) - - -class egg_info(InfoCommon, Command): - description = "create a distribution's .egg-info directory" - - user_options = [ - ('egg-base=', 'e', "directory containing .egg-info directories" - " (default: top of the source tree)"), - ('tag-date', 'd', "Add date stamp (e.g. 20050528) to version number"), - ('tag-build=', 'b', "Specify explicit tag to add to version number"), - ('no-date', 'D', "Don't include date stamp [default]"), - ] - - boolean_options = ['tag-date'] - negative_opt = { - 'no-date': 'tag-date', - } - - def initialize_options(self): - self.egg_base = None - self.egg_name = None - self.egg_info = None - self.egg_version = None - self.broken_egg_info = False - self.ignore_egg_info_in_manifest = False - - #################################### - # allow the 'tag_svn_revision' to be detected and - # set, supporting sdists built on older Setuptools. - @property - def tag_svn_revision(self): - pass - - @tag_svn_revision.setter - def tag_svn_revision(self, value): - pass - #################################### - - def save_version_info(self, filename): - """ - Materialize the value of date into the - build tag. Install build keys in a deterministic order - to avoid arbitrary reordering on subsequent builds. - """ - egg_info = collections.OrderedDict() - # follow the order these keys would have been added - # when PYTHONHASHSEED=0 - egg_info['tag_build'] = self.tags() - egg_info['tag_date'] = 0 - edit_config(filename, dict(egg_info=egg_info)) - - def finalize_options(self): - # Note: we need to capture the current value returned - # by `self.tagged_version()`, so we can later update - # `self.distribution.metadata.version` without - # repercussions. - self.egg_name = self.name - self.egg_version = self.tagged_version() - parsed_version = parse_version(self.egg_version) - - try: - is_version = isinstance(parsed_version, packaging.version.Version) - spec = "%s==%s" if is_version else "%s===%s" - Requirement(spec % (self.egg_name, self.egg_version)) - except ValueError as e: - raise distutils.errors.DistutilsOptionError( - "Invalid distribution name or version syntax: %s-%s" % - (self.egg_name, self.egg_version) - ) from e - - if self.egg_base is None: - dirs = self.distribution.package_dir - self.egg_base = (dirs or {}).get('', os.curdir) - - self.ensure_dirname('egg_base') - self.egg_info = to_filename(self.egg_name) + '.egg-info' - if self.egg_base != os.curdir: - self.egg_info = os.path.join(self.egg_base, self.egg_info) - if '-' in self.egg_name: - self.check_broken_egg_info() - - # Set package version for the benefit of dumber commands - # (e.g. sdist, bdist_wininst, etc.) - # - self.distribution.metadata.version = self.egg_version - - # If we bootstrapped around the lack of a PKG-INFO, as might be the - # case in a fresh checkout, make sure that any special tags get added - # to the version info - # - pd = self.distribution._patched_dist - if pd is not None and pd.key == self.egg_name.lower(): - pd._version = self.egg_version - pd._parsed_version = parse_version(self.egg_version) - self.distribution._patched_dist = None - - def write_or_delete_file(self, what, filename, data, force=False): - """Write `data` to `filename` or delete if empty - - If `data` is non-empty, this routine is the same as ``write_file()``. - If `data` is empty but not ``None``, this is the same as calling - ``delete_file(filename)`. If `data` is ``None``, then this is a no-op - unless `filename` exists, in which case a warning is issued about the - orphaned file (if `force` is false), or deleted (if `force` is true). - """ - if data: - self.write_file(what, filename, data) - elif os.path.exists(filename): - if data is None and not force: - log.warn( - "%s not set in setup(), but %s exists", what, filename - ) - return - else: - self.delete_file(filename) - - def write_file(self, what, filename, data): - """Write `data` to `filename` (if not a dry run) after announcing it - - `what` is used in a log message to identify what is being written - to the file. - """ - log.info("writing %s to %s", what, filename) - data = data.encode("utf-8") - if not self.dry_run: - f = open(filename, 'wb') - f.write(data) - f.close() - - def delete_file(self, filename): - """Delete `filename` (if not a dry run) after announcing it""" - log.info("deleting %s", filename) - if not self.dry_run: - os.unlink(filename) - - def run(self): - self.mkpath(self.egg_info) - try: - os.utime(self.egg_info, None) - except OSError as e: - msg = f"Cannot update time stamp of directory '{self.egg_info}'" - raise distutils.errors.DistutilsFileError(msg) from e - for ep in metadata.entry_points(group='egg_info.writers'): - writer = ep.load() - writer(self, ep.name, os.path.join(self.egg_info, ep.name)) - - # Get rid of native_libs.txt if it was put there by older bdist_egg - nl = os.path.join(self.egg_info, "native_libs.txt") - if os.path.exists(nl): - self.delete_file(nl) - - self.find_sources() - - def find_sources(self): - """Generate SOURCES.txt manifest file""" - manifest_filename = os.path.join(self.egg_info, "SOURCES.txt") - mm = manifest_maker(self.distribution) - mm.ignore_egg_info_dir = self.ignore_egg_info_in_manifest - mm.manifest = manifest_filename - mm.run() - self.filelist = mm.filelist - - def check_broken_egg_info(self): - bei = self.egg_name + '.egg-info' - if self.egg_base != os.curdir: - bei = os.path.join(self.egg_base, bei) - if os.path.exists(bei): - log.warn( - "-" * 78 + '\n' - "Note: Your current .egg-info directory has a '-' in its name;" - '\nthis will not work correctly with "setup.py develop".\n\n' - 'Please rename %s to %s to correct this problem.\n' + '-' * 78, - bei, self.egg_info - ) - self.broken_egg_info = self.egg_info - self.egg_info = bei # make it work for now - - -class FileList(_FileList): - # Implementations of the various MANIFEST.in commands - - def __init__(self, warn=None, debug_print=None, ignore_egg_info_dir=False): - super().__init__(warn, debug_print) - self.ignore_egg_info_dir = ignore_egg_info_dir - - def process_template_line(self, line): - # Parse the line: split it up, make sure the right number of words - # is there, and return the relevant words. 'action' is always - # defined: it's the first word of the line. Which of the other - # three are defined depends on the action; it'll be either - # patterns, (dir and patterns), or (dir_pattern). - (action, patterns, dir, dir_pattern) = self._parse_template_line(line) - - action_map = { - 'include': self.include, - 'exclude': self.exclude, - 'global-include': self.global_include, - 'global-exclude': self.global_exclude, - 'recursive-include': functools.partial( - self.recursive_include, dir, - ), - 'recursive-exclude': functools.partial( - self.recursive_exclude, dir, - ), - 'graft': self.graft, - 'prune': self.prune, - } - log_map = { - 'include': "warning: no files found matching '%s'", - 'exclude': ( - "warning: no previously-included files found " - "matching '%s'" - ), - 'global-include': ( - "warning: no files found matching '%s' " - "anywhere in distribution" - ), - 'global-exclude': ( - "warning: no previously-included files matching " - "'%s' found anywhere in distribution" - ), - 'recursive-include': ( - "warning: no files found matching '%s' " - "under directory '%s'" - ), - 'recursive-exclude': ( - "warning: no previously-included files matching " - "'%s' found under directory '%s'" - ), - 'graft': "warning: no directories found matching '%s'", - 'prune': "no previously-included directories found matching '%s'", - } - - try: - process_action = action_map[action] - except KeyError: - raise DistutilsInternalError( - "this cannot happen: invalid action '{action!s}'". - format(action=action), - ) - - # OK, now we know that the action is valid and we have the - # right number of words on the line for that action -- so we - # can proceed with minimal error-checking. - - action_is_recursive = action.startswith('recursive-') - if action in {'graft', 'prune'}: - patterns = [dir_pattern] - extra_log_args = (dir, ) if action_is_recursive else () - log_tmpl = log_map[action] - - self.debug_print( - ' '.join( - [action] + - ([dir] if action_is_recursive else []) + - patterns, - ) - ) - for pattern in patterns: - if not process_action(pattern): - log.warn(log_tmpl, pattern, *extra_log_args) - - def _remove_files(self, predicate): - """ - Remove all files from the file list that match the predicate. - Return True if any matching files were removed - """ - found = False - for i in range(len(self.files) - 1, -1, -1): - if predicate(self.files[i]): - self.debug_print(" removing " + self.files[i]) - del self.files[i] - found = True - return found - - def include(self, pattern): - """Include files that match 'pattern'.""" - found = [f for f in glob(pattern) if not os.path.isdir(f)] - self.extend(found) - return bool(found) - - def exclude(self, pattern): - """Exclude files that match 'pattern'.""" - match = translate_pattern(pattern) - return self._remove_files(match.match) - - def recursive_include(self, dir, pattern): - """ - Include all files anywhere in 'dir/' that match the pattern. - """ - full_pattern = os.path.join(dir, '**', pattern) - found = [f for f in glob(full_pattern, recursive=True) - if not os.path.isdir(f)] - self.extend(found) - return bool(found) - - def recursive_exclude(self, dir, pattern): - """ - Exclude any file anywhere in 'dir/' that match the pattern. - """ - match = translate_pattern(os.path.join(dir, '**', pattern)) - return self._remove_files(match.match) - - def graft(self, dir): - """Include all files from 'dir/'.""" - found = [ - item - for match_dir in glob(dir) - for item in distutils.filelist.findall(match_dir) - ] - self.extend(found) - return bool(found) - - def prune(self, dir): - """Filter out files from 'dir/'.""" - match = translate_pattern(os.path.join(dir, '**')) - return self._remove_files(match.match) - - def global_include(self, pattern): - """ - Include all files anywhere in the current directory that match the - pattern. This is very inefficient on large file trees. - """ - if self.allfiles is None: - self.findall() - match = translate_pattern(os.path.join('**', pattern)) - found = [f for f in self.allfiles if match.match(f)] - self.extend(found) - return bool(found) - - def global_exclude(self, pattern): - """ - Exclude all files anywhere that match the pattern. - """ - match = translate_pattern(os.path.join('**', pattern)) - return self._remove_files(match.match) - - def append(self, item): - if item.endswith('\r'): # Fix older sdists built on Windows - item = item[:-1] - path = convert_path(item) - - if self._safe_path(path): - self.files.append(path) - - def extend(self, paths): - self.files.extend(filter(self._safe_path, paths)) - - def _repair(self): - """ - Replace self.files with only safe paths - - Because some owners of FileList manipulate the underlying - ``files`` attribute directly, this method must be called to - repair those paths. - """ - self.files = list(filter(self._safe_path, self.files)) - - def _safe_path(self, path): - enc_warn = "'%s' not %s encodable -- skipping" - - # To avoid accidental trans-codings errors, first to unicode - u_path = unicode_utils.filesys_decode(path) - if u_path is None: - log.warn("'%s' in unexpected encoding -- skipping" % path) - return False - - # Must ensure utf-8 encodability - utf8_path = unicode_utils.try_encode(u_path, "utf-8") - if utf8_path is None: - log.warn(enc_warn, path, 'utf-8') - return False - - try: - # ignore egg-info paths - is_egg_info = ".egg-info" in u_path or b".egg-info" in utf8_path - if self.ignore_egg_info_dir and is_egg_info: - return False - # accept is either way checks out - if os.path.exists(u_path) or os.path.exists(utf8_path): - return True - # this will catch any encode errors decoding u_path - except UnicodeEncodeError: - log.warn(enc_warn, path, sys.getfilesystemencoding()) - - -class manifest_maker(sdist): - template = "MANIFEST.in" - - def initialize_options(self): - self.use_defaults = 1 - self.prune = 1 - self.manifest_only = 1 - self.force_manifest = 1 - self.ignore_egg_info_dir = False - - def finalize_options(self): - pass - - def run(self): - self.filelist = FileList(ignore_egg_info_dir=self.ignore_egg_info_dir) - if not os.path.exists(self.manifest): - self.write_manifest() # it must exist so it'll get in the list - self.add_defaults() - if os.path.exists(self.template): - self.read_template() - self.add_license_files() - self._add_referenced_files() - self.prune_file_list() - self.filelist.sort() - self.filelist.remove_duplicates() - self.write_manifest() - - def _manifest_normalize(self, path): - path = unicode_utils.filesys_decode(path) - return path.replace(os.sep, '/') - - def write_manifest(self): - """ - Write the file list in 'self.filelist' to the manifest file - named by 'self.manifest'. - """ - self.filelist._repair() - - # Now _repairs should encodability, but not unicode - files = [self._manifest_normalize(f) for f in self.filelist.files] - msg = "writing manifest file '%s'" % self.manifest - self.execute(write_file, (self.manifest, files), msg) - - def warn(self, msg): - if not self._should_suppress_warning(msg): - sdist.warn(self, msg) - - @staticmethod - def _should_suppress_warning(msg): - """ - suppress missing-file warnings from sdist - """ - return re.match(r"standard file .*not found", msg) - - def add_defaults(self): - sdist.add_defaults(self) - self.filelist.append(self.template) - self.filelist.append(self.manifest) - rcfiles = list(walk_revctrl()) - if rcfiles: - self.filelist.extend(rcfiles) - elif os.path.exists(self.manifest): - self.read_manifest() - - if os.path.exists("setup.py"): - # setup.py should be included by default, even if it's not - # the script called to create the sdist - self.filelist.append("setup.py") - - ei_cmd = self.get_finalized_command('egg_info') - self.filelist.graft(ei_cmd.egg_info) - - def add_license_files(self): - license_files = self.distribution.metadata.license_files or [] - for lf in license_files: - log.info("adding license file '%s'", lf) - self.filelist.extend(license_files) - - def _add_referenced_files(self): - """Add files referenced by the config (e.g. `file:` directive) to filelist""" - referenced = getattr(self.distribution, '_referenced_files', []) - # ^-- fallback if dist comes from distutils or is a custom class - for rf in referenced: - log.debug("adding file referenced by config '%s'", rf) - self.filelist.extend(referenced) - - def prune_file_list(self): - build = self.get_finalized_command('build') - base_dir = self.distribution.get_fullname() - self.filelist.prune(build.build_base) - self.filelist.prune(base_dir) - sep = re.escape(os.sep) - self.filelist.exclude_pattern(r'(^|' + sep + r')(RCS|CVS|\.svn)' + sep, - is_regex=1) - - def _safe_data_files(self, build_py): - """ - The parent class implementation of this method - (``sdist``) will try to include data files, which - might cause recursion problems when - ``include_package_data=True``. - - Therefore, avoid triggering any attempt of - analyzing/building the manifest again. - """ - if hasattr(build_py, 'get_data_files_without_manifest'): - return build_py.get_data_files_without_manifest() - - warnings.warn( - "Custom 'build_py' does not implement " - "'get_data_files_without_manifest'.\nPlease extend command classes" - " from setuptools instead of distutils.", - SetuptoolsDeprecationWarning - ) - return build_py.get_data_files() - - -def write_file(filename, contents): - """Create a file with the specified name and write 'contents' (a - sequence of strings without line terminators) to it. - """ - contents = "\n".join(contents) - - # assuming the contents has been vetted for utf-8 encoding - contents = contents.encode("utf-8") - - with open(filename, "wb") as f: # always write POSIX-style manifest - f.write(contents) - - -def write_pkg_info(cmd, basename, filename): - log.info("writing %s", filename) - if not cmd.dry_run: - metadata = cmd.distribution.metadata - metadata.version, oldver = cmd.egg_version, metadata.version - metadata.name, oldname = cmd.egg_name, metadata.name - - try: - # write unescaped data to PKG-INFO, so older pkg_resources - # can still parse it - metadata.write_pkg_info(cmd.egg_info) - finally: - metadata.name, metadata.version = oldname, oldver - - safe = getattr(cmd.distribution, 'zip_safe', None) - - bdist_egg.write_safety_flag(cmd.egg_info, safe) - - -def warn_depends_obsolete(cmd, basename, filename): - if os.path.exists(filename): - log.warn( - "WARNING: 'depends.txt' is not used by setuptools 0.6!\n" - "Use the install_requires/extras_require setup() args instead." - ) - - -def _write_requirements(stream, reqs): - lines = yield_lines(reqs or ()) - - def append_cr(line): - return line + '\n' - lines = map(append_cr, sorted(lines)) - stream.writelines(lines) - - -def write_requirements(cmd, basename, filename): - dist = cmd.distribution - data = io.StringIO() - _write_requirements(data, dist.install_requires) - extras_require = dist.extras_require or {} - for extra in sorted(extras_require): - data.write('\n[{extra}]\n'.format(**vars())) - _write_requirements(data, extras_require[extra]) - cmd.write_or_delete_file("requirements", filename, data.getvalue()) - - -def write_setup_requirements(cmd, basename, filename): - data = io.StringIO() - _write_requirements(data, cmd.distribution.setup_requires) - cmd.write_or_delete_file("setup-requirements", filename, data.getvalue()) - - -def write_toplevel_names(cmd, basename, filename): - pkgs = dict.fromkeys( - [ - k.split('.', 1)[0] - for k in cmd.distribution.iter_distribution_names() - ] - ) - cmd.write_file("top-level names", filename, '\n'.join(sorted(pkgs)) + '\n') - - -def overwrite_arg(cmd, basename, filename): - write_arg(cmd, basename, filename, True) - - -def write_arg(cmd, basename, filename, force=False): - argname = os.path.splitext(basename)[0] - value = getattr(cmd.distribution, argname, None) - if value is not None: - value = '\n'.join(value) + '\n' - cmd.write_or_delete_file(argname, filename, value, force) - - -def write_entries(cmd, basename, filename): - eps = _entry_points.load(cmd.distribution.entry_points) - defn = _entry_points.render(eps) - cmd.write_or_delete_file('entry points', filename, defn, True) - - -def get_pkg_info_revision(): - """ - Get a -r### off of PKG-INFO Version in case this is an sdist of - a subversion revision. - """ - warnings.warn( - "get_pkg_info_revision is deprecated.", EggInfoDeprecationWarning) - if os.path.exists('PKG-INFO'): - with io.open('PKG-INFO') as f: - for line in f: - match = re.match(r"Version:.*-r(\d+)\s*$", line) - if match: - return int(match.group(1)) - return 0 - - -class EggInfoDeprecationWarning(SetuptoolsDeprecationWarning): - """Deprecated behavior warning for EggInfo, bypassing suppression.""" diff --git a/venv/lib/python3.11/site-packages/setuptools/command/install.py b/venv/lib/python3.11/site-packages/setuptools/command/install.py deleted file mode 100755 index 55fdb12..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/install.py +++ /dev/null @@ -1,139 +0,0 @@ -from distutils.errors import DistutilsArgError -import inspect -import glob -import warnings -import platform -import distutils.command.install as orig - -import setuptools - -# Prior to numpy 1.9, NumPy relies on the '_install' name, so provide it for -# now. See https://github.com/pypa/setuptools/issues/199/ -_install = orig.install - - -class install(orig.install): - """Use easy_install to install the package, w/dependencies""" - - user_options = orig.install.user_options + [ - ('old-and-unmanageable', None, "Try not to use this!"), - ('single-version-externally-managed', None, - "used by system package builders to create 'flat' eggs"), - ] - boolean_options = orig.install.boolean_options + [ - 'old-and-unmanageable', 'single-version-externally-managed', - ] - new_commands = [ - ('install_egg_info', lambda self: True), - ('install_scripts', lambda self: True), - ] - _nc = dict(new_commands) - - def initialize_options(self): - - warnings.warn( - "setup.py install is deprecated. " - "Use build and pip and other standards-based tools.", - setuptools.SetuptoolsDeprecationWarning, - ) - - orig.install.initialize_options(self) - self.old_and_unmanageable = None - self.single_version_externally_managed = None - - def finalize_options(self): - orig.install.finalize_options(self) - if self.root: - self.single_version_externally_managed = True - elif self.single_version_externally_managed: - if not self.root and not self.record: - raise DistutilsArgError( - "You must specify --record or --root when building system" - " packages" - ) - - def handle_extra_path(self): - if self.root or self.single_version_externally_managed: - # explicit backward-compatibility mode, allow extra_path to work - return orig.install.handle_extra_path(self) - - # Ignore extra_path when installing an egg (or being run by another - # command without --root or --single-version-externally-managed - self.path_file = None - self.extra_dirs = '' - - def run(self): - # Explicit request for old-style install? Just do it - if self.old_and_unmanageable or self.single_version_externally_managed: - return orig.install.run(self) - - if not self._called_from_setup(inspect.currentframe()): - # Run in backward-compatibility mode to support bdist_* commands. - orig.install.run(self) - else: - self.do_egg_install() - - @staticmethod - def _called_from_setup(run_frame): - """ - Attempt to detect whether run() was called from setup() or by another - command. If called by setup(), the parent caller will be the - 'run_command' method in 'distutils.dist', and *its* caller will be - the 'run_commands' method. If called any other way, the - immediate caller *might* be 'run_command', but it won't have been - called by 'run_commands'. Return True in that case or if a call stack - is unavailable. Return False otherwise. - """ - if run_frame is None: - msg = "Call stack not available. bdist_* commands may fail." - warnings.warn(msg) - if platform.python_implementation() == 'IronPython': - msg = "For best results, pass -X:Frames to enable call stack." - warnings.warn(msg) - return True - - frames = inspect.getouterframes(run_frame) - for frame in frames[2:4]: - caller, = frame[:1] - info = inspect.getframeinfo(caller) - caller_module = caller.f_globals.get('__name__', '') - - if caller_module == "setuptools.dist" and info.function == "run_command": - # Starting from v61.0.0 setuptools overwrites dist.run_command - continue - - return ( - caller_module == 'distutils.dist' - and info.function == 'run_commands' - ) - - def do_egg_install(self): - - easy_install = self.distribution.get_command_class('easy_install') - - cmd = easy_install( - self.distribution, args="x", root=self.root, record=self.record, - ) - cmd.ensure_finalized() # finalize before bdist_egg munges install cmd - cmd.always_copy_from = '.' # make sure local-dir eggs get installed - - # pick up setup-dir .egg files only: no .egg-info - cmd.package_index.scan(glob.glob('*.egg')) - - self.run_command('bdist_egg') - args = [self.distribution.get_command_obj('bdist_egg').egg_output] - - if setuptools.bootstrap_install_from: - # Bootstrap self-installation of setuptools - args.insert(0, setuptools.bootstrap_install_from) - - cmd.args = args - cmd.run(show_deprecation=False) - setuptools.bootstrap_install_from = None - - -# XXX Python 3.1 doesn't see _nc if this is inside the class -install.sub_commands = ( - [cmd for cmd in orig.install.sub_commands if cmd[0] not in install._nc] + - install.new_commands -) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/install_egg_info.py b/venv/lib/python3.11/site-packages/setuptools/command/install_egg_info.py deleted file mode 100755 index 025f5b2..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/install_egg_info.py +++ /dev/null @@ -1,83 +0,0 @@ -from distutils import log, dir_util -import os, sys - -from setuptools import Command -from setuptools import namespaces -from setuptools.archive_util import unpack_archive -from .._path import ensure_directory -import pkg_resources - - -class install_egg_info(namespaces.Installer, Command): - """Install an .egg-info directory for the package""" - - description = "Install an .egg-info directory for the package" - - user_options = [ - ('install-dir=', 'd', "directory to install to"), - ] - - def initialize_options(self): - self.install_dir = None - self.install_layout = None - self.prefix_option = None - - def finalize_options(self): - self.set_undefined_options('install_lib', - ('install_dir', 'install_dir')) - self.set_undefined_options('install',('install_layout','install_layout')) - if sys.hexversion > 0x2060000: - self.set_undefined_options('install',('prefix_option','prefix_option')) - ei_cmd = self.get_finalized_command("egg_info") - basename = pkg_resources.Distribution( - None, None, ei_cmd.egg_name, ei_cmd.egg_version - ).egg_name() + '.egg-info' - - if self.install_layout: - if not self.install_layout.lower() in ['deb']: - raise DistutilsOptionError("unknown value for --install-layout") - self.install_layout = self.install_layout.lower() - basename = basename.replace('-py%s' % pkg_resources.PY_MAJOR, '') - elif self.prefix_option or 'real_prefix' in sys.__dict__: - # don't modify for virtualenv - pass - else: - basename = basename.replace('-py%s' % pkg_resources.PY_MAJOR, '') - - self.source = ei_cmd.egg_info - self.target = os.path.join(self.install_dir, basename) - self.outputs = [] - - def run(self): - self.run_command('egg_info') - if os.path.isdir(self.target) and not os.path.islink(self.target): - dir_util.remove_tree(self.target, dry_run=self.dry_run) - elif os.path.exists(self.target): - self.execute(os.unlink, (self.target,), "Removing " + self.target) - if not self.dry_run: - ensure_directory(self.target) - self.execute( - self.copytree, (), "Copying %s to %s" % (self.source, self.target) - ) - self.install_namespaces() - - def get_outputs(self): - return self.outputs - - def copytree(self): - # Copy the .egg-info tree to site-packages - def skimmer(src, dst): - # filter out source-control directories; note that 'src' is always - # a '/'-separated path, regardless of platform. 'dst' is a - # platform-specific path. - for skip in '.svn/', 'CVS/': - if src.startswith(skip) or '/' + skip in src: - return None - if self.install_layout and self.install_layout in ['deb'] and src.startswith('SOURCES.txt'): - log.info("Skipping SOURCES.txt") - return None - self.outputs.append(dst) - log.debug("Copying %s to %s", src, dst) - return dst - - unpack_archive(self.source, self.target, skimmer) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/install_lib.py b/venv/lib/python3.11/site-packages/setuptools/command/install_lib.py deleted file mode 100755 index 65e318e..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/install_lib.py +++ /dev/null @@ -1,148 +0,0 @@ -import os -import sys -from itertools import product, starmap -import distutils.command.install_lib as orig - - -class install_lib(orig.install_lib): - """Don't add compiled flags to filenames of non-Python files""" - - def initialize_options(self): - orig.install_lib.initialize_options(self) - self.multiarch = None - self.install_layout = None - - def finalize_options(self): - orig.install_lib.finalize_options(self) - self.set_undefined_options('install',('install_layout','install_layout')) - if self.install_layout == 'deb' and sys.version_info[:2] >= (3, 3): - import sysconfig - self.multiarch = sysconfig.get_config_var('MULTIARCH') - - def run(self): - self.build() - outfiles = self.install() - if outfiles is not None: - # always compile, in case we have any extension stubs to deal with - self.byte_compile(outfiles) - - def get_exclusions(self): - """ - Return a collections.Sized collections.Container of paths to be - excluded for single_version_externally_managed installations. - """ - all_packages = ( - pkg - for ns_pkg in self._get_SVEM_NSPs() - for pkg in self._all_packages(ns_pkg) - ) - - excl_specs = product(all_packages, self._gen_exclusion_paths()) - return set(starmap(self._exclude_pkg_path, excl_specs)) - - def _exclude_pkg_path(self, pkg, exclusion_path): - """ - Given a package name and exclusion path within that package, - compute the full exclusion path. - """ - parts = pkg.split('.') + [exclusion_path] - return os.path.join(self.install_dir, *parts) - - @staticmethod - def _all_packages(pkg_name): - """ - >>> list(install_lib._all_packages('foo.bar.baz')) - ['foo.bar.baz', 'foo.bar', 'foo'] - """ - while pkg_name: - yield pkg_name - pkg_name, sep, child = pkg_name.rpartition('.') - - def _get_SVEM_NSPs(self): - """ - Get namespace packages (list) but only for - single_version_externally_managed installations and empty otherwise. - """ - # TODO: is it necessary to short-circuit here? i.e. what's the cost - # if get_finalized_command is called even when namespace_packages is - # False? - if not self.distribution.namespace_packages: - return [] - - install_cmd = self.get_finalized_command('install') - svem = install_cmd.single_version_externally_managed - - return self.distribution.namespace_packages if svem else [] - - @staticmethod - def _gen_exclusion_paths(): - """ - Generate file paths to be excluded for namespace packages (bytecode - cache files). - """ - # always exclude the package module itself - yield '__init__.py' - - yield '__init__.pyc' - yield '__init__.pyo' - - if not hasattr(sys, 'implementation'): - return - - base = os.path.join( - '__pycache__', '__init__.' + sys.implementation.cache_tag) - yield base + '.pyc' - yield base + '.pyo' - yield base + '.opt-1.pyc' - yield base + '.opt-2.pyc' - - def copy_tree( - self, infile, outfile, - preserve_mode=1, preserve_times=1, preserve_symlinks=0, level=1 - ): - assert preserve_mode and preserve_times and not preserve_symlinks - exclude = self.get_exclusions() - - if not exclude: - import distutils.dir_util - distutils.dir_util._multiarch = self.multiarch - return orig.install_lib.copy_tree(self, infile, outfile) - - # Exclude namespace package __init__.py* files from the output - - from setuptools.archive_util import unpack_directory - from distutils import log - - outfiles = [] - - if self.multiarch: - import sysconfig - ext_suffix = sysconfig.get_config_var ('EXT_SUFFIX') - if ext_suffix.endswith(self.multiarch + ext_suffix[-3:]): - new_suffix = None - else: - new_suffix = "%s-%s%s" % (ext_suffix[:-3], self.multiarch, ext_suffix[-3:]) - - def pf(src, dst): - if dst in exclude: - log.warn("Skipping installation of %s (namespace package)", - dst) - return False - - if self.multiarch and new_suffix and dst.endswith(ext_suffix) and not dst.endswith(new_suffix): - dst = dst.replace(ext_suffix, new_suffix) - log.info("renaming extension to %s", os.path.basename(dst)) - - log.info("copying %s -> %s", src, os.path.dirname(dst)) - outfiles.append(dst) - return dst - - unpack_directory(infile, outfile, pf) - return outfiles - - def get_outputs(self): - outputs = orig.install_lib.get_outputs(self) - exclude = self.get_exclusions() - if exclude: - return [f for f in outputs if f not in exclude] - return outputs diff --git a/venv/lib/python3.11/site-packages/setuptools/command/install_scripts.py b/venv/lib/python3.11/site-packages/setuptools/command/install_scripts.py deleted file mode 100755 index aeb0e42..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/install_scripts.py +++ /dev/null @@ -1,70 +0,0 @@ -from distutils import log -import distutils.command.install_scripts as orig -from distutils.errors import DistutilsModuleError -import os -import sys - -from pkg_resources import Distribution, PathMetadata -from .._path import ensure_directory - - -class install_scripts(orig.install_scripts): - """Do normal script install, plus any egg_info wrapper scripts""" - - def initialize_options(self): - orig.install_scripts.initialize_options(self) - self.no_ep = False - - def run(self): - import setuptools.command.easy_install as ei - - self.run_command("egg_info") - if self.distribution.scripts: - orig.install_scripts.run(self) # run first to set up self.outfiles - else: - self.outfiles = [] - if self.no_ep: - # don't install entry point scripts into .egg file! - return - - ei_cmd = self.get_finalized_command("egg_info") - dist = Distribution( - ei_cmd.egg_base, PathMetadata(ei_cmd.egg_base, ei_cmd.egg_info), - ei_cmd.egg_name, ei_cmd.egg_version, - ) - bs_cmd = self.get_finalized_command('build_scripts') - exec_param = getattr(bs_cmd, 'executable', None) - try: - bw_cmd = self.get_finalized_command("bdist_wininst") - is_wininst = getattr(bw_cmd, '_is_running', False) - except (ImportError, DistutilsModuleError): - is_wininst = False - writer = ei.ScriptWriter - if is_wininst: - exec_param = "python.exe" - writer = ei.WindowsScriptWriter - if exec_param == sys.executable: - # In case the path to the Python executable contains a space, wrap - # it so it's not split up. - exec_param = [exec_param] - # resolve the writer to the environment - writer = writer.best() - cmd = writer.command_spec_class.best().from_param(exec_param) - for args in writer.get_args(dist, cmd.as_header()): - self.write_script(*args) - - def write_script(self, script_name, contents, mode="t", *ignored): - """Write an executable file to the scripts directory""" - from setuptools.command.easy_install import chmod, current_umask - - log.info("Installing %s script to %s", script_name, self.install_dir) - target = os.path.join(self.install_dir, script_name) - self.outfiles.append(target) - - mask = current_umask() - if not self.dry_run: - ensure_directory(target) - f = open(target, "w" + mode) - f.write(contents) - f.close() - chmod(target, 0o777 - mask) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/launcher manifest.xml b/venv/lib/python3.11/site-packages/setuptools/command/launcher manifest.xml deleted file mode 100755 index 5972a96..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/launcher manifest.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - diff --git a/venv/lib/python3.11/site-packages/setuptools/command/py36compat.py b/venv/lib/python3.11/site-packages/setuptools/command/py36compat.py deleted file mode 100755 index 343547a..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/py36compat.py +++ /dev/null @@ -1,134 +0,0 @@ -import os -from glob import glob -from distutils.util import convert_path -from distutils.command import sdist - - -class sdist_add_defaults: - """ - Mix-in providing forward-compatibility for functionality as found in - distutils on Python 3.7. - - Do not edit the code in this class except to update functionality - as implemented in distutils. Instead, override in the subclass. - """ - - def add_defaults(self): - """Add all the default files to self.filelist: - - README or README.txt - - setup.py - - test/test*.py - - all pure Python modules mentioned in setup script - - all files pointed by package_data (build_py) - - all files defined in data_files. - - all files defined as scripts. - - all C sources listed as part of extensions or C libraries - in the setup script (doesn't catch C headers!) - Warns if (README or README.txt) or setup.py are missing; everything - else is optional. - """ - self._add_defaults_standards() - self._add_defaults_optional() - self._add_defaults_python() - self._add_defaults_data_files() - self._add_defaults_ext() - self._add_defaults_c_libs() - self._add_defaults_scripts() - - @staticmethod - def _cs_path_exists(fspath): - """ - Case-sensitive path existence check - - >>> sdist_add_defaults._cs_path_exists(__file__) - True - >>> sdist_add_defaults._cs_path_exists(__file__.upper()) - False - """ - if not os.path.exists(fspath): - return False - # make absolute so we always have a directory - abspath = os.path.abspath(fspath) - directory, filename = os.path.split(abspath) - return filename in os.listdir(directory) - - def _add_defaults_standards(self): - standards = [self.READMES, self.distribution.script_name] - for fn in standards: - if isinstance(fn, tuple): - alts = fn - got_it = False - for fn in alts: - if self._cs_path_exists(fn): - got_it = True - self.filelist.append(fn) - break - - if not got_it: - self.warn("standard file not found: should have one of " + - ', '.join(alts)) - else: - if self._cs_path_exists(fn): - self.filelist.append(fn) - else: - self.warn("standard file '%s' not found" % fn) - - def _add_defaults_optional(self): - optional = ['test/test*.py', 'setup.cfg'] - for pattern in optional: - files = filter(os.path.isfile, glob(pattern)) - self.filelist.extend(files) - - def _add_defaults_python(self): - # build_py is used to get: - # - python modules - # - files defined in package_data - build_py = self.get_finalized_command('build_py') - - # getting python files - if self.distribution.has_pure_modules(): - self.filelist.extend(build_py.get_source_files()) - - # getting package_data files - # (computed in build_py.data_files by build_py.finalize_options) - for pkg, src_dir, build_dir, filenames in build_py.data_files: - for filename in filenames: - self.filelist.append(os.path.join(src_dir, filename)) - - def _add_defaults_data_files(self): - # getting distribution.data_files - if self.distribution.has_data_files(): - for item in self.distribution.data_files: - if isinstance(item, str): - # plain file - item = convert_path(item) - if os.path.isfile(item): - self.filelist.append(item) - else: - # a (dirname, filenames) tuple - dirname, filenames = item - for f in filenames: - f = convert_path(f) - if os.path.isfile(f): - self.filelist.append(f) - - def _add_defaults_ext(self): - if self.distribution.has_ext_modules(): - build_ext = self.get_finalized_command('build_ext') - self.filelist.extend(build_ext.get_source_files()) - - def _add_defaults_c_libs(self): - if self.distribution.has_c_libraries(): - build_clib = self.get_finalized_command('build_clib') - self.filelist.extend(build_clib.get_source_files()) - - def _add_defaults_scripts(self): - if self.distribution.has_scripts(): - build_scripts = self.get_finalized_command('build_scripts') - self.filelist.extend(build_scripts.get_source_files()) - - -if hasattr(sdist.sdist, '_add_defaults_standards'): - # disable the functionality already available upstream - class sdist_add_defaults: # noqa - pass diff --git a/venv/lib/python3.11/site-packages/setuptools/command/register.py b/venv/lib/python3.11/site-packages/setuptools/command/register.py deleted file mode 100755 index b8266b9..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/register.py +++ /dev/null @@ -1,18 +0,0 @@ -from distutils import log -import distutils.command.register as orig - -from setuptools.errors import RemovedCommandError - - -class register(orig.register): - """Formerly used to register packages on PyPI.""" - - def run(self): - msg = ( - "The register command has been removed, use twine to upload " - + "instead (https://pypi.org/p/twine)" - ) - - self.announce("ERROR: " + msg, log.ERROR) - - raise RemovedCommandError(msg) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/rotate.py b/venv/lib/python3.11/site-packages/setuptools/command/rotate.py deleted file mode 100755 index 74795ba..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/rotate.py +++ /dev/null @@ -1,64 +0,0 @@ -from distutils.util import convert_path -from distutils import log -from distutils.errors import DistutilsOptionError -import os -import shutil - -from setuptools import Command - - -class rotate(Command): - """Delete older distributions""" - - description = "delete older distributions, keeping N newest files" - user_options = [ - ('match=', 'm', "patterns to match (required)"), - ('dist-dir=', 'd', "directory where the distributions are"), - ('keep=', 'k', "number of matching distributions to keep"), - ] - - boolean_options = [] - - def initialize_options(self): - self.match = None - self.dist_dir = None - self.keep = None - - def finalize_options(self): - if self.match is None: - raise DistutilsOptionError( - "Must specify one or more (comma-separated) match patterns " - "(e.g. '.zip' or '.egg')" - ) - if self.keep is None: - raise DistutilsOptionError("Must specify number of files to keep") - try: - self.keep = int(self.keep) - except ValueError as e: - raise DistutilsOptionError("--keep must be an integer") from e - if isinstance(self.match, str): - self.match = [ - convert_path(p.strip()) for p in self.match.split(',') - ] - self.set_undefined_options('bdist', ('dist_dir', 'dist_dir')) - - def run(self): - self.run_command("egg_info") - from glob import glob - - for pattern in self.match: - pattern = self.distribution.get_name() + '*' + pattern - files = glob(os.path.join(self.dist_dir, pattern)) - files = [(os.path.getmtime(f), f) for f in files] - files.sort() - files.reverse() - - log.info("%d file(s) matching %s", len(files), pattern) - files = files[self.keep:] - for (t, f) in files: - log.info("Deleting %s", f) - if not self.dry_run: - if os.path.isdir(f): - shutil.rmtree(f) - else: - os.unlink(f) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/saveopts.py b/venv/lib/python3.11/site-packages/setuptools/command/saveopts.py deleted file mode 100755 index 611cec5..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/saveopts.py +++ /dev/null @@ -1,22 +0,0 @@ -from setuptools.command.setopt import edit_config, option_base - - -class saveopts(option_base): - """Save command-line options to a file""" - - description = "save supplied options to setup.cfg or other config file" - - def run(self): - dist = self.distribution - settings = {} - - for cmd in dist.command_options: - - if cmd == 'saveopts': - continue # don't save our own options! - - for opt, (src, val) in dist.get_option_dict(cmd).items(): - if src == "command line": - settings.setdefault(cmd, {})[opt] = val - - edit_config(self.filename, settings, self.dry_run) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/sdist.py b/venv/lib/python3.11/site-packages/setuptools/command/sdist.py deleted file mode 100755 index 4a8cde7..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/sdist.py +++ /dev/null @@ -1,210 +0,0 @@ -from distutils import log -import distutils.command.sdist as orig -import os -import sys -import io -import contextlib -from itertools import chain - -from .py36compat import sdist_add_defaults - -from .._importlib import metadata -from .build import _ORIGINAL_SUBCOMMANDS - -_default_revctrl = list - - -def walk_revctrl(dirname=''): - """Find all files under revision control""" - for ep in metadata.entry_points(group='setuptools.file_finders'): - for item in ep.load()(dirname): - yield item - - -class sdist(sdist_add_defaults, orig.sdist): - """Smart sdist that finds anything supported by revision control""" - - user_options = [ - ('formats=', None, - "formats for source distribution (comma-separated list)"), - ('keep-temp', 'k', - "keep the distribution tree around after creating " + - "archive file(s)"), - ('dist-dir=', 'd', - "directory to put the source distribution archive(s) in " - "[default: dist]"), - ('owner=', 'u', - "Owner name used when creating a tar file [default: current user]"), - ('group=', 'g', - "Group name used when creating a tar file [default: current group]"), - ] - - negative_opt = {} - - README_EXTENSIONS = ['', '.rst', '.txt', '.md'] - READMES = tuple('README{0}'.format(ext) for ext in README_EXTENSIONS) - - def run(self): - self.run_command('egg_info') - ei_cmd = self.get_finalized_command('egg_info') - self.filelist = ei_cmd.filelist - self.filelist.append(os.path.join(ei_cmd.egg_info, 'SOURCES.txt')) - self.check_readme() - - # Run sub commands - for cmd_name in self.get_sub_commands(): - self.run_command(cmd_name) - - self.make_distribution() - - dist_files = getattr(self.distribution, 'dist_files', []) - for file in self.archive_files: - data = ('sdist', '', file) - if data not in dist_files: - dist_files.append(data) - - def initialize_options(self): - orig.sdist.initialize_options(self) - - self._default_to_gztar() - - def _default_to_gztar(self): - # only needed on Python prior to 3.6. - if sys.version_info >= (3, 6, 0, 'beta', 1): - return - self.formats = ['gztar'] - - def make_distribution(self): - """ - Workaround for #516 - """ - with self._remove_os_link(): - orig.sdist.make_distribution(self) - - @staticmethod - @contextlib.contextmanager - def _remove_os_link(): - """ - In a context, remove and restore os.link if it exists - """ - - class NoValue: - pass - - orig_val = getattr(os, 'link', NoValue) - try: - del os.link - except Exception: - pass - try: - yield - finally: - if orig_val is not NoValue: - setattr(os, 'link', orig_val) - - def add_defaults(self): - super().add_defaults() - self._add_defaults_build_sub_commands() - - def _add_defaults_optional(self): - super()._add_defaults_optional() - if os.path.isfile('pyproject.toml'): - self.filelist.append('pyproject.toml') - - def _add_defaults_python(self): - """getting python files""" - if self.distribution.has_pure_modules(): - build_py = self.get_finalized_command('build_py') - self.filelist.extend(build_py.get_source_files()) - self._add_data_files(self._safe_data_files(build_py)) - - def _add_defaults_build_sub_commands(self): - build = self.get_finalized_command("build") - missing_cmds = set(build.get_sub_commands()) - _ORIGINAL_SUBCOMMANDS - # ^-- the original built-in sub-commands are already handled by default. - cmds = (self.get_finalized_command(c) for c in missing_cmds) - files = (c.get_source_files() for c in cmds if hasattr(c, "get_source_files")) - self.filelist.extend(chain.from_iterable(files)) - - def _safe_data_files(self, build_py): - """ - Since the ``sdist`` class is also used to compute the MANIFEST - (via :obj:`setuptools.command.egg_info.manifest_maker`), - there might be recursion problems when trying to obtain the list of - data_files and ``include_package_data=True`` (which in turn depends on - the files included in the MANIFEST). - - To avoid that, ``manifest_maker`` should be able to overwrite this - method and avoid recursive attempts to build/analyze the MANIFEST. - """ - return build_py.data_files - - def _add_data_files(self, data_files): - """ - Add data files as found in build_py.data_files. - """ - self.filelist.extend( - os.path.join(src_dir, name) - for _, src_dir, _, filenames in data_files - for name in filenames - ) - - def _add_defaults_data_files(self): - try: - super()._add_defaults_data_files() - except TypeError: - log.warn("data_files contains unexpected objects") - - def check_readme(self): - for f in self.READMES: - if os.path.exists(f): - return - else: - self.warn( - "standard file not found: should have one of " + - ', '.join(self.READMES) - ) - - def make_release_tree(self, base_dir, files): - orig.sdist.make_release_tree(self, base_dir, files) - - # Save any egg_info command line options used to create this sdist - dest = os.path.join(base_dir, 'setup.cfg') - if hasattr(os, 'link') and os.path.exists(dest): - # unlink and re-copy, since it might be hard-linked, and - # we don't want to change the source version - os.unlink(dest) - self.copy_file('setup.cfg', dest) - - self.get_finalized_command('egg_info').save_version_info(dest) - - def _manifest_is_not_generated(self): - # check for special comment used in 2.7.1 and higher - if not os.path.isfile(self.manifest): - return False - - with io.open(self.manifest, 'rb') as fp: - first_line = fp.readline() - return (first_line != - '# file GENERATED by distutils, do NOT edit\n'.encode()) - - def read_manifest(self): - """Read the manifest file (named by 'self.manifest') and use it to - fill in 'self.filelist', the list of files to include in the source - distribution. - """ - log.info("reading manifest file '%s'", self.manifest) - manifest = open(self.manifest, 'rb') - for line in manifest: - # The manifest must contain UTF-8. See #303. - try: - line = line.decode('UTF-8') - except UnicodeDecodeError: - log.warn("%r not UTF-8 decodable -- skipping" % line) - continue - # ignore comments and blank lines - line = line.strip() - if line.startswith('#') or not line: - continue - self.filelist.append(line) - manifest.close() diff --git a/venv/lib/python3.11/site-packages/setuptools/command/setopt.py b/venv/lib/python3.11/site-packages/setuptools/command/setopt.py deleted file mode 100755 index 6358c04..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/setopt.py +++ /dev/null @@ -1,149 +0,0 @@ -from distutils.util import convert_path -from distutils import log -from distutils.errors import DistutilsOptionError -import distutils -import os -import configparser - -from setuptools import Command - -__all__ = ['config_file', 'edit_config', 'option_base', 'setopt'] - - -def config_file(kind="local"): - """Get the filename of the distutils, local, global, or per-user config - - `kind` must be one of "local", "global", or "user" - """ - if kind == 'local': - return 'setup.cfg' - if kind == 'global': - return os.path.join( - os.path.dirname(distutils.__file__), 'distutils.cfg' - ) - if kind == 'user': - dot = os.name == 'posix' and '.' or '' - return os.path.expanduser(convert_path("~/%spydistutils.cfg" % dot)) - raise ValueError( - "config_file() type must be 'local', 'global', or 'user'", kind - ) - - -def edit_config(filename, settings, dry_run=False): - """Edit a configuration file to include `settings` - - `settings` is a dictionary of dictionaries or ``None`` values, keyed by - command/section name. A ``None`` value means to delete the entire section, - while a dictionary lists settings to be changed or deleted in that section. - A setting of ``None`` means to delete that setting. - """ - log.debug("Reading configuration from %s", filename) - opts = configparser.RawConfigParser() - opts.optionxform = lambda x: x - opts.read([filename]) - for section, options in settings.items(): - if options is None: - log.info("Deleting section [%s] from %s", section, filename) - opts.remove_section(section) - else: - if not opts.has_section(section): - log.debug("Adding new section [%s] to %s", section, filename) - opts.add_section(section) - for option, value in options.items(): - if value is None: - log.debug( - "Deleting %s.%s from %s", - section, option, filename - ) - opts.remove_option(section, option) - if not opts.options(section): - log.info("Deleting empty [%s] section from %s", - section, filename) - opts.remove_section(section) - else: - log.debug( - "Setting %s.%s to %r in %s", - section, option, value, filename - ) - opts.set(section, option, value) - - log.info("Writing %s", filename) - if not dry_run: - with open(filename, 'w') as f: - opts.write(f) - - -class option_base(Command): - """Abstract base class for commands that mess with config files""" - - user_options = [ - ('global-config', 'g', - "save options to the site-wide distutils.cfg file"), - ('user-config', 'u', - "save options to the current user's pydistutils.cfg file"), - ('filename=', 'f', - "configuration file to use (default=setup.cfg)"), - ] - - boolean_options = [ - 'global-config', 'user-config', - ] - - def initialize_options(self): - self.global_config = None - self.user_config = None - self.filename = None - - def finalize_options(self): - filenames = [] - if self.global_config: - filenames.append(config_file('global')) - if self.user_config: - filenames.append(config_file('user')) - if self.filename is not None: - filenames.append(self.filename) - if not filenames: - filenames.append(config_file('local')) - if len(filenames) > 1: - raise DistutilsOptionError( - "Must specify only one configuration file option", - filenames - ) - self.filename, = filenames - - -class setopt(option_base): - """Save command-line options to a file""" - - description = "set an option in setup.cfg or another config file" - - user_options = [ - ('command=', 'c', 'command to set an option for'), - ('option=', 'o', 'option to set'), - ('set-value=', 's', 'value of the option'), - ('remove', 'r', 'remove (unset) the value'), - ] + option_base.user_options - - boolean_options = option_base.boolean_options + ['remove'] - - def initialize_options(self): - option_base.initialize_options(self) - self.command = None - self.option = None - self.set_value = None - self.remove = None - - def finalize_options(self): - option_base.finalize_options(self) - if self.command is None or self.option is None: - raise DistutilsOptionError("Must specify --command *and* --option") - if self.set_value is None and not self.remove: - raise DistutilsOptionError("Must specify --set-value or --remove") - - def run(self): - edit_config( - self.filename, { - self.command: {self.option.replace('-', '_'): self.set_value} - }, - self.dry_run - ) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/test.py b/venv/lib/python3.11/site-packages/setuptools/command/test.py deleted file mode 100755 index 8dde513..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/test.py +++ /dev/null @@ -1,251 +0,0 @@ -import os -import operator -import sys -import contextlib -import itertools -import unittest -from distutils.errors import DistutilsError, DistutilsOptionError -from distutils import log -from unittest import TestLoader - -from pkg_resources import ( - resource_listdir, - resource_exists, - normalize_path, - working_set, - evaluate_marker, - add_activation_listener, - require, -) -from .._importlib import metadata -from setuptools import Command -from setuptools.extern.more_itertools import unique_everseen -from setuptools.extern.jaraco.functools import pass_none - - -class ScanningLoader(TestLoader): - def __init__(self): - TestLoader.__init__(self) - self._visited = set() - - def loadTestsFromModule(self, module, pattern=None): - """Return a suite of all tests cases contained in the given module - - If the module is a package, load tests from all the modules in it. - If the module has an ``additional_tests`` function, call it and add - the return value to the tests. - """ - if module in self._visited: - return None - self._visited.add(module) - - tests = [] - tests.append(TestLoader.loadTestsFromModule(self, module)) - - if hasattr(module, "additional_tests"): - tests.append(module.additional_tests()) - - if hasattr(module, '__path__'): - for file in resource_listdir(module.__name__, ''): - if file.endswith('.py') and file != '__init__.py': - submodule = module.__name__ + '.' + file[:-3] - else: - if resource_exists(module.__name__, file + '/__init__.py'): - submodule = module.__name__ + '.' + file - else: - continue - tests.append(self.loadTestsFromName(submodule)) - - if len(tests) != 1: - return self.suiteClass(tests) - else: - return tests[0] # don't create a nested suite for only one return - - -# adapted from jaraco.classes.properties:NonDataProperty -class NonDataProperty: - def __init__(self, fget): - self.fget = fget - - def __get__(self, obj, objtype=None): - if obj is None: - return self - return self.fget(obj) - - -class test(Command): - """Command to run unit tests after in-place build""" - - description = "run unit tests after in-place build (deprecated)" - - user_options = [ - ('test-module=', 'm', "Run 'test_suite' in specified module"), - ( - 'test-suite=', - 's', - "Run single test, case or suite (e.g. 'module.test_suite')", - ), - ('test-runner=', 'r', "Test runner to use"), - ] - - def initialize_options(self): - self.test_suite = None - self.test_module = None - self.test_loader = None - self.test_runner = None - - def finalize_options(self): - - if self.test_suite and self.test_module: - msg = "You may specify a module or a suite, but not both" - raise DistutilsOptionError(msg) - - if self.test_suite is None: - if self.test_module is None: - self.test_suite = self.distribution.test_suite - else: - self.test_suite = self.test_module + ".test_suite" - - if self.test_loader is None: - self.test_loader = getattr(self.distribution, 'test_loader', None) - if self.test_loader is None: - self.test_loader = "setuptools.command.test:ScanningLoader" - if self.test_runner is None: - self.test_runner = getattr(self.distribution, 'test_runner', None) - - @NonDataProperty - def test_args(self): - return list(self._test_args()) - - def _test_args(self): - if not self.test_suite: - yield 'discover' - if self.verbose: - yield '--verbose' - if self.test_suite: - yield self.test_suite - - def with_project_on_sys_path(self, func): - """ - Backward compatibility for project_on_sys_path context. - """ - with self.project_on_sys_path(): - func() - - @contextlib.contextmanager - def project_on_sys_path(self, include_dists=[]): - self.run_command('egg_info') - - # Build extensions in-place - self.reinitialize_command('build_ext', inplace=1) - self.run_command('build_ext') - - ei_cmd = self.get_finalized_command("egg_info") - - old_path = sys.path[:] - old_modules = sys.modules.copy() - - try: - project_path = normalize_path(ei_cmd.egg_base) - sys.path.insert(0, project_path) - working_set.__init__() - add_activation_listener(lambda dist: dist.activate()) - require('%s==%s' % (ei_cmd.egg_name, ei_cmd.egg_version)) - with self.paths_on_pythonpath([project_path]): - yield - finally: - sys.path[:] = old_path - sys.modules.clear() - sys.modules.update(old_modules) - working_set.__init__() - - @staticmethod - @contextlib.contextmanager - def paths_on_pythonpath(paths): - """ - Add the indicated paths to the head of the PYTHONPATH environment - variable so that subprocesses will also see the packages at - these paths. - - Do this in a context that restores the value on exit. - """ - nothing = object() - orig_pythonpath = os.environ.get('PYTHONPATH', nothing) - current_pythonpath = os.environ.get('PYTHONPATH', '') - try: - prefix = os.pathsep.join(unique_everseen(paths)) - to_join = filter(None, [prefix, current_pythonpath]) - new_path = os.pathsep.join(to_join) - if new_path: - os.environ['PYTHONPATH'] = new_path - yield - finally: - if orig_pythonpath is nothing: - os.environ.pop('PYTHONPATH', None) - else: - os.environ['PYTHONPATH'] = orig_pythonpath - - @staticmethod - def install_dists(dist): - """ - Install the requirements indicated by self.distribution and - return an iterable of the dists that were built. - """ - ir_d = dist.fetch_build_eggs(dist.install_requires) - tr_d = dist.fetch_build_eggs(dist.tests_require or []) - er_d = dist.fetch_build_eggs( - v - for k, v in dist.extras_require.items() - if k.startswith(':') and evaluate_marker(k[1:]) - ) - return itertools.chain(ir_d, tr_d, er_d) - - def run(self): - self.announce( - "WARNING: Testing via this command is deprecated and will be " - "removed in a future version. Users looking for a generic test " - "entry point independent of test runner are encouraged to use " - "tox.", - log.WARN, - ) - - installed_dists = self.install_dists(self.distribution) - - cmd = ' '.join(self._argv) - if self.dry_run: - self.announce('skipping "%s" (dry run)' % cmd) - return - - self.announce('running "%s"' % cmd) - - paths = map(operator.attrgetter('location'), installed_dists) - with self.paths_on_pythonpath(paths): - with self.project_on_sys_path(): - self.run_tests() - - def run_tests(self): - test = unittest.main( - None, - None, - self._argv, - testLoader=self._resolve_as_ep(self.test_loader), - testRunner=self._resolve_as_ep(self.test_runner), - exit=False, - ) - if not test.result.wasSuccessful(): - msg = 'Test failed: %s' % test.result - self.announce(msg, log.ERROR) - raise DistutilsError(msg) - - @property - def _argv(self): - return ['unittest'] + self.test_args - - @staticmethod - @pass_none - def _resolve_as_ep(val): - """ - Load the indicated attribute value, called, as a as if it were - specified as an entry point. - """ - return metadata.EntryPoint(value=val, name=None, group=None).load()() diff --git a/venv/lib/python3.11/site-packages/setuptools/command/upload.py b/venv/lib/python3.11/site-packages/setuptools/command/upload.py deleted file mode 100755 index ec7f81e..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/upload.py +++ /dev/null @@ -1,17 +0,0 @@ -from distutils import log -from distutils.command import upload as orig - -from setuptools.errors import RemovedCommandError - - -class upload(orig.upload): - """Formerly used to upload packages to PyPI.""" - - def run(self): - msg = ( - "The upload command has been removed, use twine to upload " - + "instead (https://pypi.org/p/twine)" - ) - - self.announce("ERROR: " + msg, log.ERROR) - raise RemovedCommandError(msg) diff --git a/venv/lib/python3.11/site-packages/setuptools/command/upload_docs.py b/venv/lib/python3.11/site-packages/setuptools/command/upload_docs.py deleted file mode 100755 index 63eb28c..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/command/upload_docs.py +++ /dev/null @@ -1,212 +0,0 @@ -"""upload_docs - -Implements a Distutils 'upload_docs' subcommand (upload documentation to -sites other than PyPi such as devpi). -""" - -from base64 import standard_b64encode -from distutils import log -from distutils.errors import DistutilsOptionError -import os -import socket -import zipfile -import tempfile -import shutil -import itertools -import functools -import http.client -import urllib.parse -import warnings - -from .._importlib import metadata -from .. import SetuptoolsDeprecationWarning - -from .upload import upload - - -def _encode(s): - return s.encode('utf-8', 'surrogateescape') - - -class upload_docs(upload): - # override the default repository as upload_docs isn't - # supported by Warehouse (and won't be). - DEFAULT_REPOSITORY = 'https://pypi.python.org/pypi/' - - description = 'Upload documentation to sites other than PyPi such as devpi' - - user_options = [ - ('repository=', 'r', - "url of repository [default: %s]" % upload.DEFAULT_REPOSITORY), - ('show-response', None, - 'display full response text from server'), - ('upload-dir=', None, 'directory to upload'), - ] - boolean_options = upload.boolean_options - - def has_sphinx(self): - return bool( - self.upload_dir is None - and metadata.entry_points(group='distutils.commands', name='build_sphinx') - ) - - sub_commands = [('build_sphinx', has_sphinx)] - - def initialize_options(self): - upload.initialize_options(self) - self.upload_dir = None - self.target_dir = None - - def finalize_options(self): - log.warn( - "Upload_docs command is deprecated. Use Read the Docs " - "(https://readthedocs.org) instead.") - upload.finalize_options(self) - if self.upload_dir is None: - if self.has_sphinx(): - build_sphinx = self.get_finalized_command('build_sphinx') - self.target_dir = dict(build_sphinx.builder_target_dirs)['html'] - else: - build = self.get_finalized_command('build') - self.target_dir = os.path.join(build.build_base, 'docs') - else: - self.ensure_dirname('upload_dir') - self.target_dir = self.upload_dir - self.announce('Using upload directory %s' % self.target_dir) - - def create_zipfile(self, filename): - zip_file = zipfile.ZipFile(filename, "w") - try: - self.mkpath(self.target_dir) # just in case - for root, dirs, files in os.walk(self.target_dir): - if root == self.target_dir and not files: - tmpl = "no files found in upload directory '%s'" - raise DistutilsOptionError(tmpl % self.target_dir) - for name in files: - full = os.path.join(root, name) - relative = root[len(self.target_dir):].lstrip(os.path.sep) - dest = os.path.join(relative, name) - zip_file.write(full, dest) - finally: - zip_file.close() - - def run(self): - warnings.warn( - "upload_docs is deprecated and will be removed in a future " - "version. Use tools like httpie or curl instead.", - SetuptoolsDeprecationWarning, - ) - - # Run sub commands - for cmd_name in self.get_sub_commands(): - self.run_command(cmd_name) - - tmp_dir = tempfile.mkdtemp() - name = self.distribution.metadata.get_name() - zip_file = os.path.join(tmp_dir, "%s.zip" % name) - try: - self.create_zipfile(zip_file) - self.upload_file(zip_file) - finally: - shutil.rmtree(tmp_dir) - - @staticmethod - def _build_part(item, sep_boundary): - key, values = item - title = '\nContent-Disposition: form-data; name="%s"' % key - # handle multiple entries for the same name - if not isinstance(values, list): - values = [values] - for value in values: - if isinstance(value, tuple): - title += '; filename="%s"' % value[0] - value = value[1] - else: - value = _encode(value) - yield sep_boundary - yield _encode(title) - yield b"\n\n" - yield value - if value and value[-1:] == b'\r': - yield b'\n' # write an extra newline (lurve Macs) - - @classmethod - def _build_multipart(cls, data): - """ - Build up the MIME payload for the POST data - """ - boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' - sep_boundary = b'\n--' + boundary.encode('ascii') - end_boundary = sep_boundary + b'--' - end_items = end_boundary, b"\n", - builder = functools.partial( - cls._build_part, - sep_boundary=sep_boundary, - ) - part_groups = map(builder, data.items()) - parts = itertools.chain.from_iterable(part_groups) - body_items = itertools.chain(parts, end_items) - content_type = 'multipart/form-data; boundary=%s' % boundary - return b''.join(body_items), content_type - - def upload_file(self, filename): - with open(filename, 'rb') as f: - content = f.read() - meta = self.distribution.metadata - data = { - ':action': 'doc_upload', - 'name': meta.get_name(), - 'content': (os.path.basename(filename), content), - } - # set up the authentication - credentials = _encode(self.username + ':' + self.password) - credentials = standard_b64encode(credentials).decode('ascii') - auth = "Basic " + credentials - - body, ct = self._build_multipart(data) - - msg = "Submitting documentation to %s" % (self.repository) - self.announce(msg, log.INFO) - - # build the Request - # We can't use urllib2 since we need to send the Basic - # auth right with the first request - schema, netloc, url, params, query, fragments = \ - urllib.parse.urlparse(self.repository) - assert not params and not query and not fragments - if schema == 'http': - conn = http.client.HTTPConnection(netloc) - elif schema == 'https': - conn = http.client.HTTPSConnection(netloc) - else: - raise AssertionError("unsupported schema " + schema) - - data = '' - try: - conn.connect() - conn.putrequest("POST", url) - content_type = ct - conn.putheader('Content-type', content_type) - conn.putheader('Content-length', str(len(body))) - conn.putheader('Authorization', auth) - conn.endheaders() - conn.send(body) - except socket.error as e: - self.announce(str(e), log.ERROR) - return - - r = conn.getresponse() - if r.status == 200: - msg = 'Server response (%s): %s' % (r.status, r.reason) - self.announce(msg, log.INFO) - elif r.status == 301: - location = r.getheader('Location') - if location is None: - location = 'https://pythonhosted.org/%s/' % meta.get_name() - msg = 'Upload successful. Visit %s' % location - self.announce(msg, log.INFO) - else: - msg = 'Upload failed (%s): %s' % (r.status, r.reason) - self.announce(msg, log.ERROR) - if self.show_response: - print('-' * 75, r.read(), '-' * 75) diff --git a/venv/lib/python3.11/site-packages/setuptools/config/__init__.py b/venv/lib/python3.11/site-packages/setuptools/config/__init__.py deleted file mode 100755 index 1a5153a..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/config/__init__.py +++ /dev/null @@ -1,35 +0,0 @@ -"""For backward compatibility, expose main functions from -``setuptools.config.setupcfg`` -""" -import warnings -from functools import wraps -from textwrap import dedent -from typing import Callable, TypeVar, cast - -from .._deprecation_warning import SetuptoolsDeprecationWarning -from . import setupcfg - -Fn = TypeVar("Fn", bound=Callable) - -__all__ = ('parse_configuration', 'read_configuration') - - -def _deprecation_notice(fn: Fn) -> Fn: - @wraps(fn) - def _wrapper(*args, **kwargs): - msg = f"""\ - As setuptools moves its configuration towards `pyproject.toml`, - `{__name__}.{fn.__name__}` became deprecated. - - For the time being, you can use the `{setupcfg.__name__}` module - to access a backward compatible API, but this module is provisional - and might be removed in the future. - """ - warnings.warn(dedent(msg), SetuptoolsDeprecationWarning, stacklevel=2) - return fn(*args, **kwargs) - - return cast(Fn, _wrapper) - - -read_configuration = _deprecation_notice(setupcfg.read_configuration) -parse_configuration = _deprecation_notice(setupcfg.parse_configuration) diff --git a/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index ecced6e..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/_apply_pyprojecttoml.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/_apply_pyprojecttoml.cpython-311.pyc deleted file mode 100755 index 6e98474..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/_apply_pyprojecttoml.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/expand.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/expand.cpython-311.pyc deleted file mode 100755 index 2d210fd..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/expand.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/pyprojecttoml.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/pyprojecttoml.cpython-311.pyc deleted file mode 100755 index 32c58d2..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/pyprojecttoml.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/setupcfg.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/setupcfg.cpython-311.pyc deleted file mode 100755 index 13a88b4..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/config/__pycache__/setupcfg.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/config/_apply_pyprojecttoml.py b/venv/lib/python3.11/site-packages/setuptools/config/_apply_pyprojecttoml.py deleted file mode 100755 index c805e63..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/config/_apply_pyprojecttoml.py +++ /dev/null @@ -1,384 +0,0 @@ -"""Translation layer between pyproject config and setuptools distribution and -metadata objects. - -The distribution and metadata objects are modeled after (an old version of) -core metadata, therefore configs in the format specified for ``pyproject.toml`` -need to be processed before being applied. - -**PRIVATE MODULE**: API reserved for setuptools internal usage only. -""" -import logging -import os -import warnings -from collections.abc import Mapping -from email.headerregistry import Address -from functools import partial, reduce -from itertools import chain -from types import MappingProxyType -from typing import (TYPE_CHECKING, Any, Callable, Dict, List, Optional, Set, Tuple, - Type, Union, cast) - -from setuptools._deprecation_warning import SetuptoolsDeprecationWarning - -if TYPE_CHECKING: - from setuptools._importlib import metadata # noqa - from setuptools.dist import Distribution # noqa - -EMPTY: Mapping = MappingProxyType({}) # Immutable dict-like -_Path = Union[os.PathLike, str] -_DictOrStr = Union[dict, str] -_CorrespFn = Callable[["Distribution", Any, _Path], None] -_Correspondence = Union[str, _CorrespFn] - -_logger = logging.getLogger(__name__) - - -def apply(dist: "Distribution", config: dict, filename: _Path) -> "Distribution": - """Apply configuration dict read with :func:`read_configuration`""" - - if not config: - return dist # short-circuit unrelated pyproject.toml file - - root_dir = os.path.dirname(filename) or "." - - _apply_project_table(dist, config, root_dir) - _apply_tool_table(dist, config, filename) - - current_directory = os.getcwd() - os.chdir(root_dir) - try: - dist._finalize_requires() - dist._finalize_license_files() - finally: - os.chdir(current_directory) - - return dist - - -def _apply_project_table(dist: "Distribution", config: dict, root_dir: _Path): - project_table = config.get("project", {}).copy() - if not project_table: - return # short-circuit - - _handle_missing_dynamic(dist, project_table) - _unify_entry_points(project_table) - - for field, value in project_table.items(): - norm_key = json_compatible_key(field) - corresp = PYPROJECT_CORRESPONDENCE.get(norm_key, norm_key) - if callable(corresp): - corresp(dist, value, root_dir) - else: - _set_config(dist, corresp, value) - - -def _apply_tool_table(dist: "Distribution", config: dict, filename: _Path): - tool_table = config.get("tool", {}).get("setuptools", {}) - if not tool_table: - return # short-circuit - - for field, value in tool_table.items(): - norm_key = json_compatible_key(field) - - if norm_key in TOOL_TABLE_DEPRECATIONS: - suggestion = TOOL_TABLE_DEPRECATIONS[norm_key] - msg = f"The parameter `{norm_key}` is deprecated, {suggestion}" - warnings.warn(msg, SetuptoolsDeprecationWarning) - - norm_key = TOOL_TABLE_RENAMES.get(norm_key, norm_key) - _set_config(dist, norm_key, value) - - _copy_command_options(config, dist, filename) - - -def _handle_missing_dynamic(dist: "Distribution", project_table: dict): - """Be temporarily forgiving with ``dynamic`` fields not listed in ``dynamic``""" - # TODO: Set fields back to `None` once the feature stabilizes - dynamic = set(project_table.get("dynamic", [])) - for field, getter in _PREVIOUSLY_DEFINED.items(): - if not (field in project_table or field in dynamic): - value = getter(dist) - if value: - msg = _WouldIgnoreField.message(field, value) - warnings.warn(msg, _WouldIgnoreField) - - -def json_compatible_key(key: str) -> str: - """As defined in :pep:`566#json-compatible-metadata`""" - return key.lower().replace("-", "_") - - -def _set_config(dist: "Distribution", field: str, value: Any): - setter = getattr(dist.metadata, f"set_{field}", None) - if setter: - setter(value) - elif hasattr(dist.metadata, field) or field in SETUPTOOLS_PATCHES: - setattr(dist.metadata, field, value) - else: - setattr(dist, field, value) - - -_CONTENT_TYPES = { - ".md": "text/markdown", - ".rst": "text/x-rst", - ".txt": "text/plain", -} - - -def _guess_content_type(file: str) -> Optional[str]: - _, ext = os.path.splitext(file.lower()) - if not ext: - return None - - if ext in _CONTENT_TYPES: - return _CONTENT_TYPES[ext] - - valid = ", ".join(f"{k} ({v})" for k, v in _CONTENT_TYPES.items()) - msg = f"only the following file extensions are recognized: {valid}." - raise ValueError(f"Undefined content type for {file}, {msg}") - - -def _long_description(dist: "Distribution", val: _DictOrStr, root_dir: _Path): - from setuptools.config import expand - - if isinstance(val, str): - file: Union[str, list] = val - text = expand.read_files(file, root_dir) - ctype = _guess_content_type(val) - else: - file = val.get("file") or [] - text = val.get("text") or expand.read_files(file, root_dir) - ctype = val["content-type"] - - _set_config(dist, "long_description", text) - - if ctype: - _set_config(dist, "long_description_content_type", ctype) - - if file: - dist._referenced_files.add(cast(str, file)) - - -def _license(dist: "Distribution", val: dict, root_dir: _Path): - from setuptools.config import expand - - if "file" in val: - _set_config(dist, "license", expand.read_files([val["file"]], root_dir)) - dist._referenced_files.add(val["file"]) - else: - _set_config(dist, "license", val["text"]) - - -def _people(dist: "Distribution", val: List[dict], _root_dir: _Path, kind: str): - field = [] - email_field = [] - for person in val: - if "name" not in person: - email_field.append(person["email"]) - elif "email" not in person: - field.append(person["name"]) - else: - addr = Address(display_name=person["name"], addr_spec=person["email"]) - email_field.append(str(addr)) - - if field: - _set_config(dist, kind, ", ".join(field)) - if email_field: - _set_config(dist, f"{kind}_email", ", ".join(email_field)) - - -def _project_urls(dist: "Distribution", val: dict, _root_dir): - _set_config(dist, "project_urls", val) - - -def _python_requires(dist: "Distribution", val: dict, _root_dir): - from setuptools.extern.packaging.specifiers import SpecifierSet - - _set_config(dist, "python_requires", SpecifierSet(val)) - - -def _dependencies(dist: "Distribution", val: list, _root_dir): - if getattr(dist, "install_requires", []): - msg = "`install_requires` overwritten in `pyproject.toml` (dependencies)" - warnings.warn(msg) - _set_config(dist, "install_requires", val) - - -def _optional_dependencies(dist: "Distribution", val: dict, _root_dir): - existing = getattr(dist, "extras_require", {}) - _set_config(dist, "extras_require", {**existing, **val}) - - -def _unify_entry_points(project_table: dict): - project = project_table - entry_points = project.pop("entry-points", project.pop("entry_points", {})) - renaming = {"scripts": "console_scripts", "gui_scripts": "gui_scripts"} - for key, value in list(project.items()): # eager to allow modifications - norm_key = json_compatible_key(key) - if norm_key in renaming and value: - entry_points[renaming[norm_key]] = project.pop(key) - - if entry_points: - project["entry-points"] = { - name: [f"{k} = {v}" for k, v in group.items()] - for name, group in entry_points.items() - } - - -def _copy_command_options(pyproject: dict, dist: "Distribution", filename: _Path): - tool_table = pyproject.get("tool", {}) - cmdclass = tool_table.get("setuptools", {}).get("cmdclass", {}) - valid_options = _valid_command_options(cmdclass) - - cmd_opts = dist.command_options - for cmd, config in pyproject.get("tool", {}).get("distutils", {}).items(): - cmd = json_compatible_key(cmd) - valid = valid_options.get(cmd, set()) - cmd_opts.setdefault(cmd, {}) - for key, value in config.items(): - key = json_compatible_key(key) - cmd_opts[cmd][key] = (str(filename), value) - if key not in valid: - # To avoid removing options that are specified dynamically we - # just log a warn... - _logger.warning(f"Command option {cmd}.{key} is not defined") - - -def _valid_command_options(cmdclass: Mapping = EMPTY) -> Dict[str, Set[str]]: - from .._importlib import metadata - from setuptools.dist import Distribution - - valid_options = {"global": _normalise_cmd_options(Distribution.global_options)} - - unloaded_entry_points = metadata.entry_points(group='distutils.commands') - loaded_entry_points = (_load_ep(ep) for ep in unloaded_entry_points) - entry_points = (ep for ep in loaded_entry_points if ep) - for cmd, cmd_class in chain(entry_points, cmdclass.items()): - opts = valid_options.get(cmd, set()) - opts = opts | _normalise_cmd_options(getattr(cmd_class, "user_options", [])) - valid_options[cmd] = opts - - return valid_options - - -def _load_ep(ep: "metadata.EntryPoint") -> Optional[Tuple[str, Type]]: - # Ignore all the errors - try: - return (ep.name, ep.load()) - except Exception as ex: - msg = f"{ex.__class__.__name__} while trying to load entry-point {ep.name}" - _logger.warning(f"{msg}: {ex}") - return None - - -def _normalise_cmd_option_key(name: str) -> str: - return json_compatible_key(name).strip("_=") - - -def _normalise_cmd_options(desc: List[Tuple[str, Optional[str], str]]) -> Set[str]: - return {_normalise_cmd_option_key(fancy_option[0]) for fancy_option in desc} - - -def _attrgetter(attr): - """ - Similar to ``operator.attrgetter`` but returns None if ``attr`` is not found - >>> from types import SimpleNamespace - >>> obj = SimpleNamespace(a=42, b=SimpleNamespace(c=13)) - >>> _attrgetter("a")(obj) - 42 - >>> _attrgetter("b.c")(obj) - 13 - >>> _attrgetter("d")(obj) is None - True - """ - return partial(reduce, lambda acc, x: getattr(acc, x, None), attr.split(".")) - - -def _some_attrgetter(*items): - """ - Return the first "truth-y" attribute or None - >>> from types import SimpleNamespace - >>> obj = SimpleNamespace(a=42, b=SimpleNamespace(c=13)) - >>> _some_attrgetter("d", "a", "b.c")(obj) - 42 - >>> _some_attrgetter("d", "e", "b.c", "a")(obj) - 13 - >>> _some_attrgetter("d", "e", "f")(obj) is None - True - """ - def _acessor(obj): - values = (_attrgetter(i)(obj) for i in items) - return next((i for i in values if i is not None), None) - return _acessor - - -PYPROJECT_CORRESPONDENCE: Dict[str, _Correspondence] = { - "readme": _long_description, - "license": _license, - "authors": partial(_people, kind="author"), - "maintainers": partial(_people, kind="maintainer"), - "urls": _project_urls, - "dependencies": _dependencies, - "optional_dependencies": _optional_dependencies, - "requires_python": _python_requires, -} - -TOOL_TABLE_RENAMES = {"script_files": "scripts"} -TOOL_TABLE_DEPRECATIONS = { - "namespace_packages": "consider using implicit namespaces instead (PEP 420)." -} - -SETUPTOOLS_PATCHES = {"long_description_content_type", "project_urls", - "provides_extras", "license_file", "license_files"} - -_PREVIOUSLY_DEFINED = { - "name": _attrgetter("metadata.name"), - "version": _attrgetter("metadata.version"), - "description": _attrgetter("metadata.description"), - "readme": _attrgetter("metadata.long_description"), - "requires-python": _some_attrgetter("python_requires", "metadata.python_requires"), - "license": _attrgetter("metadata.license"), - "authors": _some_attrgetter("metadata.author", "metadata.author_email"), - "maintainers": _some_attrgetter("metadata.maintainer", "metadata.maintainer_email"), - "keywords": _attrgetter("metadata.keywords"), - "classifiers": _attrgetter("metadata.classifiers"), - "urls": _attrgetter("metadata.project_urls"), - "entry-points": _attrgetter("entry_points"), - "dependencies": _some_attrgetter("_orig_install_requires", "install_requires"), - "optional-dependencies": _some_attrgetter("_orig_extras_require", "extras_require"), -} - - -class _WouldIgnoreField(UserWarning): - """Inform users that ``pyproject.toml`` would overwrite previous metadata.""" - - MESSAGE = """\ - {field!r} defined outside of `pyproject.toml` would be ignored. - !!\n\n - ########################################################################## - # configuration would be ignored/result in error due to `pyproject.toml` # - ########################################################################## - - The following seems to be defined outside of `pyproject.toml`: - - `{field} = {value!r}` - - According to the spec (see the link below), however, setuptools CANNOT - consider this value unless {field!r} is listed as `dynamic`. - - https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ - - For the time being, `setuptools` will still consider the given value (as a - **transitional** measure), but please note that future releases of setuptools will - follow strictly the standard. - - To prevent this warning, you can list {field!r} under `dynamic` or alternatively - remove the `[project]` table from your file and rely entirely on other means of - configuration. - \n\n!! - """ - - @classmethod - def message(cls, field, value): - from inspect import cleandoc - return cleandoc(cls.MESSAGE.format(field=field, value=value)) diff --git a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__init__.py b/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__init__.py deleted file mode 100755 index dbe6cb4..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__init__.py +++ /dev/null @@ -1,34 +0,0 @@ -from functools import reduce -from typing import Any, Callable, Dict - -from . import formats -from .error_reporting import detailed_errors, ValidationError -from .extra_validations import EXTRA_VALIDATIONS -from .fastjsonschema_exceptions import JsonSchemaException, JsonSchemaValueException -from .fastjsonschema_validations import validate as _validate - -__all__ = [ - "validate", - "FORMAT_FUNCTIONS", - "EXTRA_VALIDATIONS", - "ValidationError", - "JsonSchemaException", - "JsonSchemaValueException", -] - - -FORMAT_FUNCTIONS: Dict[str, Callable[[str], bool]] = { - fn.__name__.replace("_", "-"): fn - for fn in formats.__dict__.values() - if callable(fn) and not fn.__name__.startswith("_") -} - - -def validate(data: Any) -> bool: - """Validate the given ``data`` object using JSON Schema - This function raises ``ValidationError`` if ``data`` is invalid. - """ - with detailed_errors(): - _validate(data, custom_formats=FORMAT_FUNCTIONS) - reduce(lambda acc, fn: fn(acc), EXTRA_VALIDATIONS, data) - return True diff --git a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index 79c091c..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/error_reporting.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/error_reporting.cpython-311.pyc deleted file mode 100755 index 28b31fa..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/error_reporting.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/extra_validations.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/extra_validations.cpython-311.pyc deleted file mode 100755 index 97957ee..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/extra_validations.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/fastjsonschema_exceptions.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/fastjsonschema_exceptions.cpython-311.pyc deleted file mode 100755 index ae6db3d..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/fastjsonschema_exceptions.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/fastjsonschema_validations.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/fastjsonschema_validations.cpython-311.pyc deleted file mode 100755 index 1f489ec..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/fastjsonschema_validations.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/formats.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/formats.cpython-311.pyc deleted file mode 100755 index 0043a47..0000000 Binary files a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/__pycache__/formats.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/error_reporting.py b/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/error_reporting.py deleted file mode 100755 index f78e483..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/error_reporting.py +++ /dev/null @@ -1,318 +0,0 @@ -import io -import json -import logging -import os -import re -from contextlib import contextmanager -from textwrap import indent, wrap -from typing import Any, Dict, Iterator, List, Optional, Sequence, Union, cast - -from .fastjsonschema_exceptions import JsonSchemaValueException - -_logger = logging.getLogger(__name__) - -_MESSAGE_REPLACEMENTS = { - "must be named by propertyName definition": "keys must be named by", - "one of contains definition": "at least one item that matches", - " same as const definition:": "", - "only specified items": "only items matching the definition", -} - -_SKIP_DETAILS = ( - "must not be empty", - "is always invalid", - "must not be there", -) - -_NEED_DETAILS = {"anyOf", "oneOf", "anyOf", "contains", "propertyNames", "not", "items"} - -_CAMEL_CASE_SPLITTER = re.compile(r"\W+|([A-Z][^A-Z\W]*)") -_IDENTIFIER = re.compile(r"^[\w_]+$", re.I) - -_TOML_JARGON = { - "object": "table", - "property": "key", - "properties": "keys", - "property names": "keys", -} - - -class ValidationError(JsonSchemaValueException): - """Report violations of a given JSON schema. - - This class extends :exc:`~fastjsonschema.JsonSchemaValueException` - by adding the following properties: - - - ``summary``: an improved version of the ``JsonSchemaValueException`` error message - with only the necessary information) - - - ``details``: more contextual information about the error like the failing schema - itself and the value that violates the schema. - - Depending on the level of the verbosity of the ``logging`` configuration - the exception message will be only ``summary`` (default) or a combination of - ``summary`` and ``details`` (when the logging level is set to :obj:`logging.DEBUG`). - """ - - summary = "" - details = "" - _original_message = "" - - @classmethod - def _from_jsonschema(cls, ex: JsonSchemaValueException): - formatter = _ErrorFormatting(ex) - obj = cls(str(formatter), ex.value, formatter.name, ex.definition, ex.rule) - debug_code = os.getenv("JSONSCHEMA_DEBUG_CODE_GENERATION", "false").lower() - if debug_code != "false": # pragma: no cover - obj.__cause__, obj.__traceback__ = ex.__cause__, ex.__traceback__ - obj._original_message = ex.message - obj.summary = formatter.summary - obj.details = formatter.details - return obj - - -@contextmanager -def detailed_errors(): - try: - yield - except JsonSchemaValueException as ex: - raise ValidationError._from_jsonschema(ex) from None - - -class _ErrorFormatting: - def __init__(self, ex: JsonSchemaValueException): - self.ex = ex - self.name = f"`{self._simplify_name(ex.name)}`" - self._original_message = self.ex.message.replace(ex.name, self.name) - self._summary = "" - self._details = "" - - def __str__(self) -> str: - if _logger.getEffectiveLevel() <= logging.DEBUG and self.details: - return f"{self.summary}\n\n{self.details}" - - return self.summary - - @property - def summary(self) -> str: - if not self._summary: - self._summary = self._expand_summary() - - return self._summary - - @property - def details(self) -> str: - if not self._details: - self._details = self._expand_details() - - return self._details - - def _simplify_name(self, name): - x = len("data.") - return name[x:] if name.startswith("data.") else name - - def _expand_summary(self): - msg = self._original_message - - for bad, repl in _MESSAGE_REPLACEMENTS.items(): - msg = msg.replace(bad, repl) - - if any(substring in msg for substring in _SKIP_DETAILS): - return msg - - schema = self.ex.rule_definition - if self.ex.rule in _NEED_DETAILS and schema: - summary = _SummaryWriter(_TOML_JARGON) - return f"{msg}:\n\n{indent(summary(schema), ' ')}" - - return msg - - def _expand_details(self) -> str: - optional = [] - desc_lines = self.ex.definition.pop("$$description", []) - desc = self.ex.definition.pop("description", None) or " ".join(desc_lines) - if desc: - description = "\n".join( - wrap( - desc, - width=80, - initial_indent=" ", - subsequent_indent=" ", - break_long_words=False, - ) - ) - optional.append(f"DESCRIPTION:\n{description}") - schema = json.dumps(self.ex.definition, indent=4) - value = json.dumps(self.ex.value, indent=4) - defaults = [ - f"GIVEN VALUE:\n{indent(value, ' ')}", - f"OFFENDING RULE: {self.ex.rule!r}", - f"DEFINITION:\n{indent(schema, ' ')}", - ] - return "\n\n".join(optional + defaults) - - -class _SummaryWriter: - _IGNORE = {"description", "default", "title", "examples"} - - def __init__(self, jargon: Optional[Dict[str, str]] = None): - self.jargon: Dict[str, str] = jargon or {} - # Clarify confusing terms - self._terms = { - "anyOf": "at least one of the following", - "oneOf": "exactly one of the following", - "allOf": "all of the following", - "not": "(*NOT* the following)", - "prefixItems": f"{self._jargon('items')} (in order)", - "items": "items", - "contains": "contains at least one of", - "propertyNames": ( - f"non-predefined acceptable {self._jargon('property names')}" - ), - "patternProperties": f"{self._jargon('properties')} named via pattern", - "const": "predefined value", - "enum": "one of", - } - # Attributes that indicate that the definition is easy and can be done - # inline (e.g. string and number) - self._guess_inline_defs = [ - "enum", - "const", - "maxLength", - "minLength", - "pattern", - "format", - "minimum", - "maximum", - "exclusiveMinimum", - "exclusiveMaximum", - "multipleOf", - ] - - def _jargon(self, term: Union[str, List[str]]) -> Union[str, List[str]]: - if isinstance(term, list): - return [self.jargon.get(t, t) for t in term] - return self.jargon.get(term, term) - - def __call__( - self, - schema: Union[dict, List[dict]], - prefix: str = "", - *, - _path: Sequence[str] = (), - ) -> str: - if isinstance(schema, list): - return self._handle_list(schema, prefix, _path) - - filtered = self._filter_unecessary(schema, _path) - simple = self._handle_simple_dict(filtered, _path) - if simple: - return f"{prefix}{simple}" - - child_prefix = self._child_prefix(prefix, " ") - item_prefix = self._child_prefix(prefix, "- ") - indent = len(prefix) * " " - with io.StringIO() as buffer: - for i, (key, value) in enumerate(filtered.items()): - child_path = [*_path, key] - line_prefix = prefix if i == 0 else indent - buffer.write(f"{line_prefix}{self._label(child_path)}:") - # ^ just the first item should receive the complete prefix - if isinstance(value, dict): - filtered = self._filter_unecessary(value, child_path) - simple = self._handle_simple_dict(filtered, child_path) - buffer.write( - f" {simple}" - if simple - else f"\n{self(value, child_prefix, _path=child_path)}" - ) - elif isinstance(value, list) and ( - key != "type" or self._is_property(child_path) - ): - children = self._handle_list(value, item_prefix, child_path) - sep = " " if children.startswith("[") else "\n" - buffer.write(f"{sep}{children}") - else: - buffer.write(f" {self._value(value, child_path)}\n") - return buffer.getvalue() - - def _is_unecessary(self, path: Sequence[str]) -> bool: - if self._is_property(path) or not path: # empty path => instruction @ root - return False - key = path[-1] - return any(key.startswith(k) for k in "$_") or key in self._IGNORE - - def _filter_unecessary(self, schema: dict, path: Sequence[str]): - return { - key: value - for key, value in schema.items() - if not self._is_unecessary([*path, key]) - } - - def _handle_simple_dict(self, value: dict, path: Sequence[str]) -> Optional[str]: - inline = any(p in value for p in self._guess_inline_defs) - simple = not any(isinstance(v, (list, dict)) for v in value.values()) - if inline or simple: - return f"{{{', '.join(self._inline_attrs(value, path))}}}\n" - return None - - def _handle_list( - self, schemas: list, prefix: str = "", path: Sequence[str] = () - ) -> str: - if self._is_unecessary(path): - return "" - - repr_ = repr(schemas) - if all(not isinstance(e, (dict, list)) for e in schemas) and len(repr_) < 60: - return f"{repr_}\n" - - item_prefix = self._child_prefix(prefix, "- ") - return "".join( - self(v, item_prefix, _path=[*path, f"[{i}]"]) for i, v in enumerate(schemas) - ) - - def _is_property(self, path: Sequence[str]): - """Check if the given path can correspond to an arbitrarily named property""" - counter = 0 - for key in path[-2::-1]: - if key not in {"properties", "patternProperties"}: - break - counter += 1 - - # If the counter if even, the path correspond to a JSON Schema keyword - # otherwise it can be any arbitrary string naming a property - return counter % 2 == 1 - - def _label(self, path: Sequence[str]) -> str: - *parents, key = path - if not self._is_property(path): - norm_key = _separate_terms(key) - return self._terms.get(key) or " ".join(self._jargon(norm_key)) - - if parents[-1] == "patternProperties": - return f"(regex {key!r})" - return repr(key) # property name - - def _value(self, value: Any, path: Sequence[str]) -> str: - if path[-1] == "type" and not self._is_property(path): - type_ = self._jargon(value) - return ( - f"[{', '.join(type_)}]" if isinstance(value, list) else cast(str, type_) - ) - return repr(value) - - def _inline_attrs(self, schema: dict, path: Sequence[str]) -> Iterator[str]: - for key, value in schema.items(): - child_path = [*path, key] - yield f"{self._label(child_path)}: {self._value(value, child_path)}" - - def _child_prefix(self, parent_prefix: str, child_prefix: str) -> str: - return len(parent_prefix) * " " + child_prefix - - -def _separate_terms(word: str) -> List[str]: - """ - >>> _separate_terms("FooBar-foo") - ['foo', 'bar', 'foo'] - """ - return [w.lower() for w in _CAMEL_CASE_SPLITTER.split(word) if w] diff --git a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/extra_validations.py b/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/extra_validations.py deleted file mode 100755 index 4130a42..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/extra_validations.py +++ /dev/null @@ -1,36 +0,0 @@ -"""The purpose of this module is implement PEP 621 validations that are -difficult to express as a JSON Schema (or that are not supported by the current -JSON Schema library). -""" - -from typing import Mapping, TypeVar - -from .error_reporting import ValidationError - -T = TypeVar("T", bound=Mapping) - - -class RedefiningStaticFieldAsDynamic(ValidationError): - """According to PEP 621: - - Build back-ends MUST raise an error if the metadata specifies a field - statically as well as being listed in dynamic. - """ - - -def validate_project_dynamic(pyproject: T) -> T: - project_table = pyproject.get("project", {}) - dynamic = project_table.get("dynamic", []) - - for field in dynamic: - if field in project_table: - msg = f"You cannot provide a value for `project.{field}` and " - msg += "list it under `project.dynamic` at the same time" - name = f"data.project.{field}" - value = {field: project_table[field], "...": " # ...", "dynamic": dynamic} - raise RedefiningStaticFieldAsDynamic(msg, value, name, rule="PEP 621") - - return pyproject - - -EXTRA_VALIDATIONS = (validate_project_dynamic,) diff --git a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_exceptions.py b/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_exceptions.py deleted file mode 100755 index d2dddd6..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_exceptions.py +++ /dev/null @@ -1,51 +0,0 @@ -import re - - -SPLIT_RE = re.compile(r'[\.\[\]]+') - - -class JsonSchemaException(ValueError): - """ - Base exception of ``fastjsonschema`` library. - """ - - -class JsonSchemaValueException(JsonSchemaException): - """ - Exception raised by validation function. Available properties: - - * ``message`` containing human-readable information what is wrong (e.g. ``data.property[index] must be smaller than or equal to 42``), - * invalid ``value`` (e.g. ``60``), - * ``name`` of a path in the data structure (e.g. ``data.property[index]``), - * ``path`` as an array in the data structure (e.g. ``['data', 'property', 'index']``), - * the whole ``definition`` which the ``value`` has to fulfil (e.g. ``{'type': 'number', 'maximum': 42}``), - * ``rule`` which the ``value`` is breaking (e.g. ``maximum``) - * and ``rule_definition`` (e.g. ``42``). - - .. versionchanged:: 2.14.0 - Added all extra properties. - """ - - def __init__(self, message, value=None, name=None, definition=None, rule=None): - super().__init__(message) - self.message = message - self.value = value - self.name = name - self.definition = definition - self.rule = rule - - @property - def path(self): - return [item for item in SPLIT_RE.split(self.name) if item != ''] - - @property - def rule_definition(self): - if not self.rule or not self.definition: - return None - return self.definition.get(self.rule) - - -class JsonSchemaDefinitionException(JsonSchemaException): - """ - Exception raised by generator of validation function. - """ diff --git a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_validations.py b/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_validations.py deleted file mode 100755 index ad5ee31..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_validations.py +++ /dev/null @@ -1,1035 +0,0 @@ -# noqa -# type: ignore -# flake8: noqa -# pylint: skip-file -# mypy: ignore-errors -# yapf: disable -# pylama:skip=1 - - -# *** PLEASE DO NOT MODIFY DIRECTLY: Automatically generated code *** - - -VERSION = "2.15.3" -import re -from .fastjsonschema_exceptions import JsonSchemaValueException - - -REGEX_PATTERNS = { - '^.*$': re.compile('^.*$'), - '.+': re.compile('.+'), - '^.+$': re.compile('^.+$'), - 'idn-email_re_pattern': re.compile('^[^@]+@[^@]+\\.[^@]+\\Z') -} - -NoneType = type(None) - -def validate(data, custom_formats={}, name_prefix=None): - validate_https___packaging_python_org_en_latest_specifications_declaring_build_dependencies(data, custom_formats, (name_prefix or "data") + "") - return data - -def validate_https___packaging_python_org_en_latest_specifications_declaring_build_dependencies(data, custom_formats={}, name_prefix=None): - if not isinstance(data, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be object", value=data, name="" + (name_prefix or "data") + "", definition={'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://packaging.python.org/en/latest/specifications/declaring-build-dependencies/', 'title': 'Data structure for ``pyproject.toml`` files', '$$description': ['File format containing build-time configurations for the Python ecosystem. ', ':pep:`517` initially defined a build-system independent format for source trees', 'which was complemented by :pep:`518` to provide a way of specifying dependencies ', 'for building Python projects.', 'Please notice the ``project`` table (as initially defined in :pep:`621`) is not included', 'in this schema and should be considered separately.'], 'type': 'object', 'additionalProperties': False, 'properties': {'build-system': {'type': 'object', 'description': 'Table used to store build-related data', 'additionalProperties': False, 'properties': {'requires': {'type': 'array', '$$description': ['List of dependencies in the :pep:`508` format required to execute the build', 'system. Please notice that the resulting dependency graph', '**MUST NOT contain cycles**'], 'items': {'type': 'string'}}, 'build-backend': {'type': 'string', 'description': 'Python object that will be used to perform the build according to :pep:`517`', 'format': 'pep517-backend-reference'}, 'backend-path': {'type': 'array', '$$description': ['List of directories to be prepended to ``sys.path`` when loading the', 'back-end, and running its hooks'], 'items': {'type': 'string', '$comment': 'Should be a path (TODO: enforce it with format?)'}}}, 'required': ['requires']}, 'project': {'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://packaging.python.org/en/latest/specifications/declaring-project-metadata/', 'title': 'Package metadata stored in the ``project`` table', '$$description': ['Data structure for the **project** table inside ``pyproject.toml``', '(as initially defined in :pep:`621`)'], 'type': 'object', 'properties': {'name': {'type': 'string', 'description': 'The name (primary identifier) of the project. MUST be statically defined.', 'format': 'pep508-identifier'}, 'version': {'type': 'string', 'description': 'The version of the project as supported by :pep:`440`.', 'format': 'pep440'}, 'description': {'type': 'string', '$$description': ['The `summary description of the project', '`_']}, 'readme': {'$$description': ['`Full/detailed description of the project in the form of a README', '`_', "with meaning similar to the one defined in `core metadata's Description", '`_'], 'oneOf': [{'type': 'string', '$$description': ['Relative path to a text file (UTF-8) containing the full description', 'of the project. If the file path ends in case-insensitive ``.md`` or', '``.rst`` suffixes, then the content-type is respectively', '``text/markdown`` or ``text/x-rst``']}, {'type': 'object', 'allOf': [{'anyOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', 'description': 'Full text describing the project.'}}, 'required': ['text']}]}, {'properties': {'content-type': {'type': 'string', '$$description': ['Content-type (:rfc:`1341`) of the full description', '(e.g. ``text/markdown``). The ``charset`` parameter is assumed', 'UTF-8 when not present.'], '$comment': 'TODO: add regex pattern or format?'}}, 'required': ['content-type']}]}]}, 'requires-python': {'type': 'string', 'format': 'pep508-versionspec', '$$description': ['`The Python version requirements of the project', '`_.']}, 'license': {'description': '`Project license `_.', 'oneOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to the file (UTF-8) which contains the license for the', 'project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', '$$description': ['The license of the project whose meaning is that of the', '`License field from the core metadata', '`_.']}}, 'required': ['text']}]}, 'authors': {'type': 'array', 'items': {'$ref': '#/definitions/author'}, '$$description': ["The people or organizations considered to be the 'authors' of the project.", 'The exact meaning is open to interpretation (e.g. original or primary authors,', 'current maintainers, or owners of the package).']}, 'maintainers': {'type': 'array', 'items': {'$ref': '#/definitions/author'}, '$$description': ["The people or organizations considered to be the 'maintainers' of the project.", 'Similarly to ``authors``, the exact meaning is open to interpretation.']}, 'keywords': {'type': 'array', 'items': {'type': 'string'}, 'description': 'List of keywords to assist searching for the distribution in a larger catalog.'}, 'classifiers': {'type': 'array', 'items': {'type': 'string', 'format': 'trove-classifier', 'description': '`PyPI classifier `_.'}, '$$description': ['`Trove classifiers `_', 'which apply to the project.']}, 'urls': {'type': 'object', 'description': 'URLs associated with the project in the form ``label => value``.', 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', 'format': 'url'}}}, 'scripts': {'$ref': '#/definitions/entry-point-group', '$$description': ['Instruct the installer to create command-line wrappers for the given', '`entry points `_.']}, 'gui-scripts': {'$ref': '#/definitions/entry-point-group', '$$description': ['Instruct the installer to create GUI wrappers for the given', '`entry points `_.', 'The difference between ``scripts`` and ``gui-scripts`` is only relevant in', 'Windows.']}, 'entry-points': {'$$description': ['Instruct the installer to expose the given modules/functions via', '``entry-point`` discovery mechanism (useful for plugins).', 'More information available in the `Python packaging guide', '`_.'], 'propertyNames': {'format': 'python-entrypoint-group'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'$ref': '#/definitions/entry-point-group'}}}, 'dependencies': {'type': 'array', 'description': 'Project (mandatory) dependencies.', 'items': {'$ref': '#/definitions/dependency'}}, 'optional-dependencies': {'type': 'object', 'description': 'Optional dependency for the project', 'propertyNames': {'format': 'pep508-identifier'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'array', 'items': {'$ref': '#/definitions/dependency'}}}}, 'dynamic': {'type': 'array', '$$description': ['Specifies which fields are intentionally unspecified and expected to be', 'dynamically provided by build tools'], 'items': {'enum': ['version', 'description', 'readme', 'requires-python', 'license', 'authors', 'maintainers', 'keywords', 'classifiers', 'urls', 'scripts', 'gui-scripts', 'entry-points', 'dependencies', 'optional-dependencies']}}}, 'required': ['name'], 'additionalProperties': False, 'if': {'not': {'required': ['dynamic'], 'properties': {'dynamic': {'contains': {'const': 'version'}, '$$description': ['version is listed in ``dynamic``']}}}, '$$comment': ['According to :pep:`621`:', ' If the core metadata specification lists a field as "Required", then', ' the metadata MUST specify the field statically or list it in dynamic', 'In turn, `core metadata`_ defines:', ' The required fields are: Metadata-Version, Name, Version.', ' All the other fields are optional.', 'Since ``Metadata-Version`` is defined by the build back-end, ``name`` and', '``version`` are the only mandatory information in ``pyproject.toml``.', '.. _core metadata: https://packaging.python.org/specifications/core-metadata/']}, 'then': {'required': ['version'], '$$description': ['version should be statically defined in the ``version`` field']}, 'definitions': {'author': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, 'entry-point-group': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'dependency': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}, 'tool': {'type': 'object', 'properties': {'distutils': {'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://docs.python.org/3/install/', 'title': '``tool.distutils`` table', '$$description': ['Originally, ``distutils`` allowed developers to configure arguments for', '``setup.py`` scripts via `distutils configuration files', '`_.', '``tool.distutils`` subtables could be used with the same purpose', '(NOT CURRENTLY IMPLEMENTED).'], 'type': 'object', 'properties': {'global': {'type': 'object', 'description': 'Global options applied to all ``distutils`` commands'}}, 'patternProperties': {'.+': {'type': 'object'}}, '$comment': 'TODO: Is there a practical way of making this schema more specific?'}, 'setuptools': {'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://setuptools.pypa.io/en/latest/references/keywords.html', 'title': '``tool.setuptools`` table', '$$description': ['Please notice for the time being the ``setuptools`` project does not specify', 'a way of configuring builds via ``pyproject.toml``.', 'Therefore this schema should be taken just as a *"thought experiment"* on how', 'this *might be done*, by following the principles established in', '`ini2toml `_.', 'It considers only ``setuptools`` `parameters', '`_', 'that can currently be configured via ``setup.cfg`` and are not covered by :pep:`621`', 'but intentionally excludes ``dependency_links`` and ``setup_requires``.', 'NOTE: ``scripts`` was renamed to ``script-files`` to avoid confusion with', 'entry-point based scripts (defined in :pep:`621`).'], 'type': 'object', 'additionalProperties': False, 'properties': {'platforms': {'type': 'array', 'items': {'type': 'string'}}, 'provides': {'$$description': ['Package and virtual package names contained within this package', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, 'obsoletes': {'$$description': ['Packages which this package renders obsolete', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, 'zip-safe': {'description': 'Whether the project can be safely installed and run from a zip file.', 'type': 'boolean'}, 'script-files': {'description': 'Legacy way of defining scripts (entry-points are preferred).', 'type': 'array', 'items': {'type': 'string'}, '$comment': 'TODO: is this field deprecated/should be removed?'}, 'eager-resources': {'$$description': ['Resources that should be extracted together, if any of them is needed,', 'or if any C extensions included in the project are imported.'], 'type': 'array', 'items': {'type': 'string'}}, 'packages': {'$$description': ['Packages that should be included in the distribution.', 'It can be given either as a list of package identifiers', 'or as a ``dict``-like structure with a single key ``find``', 'which corresponds to a dynamic call to', '``setuptools.config.expand.find_packages`` function.', 'The ``find`` key is associated with a nested ``dict``-like structure that can', 'contain ``where``, ``include``, ``exclude`` and ``namespaces`` keys,', 'mimicking the keyword arguments of the associated function.'], 'oneOf': [{'title': 'Array of Python package identifiers', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}}, {'$ref': '#/definitions/find-directive'}]}, 'package-dir': {'$$description': [':class:`dict`-like structure mapping from package names to directories where their', 'code can be found.', 'The empty string (as key) means that all packages are contained inside', 'the given directory will be included in the distribution.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': ''}]}, 'patternProperties': {'^.*$': {'type': 'string'}}}, 'package-data': {'$$description': ['Mapping from package names to lists of glob patterns.', 'Usually this option is not needed when using ``include-package-data = true``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'include-package-data': {'$$description': ['Automatically include any data files inside the package directories', 'that are specified by ``MANIFEST.in``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'boolean'}, 'exclude-package-data': {'$$description': ['Mapping from package names to lists of glob patterns that should be excluded', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'namespace-packages': {'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'https://setuptools.pypa.io/en/latest/userguide/package_discovery.html'}, 'py-modules': {'description': 'Modules that setuptools will manipulate', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'TODO: clarify the relationship with ``packages``'}, 'data-files': {'$$description': ['**DEPRECATED**: dict-like structure where each key represents a directory and', 'the value is a list of glob patterns that should be installed in them.', "Please notice this don't work with wheels. See `data files support", '`_'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'cmdclass': {'$$description': ['Mapping of distutils-style command names to ``setuptools.Command`` subclasses', 'which in turn should be represented by strings with a qualified class name', '(i.e., "dotted" form with module), e.g.::\n\n', ' cmdclass = {mycmd = "pkg.subpkg.module.CommandClass"}\n\n', 'The command class should be a directly defined at the top-level of the', 'containing module (no class nesting).'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'string', 'format': 'python-qualified-identifier'}}}, 'license-files': {'type': 'array', 'items': {'type': 'string'}, '$$description': ['PROVISIONAL: List of glob patterns for all license files being distributed.', '(might become standard with PEP 639).'], 'default': ['LICEN[CS]E*', ' COPYING*', ' NOTICE*', 'AUTHORS*'], '$comment': 'TODO: revise if PEP 639 is accepted. Probably ``project.license-files``?'}, 'dynamic': {'type': 'object', 'description': 'Instructions for loading :pep:`621`-related metadata dynamically', 'additionalProperties': False, 'properties': {'version': {'$$description': ['A version dynamically loaded via either the ``attr:`` or ``file:``', 'directives. Please make sure the given file or attribute respects :pep:`440`.'], 'oneOf': [{'$ref': '#/definitions/attr-directive'}, {'$ref': '#/definitions/file-directive'}]}, 'classifiers': {'$ref': '#/definitions/file-directive'}, 'description': {'$ref': '#/definitions/file-directive'}, 'dependencies': {'$ref': '#/definitions/file-directive'}, 'entry-points': {'$ref': '#/definitions/file-directive'}, 'optional-dependencies': {'type': 'object', 'propertyNames': {'format': 'python-identifier'}, 'additionalProperties': False, 'patternProperties': {'.+': {'$ref': '#/definitions/file-directive'}}}, 'readme': {'anyOf': [{'$ref': '#/definitions/file-directive'}, {'properties': {'content-type': {'type': 'string'}}}], 'required': ['file']}}}}, 'definitions': {'file-directive': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'attr-directive': {'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, 'find-directive': {'$id': '#/definitions/find-directive', 'title': "'find:' directive", 'type': 'object', 'additionalProperties': False, 'properties': {'find': {'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}}}}}}}}, 'project': {'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://packaging.python.org/en/latest/specifications/declaring-project-metadata/', 'title': 'Package metadata stored in the ``project`` table', '$$description': ['Data structure for the **project** table inside ``pyproject.toml``', '(as initially defined in :pep:`621`)'], 'type': 'object', 'properties': {'name': {'type': 'string', 'description': 'The name (primary identifier) of the project. MUST be statically defined.', 'format': 'pep508-identifier'}, 'version': {'type': 'string', 'description': 'The version of the project as supported by :pep:`440`.', 'format': 'pep440'}, 'description': {'type': 'string', '$$description': ['The `summary description of the project', '`_']}, 'readme': {'$$description': ['`Full/detailed description of the project in the form of a README', '`_', "with meaning similar to the one defined in `core metadata's Description", '`_'], 'oneOf': [{'type': 'string', '$$description': ['Relative path to a text file (UTF-8) containing the full description', 'of the project. If the file path ends in case-insensitive ``.md`` or', '``.rst`` suffixes, then the content-type is respectively', '``text/markdown`` or ``text/x-rst``']}, {'type': 'object', 'allOf': [{'anyOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', 'description': 'Full text describing the project.'}}, 'required': ['text']}]}, {'properties': {'content-type': {'type': 'string', '$$description': ['Content-type (:rfc:`1341`) of the full description', '(e.g. ``text/markdown``). The ``charset`` parameter is assumed', 'UTF-8 when not present.'], '$comment': 'TODO: add regex pattern or format?'}}, 'required': ['content-type']}]}]}, 'requires-python': {'type': 'string', 'format': 'pep508-versionspec', '$$description': ['`The Python version requirements of the project', '`_.']}, 'license': {'description': '`Project license `_.', 'oneOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to the file (UTF-8) which contains the license for the', 'project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', '$$description': ['The license of the project whose meaning is that of the', '`License field from the core metadata', '`_.']}}, 'required': ['text']}]}, 'authors': {'type': 'array', 'items': {'$ref': '#/definitions/author'}, '$$description': ["The people or organizations considered to be the 'authors' of the project.", 'The exact meaning is open to interpretation (e.g. original or primary authors,', 'current maintainers, or owners of the package).']}, 'maintainers': {'type': 'array', 'items': {'$ref': '#/definitions/author'}, '$$description': ["The people or organizations considered to be the 'maintainers' of the project.", 'Similarly to ``authors``, the exact meaning is open to interpretation.']}, 'keywords': {'type': 'array', 'items': {'type': 'string'}, 'description': 'List of keywords to assist searching for the distribution in a larger catalog.'}, 'classifiers': {'type': 'array', 'items': {'type': 'string', 'format': 'trove-classifier', 'description': '`PyPI classifier `_.'}, '$$description': ['`Trove classifiers `_', 'which apply to the project.']}, 'urls': {'type': 'object', 'description': 'URLs associated with the project in the form ``label => value``.', 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', 'format': 'url'}}}, 'scripts': {'$ref': '#/definitions/entry-point-group', '$$description': ['Instruct the installer to create command-line wrappers for the given', '`entry points `_.']}, 'gui-scripts': {'$ref': '#/definitions/entry-point-group', '$$description': ['Instruct the installer to create GUI wrappers for the given', '`entry points `_.', 'The difference between ``scripts`` and ``gui-scripts`` is only relevant in', 'Windows.']}, 'entry-points': {'$$description': ['Instruct the installer to expose the given modules/functions via', '``entry-point`` discovery mechanism (useful for plugins).', 'More information available in the `Python packaging guide', '`_.'], 'propertyNames': {'format': 'python-entrypoint-group'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'$ref': '#/definitions/entry-point-group'}}}, 'dependencies': {'type': 'array', 'description': 'Project (mandatory) dependencies.', 'items': {'$ref': '#/definitions/dependency'}}, 'optional-dependencies': {'type': 'object', 'description': 'Optional dependency for the project', 'propertyNames': {'format': 'pep508-identifier'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'array', 'items': {'$ref': '#/definitions/dependency'}}}}, 'dynamic': {'type': 'array', '$$description': ['Specifies which fields are intentionally unspecified and expected to be', 'dynamically provided by build tools'], 'items': {'enum': ['version', 'description', 'readme', 'requires-python', 'license', 'authors', 'maintainers', 'keywords', 'classifiers', 'urls', 'scripts', 'gui-scripts', 'entry-points', 'dependencies', 'optional-dependencies']}}}, 'required': ['name'], 'additionalProperties': False, 'if': {'not': {'required': ['dynamic'], 'properties': {'dynamic': {'contains': {'const': 'version'}, '$$description': ['version is listed in ``dynamic``']}}}, '$$comment': ['According to :pep:`621`:', ' If the core metadata specification lists a field as "Required", then', ' the metadata MUST specify the field statically or list it in dynamic', 'In turn, `core metadata`_ defines:', ' The required fields are: Metadata-Version, Name, Version.', ' All the other fields are optional.', 'Since ``Metadata-Version`` is defined by the build back-end, ``name`` and', '``version`` are the only mandatory information in ``pyproject.toml``.', '.. _core metadata: https://packaging.python.org/specifications/core-metadata/']}, 'then': {'required': ['version'], '$$description': ['version should be statically defined in the ``version`` field']}, 'definitions': {'author': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, 'entry-point-group': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'dependency': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}}, rule='type') - data_is_dict = isinstance(data, dict) - if data_is_dict: - data_keys = set(data.keys()) - if "build-system" in data_keys: - data_keys.remove("build-system") - data__buildsystem = data["build-system"] - if not isinstance(data__buildsystem, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".build-system must be object", value=data__buildsystem, name="" + (name_prefix or "data") + ".build-system", definition={'type': 'object', 'description': 'Table used to store build-related data', 'additionalProperties': False, 'properties': {'requires': {'type': 'array', '$$description': ['List of dependencies in the :pep:`508` format required to execute the build', 'system. Please notice that the resulting dependency graph', '**MUST NOT contain cycles**'], 'items': {'type': 'string'}}, 'build-backend': {'type': 'string', 'description': 'Python object that will be used to perform the build according to :pep:`517`', 'format': 'pep517-backend-reference'}, 'backend-path': {'type': 'array', '$$description': ['List of directories to be prepended to ``sys.path`` when loading the', 'back-end, and running its hooks'], 'items': {'type': 'string', '$comment': 'Should be a path (TODO: enforce it with format?)'}}}, 'required': ['requires']}, rule='type') - data__buildsystem_is_dict = isinstance(data__buildsystem, dict) - if data__buildsystem_is_dict: - data__buildsystem_len = len(data__buildsystem) - if not all(prop in data__buildsystem for prop in ['requires']): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".build-system must contain ['requires'] properties", value=data__buildsystem, name="" + (name_prefix or "data") + ".build-system", definition={'type': 'object', 'description': 'Table used to store build-related data', 'additionalProperties': False, 'properties': {'requires': {'type': 'array', '$$description': ['List of dependencies in the :pep:`508` format required to execute the build', 'system. Please notice that the resulting dependency graph', '**MUST NOT contain cycles**'], 'items': {'type': 'string'}}, 'build-backend': {'type': 'string', 'description': 'Python object that will be used to perform the build according to :pep:`517`', 'format': 'pep517-backend-reference'}, 'backend-path': {'type': 'array', '$$description': ['List of directories to be prepended to ``sys.path`` when loading the', 'back-end, and running its hooks'], 'items': {'type': 'string', '$comment': 'Should be a path (TODO: enforce it with format?)'}}}, 'required': ['requires']}, rule='required') - data__buildsystem_keys = set(data__buildsystem.keys()) - if "requires" in data__buildsystem_keys: - data__buildsystem_keys.remove("requires") - data__buildsystem__requires = data__buildsystem["requires"] - if not isinstance(data__buildsystem__requires, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".build-system.requires must be array", value=data__buildsystem__requires, name="" + (name_prefix or "data") + ".build-system.requires", definition={'type': 'array', '$$description': ['List of dependencies in the :pep:`508` format required to execute the build', 'system. Please notice that the resulting dependency graph', '**MUST NOT contain cycles**'], 'items': {'type': 'string'}}, rule='type') - data__buildsystem__requires_is_list = isinstance(data__buildsystem__requires, (list, tuple)) - if data__buildsystem__requires_is_list: - data__buildsystem__requires_len = len(data__buildsystem__requires) - for data__buildsystem__requires_x, data__buildsystem__requires_item in enumerate(data__buildsystem__requires): - if not isinstance(data__buildsystem__requires_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".build-system.requires[{data__buildsystem__requires_x}]".format(**locals()) + " must be string", value=data__buildsystem__requires_item, name="" + (name_prefix or "data") + ".build-system.requires[{data__buildsystem__requires_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if "build-backend" in data__buildsystem_keys: - data__buildsystem_keys.remove("build-backend") - data__buildsystem__buildbackend = data__buildsystem["build-backend"] - if not isinstance(data__buildsystem__buildbackend, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".build-system.build-backend must be string", value=data__buildsystem__buildbackend, name="" + (name_prefix or "data") + ".build-system.build-backend", definition={'type': 'string', 'description': 'Python object that will be used to perform the build according to :pep:`517`', 'format': 'pep517-backend-reference'}, rule='type') - if isinstance(data__buildsystem__buildbackend, str): - if not custom_formats["pep517-backend-reference"](data__buildsystem__buildbackend): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".build-system.build-backend must be pep517-backend-reference", value=data__buildsystem__buildbackend, name="" + (name_prefix or "data") + ".build-system.build-backend", definition={'type': 'string', 'description': 'Python object that will be used to perform the build according to :pep:`517`', 'format': 'pep517-backend-reference'}, rule='format') - if "backend-path" in data__buildsystem_keys: - data__buildsystem_keys.remove("backend-path") - data__buildsystem__backendpath = data__buildsystem["backend-path"] - if not isinstance(data__buildsystem__backendpath, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".build-system.backend-path must be array", value=data__buildsystem__backendpath, name="" + (name_prefix or "data") + ".build-system.backend-path", definition={'type': 'array', '$$description': ['List of directories to be prepended to ``sys.path`` when loading the', 'back-end, and running its hooks'], 'items': {'type': 'string', '$comment': 'Should be a path (TODO: enforce it with format?)'}}, rule='type') - data__buildsystem__backendpath_is_list = isinstance(data__buildsystem__backendpath, (list, tuple)) - if data__buildsystem__backendpath_is_list: - data__buildsystem__backendpath_len = len(data__buildsystem__backendpath) - for data__buildsystem__backendpath_x, data__buildsystem__backendpath_item in enumerate(data__buildsystem__backendpath): - if not isinstance(data__buildsystem__backendpath_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".build-system.backend-path[{data__buildsystem__backendpath_x}]".format(**locals()) + " must be string", value=data__buildsystem__backendpath_item, name="" + (name_prefix or "data") + ".build-system.backend-path[{data__buildsystem__backendpath_x}]".format(**locals()) + "", definition={'type': 'string', '$comment': 'Should be a path (TODO: enforce it with format?)'}, rule='type') - if data__buildsystem_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".build-system must not contain "+str(data__buildsystem_keys)+" properties", value=data__buildsystem, name="" + (name_prefix or "data") + ".build-system", definition={'type': 'object', 'description': 'Table used to store build-related data', 'additionalProperties': False, 'properties': {'requires': {'type': 'array', '$$description': ['List of dependencies in the :pep:`508` format required to execute the build', 'system. Please notice that the resulting dependency graph', '**MUST NOT contain cycles**'], 'items': {'type': 'string'}}, 'build-backend': {'type': 'string', 'description': 'Python object that will be used to perform the build according to :pep:`517`', 'format': 'pep517-backend-reference'}, 'backend-path': {'type': 'array', '$$description': ['List of directories to be prepended to ``sys.path`` when loading the', 'back-end, and running its hooks'], 'items': {'type': 'string', '$comment': 'Should be a path (TODO: enforce it with format?)'}}}, 'required': ['requires']}, rule='additionalProperties') - if "project" in data_keys: - data_keys.remove("project") - data__project = data["project"] - validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata(data__project, custom_formats, (name_prefix or "data") + ".project") - if "tool" in data_keys: - data_keys.remove("tool") - data__tool = data["tool"] - if not isinstance(data__tool, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".tool must be object", value=data__tool, name="" + (name_prefix or "data") + ".tool", definition={'type': 'object', 'properties': {'distutils': {'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://docs.python.org/3/install/', 'title': '``tool.distutils`` table', '$$description': ['Originally, ``distutils`` allowed developers to configure arguments for', '``setup.py`` scripts via `distutils configuration files', '`_.', '``tool.distutils`` subtables could be used with the same purpose', '(NOT CURRENTLY IMPLEMENTED).'], 'type': 'object', 'properties': {'global': {'type': 'object', 'description': 'Global options applied to all ``distutils`` commands'}}, 'patternProperties': {'.+': {'type': 'object'}}, '$comment': 'TODO: Is there a practical way of making this schema more specific?'}, 'setuptools': {'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://setuptools.pypa.io/en/latest/references/keywords.html', 'title': '``tool.setuptools`` table', '$$description': ['Please notice for the time being the ``setuptools`` project does not specify', 'a way of configuring builds via ``pyproject.toml``.', 'Therefore this schema should be taken just as a *"thought experiment"* on how', 'this *might be done*, by following the principles established in', '`ini2toml `_.', 'It considers only ``setuptools`` `parameters', '`_', 'that can currently be configured via ``setup.cfg`` and are not covered by :pep:`621`', 'but intentionally excludes ``dependency_links`` and ``setup_requires``.', 'NOTE: ``scripts`` was renamed to ``script-files`` to avoid confusion with', 'entry-point based scripts (defined in :pep:`621`).'], 'type': 'object', 'additionalProperties': False, 'properties': {'platforms': {'type': 'array', 'items': {'type': 'string'}}, 'provides': {'$$description': ['Package and virtual package names contained within this package', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, 'obsoletes': {'$$description': ['Packages which this package renders obsolete', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, 'zip-safe': {'description': 'Whether the project can be safely installed and run from a zip file.', 'type': 'boolean'}, 'script-files': {'description': 'Legacy way of defining scripts (entry-points are preferred).', 'type': 'array', 'items': {'type': 'string'}, '$comment': 'TODO: is this field deprecated/should be removed?'}, 'eager-resources': {'$$description': ['Resources that should be extracted together, if any of them is needed,', 'or if any C extensions included in the project are imported.'], 'type': 'array', 'items': {'type': 'string'}}, 'packages': {'$$description': ['Packages that should be included in the distribution.', 'It can be given either as a list of package identifiers', 'or as a ``dict``-like structure with a single key ``find``', 'which corresponds to a dynamic call to', '``setuptools.config.expand.find_packages`` function.', 'The ``find`` key is associated with a nested ``dict``-like structure that can', 'contain ``where``, ``include``, ``exclude`` and ``namespaces`` keys,', 'mimicking the keyword arguments of the associated function.'], 'oneOf': [{'title': 'Array of Python package identifiers', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}}, {'$ref': '#/definitions/find-directive'}]}, 'package-dir': {'$$description': [':class:`dict`-like structure mapping from package names to directories where their', 'code can be found.', 'The empty string (as key) means that all packages are contained inside', 'the given directory will be included in the distribution.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': ''}]}, 'patternProperties': {'^.*$': {'type': 'string'}}}, 'package-data': {'$$description': ['Mapping from package names to lists of glob patterns.', 'Usually this option is not needed when using ``include-package-data = true``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'include-package-data': {'$$description': ['Automatically include any data files inside the package directories', 'that are specified by ``MANIFEST.in``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'boolean'}, 'exclude-package-data': {'$$description': ['Mapping from package names to lists of glob patterns that should be excluded', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'namespace-packages': {'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'https://setuptools.pypa.io/en/latest/userguide/package_discovery.html'}, 'py-modules': {'description': 'Modules that setuptools will manipulate', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'TODO: clarify the relationship with ``packages``'}, 'data-files': {'$$description': ['**DEPRECATED**: dict-like structure where each key represents a directory and', 'the value is a list of glob patterns that should be installed in them.', "Please notice this don't work with wheels. See `data files support", '`_'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'cmdclass': {'$$description': ['Mapping of distutils-style command names to ``setuptools.Command`` subclasses', 'which in turn should be represented by strings with a qualified class name', '(i.e., "dotted" form with module), e.g.::\n\n', ' cmdclass = {mycmd = "pkg.subpkg.module.CommandClass"}\n\n', 'The command class should be a directly defined at the top-level of the', 'containing module (no class nesting).'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'string', 'format': 'python-qualified-identifier'}}}, 'license-files': {'type': 'array', 'items': {'type': 'string'}, '$$description': ['PROVISIONAL: List of glob patterns for all license files being distributed.', '(might become standard with PEP 639).'], 'default': ['LICEN[CS]E*', ' COPYING*', ' NOTICE*', 'AUTHORS*'], '$comment': 'TODO: revise if PEP 639 is accepted. Probably ``project.license-files``?'}, 'dynamic': {'type': 'object', 'description': 'Instructions for loading :pep:`621`-related metadata dynamically', 'additionalProperties': False, 'properties': {'version': {'$$description': ['A version dynamically loaded via either the ``attr:`` or ``file:``', 'directives. Please make sure the given file or attribute respects :pep:`440`.'], 'oneOf': [{'$ref': '#/definitions/attr-directive'}, {'$ref': '#/definitions/file-directive'}]}, 'classifiers': {'$ref': '#/definitions/file-directive'}, 'description': {'$ref': '#/definitions/file-directive'}, 'dependencies': {'$ref': '#/definitions/file-directive'}, 'entry-points': {'$ref': '#/definitions/file-directive'}, 'optional-dependencies': {'type': 'object', 'propertyNames': {'format': 'python-identifier'}, 'additionalProperties': False, 'patternProperties': {'.+': {'$ref': '#/definitions/file-directive'}}}, 'readme': {'anyOf': [{'$ref': '#/definitions/file-directive'}, {'properties': {'content-type': {'type': 'string'}}}], 'required': ['file']}}}}, 'definitions': {'file-directive': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'attr-directive': {'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, 'find-directive': {'$id': '#/definitions/find-directive', 'title': "'find:' directive", 'type': 'object', 'additionalProperties': False, 'properties': {'find': {'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}}}}}}}, rule='type') - data__tool_is_dict = isinstance(data__tool, dict) - if data__tool_is_dict: - data__tool_keys = set(data__tool.keys()) - if "distutils" in data__tool_keys: - data__tool_keys.remove("distutils") - data__tool__distutils = data__tool["distutils"] - validate_https___docs_python_org_3_install(data__tool__distutils, custom_formats, (name_prefix or "data") + ".tool.distutils") - if "setuptools" in data__tool_keys: - data__tool_keys.remove("setuptools") - data__tool__setuptools = data__tool["setuptools"] - validate_https___setuptools_pypa_io_en_latest_references_keywords_html(data__tool__setuptools, custom_formats, (name_prefix or "data") + ".tool.setuptools") - if data_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + " must not contain "+str(data_keys)+" properties", value=data, name="" + (name_prefix or "data") + "", definition={'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://packaging.python.org/en/latest/specifications/declaring-build-dependencies/', 'title': 'Data structure for ``pyproject.toml`` files', '$$description': ['File format containing build-time configurations for the Python ecosystem. ', ':pep:`517` initially defined a build-system independent format for source trees', 'which was complemented by :pep:`518` to provide a way of specifying dependencies ', 'for building Python projects.', 'Please notice the ``project`` table (as initially defined in :pep:`621`) is not included', 'in this schema and should be considered separately.'], 'type': 'object', 'additionalProperties': False, 'properties': {'build-system': {'type': 'object', 'description': 'Table used to store build-related data', 'additionalProperties': False, 'properties': {'requires': {'type': 'array', '$$description': ['List of dependencies in the :pep:`508` format required to execute the build', 'system. Please notice that the resulting dependency graph', '**MUST NOT contain cycles**'], 'items': {'type': 'string'}}, 'build-backend': {'type': 'string', 'description': 'Python object that will be used to perform the build according to :pep:`517`', 'format': 'pep517-backend-reference'}, 'backend-path': {'type': 'array', '$$description': ['List of directories to be prepended to ``sys.path`` when loading the', 'back-end, and running its hooks'], 'items': {'type': 'string', '$comment': 'Should be a path (TODO: enforce it with format?)'}}}, 'required': ['requires']}, 'project': {'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://packaging.python.org/en/latest/specifications/declaring-project-metadata/', 'title': 'Package metadata stored in the ``project`` table', '$$description': ['Data structure for the **project** table inside ``pyproject.toml``', '(as initially defined in :pep:`621`)'], 'type': 'object', 'properties': {'name': {'type': 'string', 'description': 'The name (primary identifier) of the project. MUST be statically defined.', 'format': 'pep508-identifier'}, 'version': {'type': 'string', 'description': 'The version of the project as supported by :pep:`440`.', 'format': 'pep440'}, 'description': {'type': 'string', '$$description': ['The `summary description of the project', '`_']}, 'readme': {'$$description': ['`Full/detailed description of the project in the form of a README', '`_', "with meaning similar to the one defined in `core metadata's Description", '`_'], 'oneOf': [{'type': 'string', '$$description': ['Relative path to a text file (UTF-8) containing the full description', 'of the project. If the file path ends in case-insensitive ``.md`` or', '``.rst`` suffixes, then the content-type is respectively', '``text/markdown`` or ``text/x-rst``']}, {'type': 'object', 'allOf': [{'anyOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', 'description': 'Full text describing the project.'}}, 'required': ['text']}]}, {'properties': {'content-type': {'type': 'string', '$$description': ['Content-type (:rfc:`1341`) of the full description', '(e.g. ``text/markdown``). The ``charset`` parameter is assumed', 'UTF-8 when not present.'], '$comment': 'TODO: add regex pattern or format?'}}, 'required': ['content-type']}]}]}, 'requires-python': {'type': 'string', 'format': 'pep508-versionspec', '$$description': ['`The Python version requirements of the project', '`_.']}, 'license': {'description': '`Project license `_.', 'oneOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to the file (UTF-8) which contains the license for the', 'project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', '$$description': ['The license of the project whose meaning is that of the', '`License field from the core metadata', '`_.']}}, 'required': ['text']}]}, 'authors': {'type': 'array', 'items': {'$ref': '#/definitions/author'}, '$$description': ["The people or organizations considered to be the 'authors' of the project.", 'The exact meaning is open to interpretation (e.g. original or primary authors,', 'current maintainers, or owners of the package).']}, 'maintainers': {'type': 'array', 'items': {'$ref': '#/definitions/author'}, '$$description': ["The people or organizations considered to be the 'maintainers' of the project.", 'Similarly to ``authors``, the exact meaning is open to interpretation.']}, 'keywords': {'type': 'array', 'items': {'type': 'string'}, 'description': 'List of keywords to assist searching for the distribution in a larger catalog.'}, 'classifiers': {'type': 'array', 'items': {'type': 'string', 'format': 'trove-classifier', 'description': '`PyPI classifier `_.'}, '$$description': ['`Trove classifiers `_', 'which apply to the project.']}, 'urls': {'type': 'object', 'description': 'URLs associated with the project in the form ``label => value``.', 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', 'format': 'url'}}}, 'scripts': {'$ref': '#/definitions/entry-point-group', '$$description': ['Instruct the installer to create command-line wrappers for the given', '`entry points `_.']}, 'gui-scripts': {'$ref': '#/definitions/entry-point-group', '$$description': ['Instruct the installer to create GUI wrappers for the given', '`entry points `_.', 'The difference between ``scripts`` and ``gui-scripts`` is only relevant in', 'Windows.']}, 'entry-points': {'$$description': ['Instruct the installer to expose the given modules/functions via', '``entry-point`` discovery mechanism (useful for plugins).', 'More information available in the `Python packaging guide', '`_.'], 'propertyNames': {'format': 'python-entrypoint-group'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'$ref': '#/definitions/entry-point-group'}}}, 'dependencies': {'type': 'array', 'description': 'Project (mandatory) dependencies.', 'items': {'$ref': '#/definitions/dependency'}}, 'optional-dependencies': {'type': 'object', 'description': 'Optional dependency for the project', 'propertyNames': {'format': 'pep508-identifier'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'array', 'items': {'$ref': '#/definitions/dependency'}}}}, 'dynamic': {'type': 'array', '$$description': ['Specifies which fields are intentionally unspecified and expected to be', 'dynamically provided by build tools'], 'items': {'enum': ['version', 'description', 'readme', 'requires-python', 'license', 'authors', 'maintainers', 'keywords', 'classifiers', 'urls', 'scripts', 'gui-scripts', 'entry-points', 'dependencies', 'optional-dependencies']}}}, 'required': ['name'], 'additionalProperties': False, 'if': {'not': {'required': ['dynamic'], 'properties': {'dynamic': {'contains': {'const': 'version'}, '$$description': ['version is listed in ``dynamic``']}}}, '$$comment': ['According to :pep:`621`:', ' If the core metadata specification lists a field as "Required", then', ' the metadata MUST specify the field statically or list it in dynamic', 'In turn, `core metadata`_ defines:', ' The required fields are: Metadata-Version, Name, Version.', ' All the other fields are optional.', 'Since ``Metadata-Version`` is defined by the build back-end, ``name`` and', '``version`` are the only mandatory information in ``pyproject.toml``.', '.. _core metadata: https://packaging.python.org/specifications/core-metadata/']}, 'then': {'required': ['version'], '$$description': ['version should be statically defined in the ``version`` field']}, 'definitions': {'author': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, 'entry-point-group': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'dependency': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}, 'tool': {'type': 'object', 'properties': {'distutils': {'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://docs.python.org/3/install/', 'title': '``tool.distutils`` table', '$$description': ['Originally, ``distutils`` allowed developers to configure arguments for', '``setup.py`` scripts via `distutils configuration files', '`_.', '``tool.distutils`` subtables could be used with the same purpose', '(NOT CURRENTLY IMPLEMENTED).'], 'type': 'object', 'properties': {'global': {'type': 'object', 'description': 'Global options applied to all ``distutils`` commands'}}, 'patternProperties': {'.+': {'type': 'object'}}, '$comment': 'TODO: Is there a practical way of making this schema more specific?'}, 'setuptools': {'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://setuptools.pypa.io/en/latest/references/keywords.html', 'title': '``tool.setuptools`` table', '$$description': ['Please notice for the time being the ``setuptools`` project does not specify', 'a way of configuring builds via ``pyproject.toml``.', 'Therefore this schema should be taken just as a *"thought experiment"* on how', 'this *might be done*, by following the principles established in', '`ini2toml `_.', 'It considers only ``setuptools`` `parameters', '`_', 'that can currently be configured via ``setup.cfg`` and are not covered by :pep:`621`', 'but intentionally excludes ``dependency_links`` and ``setup_requires``.', 'NOTE: ``scripts`` was renamed to ``script-files`` to avoid confusion with', 'entry-point based scripts (defined in :pep:`621`).'], 'type': 'object', 'additionalProperties': False, 'properties': {'platforms': {'type': 'array', 'items': {'type': 'string'}}, 'provides': {'$$description': ['Package and virtual package names contained within this package', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, 'obsoletes': {'$$description': ['Packages which this package renders obsolete', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, 'zip-safe': {'description': 'Whether the project can be safely installed and run from a zip file.', 'type': 'boolean'}, 'script-files': {'description': 'Legacy way of defining scripts (entry-points are preferred).', 'type': 'array', 'items': {'type': 'string'}, '$comment': 'TODO: is this field deprecated/should be removed?'}, 'eager-resources': {'$$description': ['Resources that should be extracted together, if any of them is needed,', 'or if any C extensions included in the project are imported.'], 'type': 'array', 'items': {'type': 'string'}}, 'packages': {'$$description': ['Packages that should be included in the distribution.', 'It can be given either as a list of package identifiers', 'or as a ``dict``-like structure with a single key ``find``', 'which corresponds to a dynamic call to', '``setuptools.config.expand.find_packages`` function.', 'The ``find`` key is associated with a nested ``dict``-like structure that can', 'contain ``where``, ``include``, ``exclude`` and ``namespaces`` keys,', 'mimicking the keyword arguments of the associated function.'], 'oneOf': [{'title': 'Array of Python package identifiers', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}}, {'$ref': '#/definitions/find-directive'}]}, 'package-dir': {'$$description': [':class:`dict`-like structure mapping from package names to directories where their', 'code can be found.', 'The empty string (as key) means that all packages are contained inside', 'the given directory will be included in the distribution.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': ''}]}, 'patternProperties': {'^.*$': {'type': 'string'}}}, 'package-data': {'$$description': ['Mapping from package names to lists of glob patterns.', 'Usually this option is not needed when using ``include-package-data = true``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'include-package-data': {'$$description': ['Automatically include any data files inside the package directories', 'that are specified by ``MANIFEST.in``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'boolean'}, 'exclude-package-data': {'$$description': ['Mapping from package names to lists of glob patterns that should be excluded', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'namespace-packages': {'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'https://setuptools.pypa.io/en/latest/userguide/package_discovery.html'}, 'py-modules': {'description': 'Modules that setuptools will manipulate', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'TODO: clarify the relationship with ``packages``'}, 'data-files': {'$$description': ['**DEPRECATED**: dict-like structure where each key represents a directory and', 'the value is a list of glob patterns that should be installed in them.', "Please notice this don't work with wheels. See `data files support", '`_'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'cmdclass': {'$$description': ['Mapping of distutils-style command names to ``setuptools.Command`` subclasses', 'which in turn should be represented by strings with a qualified class name', '(i.e., "dotted" form with module), e.g.::\n\n', ' cmdclass = {mycmd = "pkg.subpkg.module.CommandClass"}\n\n', 'The command class should be a directly defined at the top-level of the', 'containing module (no class nesting).'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'string', 'format': 'python-qualified-identifier'}}}, 'license-files': {'type': 'array', 'items': {'type': 'string'}, '$$description': ['PROVISIONAL: List of glob patterns for all license files being distributed.', '(might become standard with PEP 639).'], 'default': ['LICEN[CS]E*', ' COPYING*', ' NOTICE*', 'AUTHORS*'], '$comment': 'TODO: revise if PEP 639 is accepted. Probably ``project.license-files``?'}, 'dynamic': {'type': 'object', 'description': 'Instructions for loading :pep:`621`-related metadata dynamically', 'additionalProperties': False, 'properties': {'version': {'$$description': ['A version dynamically loaded via either the ``attr:`` or ``file:``', 'directives. Please make sure the given file or attribute respects :pep:`440`.'], 'oneOf': [{'$ref': '#/definitions/attr-directive'}, {'$ref': '#/definitions/file-directive'}]}, 'classifiers': {'$ref': '#/definitions/file-directive'}, 'description': {'$ref': '#/definitions/file-directive'}, 'dependencies': {'$ref': '#/definitions/file-directive'}, 'entry-points': {'$ref': '#/definitions/file-directive'}, 'optional-dependencies': {'type': 'object', 'propertyNames': {'format': 'python-identifier'}, 'additionalProperties': False, 'patternProperties': {'.+': {'$ref': '#/definitions/file-directive'}}}, 'readme': {'anyOf': [{'$ref': '#/definitions/file-directive'}, {'properties': {'content-type': {'type': 'string'}}}], 'required': ['file']}}}}, 'definitions': {'file-directive': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'attr-directive': {'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, 'find-directive': {'$id': '#/definitions/find-directive', 'title': "'find:' directive", 'type': 'object', 'additionalProperties': False, 'properties': {'find': {'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}}}}}}}}, 'project': {'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://packaging.python.org/en/latest/specifications/declaring-project-metadata/', 'title': 'Package metadata stored in the ``project`` table', '$$description': ['Data structure for the **project** table inside ``pyproject.toml``', '(as initially defined in :pep:`621`)'], 'type': 'object', 'properties': {'name': {'type': 'string', 'description': 'The name (primary identifier) of the project. MUST be statically defined.', 'format': 'pep508-identifier'}, 'version': {'type': 'string', 'description': 'The version of the project as supported by :pep:`440`.', 'format': 'pep440'}, 'description': {'type': 'string', '$$description': ['The `summary description of the project', '`_']}, 'readme': {'$$description': ['`Full/detailed description of the project in the form of a README', '`_', "with meaning similar to the one defined in `core metadata's Description", '`_'], 'oneOf': [{'type': 'string', '$$description': ['Relative path to a text file (UTF-8) containing the full description', 'of the project. If the file path ends in case-insensitive ``.md`` or', '``.rst`` suffixes, then the content-type is respectively', '``text/markdown`` or ``text/x-rst``']}, {'type': 'object', 'allOf': [{'anyOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', 'description': 'Full text describing the project.'}}, 'required': ['text']}]}, {'properties': {'content-type': {'type': 'string', '$$description': ['Content-type (:rfc:`1341`) of the full description', '(e.g. ``text/markdown``). The ``charset`` parameter is assumed', 'UTF-8 when not present.'], '$comment': 'TODO: add regex pattern or format?'}}, 'required': ['content-type']}]}]}, 'requires-python': {'type': 'string', 'format': 'pep508-versionspec', '$$description': ['`The Python version requirements of the project', '`_.']}, 'license': {'description': '`Project license `_.', 'oneOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to the file (UTF-8) which contains the license for the', 'project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', '$$description': ['The license of the project whose meaning is that of the', '`License field from the core metadata', '`_.']}}, 'required': ['text']}]}, 'authors': {'type': 'array', 'items': {'$ref': '#/definitions/author'}, '$$description': ["The people or organizations considered to be the 'authors' of the project.", 'The exact meaning is open to interpretation (e.g. original or primary authors,', 'current maintainers, or owners of the package).']}, 'maintainers': {'type': 'array', 'items': {'$ref': '#/definitions/author'}, '$$description': ["The people or organizations considered to be the 'maintainers' of the project.", 'Similarly to ``authors``, the exact meaning is open to interpretation.']}, 'keywords': {'type': 'array', 'items': {'type': 'string'}, 'description': 'List of keywords to assist searching for the distribution in a larger catalog.'}, 'classifiers': {'type': 'array', 'items': {'type': 'string', 'format': 'trove-classifier', 'description': '`PyPI classifier `_.'}, '$$description': ['`Trove classifiers `_', 'which apply to the project.']}, 'urls': {'type': 'object', 'description': 'URLs associated with the project in the form ``label => value``.', 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', 'format': 'url'}}}, 'scripts': {'$ref': '#/definitions/entry-point-group', '$$description': ['Instruct the installer to create command-line wrappers for the given', '`entry points `_.']}, 'gui-scripts': {'$ref': '#/definitions/entry-point-group', '$$description': ['Instruct the installer to create GUI wrappers for the given', '`entry points `_.', 'The difference between ``scripts`` and ``gui-scripts`` is only relevant in', 'Windows.']}, 'entry-points': {'$$description': ['Instruct the installer to expose the given modules/functions via', '``entry-point`` discovery mechanism (useful for plugins).', 'More information available in the `Python packaging guide', '`_.'], 'propertyNames': {'format': 'python-entrypoint-group'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'$ref': '#/definitions/entry-point-group'}}}, 'dependencies': {'type': 'array', 'description': 'Project (mandatory) dependencies.', 'items': {'$ref': '#/definitions/dependency'}}, 'optional-dependencies': {'type': 'object', 'description': 'Optional dependency for the project', 'propertyNames': {'format': 'pep508-identifier'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'array', 'items': {'$ref': '#/definitions/dependency'}}}}, 'dynamic': {'type': 'array', '$$description': ['Specifies which fields are intentionally unspecified and expected to be', 'dynamically provided by build tools'], 'items': {'enum': ['version', 'description', 'readme', 'requires-python', 'license', 'authors', 'maintainers', 'keywords', 'classifiers', 'urls', 'scripts', 'gui-scripts', 'entry-points', 'dependencies', 'optional-dependencies']}}}, 'required': ['name'], 'additionalProperties': False, 'if': {'not': {'required': ['dynamic'], 'properties': {'dynamic': {'contains': {'const': 'version'}, '$$description': ['version is listed in ``dynamic``']}}}, '$$comment': ['According to :pep:`621`:', ' If the core metadata specification lists a field as "Required", then', ' the metadata MUST specify the field statically or list it in dynamic', 'In turn, `core metadata`_ defines:', ' The required fields are: Metadata-Version, Name, Version.', ' All the other fields are optional.', 'Since ``Metadata-Version`` is defined by the build back-end, ``name`` and', '``version`` are the only mandatory information in ``pyproject.toml``.', '.. _core metadata: https://packaging.python.org/specifications/core-metadata/']}, 'then': {'required': ['version'], '$$description': ['version should be statically defined in the ``version`` field']}, 'definitions': {'author': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, 'entry-point-group': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'dependency': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}}, rule='additionalProperties') - return data - -def validate_https___setuptools_pypa_io_en_latest_references_keywords_html(data, custom_formats={}, name_prefix=None): - if not isinstance(data, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be object", value=data, name="" + (name_prefix or "data") + "", definition={'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://setuptools.pypa.io/en/latest/references/keywords.html', 'title': '``tool.setuptools`` table', '$$description': ['Please notice for the time being the ``setuptools`` project does not specify', 'a way of configuring builds via ``pyproject.toml``.', 'Therefore this schema should be taken just as a *"thought experiment"* on how', 'this *might be done*, by following the principles established in', '`ini2toml `_.', 'It considers only ``setuptools`` `parameters', '`_', 'that can currently be configured via ``setup.cfg`` and are not covered by :pep:`621`', 'but intentionally excludes ``dependency_links`` and ``setup_requires``.', 'NOTE: ``scripts`` was renamed to ``script-files`` to avoid confusion with', 'entry-point based scripts (defined in :pep:`621`).'], 'type': 'object', 'additionalProperties': False, 'properties': {'platforms': {'type': 'array', 'items': {'type': 'string'}}, 'provides': {'$$description': ['Package and virtual package names contained within this package', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, 'obsoletes': {'$$description': ['Packages which this package renders obsolete', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, 'zip-safe': {'description': 'Whether the project can be safely installed and run from a zip file.', 'type': 'boolean'}, 'script-files': {'description': 'Legacy way of defining scripts (entry-points are preferred).', 'type': 'array', 'items': {'type': 'string'}, '$comment': 'TODO: is this field deprecated/should be removed?'}, 'eager-resources': {'$$description': ['Resources that should be extracted together, if any of them is needed,', 'or if any C extensions included in the project are imported.'], 'type': 'array', 'items': {'type': 'string'}}, 'packages': {'$$description': ['Packages that should be included in the distribution.', 'It can be given either as a list of package identifiers', 'or as a ``dict``-like structure with a single key ``find``', 'which corresponds to a dynamic call to', '``setuptools.config.expand.find_packages`` function.', 'The ``find`` key is associated with a nested ``dict``-like structure that can', 'contain ``where``, ``include``, ``exclude`` and ``namespaces`` keys,', 'mimicking the keyword arguments of the associated function.'], 'oneOf': [{'title': 'Array of Python package identifiers', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}}, {'$id': '#/definitions/find-directive', 'title': "'find:' directive", 'type': 'object', 'additionalProperties': False, 'properties': {'find': {'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}}}]}, 'package-dir': {'$$description': [':class:`dict`-like structure mapping from package names to directories where their', 'code can be found.', 'The empty string (as key) means that all packages are contained inside', 'the given directory will be included in the distribution.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': ''}]}, 'patternProperties': {'^.*$': {'type': 'string'}}}, 'package-data': {'$$description': ['Mapping from package names to lists of glob patterns.', 'Usually this option is not needed when using ``include-package-data = true``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'include-package-data': {'$$description': ['Automatically include any data files inside the package directories', 'that are specified by ``MANIFEST.in``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'boolean'}, 'exclude-package-data': {'$$description': ['Mapping from package names to lists of glob patterns that should be excluded', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'namespace-packages': {'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'https://setuptools.pypa.io/en/latest/userguide/package_discovery.html'}, 'py-modules': {'description': 'Modules that setuptools will manipulate', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'TODO: clarify the relationship with ``packages``'}, 'data-files': {'$$description': ['**DEPRECATED**: dict-like structure where each key represents a directory and', 'the value is a list of glob patterns that should be installed in them.', "Please notice this don't work with wheels. See `data files support", '`_'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'cmdclass': {'$$description': ['Mapping of distutils-style command names to ``setuptools.Command`` subclasses', 'which in turn should be represented by strings with a qualified class name', '(i.e., "dotted" form with module), e.g.::\n\n', ' cmdclass = {mycmd = "pkg.subpkg.module.CommandClass"}\n\n', 'The command class should be a directly defined at the top-level of the', 'containing module (no class nesting).'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'string', 'format': 'python-qualified-identifier'}}}, 'license-files': {'type': 'array', 'items': {'type': 'string'}, '$$description': ['PROVISIONAL: List of glob patterns for all license files being distributed.', '(might become standard with PEP 639).'], 'default': ['LICEN[CS]E*', ' COPYING*', ' NOTICE*', 'AUTHORS*'], '$comment': 'TODO: revise if PEP 639 is accepted. Probably ``project.license-files``?'}, 'dynamic': {'type': 'object', 'description': 'Instructions for loading :pep:`621`-related metadata dynamically', 'additionalProperties': False, 'properties': {'version': {'$$description': ['A version dynamically loaded via either the ``attr:`` or ``file:``', 'directives. Please make sure the given file or attribute respects :pep:`440`.'], 'oneOf': [{'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}]}, 'classifiers': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'description': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'dependencies': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'entry-points': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'optional-dependencies': {'type': 'object', 'propertyNames': {'format': 'python-identifier'}, 'additionalProperties': False, 'patternProperties': {'.+': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}}}, 'readme': {'anyOf': [{'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, {'properties': {'content-type': {'type': 'string'}}}], 'required': ['file']}}}}, 'definitions': {'file-directive': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'attr-directive': {'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, 'find-directive': {'$id': '#/definitions/find-directive', 'title': "'find:' directive", 'type': 'object', 'additionalProperties': False, 'properties': {'find': {'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}}}}}, rule='type') - data_is_dict = isinstance(data, dict) - if data_is_dict: - data_keys = set(data.keys()) - if "platforms" in data_keys: - data_keys.remove("platforms") - data__platforms = data["platforms"] - if not isinstance(data__platforms, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".platforms must be array", value=data__platforms, name="" + (name_prefix or "data") + ".platforms", definition={'type': 'array', 'items': {'type': 'string'}}, rule='type') - data__platforms_is_list = isinstance(data__platforms, (list, tuple)) - if data__platforms_is_list: - data__platforms_len = len(data__platforms) - for data__platforms_x, data__platforms_item in enumerate(data__platforms): - if not isinstance(data__platforms_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".platforms[{data__platforms_x}]".format(**locals()) + " must be string", value=data__platforms_item, name="" + (name_prefix or "data") + ".platforms[{data__platforms_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if "provides" in data_keys: - data_keys.remove("provides") - data__provides = data["provides"] - if not isinstance(data__provides, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".provides must be array", value=data__provides, name="" + (name_prefix or "data") + ".provides", definition={'$$description': ['Package and virtual package names contained within this package', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, rule='type') - data__provides_is_list = isinstance(data__provides, (list, tuple)) - if data__provides_is_list: - data__provides_len = len(data__provides) - for data__provides_x, data__provides_item in enumerate(data__provides): - if not isinstance(data__provides_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".provides[{data__provides_x}]".format(**locals()) + " must be string", value=data__provides_item, name="" + (name_prefix or "data") + ".provides[{data__provides_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'pep508-identifier'}, rule='type') - if isinstance(data__provides_item, str): - if not custom_formats["pep508-identifier"](data__provides_item): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".provides[{data__provides_x}]".format(**locals()) + " must be pep508-identifier", value=data__provides_item, name="" + (name_prefix or "data") + ".provides[{data__provides_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'pep508-identifier'}, rule='format') - if "obsoletes" in data_keys: - data_keys.remove("obsoletes") - data__obsoletes = data["obsoletes"] - if not isinstance(data__obsoletes, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".obsoletes must be array", value=data__obsoletes, name="" + (name_prefix or "data") + ".obsoletes", definition={'$$description': ['Packages which this package renders obsolete', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, rule='type') - data__obsoletes_is_list = isinstance(data__obsoletes, (list, tuple)) - if data__obsoletes_is_list: - data__obsoletes_len = len(data__obsoletes) - for data__obsoletes_x, data__obsoletes_item in enumerate(data__obsoletes): - if not isinstance(data__obsoletes_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".obsoletes[{data__obsoletes_x}]".format(**locals()) + " must be string", value=data__obsoletes_item, name="" + (name_prefix or "data") + ".obsoletes[{data__obsoletes_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'pep508-identifier'}, rule='type') - if isinstance(data__obsoletes_item, str): - if not custom_formats["pep508-identifier"](data__obsoletes_item): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".obsoletes[{data__obsoletes_x}]".format(**locals()) + " must be pep508-identifier", value=data__obsoletes_item, name="" + (name_prefix or "data") + ".obsoletes[{data__obsoletes_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'pep508-identifier'}, rule='format') - if "zip-safe" in data_keys: - data_keys.remove("zip-safe") - data__zipsafe = data["zip-safe"] - if not isinstance(data__zipsafe, (bool)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".zip-safe must be boolean", value=data__zipsafe, name="" + (name_prefix or "data") + ".zip-safe", definition={'description': 'Whether the project can be safely installed and run from a zip file.', 'type': 'boolean'}, rule='type') - if "script-files" in data_keys: - data_keys.remove("script-files") - data__scriptfiles = data["script-files"] - if not isinstance(data__scriptfiles, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".script-files must be array", value=data__scriptfiles, name="" + (name_prefix or "data") + ".script-files", definition={'description': 'Legacy way of defining scripts (entry-points are preferred).', 'type': 'array', 'items': {'type': 'string'}, '$comment': 'TODO: is this field deprecated/should be removed?'}, rule='type') - data__scriptfiles_is_list = isinstance(data__scriptfiles, (list, tuple)) - if data__scriptfiles_is_list: - data__scriptfiles_len = len(data__scriptfiles) - for data__scriptfiles_x, data__scriptfiles_item in enumerate(data__scriptfiles): - if not isinstance(data__scriptfiles_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".script-files[{data__scriptfiles_x}]".format(**locals()) + " must be string", value=data__scriptfiles_item, name="" + (name_prefix or "data") + ".script-files[{data__scriptfiles_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if "eager-resources" in data_keys: - data_keys.remove("eager-resources") - data__eagerresources = data["eager-resources"] - if not isinstance(data__eagerresources, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".eager-resources must be array", value=data__eagerresources, name="" + (name_prefix or "data") + ".eager-resources", definition={'$$description': ['Resources that should be extracted together, if any of them is needed,', 'or if any C extensions included in the project are imported.'], 'type': 'array', 'items': {'type': 'string'}}, rule='type') - data__eagerresources_is_list = isinstance(data__eagerresources, (list, tuple)) - if data__eagerresources_is_list: - data__eagerresources_len = len(data__eagerresources) - for data__eagerresources_x, data__eagerresources_item in enumerate(data__eagerresources): - if not isinstance(data__eagerresources_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".eager-resources[{data__eagerresources_x}]".format(**locals()) + " must be string", value=data__eagerresources_item, name="" + (name_prefix or "data") + ".eager-resources[{data__eagerresources_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if "packages" in data_keys: - data_keys.remove("packages") - data__packages = data["packages"] - data__packages_one_of_count1 = 0 - if data__packages_one_of_count1 < 2: - try: - if not isinstance(data__packages, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".packages must be array", value=data__packages, name="" + (name_prefix or "data") + ".packages", definition={'title': 'Array of Python package identifiers', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}}, rule='type') - data__packages_is_list = isinstance(data__packages, (list, tuple)) - if data__packages_is_list: - data__packages_len = len(data__packages) - for data__packages_x, data__packages_item in enumerate(data__packages): - if not isinstance(data__packages_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".packages[{data__packages_x}]".format(**locals()) + " must be string", value=data__packages_item, name="" + (name_prefix or "data") + ".packages[{data__packages_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'python-module-name'}, rule='type') - if isinstance(data__packages_item, str): - if not custom_formats["python-module-name"](data__packages_item): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".packages[{data__packages_x}]".format(**locals()) + " must be python-module-name", value=data__packages_item, name="" + (name_prefix or "data") + ".packages[{data__packages_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'python-module-name'}, rule='format') - data__packages_one_of_count1 += 1 - except JsonSchemaValueException: pass - if data__packages_one_of_count1 < 2: - try: - validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_find_directive(data__packages, custom_formats, (name_prefix or "data") + ".packages") - data__packages_one_of_count1 += 1 - except JsonSchemaValueException: pass - if data__packages_one_of_count1 != 1: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".packages must be valid exactly by one definition" + (" (" + str(data__packages_one_of_count1) + " matches found)"), value=data__packages, name="" + (name_prefix or "data") + ".packages", definition={'$$description': ['Packages that should be included in the distribution.', 'It can be given either as a list of package identifiers', 'or as a ``dict``-like structure with a single key ``find``', 'which corresponds to a dynamic call to', '``setuptools.config.expand.find_packages`` function.', 'The ``find`` key is associated with a nested ``dict``-like structure that can', 'contain ``where``, ``include``, ``exclude`` and ``namespaces`` keys,', 'mimicking the keyword arguments of the associated function.'], 'oneOf': [{'title': 'Array of Python package identifiers', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}}, {'$id': '#/definitions/find-directive', 'title': "'find:' directive", 'type': 'object', 'additionalProperties': False, 'properties': {'find': {'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}}}]}, rule='oneOf') - if "package-dir" in data_keys: - data_keys.remove("package-dir") - data__packagedir = data["package-dir"] - if not isinstance(data__packagedir, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-dir must be object", value=data__packagedir, name="" + (name_prefix or "data") + ".package-dir", definition={'$$description': [':class:`dict`-like structure mapping from package names to directories where their', 'code can be found.', 'The empty string (as key) means that all packages are contained inside', 'the given directory will be included in the distribution.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': ''}]}, 'patternProperties': {'^.*$': {'type': 'string'}}}, rule='type') - data__packagedir_is_dict = isinstance(data__packagedir, dict) - if data__packagedir_is_dict: - data__packagedir_keys = set(data__packagedir.keys()) - for data__packagedir_key, data__packagedir_val in data__packagedir.items(): - if REGEX_PATTERNS['^.*$'].search(data__packagedir_key): - if data__packagedir_key in data__packagedir_keys: - data__packagedir_keys.remove(data__packagedir_key) - if not isinstance(data__packagedir_val, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-dir.{data__packagedir_key}".format(**locals()) + " must be string", value=data__packagedir_val, name="" + (name_prefix or "data") + ".package-dir.{data__packagedir_key}".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if data__packagedir_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-dir must not contain "+str(data__packagedir_keys)+" properties", value=data__packagedir, name="" + (name_prefix or "data") + ".package-dir", definition={'$$description': [':class:`dict`-like structure mapping from package names to directories where their', 'code can be found.', 'The empty string (as key) means that all packages are contained inside', 'the given directory will be included in the distribution.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': ''}]}, 'patternProperties': {'^.*$': {'type': 'string'}}}, rule='additionalProperties') - data__packagedir_len = len(data__packagedir) - if data__packagedir_len != 0: - data__packagedir_property_names = True - for data__packagedir_key in data__packagedir: - try: - data__packagedir_key_one_of_count2 = 0 - if data__packagedir_key_one_of_count2 < 2: - try: - if isinstance(data__packagedir_key, str): - if not custom_formats["python-module-name"](data__packagedir_key): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-dir must be python-module-name", value=data__packagedir_key, name="" + (name_prefix or "data") + ".package-dir", definition={'format': 'python-module-name'}, rule='format') - data__packagedir_key_one_of_count2 += 1 - except JsonSchemaValueException: pass - if data__packagedir_key_one_of_count2 < 2: - try: - if data__packagedir_key != "": - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-dir must be same as const definition: ", value=data__packagedir_key, name="" + (name_prefix or "data") + ".package-dir", definition={'const': ''}, rule='const') - data__packagedir_key_one_of_count2 += 1 - except JsonSchemaValueException: pass - if data__packagedir_key_one_of_count2 != 1: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-dir must be valid exactly by one definition" + (" (" + str(data__packagedir_key_one_of_count2) + " matches found)"), value=data__packagedir_key, name="" + (name_prefix or "data") + ".package-dir", definition={'oneOf': [{'format': 'python-module-name'}, {'const': ''}]}, rule='oneOf') - except JsonSchemaValueException: - data__packagedir_property_names = False - if not data__packagedir_property_names: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-dir must be named by propertyName definition", value=data__packagedir, name="" + (name_prefix or "data") + ".package-dir", definition={'$$description': [':class:`dict`-like structure mapping from package names to directories where their', 'code can be found.', 'The empty string (as key) means that all packages are contained inside', 'the given directory will be included in the distribution.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': ''}]}, 'patternProperties': {'^.*$': {'type': 'string'}}}, rule='propertyNames') - if "package-data" in data_keys: - data_keys.remove("package-data") - data__packagedata = data["package-data"] - if not isinstance(data__packagedata, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-data must be object", value=data__packagedata, name="" + (name_prefix or "data") + ".package-data", definition={'$$description': ['Mapping from package names to lists of glob patterns.', 'Usually this option is not needed when using ``include-package-data = true``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, rule='type') - data__packagedata_is_dict = isinstance(data__packagedata, dict) - if data__packagedata_is_dict: - data__packagedata_keys = set(data__packagedata.keys()) - for data__packagedata_key, data__packagedata_val in data__packagedata.items(): - if REGEX_PATTERNS['^.*$'].search(data__packagedata_key): - if data__packagedata_key in data__packagedata_keys: - data__packagedata_keys.remove(data__packagedata_key) - if not isinstance(data__packagedata_val, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-data.{data__packagedata_key}".format(**locals()) + " must be array", value=data__packagedata_val, name="" + (name_prefix or "data") + ".package-data.{data__packagedata_key}".format(**locals()) + "", definition={'type': 'array', 'items': {'type': 'string'}}, rule='type') - data__packagedata_val_is_list = isinstance(data__packagedata_val, (list, tuple)) - if data__packagedata_val_is_list: - data__packagedata_val_len = len(data__packagedata_val) - for data__packagedata_val_x, data__packagedata_val_item in enumerate(data__packagedata_val): - if not isinstance(data__packagedata_val_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-data.{data__packagedata_key}[{data__packagedata_val_x}]".format(**locals()) + " must be string", value=data__packagedata_val_item, name="" + (name_prefix or "data") + ".package-data.{data__packagedata_key}[{data__packagedata_val_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if data__packagedata_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-data must not contain "+str(data__packagedata_keys)+" properties", value=data__packagedata, name="" + (name_prefix or "data") + ".package-data", definition={'$$description': ['Mapping from package names to lists of glob patterns.', 'Usually this option is not needed when using ``include-package-data = true``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, rule='additionalProperties') - data__packagedata_len = len(data__packagedata) - if data__packagedata_len != 0: - data__packagedata_property_names = True - for data__packagedata_key in data__packagedata: - try: - data__packagedata_key_one_of_count3 = 0 - if data__packagedata_key_one_of_count3 < 2: - try: - if isinstance(data__packagedata_key, str): - if not custom_formats["python-module-name"](data__packagedata_key): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-data must be python-module-name", value=data__packagedata_key, name="" + (name_prefix or "data") + ".package-data", definition={'format': 'python-module-name'}, rule='format') - data__packagedata_key_one_of_count3 += 1 - except JsonSchemaValueException: pass - if data__packagedata_key_one_of_count3 < 2: - try: - if data__packagedata_key != "*": - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-data must be same as const definition: *", value=data__packagedata_key, name="" + (name_prefix or "data") + ".package-data", definition={'const': '*'}, rule='const') - data__packagedata_key_one_of_count3 += 1 - except JsonSchemaValueException: pass - if data__packagedata_key_one_of_count3 != 1: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-data must be valid exactly by one definition" + (" (" + str(data__packagedata_key_one_of_count3) + " matches found)"), value=data__packagedata_key, name="" + (name_prefix or "data") + ".package-data", definition={'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, rule='oneOf') - except JsonSchemaValueException: - data__packagedata_property_names = False - if not data__packagedata_property_names: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".package-data must be named by propertyName definition", value=data__packagedata, name="" + (name_prefix or "data") + ".package-data", definition={'$$description': ['Mapping from package names to lists of glob patterns.', 'Usually this option is not needed when using ``include-package-data = true``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, rule='propertyNames') - if "include-package-data" in data_keys: - data_keys.remove("include-package-data") - data__includepackagedata = data["include-package-data"] - if not isinstance(data__includepackagedata, (bool)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".include-package-data must be boolean", value=data__includepackagedata, name="" + (name_prefix or "data") + ".include-package-data", definition={'$$description': ['Automatically include any data files inside the package directories', 'that are specified by ``MANIFEST.in``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'boolean'}, rule='type') - if "exclude-package-data" in data_keys: - data_keys.remove("exclude-package-data") - data__excludepackagedata = data["exclude-package-data"] - if not isinstance(data__excludepackagedata, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".exclude-package-data must be object", value=data__excludepackagedata, name="" + (name_prefix or "data") + ".exclude-package-data", definition={'$$description': ['Mapping from package names to lists of glob patterns that should be excluded', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, rule='type') - data__excludepackagedata_is_dict = isinstance(data__excludepackagedata, dict) - if data__excludepackagedata_is_dict: - data__excludepackagedata_keys = set(data__excludepackagedata.keys()) - for data__excludepackagedata_key, data__excludepackagedata_val in data__excludepackagedata.items(): - if REGEX_PATTERNS['^.*$'].search(data__excludepackagedata_key): - if data__excludepackagedata_key in data__excludepackagedata_keys: - data__excludepackagedata_keys.remove(data__excludepackagedata_key) - if not isinstance(data__excludepackagedata_val, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".exclude-package-data.{data__excludepackagedata_key}".format(**locals()) + " must be array", value=data__excludepackagedata_val, name="" + (name_prefix or "data") + ".exclude-package-data.{data__excludepackagedata_key}".format(**locals()) + "", definition={'type': 'array', 'items': {'type': 'string'}}, rule='type') - data__excludepackagedata_val_is_list = isinstance(data__excludepackagedata_val, (list, tuple)) - if data__excludepackagedata_val_is_list: - data__excludepackagedata_val_len = len(data__excludepackagedata_val) - for data__excludepackagedata_val_x, data__excludepackagedata_val_item in enumerate(data__excludepackagedata_val): - if not isinstance(data__excludepackagedata_val_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".exclude-package-data.{data__excludepackagedata_key}[{data__excludepackagedata_val_x}]".format(**locals()) + " must be string", value=data__excludepackagedata_val_item, name="" + (name_prefix or "data") + ".exclude-package-data.{data__excludepackagedata_key}[{data__excludepackagedata_val_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if data__excludepackagedata_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".exclude-package-data must not contain "+str(data__excludepackagedata_keys)+" properties", value=data__excludepackagedata, name="" + (name_prefix or "data") + ".exclude-package-data", definition={'$$description': ['Mapping from package names to lists of glob patterns that should be excluded', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, rule='additionalProperties') - data__excludepackagedata_len = len(data__excludepackagedata) - if data__excludepackagedata_len != 0: - data__excludepackagedata_property_names = True - for data__excludepackagedata_key in data__excludepackagedata: - try: - data__excludepackagedata_key_one_of_count4 = 0 - if data__excludepackagedata_key_one_of_count4 < 2: - try: - if isinstance(data__excludepackagedata_key, str): - if not custom_formats["python-module-name"](data__excludepackagedata_key): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".exclude-package-data must be python-module-name", value=data__excludepackagedata_key, name="" + (name_prefix or "data") + ".exclude-package-data", definition={'format': 'python-module-name'}, rule='format') - data__excludepackagedata_key_one_of_count4 += 1 - except JsonSchemaValueException: pass - if data__excludepackagedata_key_one_of_count4 < 2: - try: - if data__excludepackagedata_key != "*": - raise JsonSchemaValueException("" + (name_prefix or "data") + ".exclude-package-data must be same as const definition: *", value=data__excludepackagedata_key, name="" + (name_prefix or "data") + ".exclude-package-data", definition={'const': '*'}, rule='const') - data__excludepackagedata_key_one_of_count4 += 1 - except JsonSchemaValueException: pass - if data__excludepackagedata_key_one_of_count4 != 1: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".exclude-package-data must be valid exactly by one definition" + (" (" + str(data__excludepackagedata_key_one_of_count4) + " matches found)"), value=data__excludepackagedata_key, name="" + (name_prefix or "data") + ".exclude-package-data", definition={'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, rule='oneOf') - except JsonSchemaValueException: - data__excludepackagedata_property_names = False - if not data__excludepackagedata_property_names: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".exclude-package-data must be named by propertyName definition", value=data__excludepackagedata, name="" + (name_prefix or "data") + ".exclude-package-data", definition={'$$description': ['Mapping from package names to lists of glob patterns that should be excluded', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, rule='propertyNames') - if "namespace-packages" in data_keys: - data_keys.remove("namespace-packages") - data__namespacepackages = data["namespace-packages"] - if not isinstance(data__namespacepackages, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".namespace-packages must be array", value=data__namespacepackages, name="" + (name_prefix or "data") + ".namespace-packages", definition={'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'https://setuptools.pypa.io/en/latest/userguide/package_discovery.html'}, rule='type') - data__namespacepackages_is_list = isinstance(data__namespacepackages, (list, tuple)) - if data__namespacepackages_is_list: - data__namespacepackages_len = len(data__namespacepackages) - for data__namespacepackages_x, data__namespacepackages_item in enumerate(data__namespacepackages): - if not isinstance(data__namespacepackages_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".namespace-packages[{data__namespacepackages_x}]".format(**locals()) + " must be string", value=data__namespacepackages_item, name="" + (name_prefix or "data") + ".namespace-packages[{data__namespacepackages_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'python-module-name'}, rule='type') - if isinstance(data__namespacepackages_item, str): - if not custom_formats["python-module-name"](data__namespacepackages_item): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".namespace-packages[{data__namespacepackages_x}]".format(**locals()) + " must be python-module-name", value=data__namespacepackages_item, name="" + (name_prefix or "data") + ".namespace-packages[{data__namespacepackages_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'python-module-name'}, rule='format') - if "py-modules" in data_keys: - data_keys.remove("py-modules") - data__pymodules = data["py-modules"] - if not isinstance(data__pymodules, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".py-modules must be array", value=data__pymodules, name="" + (name_prefix or "data") + ".py-modules", definition={'description': 'Modules that setuptools will manipulate', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'TODO: clarify the relationship with ``packages``'}, rule='type') - data__pymodules_is_list = isinstance(data__pymodules, (list, tuple)) - if data__pymodules_is_list: - data__pymodules_len = len(data__pymodules) - for data__pymodules_x, data__pymodules_item in enumerate(data__pymodules): - if not isinstance(data__pymodules_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".py-modules[{data__pymodules_x}]".format(**locals()) + " must be string", value=data__pymodules_item, name="" + (name_prefix or "data") + ".py-modules[{data__pymodules_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'python-module-name'}, rule='type') - if isinstance(data__pymodules_item, str): - if not custom_formats["python-module-name"](data__pymodules_item): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".py-modules[{data__pymodules_x}]".format(**locals()) + " must be python-module-name", value=data__pymodules_item, name="" + (name_prefix or "data") + ".py-modules[{data__pymodules_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'python-module-name'}, rule='format') - if "data-files" in data_keys: - data_keys.remove("data-files") - data__datafiles = data["data-files"] - if not isinstance(data__datafiles, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".data-files must be object", value=data__datafiles, name="" + (name_prefix or "data") + ".data-files", definition={'$$description': ['**DEPRECATED**: dict-like structure where each key represents a directory and', 'the value is a list of glob patterns that should be installed in them.', "Please notice this don't work with wheels. See `data files support", '`_'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, rule='type') - data__datafiles_is_dict = isinstance(data__datafiles, dict) - if data__datafiles_is_dict: - data__datafiles_keys = set(data__datafiles.keys()) - for data__datafiles_key, data__datafiles_val in data__datafiles.items(): - if REGEX_PATTERNS['^.*$'].search(data__datafiles_key): - if data__datafiles_key in data__datafiles_keys: - data__datafiles_keys.remove(data__datafiles_key) - if not isinstance(data__datafiles_val, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".data-files.{data__datafiles_key}".format(**locals()) + " must be array", value=data__datafiles_val, name="" + (name_prefix or "data") + ".data-files.{data__datafiles_key}".format(**locals()) + "", definition={'type': 'array', 'items': {'type': 'string'}}, rule='type') - data__datafiles_val_is_list = isinstance(data__datafiles_val, (list, tuple)) - if data__datafiles_val_is_list: - data__datafiles_val_len = len(data__datafiles_val) - for data__datafiles_val_x, data__datafiles_val_item in enumerate(data__datafiles_val): - if not isinstance(data__datafiles_val_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".data-files.{data__datafiles_key}[{data__datafiles_val_x}]".format(**locals()) + " must be string", value=data__datafiles_val_item, name="" + (name_prefix or "data") + ".data-files.{data__datafiles_key}[{data__datafiles_val_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if "cmdclass" in data_keys: - data_keys.remove("cmdclass") - data__cmdclass = data["cmdclass"] - if not isinstance(data__cmdclass, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".cmdclass must be object", value=data__cmdclass, name="" + (name_prefix or "data") + ".cmdclass", definition={'$$description': ['Mapping of distutils-style command names to ``setuptools.Command`` subclasses', 'which in turn should be represented by strings with a qualified class name', '(i.e., "dotted" form with module), e.g.::\n\n', ' cmdclass = {mycmd = "pkg.subpkg.module.CommandClass"}\n\n', 'The command class should be a directly defined at the top-level of the', 'containing module (no class nesting).'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'string', 'format': 'python-qualified-identifier'}}}, rule='type') - data__cmdclass_is_dict = isinstance(data__cmdclass, dict) - if data__cmdclass_is_dict: - data__cmdclass_keys = set(data__cmdclass.keys()) - for data__cmdclass_key, data__cmdclass_val in data__cmdclass.items(): - if REGEX_PATTERNS['^.*$'].search(data__cmdclass_key): - if data__cmdclass_key in data__cmdclass_keys: - data__cmdclass_keys.remove(data__cmdclass_key) - if not isinstance(data__cmdclass_val, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".cmdclass.{data__cmdclass_key}".format(**locals()) + " must be string", value=data__cmdclass_val, name="" + (name_prefix or "data") + ".cmdclass.{data__cmdclass_key}".format(**locals()) + "", definition={'type': 'string', 'format': 'python-qualified-identifier'}, rule='type') - if isinstance(data__cmdclass_val, str): - if not custom_formats["python-qualified-identifier"](data__cmdclass_val): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".cmdclass.{data__cmdclass_key}".format(**locals()) + " must be python-qualified-identifier", value=data__cmdclass_val, name="" + (name_prefix or "data") + ".cmdclass.{data__cmdclass_key}".format(**locals()) + "", definition={'type': 'string', 'format': 'python-qualified-identifier'}, rule='format') - if "license-files" in data_keys: - data_keys.remove("license-files") - data__licensefiles = data["license-files"] - if not isinstance(data__licensefiles, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".license-files must be array", value=data__licensefiles, name="" + (name_prefix or "data") + ".license-files", definition={'type': 'array', 'items': {'type': 'string'}, '$$description': ['PROVISIONAL: List of glob patterns for all license files being distributed.', '(might become standard with PEP 639).'], 'default': ['LICEN[CS]E*', ' COPYING*', ' NOTICE*', 'AUTHORS*'], '$comment': 'TODO: revise if PEP 639 is accepted. Probably ``project.license-files``?'}, rule='type') - data__licensefiles_is_list = isinstance(data__licensefiles, (list, tuple)) - if data__licensefiles_is_list: - data__licensefiles_len = len(data__licensefiles) - for data__licensefiles_x, data__licensefiles_item in enumerate(data__licensefiles): - if not isinstance(data__licensefiles_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".license-files[{data__licensefiles_x}]".format(**locals()) + " must be string", value=data__licensefiles_item, name="" + (name_prefix or "data") + ".license-files[{data__licensefiles_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - else: data["license-files"] = ['LICEN[CS]E*', ' COPYING*', ' NOTICE*', 'AUTHORS*'] - if "dynamic" in data_keys: - data_keys.remove("dynamic") - data__dynamic = data["dynamic"] - if not isinstance(data__dynamic, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic must be object", value=data__dynamic, name="" + (name_prefix or "data") + ".dynamic", definition={'type': 'object', 'description': 'Instructions for loading :pep:`621`-related metadata dynamically', 'additionalProperties': False, 'properties': {'version': {'$$description': ['A version dynamically loaded via either the ``attr:`` or ``file:``', 'directives. Please make sure the given file or attribute respects :pep:`440`.'], 'oneOf': [{'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}]}, 'classifiers': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'description': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'dependencies': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'entry-points': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'optional-dependencies': {'type': 'object', 'propertyNames': {'format': 'python-identifier'}, 'additionalProperties': False, 'patternProperties': {'.+': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}}}, 'readme': {'anyOf': [{'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, {'properties': {'content-type': {'type': 'string'}}}], 'required': ['file']}}}, rule='type') - data__dynamic_is_dict = isinstance(data__dynamic, dict) - if data__dynamic_is_dict: - data__dynamic_keys = set(data__dynamic.keys()) - if "version" in data__dynamic_keys: - data__dynamic_keys.remove("version") - data__dynamic__version = data__dynamic["version"] - data__dynamic__version_one_of_count5 = 0 - if data__dynamic__version_one_of_count5 < 2: - try: - validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_attr_directive(data__dynamic__version, custom_formats, (name_prefix or "data") + ".dynamic.version") - data__dynamic__version_one_of_count5 += 1 - except JsonSchemaValueException: pass - if data__dynamic__version_one_of_count5 < 2: - try: - validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_file_directive(data__dynamic__version, custom_formats, (name_prefix or "data") + ".dynamic.version") - data__dynamic__version_one_of_count5 += 1 - except JsonSchemaValueException: pass - if data__dynamic__version_one_of_count5 != 1: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic.version must be valid exactly by one definition" + (" (" + str(data__dynamic__version_one_of_count5) + " matches found)"), value=data__dynamic__version, name="" + (name_prefix or "data") + ".dynamic.version", definition={'$$description': ['A version dynamically loaded via either the ``attr:`` or ``file:``', 'directives. Please make sure the given file or attribute respects :pep:`440`.'], 'oneOf': [{'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}]}, rule='oneOf') - if "classifiers" in data__dynamic_keys: - data__dynamic_keys.remove("classifiers") - data__dynamic__classifiers = data__dynamic["classifiers"] - validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_file_directive(data__dynamic__classifiers, custom_formats, (name_prefix or "data") + ".dynamic.classifiers") - if "description" in data__dynamic_keys: - data__dynamic_keys.remove("description") - data__dynamic__description = data__dynamic["description"] - validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_file_directive(data__dynamic__description, custom_formats, (name_prefix or "data") + ".dynamic.description") - if "dependencies" in data__dynamic_keys: - data__dynamic_keys.remove("dependencies") - data__dynamic__dependencies = data__dynamic["dependencies"] - validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_file_directive(data__dynamic__dependencies, custom_formats, (name_prefix or "data") + ".dynamic.dependencies") - if "entry-points" in data__dynamic_keys: - data__dynamic_keys.remove("entry-points") - data__dynamic__entrypoints = data__dynamic["entry-points"] - validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_file_directive(data__dynamic__entrypoints, custom_formats, (name_prefix or "data") + ".dynamic.entry-points") - if "optional-dependencies" in data__dynamic_keys: - data__dynamic_keys.remove("optional-dependencies") - data__dynamic__optionaldependencies = data__dynamic["optional-dependencies"] - if not isinstance(data__dynamic__optionaldependencies, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic.optional-dependencies must be object", value=data__dynamic__optionaldependencies, name="" + (name_prefix or "data") + ".dynamic.optional-dependencies", definition={'type': 'object', 'propertyNames': {'format': 'python-identifier'}, 'additionalProperties': False, 'patternProperties': {'.+': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}}}, rule='type') - data__dynamic__optionaldependencies_is_dict = isinstance(data__dynamic__optionaldependencies, dict) - if data__dynamic__optionaldependencies_is_dict: - data__dynamic__optionaldependencies_keys = set(data__dynamic__optionaldependencies.keys()) - for data__dynamic__optionaldependencies_key, data__dynamic__optionaldependencies_val in data__dynamic__optionaldependencies.items(): - if REGEX_PATTERNS['.+'].search(data__dynamic__optionaldependencies_key): - if data__dynamic__optionaldependencies_key in data__dynamic__optionaldependencies_keys: - data__dynamic__optionaldependencies_keys.remove(data__dynamic__optionaldependencies_key) - validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_file_directive(data__dynamic__optionaldependencies_val, custom_formats, (name_prefix or "data") + ".dynamic.optional-dependencies.{data__dynamic__optionaldependencies_key}") - if data__dynamic__optionaldependencies_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic.optional-dependencies must not contain "+str(data__dynamic__optionaldependencies_keys)+" properties", value=data__dynamic__optionaldependencies, name="" + (name_prefix or "data") + ".dynamic.optional-dependencies", definition={'type': 'object', 'propertyNames': {'format': 'python-identifier'}, 'additionalProperties': False, 'patternProperties': {'.+': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}}}, rule='additionalProperties') - data__dynamic__optionaldependencies_len = len(data__dynamic__optionaldependencies) - if data__dynamic__optionaldependencies_len != 0: - data__dynamic__optionaldependencies_property_names = True - for data__dynamic__optionaldependencies_key in data__dynamic__optionaldependencies: - try: - if isinstance(data__dynamic__optionaldependencies_key, str): - if not custom_formats["python-identifier"](data__dynamic__optionaldependencies_key): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic.optional-dependencies must be python-identifier", value=data__dynamic__optionaldependencies_key, name="" + (name_prefix or "data") + ".dynamic.optional-dependencies", definition={'format': 'python-identifier'}, rule='format') - except JsonSchemaValueException: - data__dynamic__optionaldependencies_property_names = False - if not data__dynamic__optionaldependencies_property_names: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic.optional-dependencies must be named by propertyName definition", value=data__dynamic__optionaldependencies, name="" + (name_prefix or "data") + ".dynamic.optional-dependencies", definition={'type': 'object', 'propertyNames': {'format': 'python-identifier'}, 'additionalProperties': False, 'patternProperties': {'.+': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}}}, rule='propertyNames') - if "readme" in data__dynamic_keys: - data__dynamic_keys.remove("readme") - data__dynamic__readme = data__dynamic["readme"] - data__dynamic__readme_any_of_count6 = 0 - if not data__dynamic__readme_any_of_count6: - try: - validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_file_directive(data__dynamic__readme, custom_formats, (name_prefix or "data") + ".dynamic.readme") - data__dynamic__readme_any_of_count6 += 1 - except JsonSchemaValueException: pass - if not data__dynamic__readme_any_of_count6: - try: - data__dynamic__readme_is_dict = isinstance(data__dynamic__readme, dict) - if data__dynamic__readme_is_dict: - data__dynamic__readme_keys = set(data__dynamic__readme.keys()) - if "content-type" in data__dynamic__readme_keys: - data__dynamic__readme_keys.remove("content-type") - data__dynamic__readme__contenttype = data__dynamic__readme["content-type"] - if not isinstance(data__dynamic__readme__contenttype, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic.readme.content-type must be string", value=data__dynamic__readme__contenttype, name="" + (name_prefix or "data") + ".dynamic.readme.content-type", definition={'type': 'string'}, rule='type') - data__dynamic__readme_any_of_count6 += 1 - except JsonSchemaValueException: pass - if not data__dynamic__readme_any_of_count6: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic.readme cannot be validated by any definition", value=data__dynamic__readme, name="" + (name_prefix or "data") + ".dynamic.readme", definition={'anyOf': [{'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, {'properties': {'content-type': {'type': 'string'}}}], 'required': ['file']}, rule='anyOf') - data__dynamic__readme_is_dict = isinstance(data__dynamic__readme, dict) - if data__dynamic__readme_is_dict: - data__dynamic__readme_len = len(data__dynamic__readme) - if not all(prop in data__dynamic__readme for prop in ['file']): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic.readme must contain ['file'] properties", value=data__dynamic__readme, name="" + (name_prefix or "data") + ".dynamic.readme", definition={'anyOf': [{'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, {'properties': {'content-type': {'type': 'string'}}}], 'required': ['file']}, rule='required') - if data__dynamic_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic must not contain "+str(data__dynamic_keys)+" properties", value=data__dynamic, name="" + (name_prefix or "data") + ".dynamic", definition={'type': 'object', 'description': 'Instructions for loading :pep:`621`-related metadata dynamically', 'additionalProperties': False, 'properties': {'version': {'$$description': ['A version dynamically loaded via either the ``attr:`` or ``file:``', 'directives. Please make sure the given file or attribute respects :pep:`440`.'], 'oneOf': [{'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}]}, 'classifiers': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'description': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'dependencies': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'entry-points': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'optional-dependencies': {'type': 'object', 'propertyNames': {'format': 'python-identifier'}, 'additionalProperties': False, 'patternProperties': {'.+': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}}}, 'readme': {'anyOf': [{'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, {'properties': {'content-type': {'type': 'string'}}}], 'required': ['file']}}}, rule='additionalProperties') - if data_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + " must not contain "+str(data_keys)+" properties", value=data, name="" + (name_prefix or "data") + "", definition={'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://setuptools.pypa.io/en/latest/references/keywords.html', 'title': '``tool.setuptools`` table', '$$description': ['Please notice for the time being the ``setuptools`` project does not specify', 'a way of configuring builds via ``pyproject.toml``.', 'Therefore this schema should be taken just as a *"thought experiment"* on how', 'this *might be done*, by following the principles established in', '`ini2toml `_.', 'It considers only ``setuptools`` `parameters', '`_', 'that can currently be configured via ``setup.cfg`` and are not covered by :pep:`621`', 'but intentionally excludes ``dependency_links`` and ``setup_requires``.', 'NOTE: ``scripts`` was renamed to ``script-files`` to avoid confusion with', 'entry-point based scripts (defined in :pep:`621`).'], 'type': 'object', 'additionalProperties': False, 'properties': {'platforms': {'type': 'array', 'items': {'type': 'string'}}, 'provides': {'$$description': ['Package and virtual package names contained within this package', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, 'obsoletes': {'$$description': ['Packages which this package renders obsolete', '**(not supported by pip)**'], 'type': 'array', 'items': {'type': 'string', 'format': 'pep508-identifier'}}, 'zip-safe': {'description': 'Whether the project can be safely installed and run from a zip file.', 'type': 'boolean'}, 'script-files': {'description': 'Legacy way of defining scripts (entry-points are preferred).', 'type': 'array', 'items': {'type': 'string'}, '$comment': 'TODO: is this field deprecated/should be removed?'}, 'eager-resources': {'$$description': ['Resources that should be extracted together, if any of them is needed,', 'or if any C extensions included in the project are imported.'], 'type': 'array', 'items': {'type': 'string'}}, 'packages': {'$$description': ['Packages that should be included in the distribution.', 'It can be given either as a list of package identifiers', 'or as a ``dict``-like structure with a single key ``find``', 'which corresponds to a dynamic call to', '``setuptools.config.expand.find_packages`` function.', 'The ``find`` key is associated with a nested ``dict``-like structure that can', 'contain ``where``, ``include``, ``exclude`` and ``namespaces`` keys,', 'mimicking the keyword arguments of the associated function.'], 'oneOf': [{'title': 'Array of Python package identifiers', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}}, {'$id': '#/definitions/find-directive', 'title': "'find:' directive", 'type': 'object', 'additionalProperties': False, 'properties': {'find': {'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}}}]}, 'package-dir': {'$$description': [':class:`dict`-like structure mapping from package names to directories where their', 'code can be found.', 'The empty string (as key) means that all packages are contained inside', 'the given directory will be included in the distribution.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': ''}]}, 'patternProperties': {'^.*$': {'type': 'string'}}}, 'package-data': {'$$description': ['Mapping from package names to lists of glob patterns.', 'Usually this option is not needed when using ``include-package-data = true``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'include-package-data': {'$$description': ['Automatically include any data files inside the package directories', 'that are specified by ``MANIFEST.in``', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'boolean'}, 'exclude-package-data': {'$$description': ['Mapping from package names to lists of glob patterns that should be excluded', 'For more information on how to include data files, check ``setuptools`` `docs', '`_.'], 'type': 'object', 'additionalProperties': False, 'propertyNames': {'oneOf': [{'format': 'python-module-name'}, {'const': '*'}]}, 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'namespace-packages': {'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'https://setuptools.pypa.io/en/latest/userguide/package_discovery.html'}, 'py-modules': {'description': 'Modules that setuptools will manipulate', 'type': 'array', 'items': {'type': 'string', 'format': 'python-module-name'}, '$comment': 'TODO: clarify the relationship with ``packages``'}, 'data-files': {'$$description': ['**DEPRECATED**: dict-like structure where each key represents a directory and', 'the value is a list of glob patterns that should be installed in them.', "Please notice this don't work with wheels. See `data files support", '`_'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'array', 'items': {'type': 'string'}}}}, 'cmdclass': {'$$description': ['Mapping of distutils-style command names to ``setuptools.Command`` subclasses', 'which in turn should be represented by strings with a qualified class name', '(i.e., "dotted" form with module), e.g.::\n\n', ' cmdclass = {mycmd = "pkg.subpkg.module.CommandClass"}\n\n', 'The command class should be a directly defined at the top-level of the', 'containing module (no class nesting).'], 'type': 'object', 'patternProperties': {'^.*$': {'type': 'string', 'format': 'python-qualified-identifier'}}}, 'license-files': {'type': 'array', 'items': {'type': 'string'}, '$$description': ['PROVISIONAL: List of glob patterns for all license files being distributed.', '(might become standard with PEP 639).'], 'default': ['LICEN[CS]E*', ' COPYING*', ' NOTICE*', 'AUTHORS*'], '$comment': 'TODO: revise if PEP 639 is accepted. Probably ``project.license-files``?'}, 'dynamic': {'type': 'object', 'description': 'Instructions for loading :pep:`621`-related metadata dynamically', 'additionalProperties': False, 'properties': {'version': {'$$description': ['A version dynamically loaded via either the ``attr:`` or ``file:``', 'directives. Please make sure the given file or attribute respects :pep:`440`.'], 'oneOf': [{'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}]}, 'classifiers': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'description': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'dependencies': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'entry-points': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'optional-dependencies': {'type': 'object', 'propertyNames': {'format': 'python-identifier'}, 'additionalProperties': False, 'patternProperties': {'.+': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}}}, 'readme': {'anyOf': [{'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, {'properties': {'content-type': {'type': 'string'}}}], 'required': ['file']}}}}, 'definitions': {'file-directive': {'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, 'attr-directive': {'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, 'find-directive': {'$id': '#/definitions/find-directive', 'title': "'find:' directive", 'type': 'object', 'additionalProperties': False, 'properties': {'find': {'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}}}}}, rule='additionalProperties') - return data - -def validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_file_directive(data, custom_formats={}, name_prefix=None): - if not isinstance(data, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be object", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, rule='type') - data_is_dict = isinstance(data, dict) - if data_is_dict: - data_len = len(data) - if not all(prop in data for prop in ['file']): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must contain ['file'] properties", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, rule='required') - data_keys = set(data.keys()) - if "file" in data_keys: - data_keys.remove("file") - data__file = data["file"] - data__file_one_of_count7 = 0 - if data__file_one_of_count7 < 2: - try: - if not isinstance(data__file, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".file must be string", value=data__file, name="" + (name_prefix or "data") + ".file", definition={'type': 'string'}, rule='type') - data__file_one_of_count7 += 1 - except JsonSchemaValueException: pass - if data__file_one_of_count7 < 2: - try: - if not isinstance(data__file, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".file must be array", value=data__file, name="" + (name_prefix or "data") + ".file", definition={'type': 'array', 'items': {'type': 'string'}}, rule='type') - data__file_is_list = isinstance(data__file, (list, tuple)) - if data__file_is_list: - data__file_len = len(data__file) - for data__file_x, data__file_item in enumerate(data__file): - if not isinstance(data__file_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".file[{data__file_x}]".format(**locals()) + " must be string", value=data__file_item, name="" + (name_prefix or "data") + ".file[{data__file_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - data__file_one_of_count7 += 1 - except JsonSchemaValueException: pass - if data__file_one_of_count7 != 1: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".file must be valid exactly by one definition" + (" (" + str(data__file_one_of_count7) + " matches found)"), value=data__file, name="" + (name_prefix or "data") + ".file", definition={'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}, rule='oneOf') - if data_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + " must not contain "+str(data_keys)+" properties", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/file-directive', 'title': "'file:' directive", 'description': 'Value is read from a file (or list of files and then concatenated)', 'type': 'object', 'additionalProperties': False, 'properties': {'file': {'oneOf': [{'type': 'string'}, {'type': 'array', 'items': {'type': 'string'}}]}}, 'required': ['file']}, rule='additionalProperties') - return data - -def validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_attr_directive(data, custom_formats={}, name_prefix=None): - if not isinstance(data, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be object", value=data, name="" + (name_prefix or "data") + "", definition={'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, rule='type') - data_is_dict = isinstance(data, dict) - if data_is_dict: - data_len = len(data) - if not all(prop in data for prop in ['attr']): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must contain ['attr'] properties", value=data, name="" + (name_prefix or "data") + "", definition={'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, rule='required') - data_keys = set(data.keys()) - if "attr" in data_keys: - data_keys.remove("attr") - data__attr = data["attr"] - if not isinstance(data__attr, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".attr must be string", value=data__attr, name="" + (name_prefix or "data") + ".attr", definition={'type': 'string'}, rule='type') - if data_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + " must not contain "+str(data_keys)+" properties", value=data, name="" + (name_prefix or "data") + "", definition={'title': "'attr:' directive", '$id': '#/definitions/attr-directive', '$$description': ['Value is read from a module attribute. Supports callables and iterables;', 'unsupported types are cast via ``str()``'], 'type': 'object', 'additionalProperties': False, 'properties': {'attr': {'type': 'string'}}, 'required': ['attr']}, rule='additionalProperties') - return data - -def validate_https___setuptools_pypa_io_en_latest_references_keywords_html__definitions_find_directive(data, custom_formats={}, name_prefix=None): - if not isinstance(data, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be object", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/find-directive', 'title': "'find:' directive", 'type': 'object', 'additionalProperties': False, 'properties': {'find': {'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}}}, rule='type') - data_is_dict = isinstance(data, dict) - if data_is_dict: - data_keys = set(data.keys()) - if "find" in data_keys: - data_keys.remove("find") - data__find = data["find"] - if not isinstance(data__find, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".find must be object", value=data__find, name="" + (name_prefix or "data") + ".find", definition={'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}, rule='type') - data__find_is_dict = isinstance(data__find, dict) - if data__find_is_dict: - data__find_keys = set(data__find.keys()) - if "where" in data__find_keys: - data__find_keys.remove("where") - data__find__where = data__find["where"] - if not isinstance(data__find__where, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".find.where must be array", value=data__find__where, name="" + (name_prefix or "data") + ".find.where", definition={'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, rule='type') - data__find__where_is_list = isinstance(data__find__where, (list, tuple)) - if data__find__where_is_list: - data__find__where_len = len(data__find__where) - for data__find__where_x, data__find__where_item in enumerate(data__find__where): - if not isinstance(data__find__where_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".find.where[{data__find__where_x}]".format(**locals()) + " must be string", value=data__find__where_item, name="" + (name_prefix or "data") + ".find.where[{data__find__where_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if "exclude" in data__find_keys: - data__find_keys.remove("exclude") - data__find__exclude = data__find["exclude"] - if not isinstance(data__find__exclude, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".find.exclude must be array", value=data__find__exclude, name="" + (name_prefix or "data") + ".find.exclude", definition={'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, rule='type') - data__find__exclude_is_list = isinstance(data__find__exclude, (list, tuple)) - if data__find__exclude_is_list: - data__find__exclude_len = len(data__find__exclude) - for data__find__exclude_x, data__find__exclude_item in enumerate(data__find__exclude): - if not isinstance(data__find__exclude_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".find.exclude[{data__find__exclude_x}]".format(**locals()) + " must be string", value=data__find__exclude_item, name="" + (name_prefix or "data") + ".find.exclude[{data__find__exclude_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if "include" in data__find_keys: - data__find_keys.remove("include") - data__find__include = data__find["include"] - if not isinstance(data__find__include, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".find.include must be array", value=data__find__include, name="" + (name_prefix or "data") + ".find.include", definition={'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, rule='type') - data__find__include_is_list = isinstance(data__find__include, (list, tuple)) - if data__find__include_is_list: - data__find__include_len = len(data__find__include) - for data__find__include_x, data__find__include_item in enumerate(data__find__include): - if not isinstance(data__find__include_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".find.include[{data__find__include_x}]".format(**locals()) + " must be string", value=data__find__include_item, name="" + (name_prefix or "data") + ".find.include[{data__find__include_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if "namespaces" in data__find_keys: - data__find_keys.remove("namespaces") - data__find__namespaces = data__find["namespaces"] - if not isinstance(data__find__namespaces, (bool)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".find.namespaces must be boolean", value=data__find__namespaces, name="" + (name_prefix or "data") + ".find.namespaces", definition={'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}, rule='type') - if data__find_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".find must not contain "+str(data__find_keys)+" properties", value=data__find, name="" + (name_prefix or "data") + ".find", definition={'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}, rule='additionalProperties') - if data_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + " must not contain "+str(data_keys)+" properties", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/find-directive', 'title': "'find:' directive", 'type': 'object', 'additionalProperties': False, 'properties': {'find': {'type': 'object', '$$description': ['Dynamic `package discovery', '`_.'], 'additionalProperties': False, 'properties': {'where': {'description': 'Directories to be searched for packages (Unix-style relative path)', 'type': 'array', 'items': {'type': 'string'}}, 'exclude': {'type': 'array', '$$description': ['Exclude packages that match the values listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'include': {'type': 'array', '$$description': ['Restrict the found packages to just the ones listed in this field.', "Can container shell-style wildcards (e.g. ``'pkg.*'``)"], 'items': {'type': 'string'}}, 'namespaces': {'type': 'boolean', '$$description': ['When ``True``, directories without a ``__init__.py`` file will also', 'be scanned for :pep:`420`-style implicit namespaces']}}}}}, rule='additionalProperties') - return data - -def validate_https___docs_python_org_3_install(data, custom_formats={}, name_prefix=None): - if not isinstance(data, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be object", value=data, name="" + (name_prefix or "data") + "", definition={'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://docs.python.org/3/install/', 'title': '``tool.distutils`` table', '$$description': ['Originally, ``distutils`` allowed developers to configure arguments for', '``setup.py`` scripts via `distutils configuration files', '`_.', '``tool.distutils`` subtables could be used with the same purpose', '(NOT CURRENTLY IMPLEMENTED).'], 'type': 'object', 'properties': {'global': {'type': 'object', 'description': 'Global options applied to all ``distutils`` commands'}}, 'patternProperties': {'.+': {'type': 'object'}}, '$comment': 'TODO: Is there a practical way of making this schema more specific?'}, rule='type') - data_is_dict = isinstance(data, dict) - if data_is_dict: - data_keys = set(data.keys()) - if "global" in data_keys: - data_keys.remove("global") - data__global = data["global"] - if not isinstance(data__global, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".global must be object", value=data__global, name="" + (name_prefix or "data") + ".global", definition={'type': 'object', 'description': 'Global options applied to all ``distutils`` commands'}, rule='type') - for data_key, data_val in data.items(): - if REGEX_PATTERNS['.+'].search(data_key): - if data_key in data_keys: - data_keys.remove(data_key) - if not isinstance(data_val, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".{data_key}".format(**locals()) + " must be object", value=data_val, name="" + (name_prefix or "data") + ".{data_key}".format(**locals()) + "", definition={'type': 'object'}, rule='type') - return data - -def validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata(data, custom_formats={}, name_prefix=None): - if not isinstance(data, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be object", value=data, name="" + (name_prefix or "data") + "", definition={'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://packaging.python.org/en/latest/specifications/declaring-project-metadata/', 'title': 'Package metadata stored in the ``project`` table', '$$description': ['Data structure for the **project** table inside ``pyproject.toml``', '(as initially defined in :pep:`621`)'], 'type': 'object', 'properties': {'name': {'type': 'string', 'description': 'The name (primary identifier) of the project. MUST be statically defined.', 'format': 'pep508-identifier'}, 'version': {'type': 'string', 'description': 'The version of the project as supported by :pep:`440`.', 'format': 'pep440'}, 'description': {'type': 'string', '$$description': ['The `summary description of the project', '`_']}, 'readme': {'$$description': ['`Full/detailed description of the project in the form of a README', '`_', "with meaning similar to the one defined in `core metadata's Description", '`_'], 'oneOf': [{'type': 'string', '$$description': ['Relative path to a text file (UTF-8) containing the full description', 'of the project. If the file path ends in case-insensitive ``.md`` or', '``.rst`` suffixes, then the content-type is respectively', '``text/markdown`` or ``text/x-rst``']}, {'type': 'object', 'allOf': [{'anyOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', 'description': 'Full text describing the project.'}}, 'required': ['text']}]}, {'properties': {'content-type': {'type': 'string', '$$description': ['Content-type (:rfc:`1341`) of the full description', '(e.g. ``text/markdown``). The ``charset`` parameter is assumed', 'UTF-8 when not present.'], '$comment': 'TODO: add regex pattern or format?'}}, 'required': ['content-type']}]}]}, 'requires-python': {'type': 'string', 'format': 'pep508-versionspec', '$$description': ['`The Python version requirements of the project', '`_.']}, 'license': {'description': '`Project license `_.', 'oneOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to the file (UTF-8) which contains the license for the', 'project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', '$$description': ['The license of the project whose meaning is that of the', '`License field from the core metadata', '`_.']}}, 'required': ['text']}]}, 'authors': {'type': 'array', 'items': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, '$$description': ["The people or organizations considered to be the 'authors' of the project.", 'The exact meaning is open to interpretation (e.g. original or primary authors,', 'current maintainers, or owners of the package).']}, 'maintainers': {'type': 'array', 'items': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, '$$description': ["The people or organizations considered to be the 'maintainers' of the project.", 'Similarly to ``authors``, the exact meaning is open to interpretation.']}, 'keywords': {'type': 'array', 'items': {'type': 'string'}, 'description': 'List of keywords to assist searching for the distribution in a larger catalog.'}, 'classifiers': {'type': 'array', 'items': {'type': 'string', 'format': 'trove-classifier', 'description': '`PyPI classifier `_.'}, '$$description': ['`Trove classifiers `_', 'which apply to the project.']}, 'urls': {'type': 'object', 'description': 'URLs associated with the project in the form ``label => value``.', 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', 'format': 'url'}}}, 'scripts': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'gui-scripts': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'entry-points': {'$$description': ['Instruct the installer to expose the given modules/functions via', '``entry-point`` discovery mechanism (useful for plugins).', 'More information available in the `Python packaging guide', '`_.'], 'propertyNames': {'format': 'python-entrypoint-group'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}}}, 'dependencies': {'type': 'array', 'description': 'Project (mandatory) dependencies.', 'items': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}, 'optional-dependencies': {'type': 'object', 'description': 'Optional dependency for the project', 'propertyNames': {'format': 'pep508-identifier'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'array', 'items': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}}, 'dynamic': {'type': 'array', '$$description': ['Specifies which fields are intentionally unspecified and expected to be', 'dynamically provided by build tools'], 'items': {'enum': ['version', 'description', 'readme', 'requires-python', 'license', 'authors', 'maintainers', 'keywords', 'classifiers', 'urls', 'scripts', 'gui-scripts', 'entry-points', 'dependencies', 'optional-dependencies']}}}, 'required': ['name'], 'additionalProperties': False, 'if': {'not': {'required': ['dynamic'], 'properties': {'dynamic': {'contains': {'const': 'version'}, '$$description': ['version is listed in ``dynamic``']}}}, '$$comment': ['According to :pep:`621`:', ' If the core metadata specification lists a field as "Required", then', ' the metadata MUST specify the field statically or list it in dynamic', 'In turn, `core metadata`_ defines:', ' The required fields are: Metadata-Version, Name, Version.', ' All the other fields are optional.', 'Since ``Metadata-Version`` is defined by the build back-end, ``name`` and', '``version`` are the only mandatory information in ``pyproject.toml``.', '.. _core metadata: https://packaging.python.org/specifications/core-metadata/']}, 'then': {'required': ['version'], '$$description': ['version should be statically defined in the ``version`` field']}, 'definitions': {'author': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, 'entry-point-group': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'dependency': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}, rule='type') - data_is_dict = isinstance(data, dict) - if data_is_dict: - data_len = len(data) - if not all(prop in data for prop in ['name']): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must contain ['name'] properties", value=data, name="" + (name_prefix or "data") + "", definition={'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://packaging.python.org/en/latest/specifications/declaring-project-metadata/', 'title': 'Package metadata stored in the ``project`` table', '$$description': ['Data structure for the **project** table inside ``pyproject.toml``', '(as initially defined in :pep:`621`)'], 'type': 'object', 'properties': {'name': {'type': 'string', 'description': 'The name (primary identifier) of the project. MUST be statically defined.', 'format': 'pep508-identifier'}, 'version': {'type': 'string', 'description': 'The version of the project as supported by :pep:`440`.', 'format': 'pep440'}, 'description': {'type': 'string', '$$description': ['The `summary description of the project', '`_']}, 'readme': {'$$description': ['`Full/detailed description of the project in the form of a README', '`_', "with meaning similar to the one defined in `core metadata's Description", '`_'], 'oneOf': [{'type': 'string', '$$description': ['Relative path to a text file (UTF-8) containing the full description', 'of the project. If the file path ends in case-insensitive ``.md`` or', '``.rst`` suffixes, then the content-type is respectively', '``text/markdown`` or ``text/x-rst``']}, {'type': 'object', 'allOf': [{'anyOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', 'description': 'Full text describing the project.'}}, 'required': ['text']}]}, {'properties': {'content-type': {'type': 'string', '$$description': ['Content-type (:rfc:`1341`) of the full description', '(e.g. ``text/markdown``). The ``charset`` parameter is assumed', 'UTF-8 when not present.'], '$comment': 'TODO: add regex pattern or format?'}}, 'required': ['content-type']}]}]}, 'requires-python': {'type': 'string', 'format': 'pep508-versionspec', '$$description': ['`The Python version requirements of the project', '`_.']}, 'license': {'description': '`Project license `_.', 'oneOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to the file (UTF-8) which contains the license for the', 'project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', '$$description': ['The license of the project whose meaning is that of the', '`License field from the core metadata', '`_.']}}, 'required': ['text']}]}, 'authors': {'type': 'array', 'items': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, '$$description': ["The people or organizations considered to be the 'authors' of the project.", 'The exact meaning is open to interpretation (e.g. original or primary authors,', 'current maintainers, or owners of the package).']}, 'maintainers': {'type': 'array', 'items': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, '$$description': ["The people or organizations considered to be the 'maintainers' of the project.", 'Similarly to ``authors``, the exact meaning is open to interpretation.']}, 'keywords': {'type': 'array', 'items': {'type': 'string'}, 'description': 'List of keywords to assist searching for the distribution in a larger catalog.'}, 'classifiers': {'type': 'array', 'items': {'type': 'string', 'format': 'trove-classifier', 'description': '`PyPI classifier `_.'}, '$$description': ['`Trove classifiers `_', 'which apply to the project.']}, 'urls': {'type': 'object', 'description': 'URLs associated with the project in the form ``label => value``.', 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', 'format': 'url'}}}, 'scripts': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'gui-scripts': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'entry-points': {'$$description': ['Instruct the installer to expose the given modules/functions via', '``entry-point`` discovery mechanism (useful for plugins).', 'More information available in the `Python packaging guide', '`_.'], 'propertyNames': {'format': 'python-entrypoint-group'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}}}, 'dependencies': {'type': 'array', 'description': 'Project (mandatory) dependencies.', 'items': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}, 'optional-dependencies': {'type': 'object', 'description': 'Optional dependency for the project', 'propertyNames': {'format': 'pep508-identifier'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'array', 'items': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}}, 'dynamic': {'type': 'array', '$$description': ['Specifies which fields are intentionally unspecified and expected to be', 'dynamically provided by build tools'], 'items': {'enum': ['version', 'description', 'readme', 'requires-python', 'license', 'authors', 'maintainers', 'keywords', 'classifiers', 'urls', 'scripts', 'gui-scripts', 'entry-points', 'dependencies', 'optional-dependencies']}}}, 'required': ['name'], 'additionalProperties': False, 'if': {'not': {'required': ['dynamic'], 'properties': {'dynamic': {'contains': {'const': 'version'}, '$$description': ['version is listed in ``dynamic``']}}}, '$$comment': ['According to :pep:`621`:', ' If the core metadata specification lists a field as "Required", then', ' the metadata MUST specify the field statically or list it in dynamic', 'In turn, `core metadata`_ defines:', ' The required fields are: Metadata-Version, Name, Version.', ' All the other fields are optional.', 'Since ``Metadata-Version`` is defined by the build back-end, ``name`` and', '``version`` are the only mandatory information in ``pyproject.toml``.', '.. _core metadata: https://packaging.python.org/specifications/core-metadata/']}, 'then': {'required': ['version'], '$$description': ['version should be statically defined in the ``version`` field']}, 'definitions': {'author': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, 'entry-point-group': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'dependency': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}, rule='required') - data_keys = set(data.keys()) - if "name" in data_keys: - data_keys.remove("name") - data__name = data["name"] - if not isinstance(data__name, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".name must be string", value=data__name, name="" + (name_prefix or "data") + ".name", definition={'type': 'string', 'description': 'The name (primary identifier) of the project. MUST be statically defined.', 'format': 'pep508-identifier'}, rule='type') - if isinstance(data__name, str): - if not custom_formats["pep508-identifier"](data__name): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".name must be pep508-identifier", value=data__name, name="" + (name_prefix or "data") + ".name", definition={'type': 'string', 'description': 'The name (primary identifier) of the project. MUST be statically defined.', 'format': 'pep508-identifier'}, rule='format') - if "version" in data_keys: - data_keys.remove("version") - data__version = data["version"] - if not isinstance(data__version, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".version must be string", value=data__version, name="" + (name_prefix or "data") + ".version", definition={'type': 'string', 'description': 'The version of the project as supported by :pep:`440`.', 'format': 'pep440'}, rule='type') - if isinstance(data__version, str): - if not custom_formats["pep440"](data__version): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".version must be pep440", value=data__version, name="" + (name_prefix or "data") + ".version", definition={'type': 'string', 'description': 'The version of the project as supported by :pep:`440`.', 'format': 'pep440'}, rule='format') - if "description" in data_keys: - data_keys.remove("description") - data__description = data["description"] - if not isinstance(data__description, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".description must be string", value=data__description, name="" + (name_prefix or "data") + ".description", definition={'type': 'string', '$$description': ['The `summary description of the project', '`_']}, rule='type') - if "readme" in data_keys: - data_keys.remove("readme") - data__readme = data["readme"] - data__readme_one_of_count8 = 0 - if data__readme_one_of_count8 < 2: - try: - if not isinstance(data__readme, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".readme must be string", value=data__readme, name="" + (name_prefix or "data") + ".readme", definition={'type': 'string', '$$description': ['Relative path to a text file (UTF-8) containing the full description', 'of the project. If the file path ends in case-insensitive ``.md`` or', '``.rst`` suffixes, then the content-type is respectively', '``text/markdown`` or ``text/x-rst``']}, rule='type') - data__readme_one_of_count8 += 1 - except JsonSchemaValueException: pass - if data__readme_one_of_count8 < 2: - try: - if not isinstance(data__readme, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".readme must be object", value=data__readme, name="" + (name_prefix or "data") + ".readme", definition={'type': 'object', 'allOf': [{'anyOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', 'description': 'Full text describing the project.'}}, 'required': ['text']}]}, {'properties': {'content-type': {'type': 'string', '$$description': ['Content-type (:rfc:`1341`) of the full description', '(e.g. ``text/markdown``). The ``charset`` parameter is assumed', 'UTF-8 when not present.'], '$comment': 'TODO: add regex pattern or format?'}}, 'required': ['content-type']}]}, rule='type') - data__readme_any_of_count9 = 0 - if not data__readme_any_of_count9: - try: - data__readme_is_dict = isinstance(data__readme, dict) - if data__readme_is_dict: - data__readme_len = len(data__readme) - if not all(prop in data__readme for prop in ['file']): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".readme must contain ['file'] properties", value=data__readme, name="" + (name_prefix or "data") + ".readme", definition={'properties': {'file': {'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}}, 'required': ['file']}, rule='required') - data__readme_keys = set(data__readme.keys()) - if "file" in data__readme_keys: - data__readme_keys.remove("file") - data__readme__file = data__readme["file"] - if not isinstance(data__readme__file, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".readme.file must be string", value=data__readme__file, name="" + (name_prefix or "data") + ".readme.file", definition={'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}, rule='type') - data__readme_any_of_count9 += 1 - except JsonSchemaValueException: pass - if not data__readme_any_of_count9: - try: - data__readme_is_dict = isinstance(data__readme, dict) - if data__readme_is_dict: - data__readme_len = len(data__readme) - if not all(prop in data__readme for prop in ['text']): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".readme must contain ['text'] properties", value=data__readme, name="" + (name_prefix or "data") + ".readme", definition={'properties': {'text': {'type': 'string', 'description': 'Full text describing the project.'}}, 'required': ['text']}, rule='required') - data__readme_keys = set(data__readme.keys()) - if "text" in data__readme_keys: - data__readme_keys.remove("text") - data__readme__text = data__readme["text"] - if not isinstance(data__readme__text, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".readme.text must be string", value=data__readme__text, name="" + (name_prefix or "data") + ".readme.text", definition={'type': 'string', 'description': 'Full text describing the project.'}, rule='type') - data__readme_any_of_count9 += 1 - except JsonSchemaValueException: pass - if not data__readme_any_of_count9: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".readme cannot be validated by any definition", value=data__readme, name="" + (name_prefix or "data") + ".readme", definition={'anyOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', 'description': 'Full text describing the project.'}}, 'required': ['text']}]}, rule='anyOf') - data__readme_is_dict = isinstance(data__readme, dict) - if data__readme_is_dict: - data__readme_len = len(data__readme) - if not all(prop in data__readme for prop in ['content-type']): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".readme must contain ['content-type'] properties", value=data__readme, name="" + (name_prefix or "data") + ".readme", definition={'properties': {'content-type': {'type': 'string', '$$description': ['Content-type (:rfc:`1341`) of the full description', '(e.g. ``text/markdown``). The ``charset`` parameter is assumed', 'UTF-8 when not present.'], '$comment': 'TODO: add regex pattern or format?'}}, 'required': ['content-type']}, rule='required') - data__readme_keys = set(data__readme.keys()) - if "content-type" in data__readme_keys: - data__readme_keys.remove("content-type") - data__readme__contenttype = data__readme["content-type"] - if not isinstance(data__readme__contenttype, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".readme.content-type must be string", value=data__readme__contenttype, name="" + (name_prefix or "data") + ".readme.content-type", definition={'type': 'string', '$$description': ['Content-type (:rfc:`1341`) of the full description', '(e.g. ``text/markdown``). The ``charset`` parameter is assumed', 'UTF-8 when not present.'], '$comment': 'TODO: add regex pattern or format?'}, rule='type') - data__readme_one_of_count8 += 1 - except JsonSchemaValueException: pass - if data__readme_one_of_count8 != 1: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".readme must be valid exactly by one definition" + (" (" + str(data__readme_one_of_count8) + " matches found)"), value=data__readme, name="" + (name_prefix or "data") + ".readme", definition={'$$description': ['`Full/detailed description of the project in the form of a README', '`_', "with meaning similar to the one defined in `core metadata's Description", '`_'], 'oneOf': [{'type': 'string', '$$description': ['Relative path to a text file (UTF-8) containing the full description', 'of the project. If the file path ends in case-insensitive ``.md`` or', '``.rst`` suffixes, then the content-type is respectively', '``text/markdown`` or ``text/x-rst``']}, {'type': 'object', 'allOf': [{'anyOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', 'description': 'Full text describing the project.'}}, 'required': ['text']}]}, {'properties': {'content-type': {'type': 'string', '$$description': ['Content-type (:rfc:`1341`) of the full description', '(e.g. ``text/markdown``). The ``charset`` parameter is assumed', 'UTF-8 when not present.'], '$comment': 'TODO: add regex pattern or format?'}}, 'required': ['content-type']}]}]}, rule='oneOf') - if "requires-python" in data_keys: - data_keys.remove("requires-python") - data__requirespython = data["requires-python"] - if not isinstance(data__requirespython, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".requires-python must be string", value=data__requirespython, name="" + (name_prefix or "data") + ".requires-python", definition={'type': 'string', 'format': 'pep508-versionspec', '$$description': ['`The Python version requirements of the project', '`_.']}, rule='type') - if isinstance(data__requirespython, str): - if not custom_formats["pep508-versionspec"](data__requirespython): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".requires-python must be pep508-versionspec", value=data__requirespython, name="" + (name_prefix or "data") + ".requires-python", definition={'type': 'string', 'format': 'pep508-versionspec', '$$description': ['`The Python version requirements of the project', '`_.']}, rule='format') - if "license" in data_keys: - data_keys.remove("license") - data__license = data["license"] - data__license_one_of_count10 = 0 - if data__license_one_of_count10 < 2: - try: - data__license_is_dict = isinstance(data__license, dict) - if data__license_is_dict: - data__license_len = len(data__license) - if not all(prop in data__license for prop in ['file']): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".license must contain ['file'] properties", value=data__license, name="" + (name_prefix or "data") + ".license", definition={'properties': {'file': {'type': 'string', '$$description': ['Relative path to the file (UTF-8) which contains the license for the', 'project.']}}, 'required': ['file']}, rule='required') - data__license_keys = set(data__license.keys()) - if "file" in data__license_keys: - data__license_keys.remove("file") - data__license__file = data__license["file"] - if not isinstance(data__license__file, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".license.file must be string", value=data__license__file, name="" + (name_prefix or "data") + ".license.file", definition={'type': 'string', '$$description': ['Relative path to the file (UTF-8) which contains the license for the', 'project.']}, rule='type') - data__license_one_of_count10 += 1 - except JsonSchemaValueException: pass - if data__license_one_of_count10 < 2: - try: - data__license_is_dict = isinstance(data__license, dict) - if data__license_is_dict: - data__license_len = len(data__license) - if not all(prop in data__license for prop in ['text']): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".license must contain ['text'] properties", value=data__license, name="" + (name_prefix or "data") + ".license", definition={'properties': {'text': {'type': 'string', '$$description': ['The license of the project whose meaning is that of the', '`License field from the core metadata', '`_.']}}, 'required': ['text']}, rule='required') - data__license_keys = set(data__license.keys()) - if "text" in data__license_keys: - data__license_keys.remove("text") - data__license__text = data__license["text"] - if not isinstance(data__license__text, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".license.text must be string", value=data__license__text, name="" + (name_prefix or "data") + ".license.text", definition={'type': 'string', '$$description': ['The license of the project whose meaning is that of the', '`License field from the core metadata', '`_.']}, rule='type') - data__license_one_of_count10 += 1 - except JsonSchemaValueException: pass - if data__license_one_of_count10 != 1: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".license must be valid exactly by one definition" + (" (" + str(data__license_one_of_count10) + " matches found)"), value=data__license, name="" + (name_prefix or "data") + ".license", definition={'description': '`Project license `_.', 'oneOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to the file (UTF-8) which contains the license for the', 'project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', '$$description': ['The license of the project whose meaning is that of the', '`License field from the core metadata', '`_.']}}, 'required': ['text']}]}, rule='oneOf') - if "authors" in data_keys: - data_keys.remove("authors") - data__authors = data["authors"] - if not isinstance(data__authors, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".authors must be array", value=data__authors, name="" + (name_prefix or "data") + ".authors", definition={'type': 'array', 'items': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, '$$description': ["The people or organizations considered to be the 'authors' of the project.", 'The exact meaning is open to interpretation (e.g. original or primary authors,', 'current maintainers, or owners of the package).']}, rule='type') - data__authors_is_list = isinstance(data__authors, (list, tuple)) - if data__authors_is_list: - data__authors_len = len(data__authors) - for data__authors_x, data__authors_item in enumerate(data__authors): - validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata___definitions_author(data__authors_item, custom_formats, (name_prefix or "data") + ".authors[{data__authors_x}]") - if "maintainers" in data_keys: - data_keys.remove("maintainers") - data__maintainers = data["maintainers"] - if not isinstance(data__maintainers, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".maintainers must be array", value=data__maintainers, name="" + (name_prefix or "data") + ".maintainers", definition={'type': 'array', 'items': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, '$$description': ["The people or organizations considered to be the 'maintainers' of the project.", 'Similarly to ``authors``, the exact meaning is open to interpretation.']}, rule='type') - data__maintainers_is_list = isinstance(data__maintainers, (list, tuple)) - if data__maintainers_is_list: - data__maintainers_len = len(data__maintainers) - for data__maintainers_x, data__maintainers_item in enumerate(data__maintainers): - validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata___definitions_author(data__maintainers_item, custom_formats, (name_prefix or "data") + ".maintainers[{data__maintainers_x}]") - if "keywords" in data_keys: - data_keys.remove("keywords") - data__keywords = data["keywords"] - if not isinstance(data__keywords, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".keywords must be array", value=data__keywords, name="" + (name_prefix or "data") + ".keywords", definition={'type': 'array', 'items': {'type': 'string'}, 'description': 'List of keywords to assist searching for the distribution in a larger catalog.'}, rule='type') - data__keywords_is_list = isinstance(data__keywords, (list, tuple)) - if data__keywords_is_list: - data__keywords_len = len(data__keywords) - for data__keywords_x, data__keywords_item in enumerate(data__keywords): - if not isinstance(data__keywords_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".keywords[{data__keywords_x}]".format(**locals()) + " must be string", value=data__keywords_item, name="" + (name_prefix or "data") + ".keywords[{data__keywords_x}]".format(**locals()) + "", definition={'type': 'string'}, rule='type') - if "classifiers" in data_keys: - data_keys.remove("classifiers") - data__classifiers = data["classifiers"] - if not isinstance(data__classifiers, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".classifiers must be array", value=data__classifiers, name="" + (name_prefix or "data") + ".classifiers", definition={'type': 'array', 'items': {'type': 'string', 'format': 'trove-classifier', 'description': '`PyPI classifier `_.'}, '$$description': ['`Trove classifiers `_', 'which apply to the project.']}, rule='type') - data__classifiers_is_list = isinstance(data__classifiers, (list, tuple)) - if data__classifiers_is_list: - data__classifiers_len = len(data__classifiers) - for data__classifiers_x, data__classifiers_item in enumerate(data__classifiers): - if not isinstance(data__classifiers_item, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".classifiers[{data__classifiers_x}]".format(**locals()) + " must be string", value=data__classifiers_item, name="" + (name_prefix or "data") + ".classifiers[{data__classifiers_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'trove-classifier', 'description': '`PyPI classifier `_.'}, rule='type') - if isinstance(data__classifiers_item, str): - if not custom_formats["trove-classifier"](data__classifiers_item): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".classifiers[{data__classifiers_x}]".format(**locals()) + " must be trove-classifier", value=data__classifiers_item, name="" + (name_prefix or "data") + ".classifiers[{data__classifiers_x}]".format(**locals()) + "", definition={'type': 'string', 'format': 'trove-classifier', 'description': '`PyPI classifier `_.'}, rule='format') - if "urls" in data_keys: - data_keys.remove("urls") - data__urls = data["urls"] - if not isinstance(data__urls, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".urls must be object", value=data__urls, name="" + (name_prefix or "data") + ".urls", definition={'type': 'object', 'description': 'URLs associated with the project in the form ``label => value``.', 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', 'format': 'url'}}}, rule='type') - data__urls_is_dict = isinstance(data__urls, dict) - if data__urls_is_dict: - data__urls_keys = set(data__urls.keys()) - for data__urls_key, data__urls_val in data__urls.items(): - if REGEX_PATTERNS['^.+$'].search(data__urls_key): - if data__urls_key in data__urls_keys: - data__urls_keys.remove(data__urls_key) - if not isinstance(data__urls_val, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".urls.{data__urls_key}".format(**locals()) + " must be string", value=data__urls_val, name="" + (name_prefix or "data") + ".urls.{data__urls_key}".format(**locals()) + "", definition={'type': 'string', 'format': 'url'}, rule='type') - if isinstance(data__urls_val, str): - if not custom_formats["url"](data__urls_val): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".urls.{data__urls_key}".format(**locals()) + " must be url", value=data__urls_val, name="" + (name_prefix or "data") + ".urls.{data__urls_key}".format(**locals()) + "", definition={'type': 'string', 'format': 'url'}, rule='format') - if data__urls_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".urls must not contain "+str(data__urls_keys)+" properties", value=data__urls, name="" + (name_prefix or "data") + ".urls", definition={'type': 'object', 'description': 'URLs associated with the project in the form ``label => value``.', 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', 'format': 'url'}}}, rule='additionalProperties') - if "scripts" in data_keys: - data_keys.remove("scripts") - data__scripts = data["scripts"] - validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata___definitions_entry_point_group(data__scripts, custom_formats, (name_prefix or "data") + ".scripts") - if "gui-scripts" in data_keys: - data_keys.remove("gui-scripts") - data__guiscripts = data["gui-scripts"] - validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata___definitions_entry_point_group(data__guiscripts, custom_formats, (name_prefix or "data") + ".gui-scripts") - if "entry-points" in data_keys: - data_keys.remove("entry-points") - data__entrypoints = data["entry-points"] - data__entrypoints_is_dict = isinstance(data__entrypoints, dict) - if data__entrypoints_is_dict: - data__entrypoints_keys = set(data__entrypoints.keys()) - for data__entrypoints_key, data__entrypoints_val in data__entrypoints.items(): - if REGEX_PATTERNS['^.+$'].search(data__entrypoints_key): - if data__entrypoints_key in data__entrypoints_keys: - data__entrypoints_keys.remove(data__entrypoints_key) - validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata___definitions_entry_point_group(data__entrypoints_val, custom_formats, (name_prefix or "data") + ".entry-points.{data__entrypoints_key}") - if data__entrypoints_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".entry-points must not contain "+str(data__entrypoints_keys)+" properties", value=data__entrypoints, name="" + (name_prefix or "data") + ".entry-points", definition={'$$description': ['Instruct the installer to expose the given modules/functions via', '``entry-point`` discovery mechanism (useful for plugins).', 'More information available in the `Python packaging guide', '`_.'], 'propertyNames': {'format': 'python-entrypoint-group'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}}}, rule='additionalProperties') - data__entrypoints_len = len(data__entrypoints) - if data__entrypoints_len != 0: - data__entrypoints_property_names = True - for data__entrypoints_key in data__entrypoints: - try: - if isinstance(data__entrypoints_key, str): - if not custom_formats["python-entrypoint-group"](data__entrypoints_key): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".entry-points must be python-entrypoint-group", value=data__entrypoints_key, name="" + (name_prefix or "data") + ".entry-points", definition={'format': 'python-entrypoint-group'}, rule='format') - except JsonSchemaValueException: - data__entrypoints_property_names = False - if not data__entrypoints_property_names: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".entry-points must be named by propertyName definition", value=data__entrypoints, name="" + (name_prefix or "data") + ".entry-points", definition={'$$description': ['Instruct the installer to expose the given modules/functions via', '``entry-point`` discovery mechanism (useful for plugins).', 'More information available in the `Python packaging guide', '`_.'], 'propertyNames': {'format': 'python-entrypoint-group'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}}}, rule='propertyNames') - if "dependencies" in data_keys: - data_keys.remove("dependencies") - data__dependencies = data["dependencies"] - if not isinstance(data__dependencies, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dependencies must be array", value=data__dependencies, name="" + (name_prefix or "data") + ".dependencies", definition={'type': 'array', 'description': 'Project (mandatory) dependencies.', 'items': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}, rule='type') - data__dependencies_is_list = isinstance(data__dependencies, (list, tuple)) - if data__dependencies_is_list: - data__dependencies_len = len(data__dependencies) - for data__dependencies_x, data__dependencies_item in enumerate(data__dependencies): - validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata___definitions_dependency(data__dependencies_item, custom_formats, (name_prefix or "data") + ".dependencies[{data__dependencies_x}]") - if "optional-dependencies" in data_keys: - data_keys.remove("optional-dependencies") - data__optionaldependencies = data["optional-dependencies"] - if not isinstance(data__optionaldependencies, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".optional-dependencies must be object", value=data__optionaldependencies, name="" + (name_prefix or "data") + ".optional-dependencies", definition={'type': 'object', 'description': 'Optional dependency for the project', 'propertyNames': {'format': 'pep508-identifier'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'array', 'items': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}}, rule='type') - data__optionaldependencies_is_dict = isinstance(data__optionaldependencies, dict) - if data__optionaldependencies_is_dict: - data__optionaldependencies_keys = set(data__optionaldependencies.keys()) - for data__optionaldependencies_key, data__optionaldependencies_val in data__optionaldependencies.items(): - if REGEX_PATTERNS['^.+$'].search(data__optionaldependencies_key): - if data__optionaldependencies_key in data__optionaldependencies_keys: - data__optionaldependencies_keys.remove(data__optionaldependencies_key) - if not isinstance(data__optionaldependencies_val, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".optional-dependencies.{data__optionaldependencies_key}".format(**locals()) + " must be array", value=data__optionaldependencies_val, name="" + (name_prefix or "data") + ".optional-dependencies.{data__optionaldependencies_key}".format(**locals()) + "", definition={'type': 'array', 'items': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}, rule='type') - data__optionaldependencies_val_is_list = isinstance(data__optionaldependencies_val, (list, tuple)) - if data__optionaldependencies_val_is_list: - data__optionaldependencies_val_len = len(data__optionaldependencies_val) - for data__optionaldependencies_val_x, data__optionaldependencies_val_item in enumerate(data__optionaldependencies_val): - validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata___definitions_dependency(data__optionaldependencies_val_item, custom_formats, (name_prefix or "data") + ".optional-dependencies.{data__optionaldependencies_key}[{data__optionaldependencies_val_x}]") - if data__optionaldependencies_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".optional-dependencies must not contain "+str(data__optionaldependencies_keys)+" properties", value=data__optionaldependencies, name="" + (name_prefix or "data") + ".optional-dependencies", definition={'type': 'object', 'description': 'Optional dependency for the project', 'propertyNames': {'format': 'pep508-identifier'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'array', 'items': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}}, rule='additionalProperties') - data__optionaldependencies_len = len(data__optionaldependencies) - if data__optionaldependencies_len != 0: - data__optionaldependencies_property_names = True - for data__optionaldependencies_key in data__optionaldependencies: - try: - if isinstance(data__optionaldependencies_key, str): - if not custom_formats["pep508-identifier"](data__optionaldependencies_key): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".optional-dependencies must be pep508-identifier", value=data__optionaldependencies_key, name="" + (name_prefix or "data") + ".optional-dependencies", definition={'format': 'pep508-identifier'}, rule='format') - except JsonSchemaValueException: - data__optionaldependencies_property_names = False - if not data__optionaldependencies_property_names: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".optional-dependencies must be named by propertyName definition", value=data__optionaldependencies, name="" + (name_prefix or "data") + ".optional-dependencies", definition={'type': 'object', 'description': 'Optional dependency for the project', 'propertyNames': {'format': 'pep508-identifier'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'array', 'items': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}}, rule='propertyNames') - if "dynamic" in data_keys: - data_keys.remove("dynamic") - data__dynamic = data["dynamic"] - if not isinstance(data__dynamic, (list, tuple)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic must be array", value=data__dynamic, name="" + (name_prefix or "data") + ".dynamic", definition={'type': 'array', '$$description': ['Specifies which fields are intentionally unspecified and expected to be', 'dynamically provided by build tools'], 'items': {'enum': ['version', 'description', 'readme', 'requires-python', 'license', 'authors', 'maintainers', 'keywords', 'classifiers', 'urls', 'scripts', 'gui-scripts', 'entry-points', 'dependencies', 'optional-dependencies']}}, rule='type') - data__dynamic_is_list = isinstance(data__dynamic, (list, tuple)) - if data__dynamic_is_list: - data__dynamic_len = len(data__dynamic) - for data__dynamic_x, data__dynamic_item in enumerate(data__dynamic): - if data__dynamic_item not in ['version', 'description', 'readme', 'requires-python', 'license', 'authors', 'maintainers', 'keywords', 'classifiers', 'urls', 'scripts', 'gui-scripts', 'entry-points', 'dependencies', 'optional-dependencies']: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic[{data__dynamic_x}]".format(**locals()) + " must be one of ['version', 'description', 'readme', 'requires-python', 'license', 'authors', 'maintainers', 'keywords', 'classifiers', 'urls', 'scripts', 'gui-scripts', 'entry-points', 'dependencies', 'optional-dependencies']", value=data__dynamic_item, name="" + (name_prefix or "data") + ".dynamic[{data__dynamic_x}]".format(**locals()) + "", definition={'enum': ['version', 'description', 'readme', 'requires-python', 'license', 'authors', 'maintainers', 'keywords', 'classifiers', 'urls', 'scripts', 'gui-scripts', 'entry-points', 'dependencies', 'optional-dependencies']}, rule='enum') - if data_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + " must not contain "+str(data_keys)+" properties", value=data, name="" + (name_prefix or "data") + "", definition={'$schema': 'http://json-schema.org/draft-07/schema', '$id': 'https://packaging.python.org/en/latest/specifications/declaring-project-metadata/', 'title': 'Package metadata stored in the ``project`` table', '$$description': ['Data structure for the **project** table inside ``pyproject.toml``', '(as initially defined in :pep:`621`)'], 'type': 'object', 'properties': {'name': {'type': 'string', 'description': 'The name (primary identifier) of the project. MUST be statically defined.', 'format': 'pep508-identifier'}, 'version': {'type': 'string', 'description': 'The version of the project as supported by :pep:`440`.', 'format': 'pep440'}, 'description': {'type': 'string', '$$description': ['The `summary description of the project', '`_']}, 'readme': {'$$description': ['`Full/detailed description of the project in the form of a README', '`_', "with meaning similar to the one defined in `core metadata's Description", '`_'], 'oneOf': [{'type': 'string', '$$description': ['Relative path to a text file (UTF-8) containing the full description', 'of the project. If the file path ends in case-insensitive ``.md`` or', '``.rst`` suffixes, then the content-type is respectively', '``text/markdown`` or ``text/x-rst``']}, {'type': 'object', 'allOf': [{'anyOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to a text file containing the full description', 'of the project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', 'description': 'Full text describing the project.'}}, 'required': ['text']}]}, {'properties': {'content-type': {'type': 'string', '$$description': ['Content-type (:rfc:`1341`) of the full description', '(e.g. ``text/markdown``). The ``charset`` parameter is assumed', 'UTF-8 when not present.'], '$comment': 'TODO: add regex pattern or format?'}}, 'required': ['content-type']}]}]}, 'requires-python': {'type': 'string', 'format': 'pep508-versionspec', '$$description': ['`The Python version requirements of the project', '`_.']}, 'license': {'description': '`Project license `_.', 'oneOf': [{'properties': {'file': {'type': 'string', '$$description': ['Relative path to the file (UTF-8) which contains the license for the', 'project.']}}, 'required': ['file']}, {'properties': {'text': {'type': 'string', '$$description': ['The license of the project whose meaning is that of the', '`License field from the core metadata', '`_.']}}, 'required': ['text']}]}, 'authors': {'type': 'array', 'items': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, '$$description': ["The people or organizations considered to be the 'authors' of the project.", 'The exact meaning is open to interpretation (e.g. original or primary authors,', 'current maintainers, or owners of the package).']}, 'maintainers': {'type': 'array', 'items': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, '$$description': ["The people or organizations considered to be the 'maintainers' of the project.", 'Similarly to ``authors``, the exact meaning is open to interpretation.']}, 'keywords': {'type': 'array', 'items': {'type': 'string'}, 'description': 'List of keywords to assist searching for the distribution in a larger catalog.'}, 'classifiers': {'type': 'array', 'items': {'type': 'string', 'format': 'trove-classifier', 'description': '`PyPI classifier `_.'}, '$$description': ['`Trove classifiers `_', 'which apply to the project.']}, 'urls': {'type': 'object', 'description': 'URLs associated with the project in the form ``label => value``.', 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', 'format': 'url'}}}, 'scripts': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'gui-scripts': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'entry-points': {'$$description': ['Instruct the installer to expose the given modules/functions via', '``entry-point`` discovery mechanism (useful for plugins).', 'More information available in the `Python packaging guide', '`_.'], 'propertyNames': {'format': 'python-entrypoint-group'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}}}, 'dependencies': {'type': 'array', 'description': 'Project (mandatory) dependencies.', 'items': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}, 'optional-dependencies': {'type': 'object', 'description': 'Optional dependency for the project', 'propertyNames': {'format': 'pep508-identifier'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'array', 'items': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}}, 'dynamic': {'type': 'array', '$$description': ['Specifies which fields are intentionally unspecified and expected to be', 'dynamically provided by build tools'], 'items': {'enum': ['version', 'description', 'readme', 'requires-python', 'license', 'authors', 'maintainers', 'keywords', 'classifiers', 'urls', 'scripts', 'gui-scripts', 'entry-points', 'dependencies', 'optional-dependencies']}}}, 'required': ['name'], 'additionalProperties': False, 'if': {'not': {'required': ['dynamic'], 'properties': {'dynamic': {'contains': {'const': 'version'}, '$$description': ['version is listed in ``dynamic``']}}}, '$$comment': ['According to :pep:`621`:', ' If the core metadata specification lists a field as "Required", then', ' the metadata MUST specify the field statically or list it in dynamic', 'In turn, `core metadata`_ defines:', ' The required fields are: Metadata-Version, Name, Version.', ' All the other fields are optional.', 'Since ``Metadata-Version`` is defined by the build back-end, ``name`` and', '``version`` are the only mandatory information in ``pyproject.toml``.', '.. _core metadata: https://packaging.python.org/specifications/core-metadata/']}, 'then': {'required': ['version'], '$$description': ['version should be statically defined in the ``version`` field']}, 'definitions': {'author': {'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, 'entry-point-group': {'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, 'dependency': {'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}}}, rule='additionalProperties') - try: - try: - data_is_dict = isinstance(data, dict) - if data_is_dict: - data_len = len(data) - if not all(prop in data for prop in ['dynamic']): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must contain ['dynamic'] properties", value=data, name="" + (name_prefix or "data") + "", definition={'required': ['dynamic'], 'properties': {'dynamic': {'contains': {'const': 'version'}, '$$description': ['version is listed in ``dynamic``']}}}, rule='required') - data_keys = set(data.keys()) - if "dynamic" in data_keys: - data_keys.remove("dynamic") - data__dynamic = data["dynamic"] - data__dynamic_is_list = isinstance(data__dynamic, (list, tuple)) - if data__dynamic_is_list: - data__dynamic_contains = False - for data__dynamic_key in data__dynamic: - try: - if data__dynamic_key != "version": - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic must be same as const definition: version", value=data__dynamic_key, name="" + (name_prefix or "data") + ".dynamic", definition={'const': 'version'}, rule='const') - data__dynamic_contains = True - break - except JsonSchemaValueException: pass - if not data__dynamic_contains: - raise JsonSchemaValueException("" + (name_prefix or "data") + ".dynamic must contain one of contains definition", value=data__dynamic, name="" + (name_prefix or "data") + ".dynamic", definition={'contains': {'const': 'version'}, '$$description': ['version is listed in ``dynamic``']}, rule='contains') - except JsonSchemaValueException: pass - else: - raise JsonSchemaValueException("" + (name_prefix or "data") + " must NOT match a disallowed definition", value=data, name="" + (name_prefix or "data") + "", definition={'not': {'required': ['dynamic'], 'properties': {'dynamic': {'contains': {'const': 'version'}, '$$description': ['version is listed in ``dynamic``']}}}, '$$comment': ['According to :pep:`621`:', ' If the core metadata specification lists a field as "Required", then', ' the metadata MUST specify the field statically or list it in dynamic', 'In turn, `core metadata`_ defines:', ' The required fields are: Metadata-Version, Name, Version.', ' All the other fields are optional.', 'Since ``Metadata-Version`` is defined by the build back-end, ``name`` and', '``version`` are the only mandatory information in ``pyproject.toml``.', '.. _core metadata: https://packaging.python.org/specifications/core-metadata/']}, rule='not') - except JsonSchemaValueException: - pass - else: - data_is_dict = isinstance(data, dict) - if data_is_dict: - data_len = len(data) - if not all(prop in data for prop in ['version']): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must contain ['version'] properties", value=data, name="" + (name_prefix or "data") + "", definition={'required': ['version'], '$$description': ['version should be statically defined in the ``version`` field']}, rule='required') - return data - -def validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata___definitions_dependency(data, custom_formats={}, name_prefix=None): - if not isinstance(data, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be string", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}, rule='type') - if isinstance(data, str): - if not custom_formats["pep508"](data): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be pep508", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/dependency', 'title': 'Dependency', 'type': 'string', 'description': 'Project dependency specification according to PEP 508', 'format': 'pep508'}, rule='format') - return data - -def validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata___definitions_entry_point_group(data, custom_formats={}, name_prefix=None): - if not isinstance(data, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be object", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, rule='type') - data_is_dict = isinstance(data, dict) - if data_is_dict: - data_keys = set(data.keys()) - for data_key, data_val in data.items(): - if REGEX_PATTERNS['^.+$'].search(data_key): - if data_key in data_keys: - data_keys.remove(data_key) - if not isinstance(data_val, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".{data_key}".format(**locals()) + " must be string", value=data_val, name="" + (name_prefix or "data") + ".{data_key}".format(**locals()) + "", definition={'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}, rule='type') - if isinstance(data_val, str): - if not custom_formats["python-entrypoint-reference"](data_val): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".{data_key}".format(**locals()) + " must be python-entrypoint-reference", value=data_val, name="" + (name_prefix or "data") + ".{data_key}".format(**locals()) + "", definition={'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}, rule='format') - if data_keys: - raise JsonSchemaValueException("" + (name_prefix or "data") + " must not contain "+str(data_keys)+" properties", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, rule='additionalProperties') - data_len = len(data) - if data_len != 0: - data_property_names = True - for data_key in data: - try: - if isinstance(data_key, str): - if not custom_formats["python-entrypoint-name"](data_key): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be python-entrypoint-name", value=data_key, name="" + (name_prefix or "data") + "", definition={'format': 'python-entrypoint-name'}, rule='format') - except JsonSchemaValueException: - data_property_names = False - if not data_property_names: - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be named by propertyName definition", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/entry-point-group', 'title': 'Entry-points', 'type': 'object', '$$description': ['Entry-points are grouped together to indicate what sort of capabilities they', 'provide.', 'See the `packaging guides', '`_', 'and `setuptools docs', '`_', 'for more information.'], 'propertyNames': {'format': 'python-entrypoint-name'}, 'additionalProperties': False, 'patternProperties': {'^.+$': {'type': 'string', '$$description': ['Reference to a Python object. It is either in the form', '``importable.module``, or ``importable.module:object.attr``.'], 'format': 'python-entrypoint-reference', '$comment': 'https://packaging.python.org/specifications/entry-points/'}}}, rule='propertyNames') - return data - -def validate_https___packaging_python_org_en_latest_specifications_declaring_project_metadata___definitions_author(data, custom_formats={}, name_prefix=None): - if not isinstance(data, (dict)): - raise JsonSchemaValueException("" + (name_prefix or "data") + " must be object", value=data, name="" + (name_prefix or "data") + "", definition={'$id': '#/definitions/author', 'title': 'Author or Maintainer', '$comment': 'https://www.python.org/dev/peps/pep-0621/#authors-maintainers', 'type': 'object', 'properties': {'name': {'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, 'email': {'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}}}, rule='type') - data_is_dict = isinstance(data, dict) - if data_is_dict: - data_keys = set(data.keys()) - if "name" in data_keys: - data_keys.remove("name") - data__name = data["name"] - if not isinstance(data__name, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".name must be string", value=data__name, name="" + (name_prefix or "data") + ".name", definition={'type': 'string', '$$description': ['MUST be a valid email name, i.e. whatever can be put as a name, before an', 'email, in :rfc:`822`.']}, rule='type') - if "email" in data_keys: - data_keys.remove("email") - data__email = data["email"] - if not isinstance(data__email, (str)): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".email must be string", value=data__email, name="" + (name_prefix or "data") + ".email", definition={'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}, rule='type') - if isinstance(data__email, str): - if not REGEX_PATTERNS["idn-email_re_pattern"].match(data__email): - raise JsonSchemaValueException("" + (name_prefix or "data") + ".email must be idn-email", value=data__email, name="" + (name_prefix or "data") + ".email", definition={'type': 'string', 'format': 'idn-email', 'description': 'MUST be a valid email address'}, rule='format') - return data \ No newline at end of file diff --git a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/formats.py b/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/formats.py deleted file mode 100755 index 638ac11..0000000 --- a/venv/lib/python3.11/site-packages/setuptools/config/_validate_pyproject/formats.py +++ /dev/null @@ -1,259 +0,0 @@ -import logging -import os -import re -import string -import typing -from itertools import chain as _chain - -_logger = logging.getLogger(__name__) - -# ------------------------------------------------------------------------------------- -# PEP 440 - -VERSION_PATTERN = r""" - v? - (?: - (?:(?P[0-9]+)!)? # epoch - (?P[0-9]+(?:\.[0-9]+)*) # release segment - (?P
                                          # pre-release
-            [-_\.]?
-            (?P(a|b|c|rc|alpha|beta|pre|preview))
-            [-_\.]?
-            (?P[0-9]+)?
-        )?
-        (?P                                         # post release
-            (?:-(?P[0-9]+))
-            |
-            (?:
-                [-_\.]?
-                (?Ppost|rev|r)
-                [-_\.]?
-                (?P[0-9]+)?
-            )
-        )?
-        (?P                                          # dev release
-            [-_\.]?
-            (?Pdev)
-            [-_\.]?
-            (?P[0-9]+)?
-        )?
-    )
-    (?:\+(?P[a-z0-9]+(?:[-_\.][a-z0-9]+)*))?       # local version
-"""
-
-VERSION_REGEX = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.X | re.I)
-
-
-def pep440(version: str) -> bool:
-    return VERSION_REGEX.match(version) is not None
-
-
-# -------------------------------------------------------------------------------------
-# PEP 508
-
-PEP508_IDENTIFIER_PATTERN = r"([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])"
-PEP508_IDENTIFIER_REGEX = re.compile(f"^{PEP508_IDENTIFIER_PATTERN}$", re.I)
-
-
-def pep508_identifier(name: str) -> bool:
-    return PEP508_IDENTIFIER_REGEX.match(name) is not None
-
-
-try:
-    try:
-        from packaging import requirements as _req
-    except ImportError:  # pragma: no cover
-        # let's try setuptools vendored version
-        from setuptools._vendor.packaging import requirements as _req  # type: ignore
-
-    def pep508(value: str) -> bool:
-        try:
-            _req.Requirement(value)
-            return True
-        except _req.InvalidRequirement:
-            return False
-
-except ImportError:  # pragma: no cover
-    _logger.warning(
-        "Could not find an installation of `packaging`. Requirements, dependencies and "
-        "versions might not be validated. "
-        "To enforce validation, please install `packaging`."
-    )
-
-    def pep508(value: str) -> bool:
-        return True
-
-
-def pep508_versionspec(value: str) -> bool:
-    """Expression that can be used to specify/lock versions (including ranges)"""
-    if any(c in value for c in (";", "]", "@")):
-        # In PEP 508:
-        # conditional markers, extras and URL specs are not included in the
-        # versionspec
-        return False
-    # Let's pretend we have a dependency called `requirement` with the given
-    # version spec, then we can re-use the pep508 function for validation:
-    return pep508(f"requirement{value}")
-
-
-# -------------------------------------------------------------------------------------
-# PEP 517
-
-
-def pep517_backend_reference(value: str) -> bool:
-    module, _, obj = value.partition(":")
-    identifiers = (i.strip() for i in _chain(module.split("."), obj.split(".")))
-    return all(python_identifier(i) for i in identifiers if i)
-
-
-# -------------------------------------------------------------------------------------
-# Classifiers - PEP 301
-
-
-def _download_classifiers() -> str:
-    import ssl
-    from email.message import Message
-    from urllib.request import urlopen
-
-    url = "https://pypi.org/pypi?:action=list_classifiers"
-    context = ssl.create_default_context()
-    with urlopen(url, context=context) as response:
-        headers = Message()
-        headers["content_type"] = response.getheader("content-type", "text/plain")
-        return response.read().decode(headers.get_param("charset", "utf-8"))
-
-
-class _TroveClassifier:
-    """The ``trove_classifiers`` package is the official way of validating classifiers,
-    however this package might not be always available.
-    As a workaround we can still download a list from PyPI.
-    We also don't want to be over strict about it, so simply skipping silently is an
-    option (classifiers will be validated anyway during the upload to PyPI).
-    """
-
-    def __init__(self):
-        self.downloaded: typing.Union[None, False, typing.Set[str]] = None
-        self._skip_download = False
-        # None => not cached yet
-        # False => cache not available
-        self.__name__ = "trove_classifier"  # Emulate a public function
-
-    def _disable_download(self):
-        # This is a private API. Only setuptools has the consent of using it.
-        self._skip_download = True
-
-    def __call__(self, value: str) -> bool:
-        if self.downloaded is False or self._skip_download is True:
-            return True
-
-        if os.getenv("NO_NETWORK") or os.getenv("VALIDATE_PYPROJECT_NO_NETWORK"):
-            self.downloaded = False
-            msg = (
-                "Install ``trove-classifiers`` to ensure proper validation. "
-                "Skipping download of classifiers list from PyPI (NO_NETWORK)."
-            )
-            _logger.debug(msg)
-            return True
-
-        if self.downloaded is None:
-            msg = (
-                "Install ``trove-classifiers`` to ensure proper validation. "
-                "Meanwhile a list of classifiers will be downloaded from PyPI."
-            )
-            _logger.debug(msg)
-            try:
-                self.downloaded = set(_download_classifiers().splitlines())
-            except Exception:
-                self.downloaded = False
-                _logger.debug("Problem with download, skipping validation")
-                return True
-
-        return value in self.downloaded or value.lower().startswith("private ::")
-
-
-try:
-    from trove_classifiers import classifiers as _trove_classifiers
-
-    def trove_classifier(value: str) -> bool:
-        return value in _trove_classifiers or value.lower().startswith("private ::")
-
-except ImportError:  # pragma: no cover
-    trove_classifier = _TroveClassifier()
-
-
-# -------------------------------------------------------------------------------------
-# Non-PEP related
-
-
-def url(value: str) -> bool:
-    from urllib.parse import urlparse
-
-    try:
-        parts = urlparse(value)
-        if not parts.scheme:
-            _logger.warning(
-                "For maximum compatibility please make sure to include a "
-                "`scheme` prefix in your URL (e.g. 'http://'). "
-                f"Given value: {value}"
-            )
-            if not (value.startswith("/") or value.startswith("\\") or "@" in value):
-                parts = urlparse(f"http://{value}")
-
-        return bool(parts.scheme and parts.netloc)
-    except Exception:
-        return False
-
-
-# https://packaging.python.org/specifications/entry-points/
-ENTRYPOINT_PATTERN = r"[^\[\s=]([^=]*[^\s=])?"
-ENTRYPOINT_REGEX = re.compile(f"^{ENTRYPOINT_PATTERN}$", re.I)
-RECOMMEDED_ENTRYPOINT_PATTERN = r"[\w.-]+"
-RECOMMEDED_ENTRYPOINT_REGEX = re.compile(f"^{RECOMMEDED_ENTRYPOINT_PATTERN}$", re.I)
-ENTRYPOINT_GROUP_PATTERN = r"\w+(\.\w+)*"
-ENTRYPOINT_GROUP_REGEX = re.compile(f"^{ENTRYPOINT_GROUP_PATTERN}$", re.I)
-
-
-def python_identifier(value: str) -> bool:
-    return value.isidentifier()
-
-
-def python_qualified_identifier(value: str) -> bool:
-    if value.startswith(".") or value.endswith("."):
-        return False
-    return all(python_identifier(m) for m in value.split("."))
-
-
-def python_module_name(value: str) -> bool:
-    return python_qualified_identifier(value)
-
-
-def python_entrypoint_group(value: str) -> bool:
-    return ENTRYPOINT_GROUP_REGEX.match(value) is not None
-
-
-def python_entrypoint_name(value: str) -> bool:
-    if not ENTRYPOINT_REGEX.match(value):
-        return False
-    if not RECOMMEDED_ENTRYPOINT_REGEX.match(value):
-        msg = f"Entry point `{value}` does not follow recommended pattern: "
-        msg += RECOMMEDED_ENTRYPOINT_PATTERN
-        _logger.warning(msg)
-    return True
-
-
-def python_entrypoint_reference(value: str) -> bool:
-    module, _, rest = value.partition(":")
-    if "[" in rest:
-        obj, _, extras_ = rest.partition("[")
-        if extras_.strip()[-1] != "]":
-            return False
-        extras = (x.strip() for x in extras_.strip(string.whitespace + "[]").split(","))
-        if not all(pep508_identifier(e) for e in extras):
-            return False
-        _logger.warning(f"`{value}` - using extras for entry points is not recommended")
-    else:
-        obj = rest
-
-    module_parts = module.split(".")
-    identifiers = _chain(module_parts, obj.split(".")) if rest else module_parts
-    return all(python_identifier(i.strip()) for i in identifiers)
diff --git a/venv/lib/python3.11/site-packages/setuptools/config/expand.py b/venv/lib/python3.11/site-packages/setuptools/config/expand.py
deleted file mode 100755
index c8db2c4..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/config/expand.py
+++ /dev/null
@@ -1,462 +0,0 @@
-"""Utility functions to expand configuration directives or special values
-(such glob patterns).
-
-We can split the process of interpreting configuration files into 2 steps:
-
-1. The parsing the file contents from strings to value objects
-   that can be understand by Python (for example a string with a comma
-   separated list of keywords into an actual Python list of strings).
-
-2. The expansion (or post-processing) of these values according to the
-   semantics ``setuptools`` assign to them (for example a configuration field
-   with the ``file:`` directive should be expanded from a list of file paths to
-   a single string with the contents of those files concatenated)
-
-This module focus on the second step, and therefore allow sharing the expansion
-functions among several configuration file formats.
-
-**PRIVATE MODULE**: API reserved for setuptools internal usage only.
-"""
-import ast
-import importlib
-import io
-import os
-import pathlib
-import sys
-import warnings
-from glob import iglob
-from configparser import ConfigParser
-from importlib.machinery import ModuleSpec
-from itertools import chain
-from typing import (
-    TYPE_CHECKING,
-    Callable,
-    Dict,
-    Iterable,
-    Iterator,
-    List,
-    Mapping,
-    Optional,
-    Tuple,
-    TypeVar,
-    Union,
-    cast
-)
-from pathlib import Path
-from types import ModuleType
-
-from distutils.errors import DistutilsOptionError
-
-from .._path import same_path as _same_path
-
-if TYPE_CHECKING:
-    from setuptools.dist import Distribution  # noqa
-    from setuptools.discovery import ConfigDiscovery  # noqa
-    from distutils.dist import DistributionMetadata  # noqa
-
-chain_iter = chain.from_iterable
-_Path = Union[str, os.PathLike]
-_K = TypeVar("_K")
-_V = TypeVar("_V", covariant=True)
-
-
-class StaticModule:
-    """Proxy to a module object that avoids executing arbitrary code."""
-
-    def __init__(self, name: str, spec: ModuleSpec):
-        module = ast.parse(pathlib.Path(spec.origin).read_bytes())
-        vars(self).update(locals())
-        del self.self
-
-    def _find_assignments(self) -> Iterator[Tuple[ast.AST, ast.AST]]:
-        for statement in self.module.body:
-            if isinstance(statement, ast.Assign):
-                yield from ((target, statement.value) for target in statement.targets)
-            elif isinstance(statement, ast.AnnAssign) and statement.value:
-                yield (statement.target, statement.value)
-
-    def __getattr__(self, attr):
-        """Attempt to load an attribute "statically", via :func:`ast.literal_eval`."""
-        try:
-            return next(
-                ast.literal_eval(value)
-                for target, value in self._find_assignments()
-                if isinstance(target, ast.Name) and target.id == attr
-            )
-        except Exception as e:
-            raise AttributeError(f"{self.name} has no attribute {attr}") from e
-
-
-def glob_relative(
-    patterns: Iterable[str], root_dir: Optional[_Path] = None
-) -> List[str]:
-    """Expand the list of glob patterns, but preserving relative paths.
-
-    :param list[str] patterns: List of glob patterns
-    :param str root_dir: Path to which globs should be relative
-                         (current directory by default)
-    :rtype: list
-    """
-    glob_characters = {'*', '?', '[', ']', '{', '}'}
-    expanded_values = []
-    root_dir = root_dir or os.getcwd()
-    for value in patterns:
-
-        # Has globby characters?
-        if any(char in value for char in glob_characters):
-            # then expand the glob pattern while keeping paths *relative*:
-            glob_path = os.path.abspath(os.path.join(root_dir, value))
-            expanded_values.extend(sorted(
-                os.path.relpath(path, root_dir).replace(os.sep, "/")
-                for path in iglob(glob_path, recursive=True)))
-
-        else:
-            # take the value as-is
-            path = os.path.relpath(value, root_dir).replace(os.sep, "/")
-            expanded_values.append(path)
-
-    return expanded_values
-
-
-def read_files(filepaths: Union[str, bytes, Iterable[_Path]], root_dir=None) -> str:
-    """Return the content of the files concatenated using ``\n`` as str
-
-    This function is sandboxed and won't reach anything outside ``root_dir``
-
-    (By default ``root_dir`` is the current directory).
-    """
-    from setuptools.extern.more_itertools import always_iterable
-
-    root_dir = os.path.abspath(root_dir or os.getcwd())
-    _filepaths = (os.path.join(root_dir, path) for path in always_iterable(filepaths))
-    return '\n'.join(
-        _read_file(path)
-        for path in _filter_existing_files(_filepaths)
-        if _assert_local(path, root_dir)
-    )
-
-
-def _filter_existing_files(filepaths: Iterable[_Path]) -> Iterator[_Path]:
-    for path in filepaths:
-        if os.path.isfile(path):
-            yield path
-        else:
-            warnings.warn(f"File {path!r} cannot be found")
-
-
-def _read_file(filepath: Union[bytes, _Path]) -> str:
-    with io.open(filepath, encoding='utf-8') as f:
-        return f.read()
-
-
-def _assert_local(filepath: _Path, root_dir: str):
-    if Path(os.path.abspath(root_dir)) not in Path(os.path.abspath(filepath)).parents:
-        msg = f"Cannot access {filepath!r} (or anything outside {root_dir!r})"
-        raise DistutilsOptionError(msg)
-
-    return True
-
-
-def read_attr(
-    attr_desc: str,
-    package_dir: Optional[Mapping[str, str]] = None,
-    root_dir: Optional[_Path] = None
-):
-    """Reads the value of an attribute from a module.
-
-    This function will try to read the attributed statically first
-    (via :func:`ast.literal_eval`), and only evaluate the module if it fails.
-
-    Examples:
-        read_attr("package.attr")
-        read_attr("package.module.attr")
-
-    :param str attr_desc: Dot-separated string describing how to reach the
-        attribute (see examples above)
-    :param dict[str, str] package_dir: Mapping of package names to their
-        location in disk (represented by paths relative to ``root_dir``).
-    :param str root_dir: Path to directory containing all the packages in
-        ``package_dir`` (current directory by default).
-    :rtype: str
-    """
-    root_dir = root_dir or os.getcwd()
-    attrs_path = attr_desc.strip().split('.')
-    attr_name = attrs_path.pop()
-    module_name = '.'.join(attrs_path)
-    module_name = module_name or '__init__'
-    _parent_path, path, module_name = _find_module(module_name, package_dir, root_dir)
-    spec = _find_spec(module_name, path)
-
-    try:
-        return getattr(StaticModule(module_name, spec), attr_name)
-    except Exception:
-        # fallback to evaluate module
-        module = _load_spec(spec, module_name)
-        return getattr(module, attr_name)
-
-
-def _find_spec(module_name: str, module_path: Optional[_Path]) -> ModuleSpec:
-    spec = importlib.util.spec_from_file_location(module_name, module_path)
-    spec = spec or importlib.util.find_spec(module_name)
-
-    if spec is None:
-        raise ModuleNotFoundError(module_name)
-
-    return spec
-
-
-def _load_spec(spec: ModuleSpec, module_name: str) -> ModuleType:
-    name = getattr(spec, "__name__", module_name)
-    if name in sys.modules:
-        return sys.modules[name]
-    module = importlib.util.module_from_spec(spec)
-    sys.modules[name] = module  # cache (it also ensures `==` works on loaded items)
-    spec.loader.exec_module(module)  # type: ignore
-    return module
-
-
-def _find_module(
-    module_name: str, package_dir: Optional[Mapping[str, str]], root_dir: _Path
-) -> Tuple[_Path, Optional[str], str]:
-    """Given a module (that could normally be imported by ``module_name``
-    after the build is complete), find the path to the parent directory where
-    it is contained and the canonical name that could be used to import it
-    considering the ``package_dir`` in the build configuration and ``root_dir``
-    """
-    parent_path = root_dir
-    module_parts = module_name.split('.')
-    if package_dir:
-        if module_parts[0] in package_dir:
-            # A custom path was specified for the module we want to import
-            custom_path = package_dir[module_parts[0]]
-            parts = custom_path.rsplit('/', 1)
-            if len(parts) > 1:
-                parent_path = os.path.join(root_dir, parts[0])
-                parent_module = parts[1]
-            else:
-                parent_module = custom_path
-            module_name = ".".join([parent_module, *module_parts[1:]])
-        elif '' in package_dir:
-            # A custom parent directory was specified for all root modules
-            parent_path = os.path.join(root_dir, package_dir[''])
-
-    path_start = os.path.join(parent_path, *module_name.split("."))
-    candidates = chain(
-        (f"{path_start}.py", os.path.join(path_start, "__init__.py")),
-        iglob(f"{path_start}.*")
-    )
-    module_path = next((x for x in candidates if os.path.isfile(x)), None)
-    return parent_path, module_path, module_name
-
-
-def resolve_class(
-    qualified_class_name: str,
-    package_dir: Optional[Mapping[str, str]] = None,
-    root_dir: Optional[_Path] = None
-) -> Callable:
-    """Given a qualified class name, return the associated class object"""
-    root_dir = root_dir or os.getcwd()
-    idx = qualified_class_name.rfind('.')
-    class_name = qualified_class_name[idx + 1 :]
-    pkg_name = qualified_class_name[:idx]
-
-    _parent_path, path, module_name = _find_module(pkg_name, package_dir, root_dir)
-    module = _load_spec(_find_spec(module_name, path), module_name)
-    return getattr(module, class_name)
-
-
-def cmdclass(
-    values: Dict[str, str],
-    package_dir: Optional[Mapping[str, str]] = None,
-    root_dir: Optional[_Path] = None
-) -> Dict[str, Callable]:
-    """Given a dictionary mapping command names to strings for qualified class
-    names, apply :func:`resolve_class` to the dict values.
-    """
-    return {k: resolve_class(v, package_dir, root_dir) for k, v in values.items()}
-
-
-def find_packages(
-    *,
-    namespaces=True,
-    fill_package_dir: Optional[Dict[str, str]] = None,
-    root_dir: Optional[_Path] = None,
-    **kwargs
-) -> List[str]:
-    """Works similarly to :func:`setuptools.find_packages`, but with all
-    arguments given as keyword arguments. Moreover, ``where`` can be given
-    as a list (the results will be simply concatenated).
-
-    When the additional keyword argument ``namespaces`` is ``True``, it will
-    behave like :func:`setuptools.find_namespace_packages`` (i.e. include
-    implicit namespaces as per :pep:`420`).
-
-    The ``where`` argument will be considered relative to ``root_dir`` (or the current
-    working directory when ``root_dir`` is not given).
-
-    If the ``fill_package_dir`` argument is passed, this function will consider it as a
-    similar data structure to the ``package_dir`` configuration parameter add fill-in
-    any missing package location.
-
-    :rtype: list
-    """
-    from setuptools.discovery import construct_package_dir
-    from setuptools.extern.more_itertools import unique_everseen, always_iterable
-
-    if namespaces:
-        from setuptools.discovery import PEP420PackageFinder as PackageFinder
-    else:
-        from setuptools.discovery import PackageFinder  # type: ignore
-
-    root_dir = root_dir or os.curdir
-    where = kwargs.pop('where', ['.'])
-    packages: List[str] = []
-    fill_package_dir = {} if fill_package_dir is None else fill_package_dir
-    search = list(unique_everseen(always_iterable(where)))
-
-    if len(search) == 1 and all(not _same_path(search[0], x) for x in (".", root_dir)):
-        fill_package_dir.setdefault("", search[0])
-
-    for path in search:
-        package_path = _nest_path(root_dir, path)
-        pkgs = PackageFinder.find(package_path, **kwargs)
-        packages.extend(pkgs)
-        if pkgs and not (
-            fill_package_dir.get("") == path
-            or os.path.samefile(package_path, root_dir)
-        ):
-            fill_package_dir.update(construct_package_dir(pkgs, path))
-
-    return packages
-
-
-def _nest_path(parent: _Path, path: _Path) -> str:
-    path = parent if path in {".", ""} else os.path.join(parent, path)
-    return os.path.normpath(path)
-
-
-def version(value: Union[Callable, Iterable[Union[str, int]], str]) -> str:
-    """When getting the version directly from an attribute,
-    it should be normalised to string.
-    """
-    if callable(value):
-        value = value()
-
-    value = cast(Iterable[Union[str, int]], value)
-
-    if not isinstance(value, str):
-        if hasattr(value, '__iter__'):
-            value = '.'.join(map(str, value))
-        else:
-            value = '%s' % value
-
-    return value
-
-
-def canonic_package_data(package_data: dict) -> dict:
-    if "*" in package_data:
-        package_data[""] = package_data.pop("*")
-    return package_data
-
-
-def canonic_data_files(
-    data_files: Union[list, dict], root_dir: Optional[_Path] = None
-) -> List[Tuple[str, List[str]]]:
-    """For compatibility with ``setup.py``, ``data_files`` should be a list
-    of pairs instead of a dict.
-
-    This function also expands glob patterns.
-    """
-    if isinstance(data_files, list):
-        return data_files
-
-    return [
-        (dest, glob_relative(patterns, root_dir))
-        for dest, patterns in data_files.items()
-    ]
-
-
-def entry_points(text: str, text_source="entry-points") -> Dict[str, dict]:
-    """Given the contents of entry-points file,
-    process it into a 2-level dictionary (``dict[str, dict[str, str]]``).
-    The first level keys are entry-point groups, the second level keys are
-    entry-point names, and the second level values are references to objects
-    (that correspond to the entry-point value).
-    """
-    parser = ConfigParser(default_section=None, delimiters=("=",))  # type: ignore
-    parser.optionxform = str  # case sensitive
-    parser.read_string(text, text_source)
-    groups = {k: dict(v.items()) for k, v in parser.items()}
-    groups.pop(parser.default_section, None)
-    return groups
-
-
-class EnsurePackagesDiscovered:
-    """Some expand functions require all the packages to already be discovered before
-    they run, e.g. :func:`read_attr`, :func:`resolve_class`, :func:`cmdclass`.
-
-    Therefore in some cases we will need to run autodiscovery during the evaluation of
-    the configuration. However, it is better to postpone calling package discovery as
-    much as possible, because some parameters can influence it (e.g. ``package_dir``),
-    and those might not have been processed yet.
-    """
-
-    def __init__(self, distribution: "Distribution"):
-        self._dist = distribution
-        self._called = False
-
-    def __call__(self):
-        """Trigger the automatic package discovery, if it is still necessary."""
-        if not self._called:
-            self._called = True
-            self._dist.set_defaults(name=False)  # Skip name, we can still be parsing
-
-    def __enter__(self):
-        return self
-
-    def __exit__(self, _exc_type, _exc_value, _traceback):
-        if self._called:
-            self._dist.set_defaults.analyse_name()  # Now we can set a default name
-
-    def _get_package_dir(self) -> Mapping[str, str]:
-        self()
-        pkg_dir = self._dist.package_dir
-        return {} if pkg_dir is None else pkg_dir
-
-    @property
-    def package_dir(self) -> Mapping[str, str]:
-        """Proxy to ``package_dir`` that may trigger auto-discovery when used."""
-        return LazyMappingProxy(self._get_package_dir)
-
-
-class LazyMappingProxy(Mapping[_K, _V]):
-    """Mapping proxy that delays resolving the target object, until really needed.
-
-    >>> def obtain_mapping():
-    ...     print("Running expensive function!")
-    ...     return {"key": "value", "other key": "other value"}
-    >>> mapping = LazyMappingProxy(obtain_mapping)
-    >>> mapping["key"]
-    Running expensive function!
-    'value'
-    >>> mapping["other key"]
-    'other value'
-    """
-
-    def __init__(self, obtain_mapping_value: Callable[[], Mapping[_K, _V]]):
-        self._obtain = obtain_mapping_value
-        self._value: Optional[Mapping[_K, _V]] = None
-
-    def _target(self) -> Mapping[_K, _V]:
-        if self._value is None:
-            self._value = self._obtain()
-        return self._value
-
-    def __getitem__(self, key: _K) -> _V:
-        return self._target()[key]
-
-    def __len__(self) -> int:
-        return len(self._target())
-
-    def __iter__(self) -> Iterator[_K]:
-        return iter(self._target())
diff --git a/venv/lib/python3.11/site-packages/setuptools/config/pyprojecttoml.py b/venv/lib/python3.11/site-packages/setuptools/config/pyprojecttoml.py
deleted file mode 100755
index 9ce5502..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/config/pyprojecttoml.py
+++ /dev/null
@@ -1,498 +0,0 @@
-"""
-Load setuptools configuration from ``pyproject.toml`` files.
-
-**PRIVATE MODULE**: API reserved for setuptools internal usage only.
-"""
-import logging
-import os
-import warnings
-from contextlib import contextmanager
-from functools import partial
-from typing import TYPE_CHECKING, Callable, Dict, Optional, Mapping, Set, Union
-
-from setuptools.errors import FileError, OptionError
-
-from . import expand as _expand
-from ._apply_pyprojecttoml import apply as _apply
-from ._apply_pyprojecttoml import _PREVIOUSLY_DEFINED, _WouldIgnoreField
-
-if TYPE_CHECKING:
-    from setuptools.dist import Distribution  # noqa
-
-_Path = Union[str, os.PathLike]
-_logger = logging.getLogger(__name__)
-
-
-def load_file(filepath: _Path) -> dict:
-    from setuptools.extern import tomli  # type: ignore
-
-    with open(filepath, "rb") as file:
-        return tomli.load(file)
-
-
-def validate(config: dict, filepath: _Path) -> bool:
-    from . import _validate_pyproject as validator
-
-    trove_classifier = validator.FORMAT_FUNCTIONS.get("trove-classifier")
-    if hasattr(trove_classifier, "_disable_download"):
-        # Improve reproducibility by default. See issue 31 for validate-pyproject.
-        trove_classifier._disable_download()  # type: ignore
-
-    try:
-        return validator.validate(config)
-    except validator.ValidationError as ex:
-        summary = f"configuration error: {ex.summary}"
-        if ex.name.strip("`") != "project":
-            # Probably it is just a field missing/misnamed, not worthy the verbosity...
-            _logger.debug(summary)
-            _logger.debug(ex.details)
-
-        error = f"invalid pyproject.toml config: {ex.name}."
-        raise ValueError(f"{error}\n{summary}") from None
-
-
-def apply_configuration(
-    dist: "Distribution",
-    filepath: _Path,
-    ignore_option_errors=False,
-) -> "Distribution":
-    """Apply the configuration from a ``pyproject.toml`` file into an existing
-    distribution object.
-    """
-    config = read_configuration(filepath, True, ignore_option_errors, dist)
-    return _apply(dist, config, filepath)
-
-
-def read_configuration(
-    filepath: _Path,
-    expand=True,
-    ignore_option_errors=False,
-    dist: Optional["Distribution"] = None,
-):
-    """Read given configuration file and returns options from it as a dict.
-
-    :param str|unicode filepath: Path to configuration file in the ``pyproject.toml``
-        format.
-
-    :param bool expand: Whether to expand directives and other computed values
-        (i.e. post-process the given configuration)
-
-    :param bool ignore_option_errors: Whether to silently ignore
-        options, values of which could not be resolved (e.g. due to exceptions
-        in directives such as file:, attr:, etc.).
-        If False exceptions are propagated as expected.
-
-    :param Distribution|None: Distribution object to which the configuration refers.
-        If not given a dummy object will be created and discarded after the
-        configuration is read. This is used for auto-discovery of packages and in the
-        case a dynamic configuration (e.g. ``attr`` or ``cmdclass``) is expanded.
-        When ``expand=False`` this object is simply ignored.
-
-    :rtype: dict
-    """
-    filepath = os.path.abspath(filepath)
-
-    if not os.path.isfile(filepath):
-        raise FileError(f"Configuration file {filepath!r} does not exist.")
-
-    asdict = load_file(filepath) or {}
-    project_table = asdict.get("project", {})
-    tool_table = asdict.get("tool", {})
-    setuptools_table = tool_table.get("setuptools", {})
-    if not asdict or not (project_table or setuptools_table):
-        return {}  # User is not using pyproject to configure setuptools
-
-    if setuptools_table:
-        # TODO: Remove the following once the feature stabilizes:
-        msg = "Support for `[tool.setuptools]` in `pyproject.toml` is still *beta*."
-        warnings.warn(msg, _BetaConfiguration)
-
-    # There is an overall sense in the community that making include_package_data=True
-    # the default would be an improvement.
-    # `ini2toml` backfills include_package_data=False when nothing is explicitly given,
-    # therefore setting a default here is backwards compatible.
-    orig_setuptools_table = setuptools_table.copy()
-    if dist and getattr(dist, "include_package_data", None) is not None:
-        setuptools_table.setdefault("include-package-data", dist.include_package_data)
-    else:
-        setuptools_table.setdefault("include-package-data", True)
-    # Persist changes:
-    asdict["tool"] = tool_table
-    tool_table["setuptools"] = setuptools_table
-
-    try:
-        # Don't complain about unrelated errors (e.g. tools not using the "tool" table)
-        subset = {"project": project_table, "tool": {"setuptools": setuptools_table}}
-        validate(subset, filepath)
-    except Exception as ex:
-        # TODO: Remove the following once the feature stabilizes:
-        if _skip_bad_config(project_table, orig_setuptools_table, dist):
-            return {}
-        # TODO: After the previous statement is removed the try/except can be replaced
-        # by the _ignore_errors context manager.
-        if ignore_option_errors:
-            _logger.debug(f"ignored error: {ex.__class__.__name__} - {ex}")
-        else:
-            raise  # re-raise exception
-
-    if expand:
-        root_dir = os.path.dirname(filepath)
-        return expand_configuration(asdict, root_dir, ignore_option_errors, dist)
-
-    return asdict
-
-
-def _skip_bad_config(
-    project_cfg: dict, setuptools_cfg: dict, dist: Optional["Distribution"]
-) -> bool:
-    """Be temporarily forgiving with invalid ``pyproject.toml``"""
-    # See pypa/setuptools#3199 and pypa/cibuildwheel#1064
-
-    if dist is None or (
-        dist.metadata.name is None
-        and dist.metadata.version is None
-        and dist.install_requires is None
-    ):
-        # It seems that the build is not getting any configuration from other places
-        return False
-
-    if setuptools_cfg:
-        # If `[tool.setuptools]` is set, then `pyproject.toml` config is intentional
-        return False
-
-    given_config = set(project_cfg.keys())
-    popular_subset = {"name", "version", "python_requires", "requires-python"}
-    if given_config <= popular_subset:
-        # It seems that the docs in cibuildtool has been inadvertently encouraging users
-        # to create `pyproject.toml` files that are not compliant with the standards.
-        # Let's be forgiving for the time being.
-        warnings.warn(_InvalidFile.message(), _InvalidFile, stacklevel=2)
-        return True
-
-    return False
-
-
-def expand_configuration(
-    config: dict,
-    root_dir: Optional[_Path] = None,
-    ignore_option_errors: bool = False,
-    dist: Optional["Distribution"] = None,
-) -> dict:
-    """Given a configuration with unresolved fields (e.g. dynamic, cmdclass, ...)
-    find their final values.
-
-    :param dict config: Dict containing the configuration for the distribution
-    :param str root_dir: Top-level directory for the distribution/project
-        (the same directory where ``pyproject.toml`` is place)
-    :param bool ignore_option_errors: see :func:`read_configuration`
-    :param Distribution|None: Distribution object to which the configuration refers.
-        If not given a dummy object will be created and discarded after the
-        configuration is read. Used in the case a dynamic configuration
-        (e.g. ``attr`` or ``cmdclass``).
-
-    :rtype: dict
-    """
-    return _ConfigExpander(config, root_dir, ignore_option_errors, dist).expand()
-
-
-class _ConfigExpander:
-    def __init__(
-        self,
-        config: dict,
-        root_dir: Optional[_Path] = None,
-        ignore_option_errors: bool = False,
-        dist: Optional["Distribution"] = None,
-    ):
-        self.config = config
-        self.root_dir = root_dir or os.getcwd()
-        self.project_cfg = config.get("project", {})
-        self.dynamic = self.project_cfg.get("dynamic", [])
-        self.setuptools_cfg = config.get("tool", {}).get("setuptools", {})
-        self.dynamic_cfg = self.setuptools_cfg.get("dynamic", {})
-        self.ignore_option_errors = ignore_option_errors
-        self._dist = dist
-        self._referenced_files: Set[str] = set()
-
-    def _ensure_dist(self) -> "Distribution":
-        from setuptools.dist import Distribution
-
-        attrs = {"src_root": self.root_dir, "name": self.project_cfg.get("name", None)}
-        return self._dist or Distribution(attrs)
-
-    def _process_field(self, container: dict, field: str, fn: Callable):
-        if field in container:
-            with _ignore_errors(self.ignore_option_errors):
-                container[field] = fn(container[field])
-
-    def _canonic_package_data(self, field="package-data"):
-        package_data = self.setuptools_cfg.get(field, {})
-        return _expand.canonic_package_data(package_data)
-
-    def expand(self):
-        self._expand_packages()
-        self._canonic_package_data()
-        self._canonic_package_data("exclude-package-data")
-
-        # A distribution object is required for discovering the correct package_dir
-        dist = self._ensure_dist()
-        ctx = _EnsurePackagesDiscovered(dist, self.project_cfg, self.setuptools_cfg)
-        with ctx as ensure_discovered:
-            package_dir = ensure_discovered.package_dir
-            self._expand_data_files()
-            self._expand_cmdclass(package_dir)
-            self._expand_all_dynamic(dist, package_dir)
-
-        dist._referenced_files.update(self._referenced_files)
-        return self.config
-
-    def _expand_packages(self):
-        packages = self.setuptools_cfg.get("packages")
-        if packages is None or isinstance(packages, (list, tuple)):
-            return
-
-        find = packages.get("find")
-        if isinstance(find, dict):
-            find["root_dir"] = self.root_dir
-            find["fill_package_dir"] = self.setuptools_cfg.setdefault("package-dir", {})
-            with _ignore_errors(self.ignore_option_errors):
-                self.setuptools_cfg["packages"] = _expand.find_packages(**find)
-
-    def _expand_data_files(self):
-        data_files = partial(_expand.canonic_data_files, root_dir=self.root_dir)
-        self._process_field(self.setuptools_cfg, "data-files", data_files)
-
-    def _expand_cmdclass(self, package_dir: Mapping[str, str]):
-        root_dir = self.root_dir
-        cmdclass = partial(_expand.cmdclass, package_dir=package_dir, root_dir=root_dir)
-        self._process_field(self.setuptools_cfg, "cmdclass", cmdclass)
-
-    def _expand_all_dynamic(self, dist: "Distribution", package_dir: Mapping[str, str]):
-        special = (  # need special handling
-            "version",
-            "readme",
-            "entry-points",
-            "scripts",
-            "gui-scripts",
-            "classifiers",
-            "dependencies",
-            "optional-dependencies",
-        )
-        # `_obtain` functions are assumed to raise appropriate exceptions/warnings.
-        obtained_dynamic = {
-            field: self._obtain(dist, field, package_dir)
-            for field in self.dynamic
-            if field not in special
-        }
-        obtained_dynamic.update(
-            self._obtain_entry_points(dist, package_dir) or {},
-            version=self._obtain_version(dist, package_dir),
-            readme=self._obtain_readme(dist),
-            classifiers=self._obtain_classifiers(dist),
-            dependencies=self._obtain_dependencies(dist),
-            optional_dependencies=self._obtain_optional_dependencies(dist),
-        )
-        # `None` indicates there is nothing in `tool.setuptools.dynamic` but the value
-        # might have already been set by setup.py/extensions, so avoid overwriting.
-        updates = {k: v for k, v in obtained_dynamic.items() if v is not None}
-        self.project_cfg.update(updates)
-
-    def _ensure_previously_set(self, dist: "Distribution", field: str):
-        previous = _PREVIOUSLY_DEFINED[field](dist)
-        if previous is None and not self.ignore_option_errors:
-            msg = (
-                f"No configuration found for dynamic {field!r}.\n"
-                "Some dynamic fields need to be specified via `tool.setuptools.dynamic`"
-                "\nothers must be specified via the equivalent attribute in `setup.py`."
-            )
-            raise OptionError(msg)
-
-    def _expand_directive(
-        self, specifier: str, directive, package_dir: Mapping[str, str]
-    ):
-        from setuptools.extern.more_itertools import always_iterable  # type: ignore
-
-        with _ignore_errors(self.ignore_option_errors):
-            root_dir = self.root_dir
-            if "file" in directive:
-                self._referenced_files.update(always_iterable(directive["file"]))
-                return _expand.read_files(directive["file"], root_dir)
-            if "attr" in directive:
-                return _expand.read_attr(directive["attr"], package_dir, root_dir)
-            raise ValueError(f"invalid `{specifier}`: {directive!r}")
-        return None
-
-    def _obtain(self, dist: "Distribution", field: str, package_dir: Mapping[str, str]):
-        if field in self.dynamic_cfg:
-            return self._expand_directive(
-                f"tool.setuptools.dynamic.{field}",
-                self.dynamic_cfg[field],
-                package_dir,
-            )
-        self._ensure_previously_set(dist, field)
-        return None
-
-    def _obtain_version(self, dist: "Distribution", package_dir: Mapping[str, str]):
-        # Since plugins can set version, let's silently skip if it cannot be obtained
-        if "version" in self.dynamic and "version" in self.dynamic_cfg:
-            return _expand.version(self._obtain(dist, "version", package_dir))
-        return None
-
-    def _obtain_readme(self, dist: "Distribution") -> Optional[Dict[str, str]]:
-        if "readme" not in self.dynamic:
-            return None
-
-        dynamic_cfg = self.dynamic_cfg
-        if "readme" in dynamic_cfg:
-            return {
-                "text": self._obtain(dist, "readme", {}),
-                "content-type": dynamic_cfg["readme"].get("content-type", "text/x-rst"),
-            }
-
-        self._ensure_previously_set(dist, "readme")
-        return None
-
-    def _obtain_entry_points(
-        self, dist: "Distribution", package_dir: Mapping[str, str]
-    ) -> Optional[Dict[str, dict]]:
-        fields = ("entry-points", "scripts", "gui-scripts")
-        if not any(field in self.dynamic for field in fields):
-            return None
-
-        text = self._obtain(dist, "entry-points", package_dir)
-        if text is None:
-            return None
-
-        groups = _expand.entry_points(text)
-        expanded = {"entry-points": groups}
-
-        def _set_scripts(field: str, group: str):
-            if group in groups:
-                value = groups.pop(group)
-                if field not in self.dynamic:
-                    msg = _WouldIgnoreField.message(field, value)
-                    warnings.warn(msg, _WouldIgnoreField)
-                # TODO: Don't set field when support for pyproject.toml stabilizes
-                #       instead raise an error as specified in PEP 621
-                expanded[field] = value
-
-        _set_scripts("scripts", "console_scripts")
-        _set_scripts("gui-scripts", "gui_scripts")
-
-        return expanded
-
-    def _obtain_classifiers(self, dist: "Distribution"):
-        if "classifiers" in self.dynamic:
-            value = self._obtain(dist, "classifiers", {})
-            if value:
-                return value.splitlines()
-        return None
-
-    def _obtain_dependencies(self, dist: "Distribution"):
-        if "dependencies" in self.dynamic:
-            value = self._obtain(dist, "dependencies", {})
-            if value:
-                return _parse_requirements_list(value)
-        return None
-
-    def _obtain_optional_dependencies(self, dist: "Distribution"):
-        if "optional-dependencies" not in self.dynamic:
-            return None
-        if "optional-dependencies" in self.dynamic_cfg:
-            optional_dependencies_map = self.dynamic_cfg["optional-dependencies"]
-            assert isinstance(optional_dependencies_map, dict)
-            return {
-                group: _parse_requirements_list(self._expand_directive(
-                    f"tool.setuptools.dynamic.optional-dependencies.{group}",
-                    directive,
-                    {},
-                ))
-                for group, directive in optional_dependencies_map.items()
-            }
-        self._ensure_previously_set(dist, "optional-dependencies")
-        return None
-
-
-def _parse_requirements_list(value):
-    return [
-        line
-        for line in value.splitlines()
-        if line.strip() and not line.strip().startswith("#")
-    ]
-
-
-@contextmanager
-def _ignore_errors(ignore_option_errors: bool):
-    if not ignore_option_errors:
-        yield
-        return
-
-    try:
-        yield
-    except Exception as ex:
-        _logger.debug(f"ignored error: {ex.__class__.__name__} - {ex}")
-
-
-class _EnsurePackagesDiscovered(_expand.EnsurePackagesDiscovered):
-    def __init__(
-        self, distribution: "Distribution", project_cfg: dict, setuptools_cfg: dict
-    ):
-        super().__init__(distribution)
-        self._project_cfg = project_cfg
-        self._setuptools_cfg = setuptools_cfg
-
-    def __enter__(self):
-        """When entering the context, the values of ``packages``, ``py_modules`` and
-        ``package_dir`` that are missing in ``dist`` are copied from ``setuptools_cfg``.
-        """
-        dist, cfg = self._dist, self._setuptools_cfg
-        package_dir: Dict[str, str] = cfg.setdefault("package-dir", {})
-        package_dir.update(dist.package_dir or {})
-        dist.package_dir = package_dir  # needs to be the same object
-
-        dist.set_defaults._ignore_ext_modules()  # pyproject.toml-specific behaviour
-
-        # Set `name`, `py_modules` and `packages` in dist to short-circuit
-        # auto-discovery, but avoid overwriting empty lists purposefully set by users.
-        if dist.metadata.name is None:
-            dist.metadata.name = self._project_cfg.get("name")
-        if dist.py_modules is None:
-            dist.py_modules = cfg.get("py-modules")
-        if dist.packages is None:
-            dist.packages = cfg.get("packages")
-
-        return super().__enter__()
-
-    def __exit__(self, exc_type, exc_value, traceback):
-        """When exiting the context, if values of ``packages``, ``py_modules`` and
-        ``package_dir`` are missing in ``setuptools_cfg``, copy from ``dist``.
-        """
-        # If anything was discovered set them back, so they count in the final config.
-        self._setuptools_cfg.setdefault("packages", self._dist.packages)
-        self._setuptools_cfg.setdefault("py-modules", self._dist.py_modules)
-        return super().__exit__(exc_type, exc_value, traceback)
-
-
-class _BetaConfiguration(UserWarning):
-    """Explicitly inform users that some `pyproject.toml` configuration is *beta*"""
-
-
-class _InvalidFile(UserWarning):
-    """The given `pyproject.toml` file is invalid and would be ignored.
-    !!\n\n
-    ############################
-    # Invalid `pyproject.toml` #
-    ############################
-
-    Any configurations in `pyproject.toml` will be ignored.
-    Please note that future releases of setuptools will halt the build process
-    if an invalid file is given.
-
-    To prevent setuptools from considering `pyproject.toml` please
-    DO NOT include the `[project]` or `[tool.setuptools]` tables in your file.
-    \n\n!!
-    """
-
-    @classmethod
-    def message(cls):
-        from inspect import cleandoc
-        return cleandoc(cls.__doc__)
diff --git a/venv/lib/python3.11/site-packages/setuptools/config/setupcfg.py b/venv/lib/python3.11/site-packages/setuptools/config/setupcfg.py
deleted file mode 100755
index 3df3b6e..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/config/setupcfg.py
+++ /dev/null
@@ -1,769 +0,0 @@
-"""
-Load setuptools configuration from ``setup.cfg`` files.
-
-**API will be made private in the future**
-"""
-import os
-
-import contextlib
-import functools
-import warnings
-from collections import defaultdict
-from functools import partial
-from functools import wraps
-from typing import (TYPE_CHECKING, Callable, Any, Dict, Generic, Iterable, List,
-                    Optional, Set, Tuple, TypeVar, Union)
-
-from distutils.errors import DistutilsOptionError, DistutilsFileError
-from setuptools.extern.packaging.requirements import Requirement, InvalidRequirement
-from setuptools.extern.packaging.version import Version, InvalidVersion
-from setuptools.extern.packaging.specifiers import SpecifierSet
-from setuptools._deprecation_warning import SetuptoolsDeprecationWarning
-
-from . import expand
-
-if TYPE_CHECKING:
-    from setuptools.dist import Distribution  # noqa
-    from distutils.dist import DistributionMetadata  # noqa
-
-_Path = Union[str, os.PathLike]
-SingleCommandOptions = Dict["str", Tuple["str", Any]]
-"""Dict that associate the name of the options of a particular command to a
-tuple. The first element of the tuple indicates the origin of the option value
-(e.g. the name of the configuration file where it was read from),
-while the second element of the tuple is the option value itself
-"""
-AllCommandOptions = Dict["str", SingleCommandOptions]  # cmd name => its options
-Target = TypeVar("Target", bound=Union["Distribution", "DistributionMetadata"])
-
-
-def read_configuration(
-    filepath: _Path,
-    find_others=False,
-    ignore_option_errors=False
-) -> dict:
-    """Read given configuration file and returns options from it as a dict.
-
-    :param str|unicode filepath: Path to configuration file
-        to get options from.
-
-    :param bool find_others: Whether to search for other configuration files
-        which could be on in various places.
-
-    :param bool ignore_option_errors: Whether to silently ignore
-        options, values of which could not be resolved (e.g. due to exceptions
-        in directives such as file:, attr:, etc.).
-        If False exceptions are propagated as expected.
-
-    :rtype: dict
-    """
-    from setuptools.dist import Distribution
-
-    dist = Distribution()
-    filenames = dist.find_config_files() if find_others else []
-    handlers = _apply(dist, filepath, filenames, ignore_option_errors)
-    return configuration_to_dict(handlers)
-
-
-def apply_configuration(dist: "Distribution", filepath: _Path) -> "Distribution":
-    """Apply the configuration from a ``setup.cfg`` file into an existing
-    distribution object.
-    """
-    _apply(dist, filepath)
-    dist._finalize_requires()
-    return dist
-
-
-def _apply(
-    dist: "Distribution", filepath: _Path,
-    other_files: Iterable[_Path] = (),
-    ignore_option_errors: bool = False,
-) -> Tuple["ConfigHandler", ...]:
-    """Read configuration from ``filepath`` and applies to the ``dist`` object."""
-    from setuptools.dist import _Distribution
-
-    filepath = os.path.abspath(filepath)
-
-    if not os.path.isfile(filepath):
-        raise DistutilsFileError('Configuration file %s does not exist.' % filepath)
-
-    current_directory = os.getcwd()
-    os.chdir(os.path.dirname(filepath))
-    filenames = [*other_files, filepath]
-
-    try:
-        _Distribution.parse_config_files(dist, filenames=filenames)
-        handlers = parse_configuration(
-            dist, dist.command_options, ignore_option_errors=ignore_option_errors
-        )
-        dist._finalize_license_files()
-    finally:
-        os.chdir(current_directory)
-
-    return handlers
-
-
-def _get_option(target_obj: Target, key: str):
-    """
-    Given a target object and option key, get that option from
-    the target object, either through a get_{key} method or
-    from an attribute directly.
-    """
-    getter_name = 'get_{key}'.format(**locals())
-    by_attribute = functools.partial(getattr, target_obj, key)
-    getter = getattr(target_obj, getter_name, by_attribute)
-    return getter()
-
-
-def configuration_to_dict(handlers: Tuple["ConfigHandler", ...]) -> dict:
-    """Returns configuration data gathered by given handlers as a dict.
-
-    :param list[ConfigHandler] handlers: Handlers list,
-        usually from parse_configuration()
-
-    :rtype: dict
-    """
-    config_dict: dict = defaultdict(dict)
-
-    for handler in handlers:
-        for option in handler.set_options:
-            value = _get_option(handler.target_obj, option)
-            config_dict[handler.section_prefix][option] = value
-
-    return config_dict
-
-
-def parse_configuration(
-    distribution: "Distribution",
-    command_options: AllCommandOptions,
-    ignore_option_errors=False
-) -> Tuple["ConfigMetadataHandler", "ConfigOptionsHandler"]:
-    """Performs additional parsing of configuration options
-    for a distribution.
-
-    Returns a list of used option handlers.
-
-    :param Distribution distribution:
-    :param dict command_options:
-    :param bool ignore_option_errors: Whether to silently ignore
-        options, values of which could not be resolved (e.g. due to exceptions
-        in directives such as file:, attr:, etc.).
-        If False exceptions are propagated as expected.
-    :rtype: list
-    """
-    with expand.EnsurePackagesDiscovered(distribution) as ensure_discovered:
-        options = ConfigOptionsHandler(
-            distribution,
-            command_options,
-            ignore_option_errors,
-            ensure_discovered,
-        )
-
-        options.parse()
-        if not distribution.package_dir:
-            distribution.package_dir = options.package_dir  # Filled by `find_packages`
-
-        meta = ConfigMetadataHandler(
-            distribution.metadata,
-            command_options,
-            ignore_option_errors,
-            ensure_discovered,
-            distribution.package_dir,
-            distribution.src_root,
-        )
-        meta.parse()
-        distribution._referenced_files.update(
-            options._referenced_files, meta._referenced_files
-        )
-
-    return meta, options
-
-
-def _warn_accidental_env_marker_misconfig(label: str, orig_value: str, parsed: list):
-    """Because users sometimes misinterpret this configuration:
-
-    [options.extras_require]
-    foo = bar;python_version<"4"
-
-    It looks like one requirement with an environment marker
-    but because there is no newline, it's parsed as two requirements
-    with a semicolon as separator.
-
-    Therefore, if:
-        * input string does not contain a newline AND
-        * parsed result contains two requirements AND
-        * parsing of the two parts from the result (";")
-        leads in a valid Requirement with a valid marker
-    a UserWarning is shown to inform the user about the possible problem.
-    """
-    if "\n" in orig_value or len(parsed) != 2:
-        return
-
-    with contextlib.suppress(InvalidRequirement):
-        original_requirements_str = ";".join(parsed)
-        req = Requirement(original_requirements_str)
-        if req.marker is not None:
-            msg = (
-                f"One of the parsed requirements in `{label}` "
-                f"looks like a valid environment marker: '{parsed[1]}'\n"
-                "Make sure that the config is correct and check "
-                "https://setuptools.pypa.io/en/latest/userguide/declarative_config.html#opt-2"  # noqa: E501
-            )
-            warnings.warn(msg, UserWarning)
-
-
-class ConfigHandler(Generic[Target]):
-    """Handles metadata supplied in configuration files."""
-
-    section_prefix: str
-    """Prefix for config sections handled by this handler.
-    Must be provided by class heirs.
-
-    """
-
-    aliases: Dict[str, str] = {}
-    """Options aliases.
-    For compatibility with various packages. E.g.: d2to1 and pbr.
-    Note: `-` in keys is replaced with `_` by config parser.
-
-    """
-
-    def __init__(
-        self,
-        target_obj: Target,
-        options: AllCommandOptions,
-        ignore_option_errors,
-        ensure_discovered: expand.EnsurePackagesDiscovered,
-    ):
-        sections: AllCommandOptions = {}
-
-        section_prefix = self.section_prefix
-        for section_name, section_options in options.items():
-            if not section_name.startswith(section_prefix):
-                continue
-
-            section_name = section_name.replace(section_prefix, '').strip('.')
-            sections[section_name] = section_options
-
-        self.ignore_option_errors = ignore_option_errors
-        self.target_obj = target_obj
-        self.sections = sections
-        self.set_options: List[str] = []
-        self.ensure_discovered = ensure_discovered
-        self._referenced_files: Set[str] = set()
-        """After parsing configurations, this property will enumerate
-        all files referenced by the "file:" directive. Private API for setuptools only.
-        """
-
-    @property
-    def parsers(self):
-        """Metadata item name to parser function mapping."""
-        raise NotImplementedError(
-            '%s must provide .parsers property' % self.__class__.__name__
-        )
-
-    def __setitem__(self, option_name, value):
-        unknown = tuple()
-        target_obj = self.target_obj
-
-        # Translate alias into real name.
-        option_name = self.aliases.get(option_name, option_name)
-
-        current_value = getattr(target_obj, option_name, unknown)
-
-        if current_value is unknown:
-            raise KeyError(option_name)
-
-        if current_value:
-            # Already inhabited. Skipping.
-            return
-
-        skip_option = False
-        parser = self.parsers.get(option_name)
-        if parser:
-            try:
-                value = parser(value)
-
-            except Exception:
-                skip_option = True
-                if not self.ignore_option_errors:
-                    raise
-
-        if skip_option:
-            return
-
-        setter = getattr(target_obj, 'set_%s' % option_name, None)
-        if setter is None:
-            setattr(target_obj, option_name, value)
-        else:
-            setter(value)
-
-        self.set_options.append(option_name)
-
-    @classmethod
-    def _parse_list(cls, value, separator=','):
-        """Represents value as a list.
-
-        Value is split either by separator (defaults to comma) or by lines.
-
-        :param value:
-        :param separator: List items separator character.
-        :rtype: list
-        """
-        if isinstance(value, list):  # _get_parser_compound case
-            return value
-
-        if '\n' in value:
-            value = value.splitlines()
-        else:
-            value = value.split(separator)
-
-        return [chunk.strip() for chunk in value if chunk.strip()]
-
-    @classmethod
-    def _parse_dict(cls, value):
-        """Represents value as a dict.
-
-        :param value:
-        :rtype: dict
-        """
-        separator = '='
-        result = {}
-        for line in cls._parse_list(value):
-            key, sep, val = line.partition(separator)
-            if sep != separator:
-                raise DistutilsOptionError(
-                    'Unable to parse option value to dict: %s' % value
-                )
-            result[key.strip()] = val.strip()
-
-        return result
-
-    @classmethod
-    def _parse_bool(cls, value):
-        """Represents value as boolean.
-
-        :param value:
-        :rtype: bool
-        """
-        value = value.lower()
-        return value in ('1', 'true', 'yes')
-
-    @classmethod
-    def _exclude_files_parser(cls, key):
-        """Returns a parser function to make sure field inputs
-        are not files.
-
-        Parses a value after getting the key so error messages are
-        more informative.
-
-        :param key:
-        :rtype: callable
-        """
-
-        def parser(value):
-            exclude_directive = 'file:'
-            if value.startswith(exclude_directive):
-                raise ValueError(
-                    'Only strings are accepted for the {0} field, '
-                    'files are not accepted'.format(key)
-                )
-            return value
-
-        return parser
-
-    def _parse_file(self, value, root_dir: _Path):
-        """Represents value as a string, allowing including text
-        from nearest files using `file:` directive.
-
-        Directive is sandboxed and won't reach anything outside
-        directory with setup.py.
-
-        Examples:
-            file: README.rst, CHANGELOG.md, src/file.txt
-
-        :param str value:
-        :rtype: str
-        """
-        include_directive = 'file:'
-
-        if not isinstance(value, str):
-            return value
-
-        if not value.startswith(include_directive):
-            return value
-
-        spec = value[len(include_directive) :]
-        filepaths = [path.strip() for path in spec.split(',')]
-        self._referenced_files.update(filepaths)
-        return expand.read_files(filepaths, root_dir)
-
-    def _parse_attr(self, value, package_dir, root_dir: _Path):
-        """Represents value as a module attribute.
-
-        Examples:
-            attr: package.attr
-            attr: package.module.attr
-
-        :param str value:
-        :rtype: str
-        """
-        attr_directive = 'attr:'
-        if not value.startswith(attr_directive):
-            return value
-
-        attr_desc = value.replace(attr_directive, '')
-
-        # Make sure package_dir is populated correctly, so `attr:` directives can work
-        package_dir.update(self.ensure_discovered.package_dir)
-        return expand.read_attr(attr_desc, package_dir, root_dir)
-
-    @classmethod
-    def _get_parser_compound(cls, *parse_methods):
-        """Returns parser function to represents value as a list.
-
-        Parses a value applying given methods one after another.
-
-        :param parse_methods:
-        :rtype: callable
-        """
-
-        def parse(value):
-            parsed = value
-
-            for method in parse_methods:
-                parsed = method(parsed)
-
-            return parsed
-
-        return parse
-
-    @classmethod
-    def _parse_section_to_dict_with_key(cls, section_options, values_parser):
-        """Parses section options into a dictionary.
-
-        Applies a given parser to each option in a section.
-
-        :param dict section_options:
-        :param callable values_parser: function with 2 args corresponding to key, value
-        :rtype: dict
-        """
-        value = {}
-        for key, (_, val) in section_options.items():
-            value[key] = values_parser(key, val)
-        return value
-
-    @classmethod
-    def _parse_section_to_dict(cls, section_options, values_parser=None):
-        """Parses section options into a dictionary.
-
-        Optionally applies a given parser to each value.
-
-        :param dict section_options:
-        :param callable values_parser: function with 1 arg corresponding to option value
-        :rtype: dict
-        """
-        parser = (lambda _, v: values_parser(v)) if values_parser else (lambda _, v: v)
-        return cls._parse_section_to_dict_with_key(section_options, parser)
-
-    def parse_section(self, section_options):
-        """Parses configuration file section.
-
-        :param dict section_options:
-        """
-        for (name, (_, value)) in section_options.items():
-            with contextlib.suppress(KeyError):
-                # Keep silent for a new option may appear anytime.
-                self[name] = value
-
-    def parse(self):
-        """Parses configuration file items from one
-        or more related sections.
-
-        """
-        for section_name, section_options in self.sections.items():
-
-            method_postfix = ''
-            if section_name:  # [section.option] variant
-                method_postfix = '_%s' % section_name
-
-            section_parser_method: Optional[Callable] = getattr(
-                self,
-                # Dots in section names are translated into dunderscores.
-                ('parse_section%s' % method_postfix).replace('.', '__'),
-                None,
-            )
-
-            if section_parser_method is None:
-                raise DistutilsOptionError(
-                    'Unsupported distribution option section: [%s.%s]'
-                    % (self.section_prefix, section_name)
-                )
-
-            section_parser_method(section_options)
-
-    def _deprecated_config_handler(self, func, msg, warning_class):
-        """this function will wrap around parameters that are deprecated
-
-        :param msg: deprecation message
-        :param warning_class: class of warning exception to be raised
-        :param func: function to be wrapped around
-        """
-
-        @wraps(func)
-        def config_handler(*args, **kwargs):
-            warnings.warn(msg, warning_class)
-            return func(*args, **kwargs)
-
-        return config_handler
-
-
-class ConfigMetadataHandler(ConfigHandler["DistributionMetadata"]):
-
-    section_prefix = 'metadata'
-
-    aliases = {
-        'home_page': 'url',
-        'summary': 'description',
-        'classifier': 'classifiers',
-        'platform': 'platforms',
-    }
-
-    strict_mode = False
-    """We need to keep it loose, to be partially compatible with
-    `pbr` and `d2to1` packages which also uses `metadata` section.
-
-    """
-
-    def __init__(
-        self,
-        target_obj: "DistributionMetadata",
-        options: AllCommandOptions,
-        ignore_option_errors: bool,
-        ensure_discovered: expand.EnsurePackagesDiscovered,
-        package_dir: Optional[dict] = None,
-        root_dir: _Path = os.curdir
-    ):
-        super().__init__(target_obj, options, ignore_option_errors, ensure_discovered)
-        self.package_dir = package_dir
-        self.root_dir = root_dir
-
-    @property
-    def parsers(self):
-        """Metadata item name to parser function mapping."""
-        parse_list = self._parse_list
-        parse_file = partial(self._parse_file, root_dir=self.root_dir)
-        parse_dict = self._parse_dict
-        exclude_files_parser = self._exclude_files_parser
-
-        return {
-            'platforms': parse_list,
-            'keywords': parse_list,
-            'provides': parse_list,
-            'requires': self._deprecated_config_handler(
-                parse_list,
-                "The requires parameter is deprecated, please use "
-                "install_requires for runtime dependencies.",
-                SetuptoolsDeprecationWarning,
-            ),
-            'obsoletes': parse_list,
-            'classifiers': self._get_parser_compound(parse_file, parse_list),
-            'license': exclude_files_parser('license'),
-            'license_file': self._deprecated_config_handler(
-                exclude_files_parser('license_file'),
-                "The license_file parameter is deprecated, "
-                "use license_files instead.",
-                SetuptoolsDeprecationWarning,
-            ),
-            'license_files': parse_list,
-            'description': parse_file,
-            'long_description': parse_file,
-            'version': self._parse_version,
-            'project_urls': parse_dict,
-        }
-
-    def _parse_version(self, value):
-        """Parses `version` option value.
-
-        :param value:
-        :rtype: str
-
-        """
-        version = self._parse_file(value, self.root_dir)
-
-        if version != value:
-            version = version.strip()
-            # Be strict about versions loaded from file because it's easy to
-            # accidentally include newlines and other unintended content
-            try:
-                Version(version)
-            except InvalidVersion:
-                tmpl = (
-                    'Version loaded from {value} does not '
-                    'comply with PEP 440: {version}'
-                )
-                raise DistutilsOptionError(tmpl.format(**locals()))
-
-            return version
-
-        return expand.version(self._parse_attr(value, self.package_dir, self.root_dir))
-
-
-class ConfigOptionsHandler(ConfigHandler["Distribution"]):
-
-    section_prefix = 'options'
-
-    def __init__(
-        self,
-        target_obj: "Distribution",
-        options: AllCommandOptions,
-        ignore_option_errors: bool,
-        ensure_discovered: expand.EnsurePackagesDiscovered,
-    ):
-        super().__init__(target_obj, options, ignore_option_errors, ensure_discovered)
-        self.root_dir = target_obj.src_root
-        self.package_dir: Dict[str, str] = {}  # To be filled by `find_packages`
-
-    @classmethod
-    def _parse_list_semicolon(cls, value):
-        return cls._parse_list(value, separator=';')
-
-    def _parse_file_in_root(self, value):
-        return self._parse_file(value, root_dir=self.root_dir)
-
-    def _parse_requirements_list(self, label: str, value: str):
-        # Parse a requirements list, either by reading in a `file:`, or a list.
-        parsed = self._parse_list_semicolon(self._parse_file_in_root(value))
-        _warn_accidental_env_marker_misconfig(label, value, parsed)
-        # Filter it to only include lines that are not comments. `parse_list`
-        # will have stripped each line and filtered out empties.
-        return [line for line in parsed if not line.startswith("#")]
-
-    @property
-    def parsers(self):
-        """Metadata item name to parser function mapping."""
-        parse_list = self._parse_list
-        parse_bool = self._parse_bool
-        parse_dict = self._parse_dict
-        parse_cmdclass = self._parse_cmdclass
-
-        return {
-            'zip_safe': parse_bool,
-            'include_package_data': parse_bool,
-            'package_dir': parse_dict,
-            'scripts': parse_list,
-            'eager_resources': parse_list,
-            'dependency_links': parse_list,
-            'namespace_packages': self._deprecated_config_handler(
-                parse_list,
-                "The namespace_packages parameter is deprecated, "
-                "consider using implicit namespaces instead (PEP 420).",
-                SetuptoolsDeprecationWarning,
-            ),
-            'install_requires': partial(
-                self._parse_requirements_list, "install_requires"
-            ),
-            'setup_requires': self._parse_list_semicolon,
-            'tests_require': self._parse_list_semicolon,
-            'packages': self._parse_packages,
-            'entry_points': self._parse_file_in_root,
-            'py_modules': parse_list,
-            'python_requires': SpecifierSet,
-            'cmdclass': parse_cmdclass,
-        }
-
-    def _parse_cmdclass(self, value):
-        package_dir = self.ensure_discovered.package_dir
-        return expand.cmdclass(self._parse_dict(value), package_dir, self.root_dir)
-
-    def _parse_packages(self, value):
-        """Parses `packages` option value.
-
-        :param value:
-        :rtype: list
-        """
-        find_directives = ['find:', 'find_namespace:']
-        trimmed_value = value.strip()
-
-        if trimmed_value not in find_directives:
-            return self._parse_list(value)
-
-        # Read function arguments from a dedicated section.
-        find_kwargs = self.parse_section_packages__find(
-            self.sections.get('packages.find', {})
-        )
-
-        find_kwargs.update(
-            namespaces=(trimmed_value == find_directives[1]),
-            root_dir=self.root_dir,
-            fill_package_dir=self.package_dir,
-        )
-
-        return expand.find_packages(**find_kwargs)
-
-    def parse_section_packages__find(self, section_options):
-        """Parses `packages.find` configuration file section.
-
-        To be used in conjunction with _parse_packages().
-
-        :param dict section_options:
-        """
-        section_data = self._parse_section_to_dict(section_options, self._parse_list)
-
-        valid_keys = ['where', 'include', 'exclude']
-
-        find_kwargs = dict(
-            [(k, v) for k, v in section_data.items() if k in valid_keys and v]
-        )
-
-        where = find_kwargs.get('where')
-        if where is not None:
-            find_kwargs['where'] = where[0]  # cast list to single val
-
-        return find_kwargs
-
-    def parse_section_entry_points(self, section_options):
-        """Parses `entry_points` configuration file section.
-
-        :param dict section_options:
-        """
-        parsed = self._parse_section_to_dict(section_options, self._parse_list)
-        self['entry_points'] = parsed
-
-    def _parse_package_data(self, section_options):
-        package_data = self._parse_section_to_dict(section_options, self._parse_list)
-        return expand.canonic_package_data(package_data)
-
-    def parse_section_package_data(self, section_options):
-        """Parses `package_data` configuration file section.
-
-        :param dict section_options:
-        """
-        self['package_data'] = self._parse_package_data(section_options)
-
-    def parse_section_exclude_package_data(self, section_options):
-        """Parses `exclude_package_data` configuration file section.
-
-        :param dict section_options:
-        """
-        self['exclude_package_data'] = self._parse_package_data(section_options)
-
-    def parse_section_extras_require(self, section_options):
-        """Parses `extras_require` configuration file section.
-
-        :param dict section_options:
-        """
-        parsed = self._parse_section_to_dict_with_key(
-            section_options,
-            lambda k, v: self._parse_requirements_list(f"extras_require[{k}]", v)
-        )
-
-        self['extras_require'] = parsed
-
-    def parse_section_data_files(self, section_options):
-        """Parses `data_files` configuration file section.
-
-        :param dict section_options:
-        """
-        parsed = self._parse_section_to_dict(section_options, self._parse_list)
-        self['data_files'] = expand.canonic_data_files(parsed, self.root_dir)
diff --git a/venv/lib/python3.11/site-packages/setuptools/dep_util.py b/venv/lib/python3.11/site-packages/setuptools/dep_util.py
deleted file mode 100755
index 521eb71..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/dep_util.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from distutils.dep_util import newer_group
-
-
-# yes, this is was almost entirely copy-pasted from
-# 'newer_pairwise()', this is just another convenience
-# function.
-def newer_pairwise_group(sources_groups, targets):
-    """Walk both arguments in parallel, testing if each source group is newer
-    than its corresponding target. Returns a pair of lists (sources_groups,
-    targets) where sources is newer than target, according to the semantics
-    of 'newer_group()'.
-    """
-    if len(sources_groups) != len(targets):
-        raise ValueError(
-            "'sources_group' and 'targets' must be the same length")
-
-    # build a pair of lists (sources_groups, targets) where source is newer
-    n_sources = []
-    n_targets = []
-    for i in range(len(sources_groups)):
-        if newer_group(sources_groups[i], targets[i]):
-            n_sources.append(sources_groups[i])
-            n_targets.append(targets[i])
-
-    return n_sources, n_targets
diff --git a/venv/lib/python3.11/site-packages/setuptools/depends.py b/venv/lib/python3.11/site-packages/setuptools/depends.py
deleted file mode 100755
index adffd12..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/depends.py
+++ /dev/null
@@ -1,176 +0,0 @@
-import sys
-import marshal
-import contextlib
-import dis
-
-from setuptools.extern.packaging import version
-
-from ._imp import find_module, PY_COMPILED, PY_FROZEN, PY_SOURCE
-from . import _imp
-
-
-__all__ = [
-    'Require', 'find_module', 'get_module_constant', 'extract_constant'
-]
-
-
-class Require:
-    """A prerequisite to building or installing a distribution"""
-
-    def __init__(
-            self, name, requested_version, module, homepage='',
-            attribute=None, format=None):
-
-        if format is None and requested_version is not None:
-            format = version.Version
-
-        if format is not None:
-            requested_version = format(requested_version)
-            if attribute is None:
-                attribute = '__version__'
-
-        self.__dict__.update(locals())
-        del self.self
-
-    def full_name(self):
-        """Return full package/distribution name, w/version"""
-        if self.requested_version is not None:
-            return '%s-%s' % (self.name, self.requested_version)
-        return self.name
-
-    def version_ok(self, version):
-        """Is 'version' sufficiently up-to-date?"""
-        return self.attribute is None or self.format is None or \
-            str(version) != "unknown" and self.format(version) >= self.requested_version
-
-    def get_version(self, paths=None, default="unknown"):
-        """Get version number of installed module, 'None', or 'default'
-
-        Search 'paths' for module.  If not found, return 'None'.  If found,
-        return the extracted version attribute, or 'default' if no version
-        attribute was specified, or the value cannot be determined without
-        importing the module.  The version is formatted according to the
-        requirement's version format (if any), unless it is 'None' or the
-        supplied 'default'.
-        """
-
-        if self.attribute is None:
-            try:
-                f, p, i = find_module(self.module, paths)
-                if f:
-                    f.close()
-                return default
-            except ImportError:
-                return None
-
-        v = get_module_constant(self.module, self.attribute, default, paths)
-
-        if v is not None and v is not default and self.format is not None:
-            return self.format(v)
-
-        return v
-
-    def is_present(self, paths=None):
-        """Return true if dependency is present on 'paths'"""
-        return self.get_version(paths) is not None
-
-    def is_current(self, paths=None):
-        """Return true if dependency is present and up-to-date on 'paths'"""
-        version = self.get_version(paths)
-        if version is None:
-            return False
-        return self.version_ok(str(version))
-
-
-def maybe_close(f):
-    @contextlib.contextmanager
-    def empty():
-        yield
-        return
-    if not f:
-        return empty()
-
-    return contextlib.closing(f)
-
-
-def get_module_constant(module, symbol, default=-1, paths=None):
-    """Find 'module' by searching 'paths', and extract 'symbol'
-
-    Return 'None' if 'module' does not exist on 'paths', or it does not define
-    'symbol'.  If the module defines 'symbol' as a constant, return the
-    constant.  Otherwise, return 'default'."""
-
-    try:
-        f, path, (suffix, mode, kind) = info = find_module(module, paths)
-    except ImportError:
-        # Module doesn't exist
-        return None
-
-    with maybe_close(f):
-        if kind == PY_COMPILED:
-            f.read(8)  # skip magic & date
-            code = marshal.load(f)
-        elif kind == PY_FROZEN:
-            code = _imp.get_frozen_object(module, paths)
-        elif kind == PY_SOURCE:
-            code = compile(f.read(), path, 'exec')
-        else:
-            # Not something we can parse; we'll have to import it.  :(
-            imported = _imp.get_module(module, paths, info)
-            return getattr(imported, symbol, None)
-
-    return extract_constant(code, symbol, default)
-
-
-def extract_constant(code, symbol, default=-1):
-    """Extract the constant value of 'symbol' from 'code'
-
-    If the name 'symbol' is bound to a constant value by the Python code
-    object 'code', return that value.  If 'symbol' is bound to an expression,
-    return 'default'.  Otherwise, return 'None'.
-
-    Return value is based on the first assignment to 'symbol'.  'symbol' must
-    be a global, or at least a non-"fast" local in the code block.  That is,
-    only 'STORE_NAME' and 'STORE_GLOBAL' opcodes are checked, and 'symbol'
-    must be present in 'code.co_names'.
-    """
-    if symbol not in code.co_names:
-        # name's not there, can't possibly be an assignment
-        return None
-
-    name_idx = list(code.co_names).index(symbol)
-
-    STORE_NAME = 90
-    STORE_GLOBAL = 97
-    LOAD_CONST = 100
-
-    const = default
-
-    for byte_code in dis.Bytecode(code):
-        op = byte_code.opcode
-        arg = byte_code.arg
-
-        if op == LOAD_CONST:
-            const = code.co_consts[arg]
-        elif arg == name_idx and (op == STORE_NAME or op == STORE_GLOBAL):
-            return const
-        else:
-            const = default
-
-
-def _update_globals():
-    """
-    Patch the globals to remove the objects not available on some platforms.
-
-    XXX it'd be better to test assertions about bytecode instead.
-    """
-
-    if not sys.platform.startswith('java') and sys.platform != 'cli':
-        return
-    incompatible = 'extract_constant', 'get_module_constant'
-    for name in incompatible:
-        del globals()[name]
-        __all__.remove(name)
-
-
-_update_globals()
diff --git a/venv/lib/python3.11/site-packages/setuptools/discovery.py b/venv/lib/python3.11/site-packages/setuptools/discovery.py
deleted file mode 100755
index 6244a18..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/discovery.py
+++ /dev/null
@@ -1,601 +0,0 @@
-"""Automatic discovery of Python modules and packages (for inclusion in the
-distribution) and other config values.
-
-For the purposes of this module, the following nomenclature is used:
-
-- "src-layout": a directory representing a Python project that contains a "src"
-  folder. Everything under the "src" folder is meant to be included in the
-  distribution when packaging the project. Example::
-
-    .
-    ├── tox.ini
-    ├── pyproject.toml
-    └── src/
-        └── mypkg/
-            ├── __init__.py
-            ├── mymodule.py
-            └── my_data_file.txt
-
-- "flat-layout": a Python project that does not use "src-layout" but instead
-  have a directory under the project root for each package::
-
-    .
-    ├── tox.ini
-    ├── pyproject.toml
-    └── mypkg/
-        ├── __init__.py
-        ├── mymodule.py
-        └── my_data_file.txt
-
-- "single-module": a project that contains a single Python script direct under
-  the project root (no directory used)::
-
-    .
-    ├── tox.ini
-    ├── pyproject.toml
-    └── mymodule.py
-
-"""
-
-import itertools
-import os
-from fnmatch import fnmatchcase
-from glob import glob
-from pathlib import Path
-from typing import (
-    TYPE_CHECKING,
-    Callable,
-    Dict,
-    Iterable,
-    Iterator,
-    List,
-    Mapping,
-    Optional,
-    Tuple,
-    Union
-)
-
-import _distutils_hack.override  # noqa: F401
-
-from distutils import log
-from distutils.util import convert_path
-
-_Path = Union[str, os.PathLike]
-_Filter = Callable[[str], bool]
-StrIter = Iterator[str]
-
-chain_iter = itertools.chain.from_iterable
-
-if TYPE_CHECKING:
-    from setuptools import Distribution  # noqa
-
-
-def _valid_name(path: _Path) -> bool:
-    # Ignore invalid names that cannot be imported directly
-    return os.path.basename(path).isidentifier()
-
-
-class _Finder:
-    """Base class that exposes functionality for module/package finders"""
-
-    ALWAYS_EXCLUDE: Tuple[str, ...] = ()
-    DEFAULT_EXCLUDE: Tuple[str, ...] = ()
-
-    @classmethod
-    def find(
-        cls,
-        where: _Path = '.',
-        exclude: Iterable[str] = (),
-        include: Iterable[str] = ('*',)
-    ) -> List[str]:
-        """Return a list of all Python items (packages or modules, depending on
-        the finder implementation) found within directory 'where'.
-
-        'where' is the root directory which will be searched.
-        It should be supplied as a "cross-platform" (i.e. URL-style) path;
-        it will be converted to the appropriate local path syntax.
-
-        'exclude' is a sequence of names to exclude; '*' can be used
-        as a wildcard in the names.
-        When finding packages, 'foo.*' will exclude all subpackages of 'foo'
-        (but not 'foo' itself).
-
-        'include' is a sequence of names to include.
-        If it's specified, only the named items will be included.
-        If it's not specified, all found items will be included.
-        'include' can contain shell style wildcard patterns just like
-        'exclude'.
-        """
-
-        exclude = exclude or cls.DEFAULT_EXCLUDE
-        return list(
-            cls._find_iter(
-                convert_path(str(where)),
-                cls._build_filter(*cls.ALWAYS_EXCLUDE, *exclude),
-                cls._build_filter(*include),
-            )
-        )
-
-    @classmethod
-    def _find_iter(cls, where: _Path, exclude: _Filter, include: _Filter) -> StrIter:
-        raise NotImplementedError
-
-    @staticmethod
-    def _build_filter(*patterns: str) -> _Filter:
-        """
-        Given a list of patterns, return a callable that will be true only if
-        the input matches at least one of the patterns.
-        """
-        return lambda name: any(fnmatchcase(name, pat) for pat in patterns)
-
-
-class PackageFinder(_Finder):
-    """
-    Generate a list of all Python packages found within a directory
-    """
-
-    ALWAYS_EXCLUDE = ("ez_setup", "*__pycache__")
-
-    @classmethod
-    def _find_iter(cls, where: _Path, exclude: _Filter, include: _Filter) -> StrIter:
-        """
-        All the packages found in 'where' that pass the 'include' filter, but
-        not the 'exclude' filter.
-        """
-        for root, dirs, files in os.walk(str(where), followlinks=True):
-            # Copy dirs to iterate over it, then empty dirs.
-            all_dirs = dirs[:]
-            dirs[:] = []
-
-            for dir in all_dirs:
-                full_path = os.path.join(root, dir)
-                rel_path = os.path.relpath(full_path, where)
-                package = rel_path.replace(os.path.sep, '.')
-
-                # Skip directory trees that are not valid packages
-                if '.' in dir or not cls._looks_like_package(full_path, package):
-                    continue
-
-                # Should this package be included?
-                if include(package) and not exclude(package):
-                    yield package
-
-                # Keep searching subdirectories, as there may be more packages
-                # down there, even if the parent was excluded.
-                dirs.append(dir)
-
-    @staticmethod
-    def _looks_like_package(path: _Path, _package_name: str) -> bool:
-        """Does a directory look like a package?"""
-        return os.path.isfile(os.path.join(path, '__init__.py'))
-
-
-class PEP420PackageFinder(PackageFinder):
-    @staticmethod
-    def _looks_like_package(_path: _Path, _package_name: str) -> bool:
-        return True
-
-
-class ModuleFinder(_Finder):
-    """Find isolated Python modules.
-    This function will **not** recurse subdirectories.
-    """
-
-    @classmethod
-    def _find_iter(cls, where: _Path, exclude: _Filter, include: _Filter) -> StrIter:
-        for file in glob(os.path.join(where, "*.py")):
-            module, _ext = os.path.splitext(os.path.basename(file))
-
-            if not cls._looks_like_module(module):
-                continue
-
-            if include(module) and not exclude(module):
-                yield module
-
-    _looks_like_module = staticmethod(_valid_name)
-
-
-# We have to be extra careful in the case of flat layout to not include files
-# and directories not meant for distribution (e.g. tool-related)
-
-
-class FlatLayoutPackageFinder(PEP420PackageFinder):
-    _EXCLUDE = (
-        "ci",
-        "bin",
-        "doc",
-        "docs",
-        "documentation",
-        "manpages",
-        "news",
-        "changelog",
-        "test",
-        "tests",
-        "unit_test",
-        "unit_tests",
-        "example",
-        "examples",
-        "scripts",
-        "tools",
-        "util",
-        "utils",
-        "python",
-        "build",
-        "dist",
-        "venv",
-        "env",
-        "requirements",
-        # ---- Task runners / Build tools ----
-        "tasks",  # invoke
-        "fabfile",  # fabric
-        "site_scons",  # SCons
-        # ---- Other tools ----
-        "benchmark",
-        "benchmarks",
-        "exercise",
-        "exercises",
-        # ---- Hidden directories/Private packages ----
-        "[._]*",
-    )
-
-    DEFAULT_EXCLUDE = tuple(chain_iter((p, f"{p}.*") for p in _EXCLUDE))
-    """Reserved package names"""
-
-    @staticmethod
-    def _looks_like_package(_path: _Path, package_name: str) -> bool:
-        names = package_name.split('.')
-        # Consider PEP 561
-        root_pkg_is_valid = names[0].isidentifier() or names[0].endswith("-stubs")
-        return root_pkg_is_valid and all(name.isidentifier() for name in names[1:])
-
-
-class FlatLayoutModuleFinder(ModuleFinder):
-    DEFAULT_EXCLUDE = (
-        "setup",
-        "conftest",
-        "test",
-        "tests",
-        "example",
-        "examples",
-        "build",
-        # ---- Task runners ----
-        "toxfile",
-        "noxfile",
-        "pavement",
-        "dodo",
-        "tasks",
-        "fabfile",
-        # ---- Other tools ----
-        "[Ss][Cc]onstruct",  # SCons
-        "conanfile",  # Connan: C/C++ build tool
-        "manage",  # Django
-        "benchmark",
-        "benchmarks",
-        "exercise",
-        "exercises",
-        "htmlcov",
-        # ---- Hidden files/Private modules ----
-        "[._]*",
-    )
-    """Reserved top-level module names"""
-
-
-def _find_packages_within(root_pkg: str, pkg_dir: _Path) -> List[str]:
-    nested = PEP420PackageFinder.find(pkg_dir)
-    return [root_pkg] + [".".join((root_pkg, n)) for n in nested]
-
-
-class ConfigDiscovery:
-    """Fill-in metadata and options that can be automatically derived
-    (from other metadata/options, the file system or conventions)
-    """
-
-    def __init__(self, distribution: "Distribution"):
-        self.dist = distribution
-        self._called = False
-        self._disabled = False
-        self._skip_ext_modules = False
-
-    def _disable(self):
-        """Internal API to disable automatic discovery"""
-        self._disabled = True
-
-    def _ignore_ext_modules(self):
-        """Internal API to disregard ext_modules.
-
-        Normally auto-discovery would not be triggered if ``ext_modules`` are set
-        (this is done for backward compatibility with existing packages relying on
-        ``setup.py`` or ``setup.cfg``). However, ``setuptools`` can call this function
-        to ignore given ``ext_modules`` and proceed with the auto-discovery if
-        ``packages`` and ``py_modules`` are not given (e.g. when using pyproject.toml
-        metadata).
-        """
-        self._skip_ext_modules = True
-
-    @property
-    def _root_dir(self) -> _Path:
-        # The best is to wait until `src_root` is set in dist, before using _root_dir.
-        return self.dist.src_root or os.curdir
-
-    @property
-    def _package_dir(self) -> Dict[str, str]:
-        if self.dist.package_dir is None:
-            return {}
-        return self.dist.package_dir
-
-    def __call__(self, force=False, name=True, ignore_ext_modules=False):
-        """Automatically discover missing configuration fields
-        and modifies the given ``distribution`` object in-place.
-
-        Note that by default this will only have an effect the first time the
-        ``ConfigDiscovery`` object is called.
-
-        To repeatedly invoke automatic discovery (e.g. when the project
-        directory changes), please use ``force=True`` (or create a new
-        ``ConfigDiscovery`` instance).
-        """
-        if force is False and (self._called or self._disabled):
-            # Avoid overhead of multiple calls
-            return
-
-        self._analyse_package_layout(ignore_ext_modules)
-        if name:
-            self.analyse_name()  # depends on ``packages`` and ``py_modules``
-
-        self._called = True
-
-    def _explicitly_specified(self, ignore_ext_modules: bool) -> bool:
-        """``True`` if the user has specified some form of package/module listing"""
-        ignore_ext_modules = ignore_ext_modules or self._skip_ext_modules
-        ext_modules = not (self.dist.ext_modules is None or ignore_ext_modules)
-        return (
-            self.dist.packages is not None
-            or self.dist.py_modules is not None
-            or ext_modules
-            or hasattr(self.dist, "configuration") and self.dist.configuration
-            # ^ Some projects use numpy.distutils.misc_util.Configuration
-        )
-
-    def _analyse_package_layout(self, ignore_ext_modules: bool) -> bool:
-        if self._explicitly_specified(ignore_ext_modules):
-            # For backward compatibility, just try to find modules/packages
-            # when nothing is given
-            return True
-
-        log.debug(
-            "No `packages` or `py_modules` configuration, performing "
-            "automatic discovery."
-        )
-
-        return (
-            self._analyse_explicit_layout()
-            or self._analyse_src_layout()
-            # flat-layout is the trickiest for discovery so it should be last
-            or self._analyse_flat_layout()
-        )
-
-    def _analyse_explicit_layout(self) -> bool:
-        """The user can explicitly give a package layout via ``package_dir``"""
-        package_dir = self._package_dir.copy()  # don't modify directly
-        package_dir.pop("", None)  # This falls under the "src-layout" umbrella
-        root_dir = self._root_dir
-
-        if not package_dir:
-            return False
-
-        log.debug(f"`explicit-layout` detected -- analysing {package_dir}")
-        pkgs = chain_iter(
-            _find_packages_within(pkg, os.path.join(root_dir, parent_dir))
-            for pkg, parent_dir in package_dir.items()
-        )
-        self.dist.packages = list(pkgs)
-        log.debug(f"discovered packages -- {self.dist.packages}")
-        return True
-
-    def _analyse_src_layout(self) -> bool:
-        """Try to find all packages or modules under the ``src`` directory
-        (or anything pointed by ``package_dir[""]``).
-
-        The "src-layout" is relatively safe for automatic discovery.
-        We assume that everything within is meant to be included in the
-        distribution.
-
-        If ``package_dir[""]`` is not given, but the ``src`` directory exists,
-        this function will set ``package_dir[""] = "src"``.
-        """
-        package_dir = self._package_dir
-        src_dir = os.path.join(self._root_dir, package_dir.get("", "src"))
-        if not os.path.isdir(src_dir):
-            return False
-
-        log.debug(f"`src-layout` detected -- analysing {src_dir}")
-        package_dir.setdefault("", os.path.basename(src_dir))
-        self.dist.package_dir = package_dir  # persist eventual modifications
-        self.dist.packages = PEP420PackageFinder.find(src_dir)
-        self.dist.py_modules = ModuleFinder.find(src_dir)
-        log.debug(f"discovered packages -- {self.dist.packages}")
-        log.debug(f"discovered py_modules -- {self.dist.py_modules}")
-        return True
-
-    def _analyse_flat_layout(self) -> bool:
-        """Try to find all packages and modules under the project root.
-
-        Since the ``flat-layout`` is more dangerous in terms of accidentally including
-        extra files/directories, this function is more conservative and will raise an
-        error if multiple packages or modules are found.
-
-        This assumes that multi-package dists are uncommon and refuse to support that
-        use case in order to be able to prevent unintended errors.
-        """
-        log.debug(f"`flat-layout` detected -- analysing {self._root_dir}")
-        return self._analyse_flat_packages() or self._analyse_flat_modules()
-
-    def _analyse_flat_packages(self) -> bool:
-        self.dist.packages = FlatLayoutPackageFinder.find(self._root_dir)
-        top_level = remove_nested_packages(remove_stubs(self.dist.packages))
-        log.debug(f"discovered packages -- {self.dist.packages}")
-        self._ensure_no_accidental_inclusion(top_level, "packages")
-        return bool(top_level)
-
-    def _analyse_flat_modules(self) -> bool:
-        self.dist.py_modules = FlatLayoutModuleFinder.find(self._root_dir)
-        log.debug(f"discovered py_modules -- {self.dist.py_modules}")
-        self._ensure_no_accidental_inclusion(self.dist.py_modules, "modules")
-        return bool(self.dist.py_modules)
-
-    def _ensure_no_accidental_inclusion(self, detected: List[str], kind: str):
-        if len(detected) > 1:
-            from inspect import cleandoc
-
-            from setuptools.errors import PackageDiscoveryError
-
-            msg = f"""Multiple top-level {kind} discovered in a flat-layout: {detected}.
-
-            To avoid accidental inclusion of unwanted files or directories,
-            setuptools will not proceed with this build.
-
-            If you are trying to create a single distribution with multiple {kind}
-            on purpose, you should not rely on automatic discovery.
-            Instead, consider the following options:
-
-            1. set up custom discovery (`find` directive with `include` or `exclude`)
-            2. use a `src-layout`
-            3. explicitly set `py_modules` or `packages` with a list of names
-
-            To find more information, look for "package discovery" on setuptools docs.
-            """
-            raise PackageDiscoveryError(cleandoc(msg))
-
-    def analyse_name(self):
-        """The packages/modules are the essential contribution of the author.
-        Therefore the name of the distribution can be derived from them.
-        """
-        if self.dist.metadata.name or self.dist.name:
-            # get_name() is not reliable (can return "UNKNOWN")
-            return None
-
-        log.debug("No `name` configuration, performing automatic discovery")
-
-        name = (
-            self._find_name_single_package_or_module()
-            or self._find_name_from_packages()
-        )
-        if name:
-            self.dist.metadata.name = name
-
-    def _find_name_single_package_or_module(self) -> Optional[str]:
-        """Exactly one module or package"""
-        for field in ('packages', 'py_modules'):
-            items = getattr(self.dist, field, None) or []
-            if items and len(items) == 1:
-                log.debug(f"Single module/package detected, name: {items[0]}")
-                return items[0]
-
-        return None
-
-    def _find_name_from_packages(self) -> Optional[str]:
-        """Try to find the root package that is not a PEP 420 namespace"""
-        if not self.dist.packages:
-            return None
-
-        packages = remove_stubs(sorted(self.dist.packages, key=len))
-        package_dir = self.dist.package_dir or {}
-
-        parent_pkg = find_parent_package(packages, package_dir, self._root_dir)
-        if parent_pkg:
-            log.debug(f"Common parent package detected, name: {parent_pkg}")
-            return parent_pkg
-
-        log.warn("No parent package detected, impossible to derive `name`")
-        return None
-
-
-def remove_nested_packages(packages: List[str]) -> List[str]:
-    """Remove nested packages from a list of packages.
-
-    >>> remove_nested_packages(["a", "a.b1", "a.b2", "a.b1.c1"])
-    ['a']
-    >>> remove_nested_packages(["a", "b", "c.d", "c.d.e.f", "g.h", "a.a1"])
-    ['a', 'b', 'c.d', 'g.h']
-    """
-    pkgs = sorted(packages, key=len)
-    top_level = pkgs[:]
-    size = len(pkgs)
-    for i, name in enumerate(reversed(pkgs)):
-        if any(name.startswith(f"{other}.") for other in top_level):
-            top_level.pop(size - i - 1)
-
-    return top_level
-
-
-def remove_stubs(packages: List[str]) -> List[str]:
-    """Remove type stubs (:pep:`561`) from a list of packages.
-
-    >>> remove_stubs(["a", "a.b", "a-stubs", "a-stubs.b.c", "b", "c-stubs"])
-    ['a', 'a.b', 'b']
-    """
-    return [pkg for pkg in packages if not pkg.split(".")[0].endswith("-stubs")]
-
-
-def find_parent_package(
-    packages: List[str], package_dir: Mapping[str, str], root_dir: _Path
-) -> Optional[str]:
-    """Find the parent package that is not a namespace."""
-    packages = sorted(packages, key=len)
-    common_ancestors = []
-    for i, name in enumerate(packages):
-        if not all(n.startswith(f"{name}.") for n in packages[i+1:]):
-            # Since packages are sorted by length, this condition is able
-            # to find a list of all common ancestors.
-            # When there is divergence (e.g. multiple root packages)
-            # the list will be empty
-            break
-        common_ancestors.append(name)
-
-    for name in common_ancestors:
-        pkg_path = find_package_path(name, package_dir, root_dir)
-        init = os.path.join(pkg_path, "__init__.py")
-        if os.path.isfile(init):
-            return name
-
-    return None
-
-
-def find_package_path(
-    name: str, package_dir: Mapping[str, str], root_dir: _Path
-) -> str:
-    """Given a package name, return the path where it should be found on
-    disk, considering the ``package_dir`` option.
-
-    >>> path = find_package_path("my.pkg", {"": "root/is/nested"}, ".")
-    >>> path.replace(os.sep, "/")
-    './root/is/nested/my/pkg'
-
-    >>> path = find_package_path("my.pkg", {"my": "root/is/nested"}, ".")
-    >>> path.replace(os.sep, "/")
-    './root/is/nested/pkg'
-
-    >>> path = find_package_path("my.pkg", {"my.pkg": "root/is/nested"}, ".")
-    >>> path.replace(os.sep, "/")
-    './root/is/nested'
-
-    >>> path = find_package_path("other.pkg", {"my.pkg": "root/is/nested"}, ".")
-    >>> path.replace(os.sep, "/")
-    './other/pkg'
-    """
-    parts = name.split(".")
-    for i in range(len(parts), 0, -1):
-        # Look backwards, the most specific package_dir first
-        partial_name = ".".join(parts[:i])
-        if partial_name in package_dir:
-            parent = package_dir[partial_name]
-            return os.path.join(root_dir, parent, *parts[i:])
-
-    parent = package_dir.get("") or ""
-    return os.path.join(root_dir, *parent.split("/"), *parts)
-
-
-def construct_package_dir(packages: List[str], package_path: _Path) -> Dict[str, str]:
-    parent_pkgs = remove_nested_packages(packages)
-    prefix = Path(package_path).parts
-    return {pkg: "/".join([*prefix, *pkg.split(".")]) for pkg in parent_pkgs}
diff --git a/venv/lib/python3.11/site-packages/setuptools/dist.py b/venv/lib/python3.11/site-packages/setuptools/dist.py
deleted file mode 100755
index 32fff13..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/dist.py
+++ /dev/null
@@ -1,1218 +0,0 @@
-__all__ = ['Distribution']
-
-import io
-import sys
-import re
-import os
-import warnings
-import numbers
-import distutils.log
-import distutils.core
-import distutils.cmd
-import distutils.dist
-import distutils.command
-from distutils.util import strtobool
-from distutils.debug import DEBUG
-from distutils.fancy_getopt import translate_longopt
-from glob import iglob
-import itertools
-import textwrap
-from typing import List, Optional, Set, TYPE_CHECKING
-from pathlib import Path
-
-from collections import defaultdict
-from email import message_from_file
-
-from distutils.errors import DistutilsOptionError, DistutilsSetupError
-from distutils.util import rfc822_escape
-
-from setuptools.extern import packaging
-from setuptools.extern import ordered_set
-from setuptools.extern.more_itertools import unique_everseen, partition
-
-from ._importlib import metadata
-
-from . import SetuptoolsDeprecationWarning
-
-import setuptools
-import setuptools.command
-from setuptools import windows_support
-from setuptools.monkey import get_unpatched
-from setuptools.config import setupcfg, pyprojecttoml
-from setuptools.discovery import ConfigDiscovery
-
-import pkg_resources
-from setuptools.extern.packaging import version
-from . import _reqs
-from . import _entry_points
-
-if TYPE_CHECKING:
-    from email.message import Message
-
-__import__('setuptools.extern.packaging.specifiers')
-__import__('setuptools.extern.packaging.version')
-
-
-def _get_unpatched(cls):
-    warnings.warn("Do not call this function", DistDeprecationWarning)
-    return get_unpatched(cls)
-
-
-def get_metadata_version(self):
-    mv = getattr(self, 'metadata_version', None)
-    if mv is None:
-        mv = version.Version('2.1')
-        self.metadata_version = mv
-    return mv
-
-
-def rfc822_unescape(content: str) -> str:
-    """Reverse RFC-822 escaping by removing leading whitespaces from content."""
-    lines = content.splitlines()
-    if len(lines) == 1:
-        return lines[0].lstrip()
-    return '\n'.join((lines[0].lstrip(), textwrap.dedent('\n'.join(lines[1:]))))
-
-
-def _read_field_from_msg(msg: "Message", field: str) -> Optional[str]:
-    """Read Message header field."""
-    value = msg[field]
-    if value == 'UNKNOWN':
-        return None
-    return value
-
-
-def _read_field_unescaped_from_msg(msg: "Message", field: str) -> Optional[str]:
-    """Read Message header field and apply rfc822_unescape."""
-    value = _read_field_from_msg(msg, field)
-    if value is None:
-        return value
-    return rfc822_unescape(value)
-
-
-def _read_list_from_msg(msg: "Message", field: str) -> Optional[List[str]]:
-    """Read Message header field and return all results as list."""
-    values = msg.get_all(field, None)
-    if values == []:
-        return None
-    return values
-
-
-def _read_payload_from_msg(msg: "Message") -> Optional[str]:
-    value = msg.get_payload().strip()
-    if value == 'UNKNOWN' or not value:
-        return None
-    return value
-
-
-def read_pkg_file(self, file):
-    """Reads the metadata values from a file object."""
-    msg = message_from_file(file)
-
-    self.metadata_version = version.Version(msg['metadata-version'])
-    self.name = _read_field_from_msg(msg, 'name')
-    self.version = _read_field_from_msg(msg, 'version')
-    self.description = _read_field_from_msg(msg, 'summary')
-    # we are filling author only.
-    self.author = _read_field_from_msg(msg, 'author')
-    self.maintainer = None
-    self.author_email = _read_field_from_msg(msg, 'author-email')
-    self.maintainer_email = None
-    self.url = _read_field_from_msg(msg, 'home-page')
-    self.download_url = _read_field_from_msg(msg, 'download-url')
-    self.license = _read_field_unescaped_from_msg(msg, 'license')
-
-    self.long_description = _read_field_unescaped_from_msg(msg, 'description')
-    if (
-        self.long_description is None and
-        self.metadata_version >= version.Version('2.1')
-    ):
-        self.long_description = _read_payload_from_msg(msg)
-    self.description = _read_field_from_msg(msg, 'summary')
-
-    if 'keywords' in msg:
-        self.keywords = _read_field_from_msg(msg, 'keywords').split(',')
-
-    self.platforms = _read_list_from_msg(msg, 'platform')
-    self.classifiers = _read_list_from_msg(msg, 'classifier')
-
-    # PEP 314 - these fields only exist in 1.1
-    if self.metadata_version == version.Version('1.1'):
-        self.requires = _read_list_from_msg(msg, 'requires')
-        self.provides = _read_list_from_msg(msg, 'provides')
-        self.obsoletes = _read_list_from_msg(msg, 'obsoletes')
-    else:
-        self.requires = None
-        self.provides = None
-        self.obsoletes = None
-
-    self.license_files = _read_list_from_msg(msg, 'license-file')
-
-
-def single_line(val):
-    """
-    Quick and dirty validation for Summary pypa/setuptools#1390.
-    """
-    if '\n' in val:
-        # TODO: Replace with `raise ValueError("newlines not allowed")`
-        # after reviewing #2893.
-        warnings.warn("newlines not allowed and will break in the future")
-        val = val.strip().split('\n')[0]
-    return val
-
-
-# Based on Python 3.5 version
-def write_pkg_file(self, file):  # noqa: C901  # is too complex (14)  # FIXME
-    """Write the PKG-INFO format data to a file object."""
-    version = self.get_metadata_version()
-
-    def write_field(key, value):
-        file.write("%s: %s\n" % (key, value))
-
-    write_field('Metadata-Version', str(version))
-    write_field('Name', self.get_name())
-    write_field('Version', self.get_version())
-
-    summary = self.get_description()
-    if summary:
-        write_field('Summary', single_line(summary))
-
-    optional_fields = (
-        ('Home-page', 'url'),
-        ('Download-URL', 'download_url'),
-        ('Author', 'author'),
-        ('Author-email', 'author_email'),
-        ('Maintainer', 'maintainer'),
-        ('Maintainer-email', 'maintainer_email'),
-    )
-
-    for field, attr in optional_fields:
-        attr_val = getattr(self, attr, None)
-        if attr_val is not None:
-            write_field(field, attr_val)
-
-    license = self.get_license()
-    if license:
-        write_field('License', rfc822_escape(license))
-
-    for project_url in self.project_urls.items():
-        write_field('Project-URL', '%s, %s' % project_url)
-
-    keywords = ','.join(self.get_keywords())
-    if keywords:
-        write_field('Keywords', keywords)
-
-    platforms = self.get_platforms() or []
-    for platform in platforms:
-        write_field('Platform', platform)
-
-    self._write_list(file, 'Classifier', self.get_classifiers())
-
-    # PEP 314
-    self._write_list(file, 'Requires', self.get_requires())
-    self._write_list(file, 'Provides', self.get_provides())
-    self._write_list(file, 'Obsoletes', self.get_obsoletes())
-
-    # Setuptools specific for PEP 345
-    if hasattr(self, 'python_requires'):
-        write_field('Requires-Python', self.python_requires)
-
-    # PEP 566
-    if self.long_description_content_type:
-        write_field('Description-Content-Type', self.long_description_content_type)
-    if self.provides_extras:
-        for extra in sorted(self.provides_extras):
-            write_field('Provides-Extra', extra)
-
-    self._write_list(file, 'License-File', self.license_files or [])
-
-    long_description = self.get_long_description()
-    if long_description:
-        file.write("\n%s" % long_description)
-        if not long_description.endswith("\n"):
-            file.write("\n")
-
-
-sequence = tuple, list
-
-
-def check_importable(dist, attr, value):
-    try:
-        ep = metadata.EntryPoint(value=value, name=None, group=None)
-        assert not ep.extras
-    except (TypeError, ValueError, AttributeError, AssertionError) as e:
-        raise DistutilsSetupError(
-            "%r must be importable 'module:attrs' string (got %r)" % (attr, value)
-        ) from e
-
-
-def assert_string_list(dist, attr, value):
-    """Verify that value is a string list"""
-    try:
-        # verify that value is a list or tuple to exclude unordered
-        # or single-use iterables
-        assert isinstance(value, (list, tuple))
-        # verify that elements of value are strings
-        assert ''.join(value) != value
-    except (TypeError, ValueError, AttributeError, AssertionError) as e:
-        raise DistutilsSetupError(
-            "%r must be a list of strings (got %r)" % (attr, value)
-        ) from e
-
-
-def check_nsp(dist, attr, value):
-    """Verify that namespace packages are valid"""
-    ns_packages = value
-    assert_string_list(dist, attr, ns_packages)
-    for nsp in ns_packages:
-        if not dist.has_contents_for(nsp):
-            raise DistutilsSetupError(
-                "Distribution contains no modules or packages for "
-                + "namespace package %r" % nsp
-            )
-        parent, sep, child = nsp.rpartition('.')
-        if parent and parent not in ns_packages:
-            distutils.log.warn(
-                "WARNING: %r is declared as a package namespace, but %r"
-                " is not: please correct this in setup.py",
-                nsp,
-                parent,
-            )
-        msg = (
-            "The namespace_packages parameter is deprecated, "
-            "consider using implicit namespaces instead (PEP 420)."
-        )
-        warnings.warn(msg, SetuptoolsDeprecationWarning)
-
-
-def check_extras(dist, attr, value):
-    """Verify that extras_require mapping is valid"""
-    try:
-        list(itertools.starmap(_check_extra, value.items()))
-    except (TypeError, ValueError, AttributeError) as e:
-        raise DistutilsSetupError(
-            "'extras_require' must be a dictionary whose values are "
-            "strings or lists of strings containing valid project/version "
-            "requirement specifiers."
-        ) from e
-
-
-def _check_extra(extra, reqs):
-    name, sep, marker = extra.partition(':')
-    if marker and pkg_resources.invalid_marker(marker):
-        raise DistutilsSetupError("Invalid environment marker: " + marker)
-    list(_reqs.parse(reqs))
-
-
-def assert_bool(dist, attr, value):
-    """Verify that value is True, False, 0, or 1"""
-    if bool(value) != value:
-        tmpl = "{attr!r} must be a boolean value (got {value!r})"
-        raise DistutilsSetupError(tmpl.format(attr=attr, value=value))
-
-
-def invalid_unless_false(dist, attr, value):
-    if not value:
-        warnings.warn(f"{attr} is ignored.", DistDeprecationWarning)
-        return
-    raise DistutilsSetupError(f"{attr} is invalid.")
-
-
-def check_requirements(dist, attr, value):
-    """Verify that install_requires is a valid requirements list"""
-    try:
-        list(_reqs.parse(value))
-        if isinstance(value, (dict, set)):
-            raise TypeError("Unordered types are not allowed")
-    except (TypeError, ValueError) as error:
-        tmpl = (
-            "{attr!r} must be a string or list of strings "
-            "containing valid project/version requirement specifiers; {error}"
-        )
-        raise DistutilsSetupError(tmpl.format(attr=attr, error=error)) from error
-
-
-def check_specifier(dist, attr, value):
-    """Verify that value is a valid version specifier"""
-    try:
-        packaging.specifiers.SpecifierSet(value)
-    except (packaging.specifiers.InvalidSpecifier, AttributeError) as error:
-        tmpl = (
-            "{attr!r} must be a string " "containing valid version specifiers; {error}"
-        )
-        raise DistutilsSetupError(tmpl.format(attr=attr, error=error)) from error
-
-
-def check_entry_points(dist, attr, value):
-    """Verify that entry_points map is parseable"""
-    try:
-        _entry_points.load(value)
-    except Exception as e:
-        raise DistutilsSetupError(e) from e
-
-
-def check_test_suite(dist, attr, value):
-    if not isinstance(value, str):
-        raise DistutilsSetupError("test_suite must be a string")
-
-
-def check_package_data(dist, attr, value):
-    """Verify that value is a dictionary of package names to glob lists"""
-    if not isinstance(value, dict):
-        raise DistutilsSetupError(
-            "{!r} must be a dictionary mapping package names to lists of "
-            "string wildcard patterns".format(attr)
-        )
-    for k, v in value.items():
-        if not isinstance(k, str):
-            raise DistutilsSetupError(
-                "keys of {!r} dict must be strings (got {!r})".format(attr, k)
-            )
-        assert_string_list(dist, 'values of {!r} dict'.format(attr), v)
-
-
-def check_packages(dist, attr, value):
-    for pkgname in value:
-        if not re.match(r'\w+(\.\w+)*', pkgname):
-            distutils.log.warn(
-                "WARNING: %r not a valid package name; please use only "
-                ".-separated package names in setup.py",
-                pkgname,
-            )
-
-
-_Distribution = get_unpatched(distutils.core.Distribution)
-
-
-class Distribution(_Distribution):
-    """Distribution with support for tests and package data
-
-    This is an enhanced version of 'distutils.dist.Distribution' that
-    effectively adds the following new optional keyword arguments to 'setup()':
-
-     'install_requires' -- a string or sequence of strings specifying project
-        versions that the distribution requires when installed, in the format
-        used by 'pkg_resources.require()'.  They will be installed
-        automatically when the package is installed.  If you wish to use
-        packages that are not available in PyPI, or want to give your users an
-        alternate download location, you can add a 'find_links' option to the
-        '[easy_install]' section of your project's 'setup.cfg' file, and then
-        setuptools will scan the listed web pages for links that satisfy the
-        requirements.
-
-     'extras_require' -- a dictionary mapping names of optional "extras" to the
-        additional requirement(s) that using those extras incurs. For example,
-        this::
-
-            extras_require = dict(reST = ["docutils>=0.3", "reSTedit"])
-
-        indicates that the distribution can optionally provide an extra
-        capability called "reST", but it can only be used if docutils and
-        reSTedit are installed.  If the user installs your package using
-        EasyInstall and requests one of your extras, the corresponding
-        additional requirements will be installed if needed.
-
-     'test_suite' -- the name of a test suite to run for the 'test' command.
-        If the user runs 'python setup.py test', the package will be installed,
-        and the named test suite will be run.  The format is the same as
-        would be used on a 'unittest.py' command line.  That is, it is the
-        dotted name of an object to import and call to generate a test suite.
-
-     'package_data' -- a dictionary mapping package names to lists of filenames
-        or globs to use to find data files contained in the named packages.
-        If the dictionary has filenames or globs listed under '""' (the empty
-        string), those names will be searched for in every package, in addition
-        to any names for the specific package.  Data files found using these
-        names/globs will be installed along with the package, in the same
-        location as the package.  Note that globs are allowed to reference
-        the contents of non-package subdirectories, as long as you use '/' as
-        a path separator.  (Globs are automatically converted to
-        platform-specific paths at runtime.)
-
-    In addition to these new keywords, this class also has several new methods
-    for manipulating the distribution's contents.  For example, the 'include()'
-    and 'exclude()' methods can be thought of as in-place add and subtract
-    commands that add or remove packages, modules, extensions, and so on from
-    the distribution.
-    """
-
-    _DISTUTILS_UNSUPPORTED_METADATA = {
-        'long_description_content_type': lambda: None,
-        'project_urls': dict,
-        'provides_extras': ordered_set.OrderedSet,
-        'license_file': lambda: None,
-        'license_files': lambda: None,
-    }
-
-    _patched_dist = None
-
-    def patch_missing_pkg_info(self, attrs):
-        # Fake up a replacement for the data that would normally come from
-        # PKG-INFO, but which might not yet be built if this is a fresh
-        # checkout.
-        #
-        if not attrs or 'name' not in attrs or 'version' not in attrs:
-            return
-        key = pkg_resources.safe_name(str(attrs['name'])).lower()
-        dist = pkg_resources.working_set.by_key.get(key)
-        if dist is not None and not dist.has_metadata('PKG-INFO'):
-            dist._version = pkg_resources.safe_version(str(attrs['version']))
-            self._patched_dist = dist
-
-    def __init__(self, attrs=None):
-        have_package_data = hasattr(self, "package_data")
-        if not have_package_data:
-            self.package_data = {}
-        attrs = attrs or {}
-        self.dist_files = []
-        # Filter-out setuptools' specific options.
-        self.src_root = attrs.pop("src_root", None)
-        self.patch_missing_pkg_info(attrs)
-        self.dependency_links = attrs.pop('dependency_links', [])
-        self.setup_requires = attrs.pop('setup_requires', [])
-        for ep in metadata.entry_points(group='distutils.setup_keywords'):
-            vars(self).setdefault(ep.name, None)
-        _Distribution.__init__(
-            self,
-            {
-                k: v
-                for k, v in attrs.items()
-                if k not in self._DISTUTILS_UNSUPPORTED_METADATA
-            },
-        )
-
-        # Private API (setuptools-use only, not restricted to Distribution)
-        # Stores files that are referenced by the configuration and need to be in the
-        # sdist (e.g. `version = file: VERSION.txt`)
-        self._referenced_files: Set[str] = set()
-
-        # Save the original dependencies before they are processed into the egg format
-        self._orig_extras_require = {}
-        self._orig_install_requires = []
-        self._tmp_extras_require = defaultdict(ordered_set.OrderedSet)
-
-        self.set_defaults = ConfigDiscovery(self)
-
-        self._set_metadata_defaults(attrs)
-
-        self.metadata.version = self._normalize_version(
-            self._validate_version(self.metadata.version)
-        )
-        self._finalize_requires()
-
-    def _validate_metadata(self):
-        required = {"name"}
-        provided = {
-            key
-            for key in vars(self.metadata)
-            if getattr(self.metadata, key, None) is not None
-        }
-        missing = required - provided
-
-        if missing:
-            msg = f"Required package metadata is missing: {missing}"
-            raise DistutilsSetupError(msg)
-
-    def _set_metadata_defaults(self, attrs):
-        """
-        Fill-in missing metadata fields not supported by distutils.
-        Some fields may have been set by other tools (e.g. pbr).
-        Those fields (vars(self.metadata)) take precedence to
-        supplied attrs.
-        """
-        for option, default in self._DISTUTILS_UNSUPPORTED_METADATA.items():
-            vars(self.metadata).setdefault(option, attrs.get(option, default()))
-
-    @staticmethod
-    def _normalize_version(version):
-        if isinstance(version, setuptools.sic) or version is None:
-            return version
-
-        normalized = str(packaging.version.Version(version))
-        if version != normalized:
-            tmpl = "Normalizing '{version}' to '{normalized}'"
-            warnings.warn(tmpl.format(**locals()))
-            return normalized
-        return version
-
-    @staticmethod
-    def _validate_version(version):
-        if isinstance(version, numbers.Number):
-            # Some people apparently take "version number" too literally :)
-            version = str(version)
-
-        if version is not None:
-            try:
-                packaging.version.Version(version)
-            except (packaging.version.InvalidVersion, TypeError):
-                warnings.warn(
-                    "The version specified (%r) is an invalid version, this "
-                    "may not work as expected with newer versions of "
-                    "setuptools, pip, and PyPI. Please see PEP 440 for more "
-                    "details." % version
-                )
-                return setuptools.sic(version)
-        return version
-
-    def _finalize_requires(self):
-        """
-        Set `metadata.python_requires` and fix environment markers
-        in `install_requires` and `extras_require`.
-        """
-        if getattr(self, 'python_requires', None):
-            self.metadata.python_requires = self.python_requires
-
-        if getattr(self, 'extras_require', None):
-            # Save original before it is messed by _convert_extras_requirements
-            self._orig_extras_require = self._orig_extras_require or self.extras_require
-            for extra in self.extras_require.keys():
-                # Since this gets called multiple times at points where the
-                # keys have become 'converted' extras, ensure that we are only
-                # truly adding extras we haven't seen before here.
-                extra = extra.split(':')[0]
-                if extra:
-                    self.metadata.provides_extras.add(extra)
-
-        if getattr(self, 'install_requires', None) and not self._orig_install_requires:
-            # Save original before it is messed by _move_install_requirements_markers
-            self._orig_install_requires = self.install_requires
-
-        self._convert_extras_requirements()
-        self._move_install_requirements_markers()
-
-    def _convert_extras_requirements(self):
-        """
-        Convert requirements in `extras_require` of the form
-        `"extra": ["barbazquux; {marker}"]` to
-        `"extra:{marker}": ["barbazquux"]`.
-        """
-        spec_ext_reqs = getattr(self, 'extras_require', None) or {}
-        tmp = defaultdict(ordered_set.OrderedSet)
-        self._tmp_extras_require = getattr(self, '_tmp_extras_require', tmp)
-        for section, v in spec_ext_reqs.items():
-            # Do not strip empty sections.
-            self._tmp_extras_require[section]
-            for r in _reqs.parse(v):
-                suffix = self._suffix_for(r)
-                self._tmp_extras_require[section + suffix].append(r)
-
-    @staticmethod
-    def _suffix_for(req):
-        """
-        For a requirement, return the 'extras_require' suffix for
-        that requirement.
-        """
-        return ':' + str(req.marker) if req.marker else ''
-
-    def _move_install_requirements_markers(self):
-        """
-        Move requirements in `install_requires` that are using environment
-        markers `extras_require`.
-        """
-
-        # divide the install_requires into two sets, simple ones still
-        # handled by install_requires and more complex ones handled
-        # by extras_require.
-
-        def is_simple_req(req):
-            return not req.marker
-
-        spec_inst_reqs = getattr(self, 'install_requires', None) or ()
-        inst_reqs = list(_reqs.parse(spec_inst_reqs))
-        simple_reqs = filter(is_simple_req, inst_reqs)
-        complex_reqs = itertools.filterfalse(is_simple_req, inst_reqs)
-        self.install_requires = list(map(str, simple_reqs))
-
-        for r in complex_reqs:
-            self._tmp_extras_require[':' + str(r.marker)].append(r)
-        self.extras_require = dict(
-            # list(dict.fromkeys(...))  ensures a list of unique strings
-            (k, list(dict.fromkeys(str(r) for r in map(self._clean_req, v))))
-            for k, v in self._tmp_extras_require.items()
-        )
-
-    def _clean_req(self, req):
-        """
-        Given a Requirement, remove environment markers and return it.
-        """
-        req.marker = None
-        return req
-
-    def _finalize_license_files(self):
-        """Compute names of all license files which should be included."""
-        license_files: Optional[List[str]] = self.metadata.license_files
-        patterns: List[str] = license_files if license_files else []
-
-        license_file: Optional[str] = self.metadata.license_file
-        if license_file and license_file not in patterns:
-            patterns.append(license_file)
-
-        if license_files is None and license_file is None:
-            # Default patterns match the ones wheel uses
-            # See https://wheel.readthedocs.io/en/stable/user_guide.html
-            # -> 'Including license files in the generated wheel file'
-            patterns = ('LICEN[CS]E*', 'COPYING*', 'NOTICE*', 'AUTHORS*')
-
-        self.metadata.license_files = list(
-            unique_everseen(self._expand_patterns(patterns))
-        )
-
-    @staticmethod
-    def _expand_patterns(patterns):
-        """
-        >>> list(Distribution._expand_patterns(['LICENSE']))
-        ['LICENSE']
-        >>> list(Distribution._expand_patterns(['setup.cfg', 'LIC*']))
-        ['setup.cfg', 'LICENSE']
-        """
-        return (
-            path
-            for pattern in patterns
-            for path in sorted(iglob(pattern))
-            if not path.endswith('~') and os.path.isfile(path)
-        )
-
-    # FIXME: 'Distribution._parse_config_files' is too complex (14)
-    def _parse_config_files(self, filenames=None):  # noqa: C901
-        """
-        Adapted from distutils.dist.Distribution.parse_config_files,
-        this method provides the same functionality in subtly-improved
-        ways.
-        """
-        from configparser import ConfigParser
-
-        # Ignore install directory options if we have a venv
-        ignore_options = (
-            []
-            if sys.prefix == sys.base_prefix
-            else [
-                'install-base',
-                'install-platbase',
-                'install-lib',
-                'install-platlib',
-                'install-purelib',
-                'install-headers',
-                'install-scripts',
-                'install-data',
-                'prefix',
-                'exec-prefix',
-                'home',
-                'user',
-                'root',
-            ]
-        )
-
-        ignore_options = frozenset(ignore_options)
-
-        if filenames is None:
-            filenames = self.find_config_files()
-
-        if DEBUG:
-            self.announce("Distribution.parse_config_files():")
-
-        parser = ConfigParser()
-        parser.optionxform = str
-        for filename in filenames:
-            with io.open(filename, encoding='utf-8') as reader:
-                if DEBUG:
-                    self.announce("  reading {filename}".format(**locals()))
-                parser.read_file(reader)
-            for section in parser.sections():
-                options = parser.options(section)
-                opt_dict = self.get_option_dict(section)
-
-                for opt in options:
-                    if opt == '__name__' or opt in ignore_options:
-                        continue
-
-                    val = parser.get(section, opt)
-                    opt = self.warn_dash_deprecation(opt, section)
-                    opt = self.make_option_lowercase(opt, section)
-                    opt_dict[opt] = (filename, val)
-
-            # Make the ConfigParser forget everything (so we retain
-            # the original filenames that options come from)
-            parser.__init__()
-
-        if 'global' not in self.command_options:
-            return
-
-        # If there was a "global" section in the config file, use it
-        # to set Distribution options.
-
-        for (opt, (src, val)) in self.command_options['global'].items():
-            alias = self.negative_opt.get(opt)
-            if alias:
-                val = not strtobool(val)
-            elif opt in ('verbose', 'dry_run'):  # ugh!
-                val = strtobool(val)
-
-            try:
-                setattr(self, alias or opt, val)
-            except ValueError as e:
-                raise DistutilsOptionError(e) from e
-
-    def warn_dash_deprecation(self, opt, section):
-        if section in (
-            'options.extras_require',
-            'options.data_files',
-        ):
-            return opt
-
-        underscore_opt = opt.replace('-', '_')
-        commands = list(itertools.chain(
-            distutils.command.__all__,
-            self._setuptools_commands(),
-        ))
-        if (
-            not section.startswith('options')
-            and section != 'metadata'
-            and section not in commands
-        ):
-            return underscore_opt
-
-        if '-' in opt:
-            warnings.warn(
-                "Usage of dash-separated '%s' will not be supported in future "
-                "versions. Please use the underscore name '%s' instead"
-                % (opt, underscore_opt)
-            )
-        return underscore_opt
-
-    def _setuptools_commands(self):
-        try:
-            return metadata.distribution('setuptools').entry_points.names
-        except metadata.PackageNotFoundError:
-            # during bootstrapping, distribution doesn't exist
-            return []
-
-    def make_option_lowercase(self, opt, section):
-        if section != 'metadata' or opt.islower():
-            return opt
-
-        lowercase_opt = opt.lower()
-        warnings.warn(
-            "Usage of uppercase key '%s' in '%s' will be deprecated in future "
-            "versions. Please use lowercase '%s' instead"
-            % (opt, section, lowercase_opt)
-        )
-        return lowercase_opt
-
-    # FIXME: 'Distribution._set_command_options' is too complex (14)
-    def _set_command_options(self, command_obj, option_dict=None):  # noqa: C901
-        """
-        Set the options for 'command_obj' from 'option_dict'.  Basically
-        this means copying elements of a dictionary ('option_dict') to
-        attributes of an instance ('command').
-
-        'command_obj' must be a Command instance.  If 'option_dict' is not
-        supplied, uses the standard option dictionary for this command
-        (from 'self.command_options').
-
-        (Adopted from distutils.dist.Distribution._set_command_options)
-        """
-        command_name = command_obj.get_command_name()
-        if option_dict is None:
-            option_dict = self.get_option_dict(command_name)
-
-        if DEBUG:
-            self.announce("  setting options for '%s' command:" % command_name)
-        for (option, (source, value)) in option_dict.items():
-            if DEBUG:
-                self.announce("    %s = %s (from %s)" % (option, value, source))
-            try:
-                bool_opts = [translate_longopt(o) for o in command_obj.boolean_options]
-            except AttributeError:
-                bool_opts = []
-            try:
-                neg_opt = command_obj.negative_opt
-            except AttributeError:
-                neg_opt = {}
-
-            try:
-                is_string = isinstance(value, str)
-                if option in neg_opt and is_string:
-                    setattr(command_obj, neg_opt[option], not strtobool(value))
-                elif option in bool_opts and is_string:
-                    setattr(command_obj, option, strtobool(value))
-                elif hasattr(command_obj, option):
-                    setattr(command_obj, option, value)
-                else:
-                    raise DistutilsOptionError(
-                        "error in %s: command '%s' has no such option '%s'"
-                        % (source, command_name, option)
-                    )
-            except ValueError as e:
-                raise DistutilsOptionError(e) from e
-
-    def _get_project_config_files(self, filenames):
-        """Add default file and split between INI and TOML"""
-        tomlfiles = []
-        standard_project_metadata = Path(self.src_root or os.curdir, "pyproject.toml")
-        if filenames is not None:
-            parts = partition(lambda f: Path(f).suffix == ".toml", filenames)
-            filenames = list(parts[0])  # 1st element => predicate is False
-            tomlfiles = list(parts[1])  # 2nd element => predicate is True
-        elif standard_project_metadata.exists():
-            tomlfiles = [standard_project_metadata]
-        return filenames, tomlfiles
-
-    def parse_config_files(self, filenames=None, ignore_option_errors=False):
-        """Parses configuration files from various levels
-        and loads configuration.
-        """
-        inifiles, tomlfiles = self._get_project_config_files(filenames)
-
-        self._parse_config_files(filenames=inifiles)
-
-        setupcfg.parse_configuration(
-            self, self.command_options, ignore_option_errors=ignore_option_errors
-        )
-        for filename in tomlfiles:
-            pyprojecttoml.apply_configuration(self, filename, ignore_option_errors)
-
-        self._finalize_requires()
-        self._finalize_license_files()
-
-    def fetch_build_eggs(self, requires):
-        """Resolve pre-setup requirements"""
-        resolved_dists = pkg_resources.working_set.resolve(
-            _reqs.parse(requires),
-            installer=self.fetch_build_egg,
-            replace_conflicting=True,
-        )
-        for dist in resolved_dists:
-            pkg_resources.working_set.add(dist, replace=True)
-        return resolved_dists
-
-    def finalize_options(self):
-        """
-        Allow plugins to apply arbitrary operations to the
-        distribution. Each hook may optionally define a 'order'
-        to influence the order of execution. Smaller numbers
-        go first and the default is 0.
-        """
-        group = 'setuptools.finalize_distribution_options'
-
-        def by_order(hook):
-            return getattr(hook, 'order', 0)
-
-        defined = metadata.entry_points(group=group)
-        filtered = itertools.filterfalse(self._removed, defined)
-        loaded = map(lambda e: e.load(), filtered)
-        for ep in sorted(loaded, key=by_order):
-            ep(self)
-
-    @staticmethod
-    def _removed(ep):
-        """
-        When removing an entry point, if metadata is loaded
-        from an older version of Setuptools, that removed
-        entry point will attempt to be loaded and will fail.
-        See #2765 for more details.
-        """
-        removed = {
-            # removed 2021-09-05
-            '2to3_doctests',
-        }
-        return ep.name in removed
-
-    def _finalize_setup_keywords(self):
-        for ep in metadata.entry_points(group='distutils.setup_keywords'):
-            value = getattr(self, ep.name, None)
-            if value is not None:
-                ep.load()(self, ep.name, value)
-
-    def get_egg_cache_dir(self):
-        egg_cache_dir = os.path.join(os.curdir, '.eggs')
-        if not os.path.exists(egg_cache_dir):
-            os.mkdir(egg_cache_dir)
-            windows_support.hide_file(egg_cache_dir)
-            readme_txt_filename = os.path.join(egg_cache_dir, 'README.txt')
-            with open(readme_txt_filename, 'w') as f:
-                f.write(
-                    'This directory contains eggs that were downloaded '
-                    'by setuptools to build, test, and run plug-ins.\n\n'
-                )
-                f.write(
-                    'This directory caches those eggs to prevent '
-                    'repeated downloads.\n\n'
-                )
-                f.write('However, it is safe to delete this directory.\n\n')
-
-        return egg_cache_dir
-
-    def fetch_build_egg(self, req):
-        """Fetch an egg needed for building"""
-        from setuptools.installer import fetch_build_egg
-
-        return fetch_build_egg(self, req)
-
-    def get_command_class(self, command):
-        """Pluggable version of get_command_class()"""
-        if command in self.cmdclass:
-            return self.cmdclass[command]
-
-        eps = metadata.entry_points(group='distutils.commands', name=command)
-        for ep in eps:
-            self.cmdclass[command] = cmdclass = ep.load()
-            return cmdclass
-        else:
-            return _Distribution.get_command_class(self, command)
-
-    def print_commands(self):
-        for ep in metadata.entry_points(group='distutils.commands'):
-            if ep.name not in self.cmdclass:
-                cmdclass = ep.load()
-                self.cmdclass[ep.name] = cmdclass
-        return _Distribution.print_commands(self)
-
-    def get_command_list(self):
-        for ep in metadata.entry_points(group='distutils.commands'):
-            if ep.name not in self.cmdclass:
-                cmdclass = ep.load()
-                self.cmdclass[ep.name] = cmdclass
-        return _Distribution.get_command_list(self)
-
-    def include(self, **attrs):
-        """Add items to distribution that are named in keyword arguments
-
-        For example, 'dist.include(py_modules=["x"])' would add 'x' to
-        the distribution's 'py_modules' attribute, if it was not already
-        there.
-
-        Currently, this method only supports inclusion for attributes that are
-        lists or tuples.  If you need to add support for adding to other
-        attributes in this or a subclass, you can add an '_include_X' method,
-        where 'X' is the name of the attribute.  The method will be called with
-        the value passed to 'include()'.  So, 'dist.include(foo={"bar":"baz"})'
-        will try to call 'dist._include_foo({"bar":"baz"})', which can then
-        handle whatever special inclusion logic is needed.
-        """
-        for k, v in attrs.items():
-            include = getattr(self, '_include_' + k, None)
-            if include:
-                include(v)
-            else:
-                self._include_misc(k, v)
-
-    def exclude_package(self, package):
-        """Remove packages, modules, and extensions in named package"""
-
-        pfx = package + '.'
-        if self.packages:
-            self.packages = [
-                p for p in self.packages if p != package and not p.startswith(pfx)
-            ]
-
-        if self.py_modules:
-            self.py_modules = [
-                p for p in self.py_modules if p != package and not p.startswith(pfx)
-            ]
-
-        if self.ext_modules:
-            self.ext_modules = [
-                p
-                for p in self.ext_modules
-                if p.name != package and not p.name.startswith(pfx)
-            ]
-
-    def has_contents_for(self, package):
-        """Return true if 'exclude_package(package)' would do something"""
-
-        pfx = package + '.'
-
-        for p in self.iter_distribution_names():
-            if p == package or p.startswith(pfx):
-                return True
-
-    def _exclude_misc(self, name, value):
-        """Handle 'exclude()' for list/tuple attrs without a special handler"""
-        if not isinstance(value, sequence):
-            raise DistutilsSetupError(
-                "%s: setting must be a list or tuple (%r)" % (name, value)
-            )
-        try:
-            old = getattr(self, name)
-        except AttributeError as e:
-            raise DistutilsSetupError("%s: No such distribution setting" % name) from e
-        if old is not None and not isinstance(old, sequence):
-            raise DistutilsSetupError(
-                name + ": this setting cannot be changed via include/exclude"
-            )
-        elif old:
-            setattr(self, name, [item for item in old if item not in value])
-
-    def _include_misc(self, name, value):
-        """Handle 'include()' for list/tuple attrs without a special handler"""
-
-        if not isinstance(value, sequence):
-            raise DistutilsSetupError("%s: setting must be a list (%r)" % (name, value))
-        try:
-            old = getattr(self, name)
-        except AttributeError as e:
-            raise DistutilsSetupError("%s: No such distribution setting" % name) from e
-        if old is None:
-            setattr(self, name, value)
-        elif not isinstance(old, sequence):
-            raise DistutilsSetupError(
-                name + ": this setting cannot be changed via include/exclude"
-            )
-        else:
-            new = [item for item in value if item not in old]
-            setattr(self, name, old + new)
-
-    def exclude(self, **attrs):
-        """Remove items from distribution that are named in keyword arguments
-
-        For example, 'dist.exclude(py_modules=["x"])' would remove 'x' from
-        the distribution's 'py_modules' attribute.  Excluding packages uses
-        the 'exclude_package()' method, so all of the package's contained
-        packages, modules, and extensions are also excluded.
-
-        Currently, this method only supports exclusion from attributes that are
-        lists or tuples.  If you need to add support for excluding from other
-        attributes in this or a subclass, you can add an '_exclude_X' method,
-        where 'X' is the name of the attribute.  The method will be called with
-        the value passed to 'exclude()'.  So, 'dist.exclude(foo={"bar":"baz"})'
-        will try to call 'dist._exclude_foo({"bar":"baz"})', which can then
-        handle whatever special exclusion logic is needed.
-        """
-        for k, v in attrs.items():
-            exclude = getattr(self, '_exclude_' + k, None)
-            if exclude:
-                exclude(v)
-            else:
-                self._exclude_misc(k, v)
-
-    def _exclude_packages(self, packages):
-        if not isinstance(packages, sequence):
-            raise DistutilsSetupError(
-                "packages: setting must be a list or tuple (%r)" % (packages,)
-            )
-        list(map(self.exclude_package, packages))
-
-    def _parse_command_opts(self, parser, args):
-        # Remove --with-X/--without-X options when processing command args
-        self.global_options = self.__class__.global_options
-        self.negative_opt = self.__class__.negative_opt
-
-        # First, expand any aliases
-        command = args[0]
-        aliases = self.get_option_dict('aliases')
-        while command in aliases:
-            src, alias = aliases[command]
-            del aliases[command]  # ensure each alias can expand only once!
-            import shlex
-
-            args[:1] = shlex.split(alias, True)
-            command = args[0]
-
-        nargs = _Distribution._parse_command_opts(self, parser, args)
-
-        # Handle commands that want to consume all remaining arguments
-        cmd_class = self.get_command_class(command)
-        if getattr(cmd_class, 'command_consumes_arguments', None):
-            self.get_option_dict(command)['args'] = ("command line", nargs)
-            if nargs is not None:
-                return []
-
-        return nargs
-
-    def get_cmdline_options(self):
-        """Return a '{cmd: {opt:val}}' map of all command-line options
-
-        Option names are all long, but do not include the leading '--', and
-        contain dashes rather than underscores.  If the option doesn't take
-        an argument (e.g. '--quiet'), the 'val' is 'None'.
-
-        Note that options provided by config files are intentionally excluded.
-        """
-
-        d = {}
-
-        for cmd, opts in self.command_options.items():
-
-            for opt, (src, val) in opts.items():
-
-                if src != "command line":
-                    continue
-
-                opt = opt.replace('_', '-')
-
-                if val == 0:
-                    cmdobj = self.get_command_obj(cmd)
-                    neg_opt = self.negative_opt.copy()
-                    neg_opt.update(getattr(cmdobj, 'negative_opt', {}))
-                    for neg, pos in neg_opt.items():
-                        if pos == opt:
-                            opt = neg
-                            val = None
-                            break
-                    else:
-                        raise AssertionError("Shouldn't be able to get here")
-
-                elif val == 1:
-                    val = None
-
-                d.setdefault(cmd, {})[opt] = val
-
-        return d
-
-    def iter_distribution_names(self):
-        """Yield all packages, modules, and extension names in distribution"""
-
-        for pkg in self.packages or ():
-            yield pkg
-
-        for module in self.py_modules or ():
-            yield module
-
-        for ext in self.ext_modules or ():
-            if isinstance(ext, tuple):
-                name, buildinfo = ext
-            else:
-                name = ext.name
-            if name.endswith('module'):
-                name = name[:-6]
-            yield name
-
-    def handle_display_options(self, option_order):
-        """If there were any non-global "display-only" options
-        (--help-commands or the metadata display options) on the command
-        line, display the requested info and return true; else return
-        false.
-        """
-        import sys
-
-        if self.help_commands:
-            return _Distribution.handle_display_options(self, option_order)
-
-        # Stdout may be StringIO (e.g. in tests)
-        if not isinstance(sys.stdout, io.TextIOWrapper):
-            return _Distribution.handle_display_options(self, option_order)
-
-        # Don't wrap stdout if utf-8 is already the encoding. Provides
-        #  workaround for #334.
-        if sys.stdout.encoding.lower() in ('utf-8', 'utf8'):
-            return _Distribution.handle_display_options(self, option_order)
-
-        # Print metadata in UTF-8 no matter the platform
-        encoding = sys.stdout.encoding
-        sys.stdout.reconfigure(encoding='utf-8')
-        try:
-            return _Distribution.handle_display_options(self, option_order)
-        finally:
-            sys.stdout.reconfigure(encoding=encoding)
-
-    def run_command(self, command):
-        self.set_defaults()
-        # Postpone defaults until all explicit configuration is considered
-        # (setup() args, config files, command line and plugins)
-
-        super().run_command(command)
-
-
-class DistDeprecationWarning(SetuptoolsDeprecationWarning):
-    """Class for warning about deprecations in dist in
-    setuptools. Not ignored by default, unlike DeprecationWarning."""
diff --git a/venv/lib/python3.11/site-packages/setuptools/errors.py b/venv/lib/python3.11/site-packages/setuptools/errors.py
deleted file mode 100755
index ec7fb3b..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/errors.py
+++ /dev/null
@@ -1,58 +0,0 @@
-"""setuptools.errors
-
-Provides exceptions used by setuptools modules.
-"""
-
-from distutils import errors as _distutils_errors
-
-
-# Re-export errors from distutils to facilitate the migration to PEP632
-
-ByteCompileError = _distutils_errors.DistutilsByteCompileError
-CCompilerError = _distutils_errors.CCompilerError
-ClassError = _distutils_errors.DistutilsClassError
-CompileError = _distutils_errors.CompileError
-ExecError = _distutils_errors.DistutilsExecError
-FileError = _distutils_errors.DistutilsFileError
-InternalError = _distutils_errors.DistutilsInternalError
-LibError = _distutils_errors.LibError
-LinkError = _distutils_errors.LinkError
-ModuleError = _distutils_errors.DistutilsModuleError
-OptionError = _distutils_errors.DistutilsOptionError
-PlatformError = _distutils_errors.DistutilsPlatformError
-PreprocessError = _distutils_errors.PreprocessError
-SetupError = _distutils_errors.DistutilsSetupError
-TemplateError = _distutils_errors.DistutilsTemplateError
-UnknownFileError = _distutils_errors.UnknownFileError
-
-# The root error class in the hierarchy
-BaseError = _distutils_errors.DistutilsError
-
-
-class RemovedCommandError(BaseError, RuntimeError):
-    """Error used for commands that have been removed in setuptools.
-
-    Since ``setuptools`` is built on ``distutils``, simply removing a command
-    from ``setuptools`` will make the behavior fall back to ``distutils``; this
-    error is raised if a command exists in ``distutils`` but has been actively
-    removed in ``setuptools``.
-    """
-
-
-class PackageDiscoveryError(BaseError, RuntimeError):
-    """Impossible to perform automatic discovery of packages and/or modules.
-
-    The current project layout or given discovery options can lead to problems when
-    scanning the project directory.
-
-    Setuptools might also refuse to complete auto-discovery if an error prone condition
-    is detected (e.g. when a project is organised as a flat-layout but contains
-    multiple directories that can be taken as top-level packages inside a single
-    distribution [*]_). In these situations the users are encouraged to be explicit
-    about which packages to include or to make the discovery parameters more specific.
-
-    .. [*] Since multi-package distributions are uncommon it is very likely that the
-       developers did not intend for all the directories to be packaged, and are just
-       leaving auxiliary code in the repository top-level, such as maintenance-related
-       scripts.
-    """
diff --git a/venv/lib/python3.11/site-packages/setuptools/extension.py b/venv/lib/python3.11/site-packages/setuptools/extension.py
deleted file mode 100755
index 58c023f..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/extension.py
+++ /dev/null
@@ -1,148 +0,0 @@
-import re
-import functools
-import distutils.core
-import distutils.errors
-import distutils.extension
-
-from .monkey import get_unpatched
-
-
-def _have_cython():
-    """
-    Return True if Cython can be imported.
-    """
-    cython_impl = 'Cython.Distutils.build_ext'
-    try:
-        # from (cython_impl) import build_ext
-        __import__(cython_impl, fromlist=['build_ext']).build_ext
-        return True
-    except Exception:
-        pass
-    return False
-
-
-# for compatibility
-have_pyrex = _have_cython
-
-_Extension = get_unpatched(distutils.core.Extension)
-
-
-class Extension(_Extension):
-    """
-    Describes a single extension module.
-
-    This means that all source files will be compiled into a single binary file
-    ``.`` (with ```` derived from ``name`` and
-    ```` defined by one of the values in
-    ``importlib.machinery.EXTENSION_SUFFIXES``).
-
-    In the case ``.pyx`` files are passed as ``sources and`` ``Cython`` is **not**
-    installed in the build environment, ``setuptools`` may also try to look for the
-    equivalent ``.cpp`` or ``.c`` files.
-
-    :arg str name:
-      the full name of the extension, including any packages -- ie.
-      *not* a filename or pathname, but Python dotted name
-
-    :arg list[str] sources:
-      list of source filenames, relative to the distribution root
-      (where the setup script lives), in Unix form (slash-separated)
-      for portability.  Source files may be C, C++, SWIG (.i),
-      platform-specific resource files, or whatever else is recognized
-      by the "build_ext" command as source for a Python extension.
-
-    :keyword list[str] include_dirs:
-      list of directories to search for C/C++ header files (in Unix
-      form for portability)
-
-    :keyword list[tuple[str, str|None]] define_macros:
-      list of macros to define; each macro is defined using a 2-tuple:
-      the first item corresponding to the name of the macro and the second
-      item either a string with its value or None to
-      define it without a particular value (equivalent of "#define
-      FOO" in source or -DFOO on Unix C compiler command line)
-
-    :keyword list[str] undef_macros:
-      list of macros to undefine explicitly
-
-    :keyword list[str] library_dirs:
-      list of directories to search for C/C++ libraries at link time
-
-    :keyword list[str] libraries:
-      list of library names (not filenames or paths) to link against
-
-    :keyword list[str] runtime_library_dirs:
-      list of directories to search for C/C++ libraries at run time
-      (for shared extensions, this is when the extension is loaded).
-      Setting this will cause an exception during build on Windows
-      platforms.
-
-    :keyword list[str] extra_objects:
-      list of extra files to link with (eg. object files not implied
-      by 'sources', static library that must be explicitly specified,
-      binary resource files, etc.)
-
-    :keyword list[str] extra_compile_args:
-      any extra platform- and compiler-specific information to use
-      when compiling the source files in 'sources'.  For platforms and
-      compilers where "command line" makes sense, this is typically a
-      list of command-line arguments, but for other platforms it could
-      be anything.
-
-    :keyword list[str] extra_link_args:
-      any extra platform- and compiler-specific information to use
-      when linking object files together to create the extension (or
-      to create a new static Python interpreter).  Similar
-      interpretation as for 'extra_compile_args'.
-
-    :keyword list[str] export_symbols:
-      list of symbols to be exported from a shared extension.  Not
-      used on all platforms, and not generally necessary for Python
-      extensions, which typically export exactly one symbol: "init" +
-      extension_name.
-
-    :keyword list[str] swig_opts:
-      any extra options to pass to SWIG if a source file has the .i
-      extension.
-
-    :keyword list[str] depends:
-      list of files that the extension depends on
-
-    :keyword str language:
-      extension language (i.e. "c", "c++", "objc"). Will be detected
-      from the source extensions if not provided.
-
-    :keyword bool optional:
-      specifies that a build failure in the extension should not abort the
-      build process, but simply not install the failing extension.
-
-    :keyword bool py_limited_api:
-      opt-in flag for the usage of :doc:`Python's limited API `.
-
-    :raises setuptools.errors.PlatformError: if 'runtime_library_dirs' is
-      specified on Windows. (since v63)
-    """
-
-    def __init__(self, name, sources, *args, **kw):
-        # The *args is needed for compatibility as calls may use positional
-        # arguments. py_limited_api may be set only via keyword.
-        self.py_limited_api = kw.pop("py_limited_api", False)
-        super().__init__(name, sources, *args, **kw)
-
-    def _convert_pyx_sources_to_lang(self):
-        """
-        Replace sources with .pyx extensions to sources with the target
-        language extension. This mechanism allows language authors to supply
-        pre-converted sources but to prefer the .pyx sources.
-        """
-        if _have_cython():
-            # the build has Cython, so allow it to compile the .pyx files
-            return
-        lang = self.language or ''
-        target_ext = '.cpp' if lang.lower() == 'c++' else '.c'
-        sub = functools.partial(re.sub, '.pyx$', target_ext)
-        self.sources = list(map(sub, self.sources))
-
-
-class Library(Extension):
-    """Just like a regular Extension, but built as a library instead"""
diff --git a/venv/lib/python3.11/site-packages/setuptools/extern/__init__.py b/venv/lib/python3.11/site-packages/setuptools/extern/__init__.py
deleted file mode 100755
index d3a6dc9..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/extern/__init__.py
+++ /dev/null
@@ -1,76 +0,0 @@
-import importlib.util
-import sys
-
-
-class VendorImporter:
-    """
-    A PEP 302 meta path importer for finding optionally-vendored
-    or otherwise naturally-installed packages from root_name.
-    """
-
-    def __init__(self, root_name, vendored_names=(), vendor_pkg=None):
-        self.root_name = root_name
-        self.vendored_names = set(vendored_names)
-        self.vendor_pkg = vendor_pkg or root_name.replace('extern', '_vendor')
-
-    @property
-    def search_path(self):
-        """
-        Search first the vendor package then as a natural package.
-        """
-        yield self.vendor_pkg + '.'
-        yield ''
-
-    def _module_matches_namespace(self, fullname):
-        """Figure out if the target module is vendored."""
-        root, base, target = fullname.partition(self.root_name + '.')
-        return not root and any(map(target.startswith, self.vendored_names))
-
-    def load_module(self, fullname):
-        """
-        Iterate over the search path to locate and load fullname.
-        """
-        root, base, target = fullname.partition(self.root_name + '.')
-        for prefix in self.search_path:
-            try:
-                extant = prefix + target
-                __import__(extant)
-                mod = sys.modules[extant]
-                sys.modules[fullname] = mod
-                return mod
-            except ImportError:
-                pass
-        else:
-            raise ImportError(
-                "The '{target}' package is required; "
-                "normally this is bundled with this package so if you get "
-                "this warning, consult the packager of your "
-                "distribution.".format(**locals())
-            )
-
-    def create_module(self, spec):
-        return self.load_module(spec.name)
-
-    def exec_module(self, module):
-        pass
-
-    def find_spec(self, fullname, path=None, target=None):
-        """Return a module spec for vendored names."""
-        return (
-            importlib.util.spec_from_loader(fullname, self)
-            if self._module_matches_namespace(fullname) else None
-        )
-
-    def install(self):
-        """
-        Install this importer into sys.meta_path if not already present.
-        """
-        if self not in sys.meta_path:
-            sys.meta_path.append(self)
-
-
-names = (
-    'packaging', 'pyparsing', 'ordered_set', 'more_itertools', 'importlib_metadata',
-    'zipp', 'importlib_resources', 'jaraco', 'typing_extensions', 'tomli',
-)
-VendorImporter(__name__, names, 'setuptools._vendor').install()
diff --git a/venv/lib/python3.11/site-packages/setuptools/extern/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/setuptools/extern/__pycache__/__init__.cpython-311.pyc
deleted file mode 100755
index f490855..0000000
Binary files a/venv/lib/python3.11/site-packages/setuptools/extern/__pycache__/__init__.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/setuptools/glob.py b/venv/lib/python3.11/site-packages/setuptools/glob.py
deleted file mode 100755
index 87062b8..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/glob.py
+++ /dev/null
@@ -1,167 +0,0 @@
-"""
-Filename globbing utility. Mostly a copy of `glob` from Python 3.5.
-
-Changes include:
- * `yield from` and PEP3102 `*` removed.
- * Hidden files are not ignored.
-"""
-
-import os
-import re
-import fnmatch
-
-__all__ = ["glob", "iglob", "escape"]
-
-
-def glob(pathname, recursive=False):
-    """Return a list of paths matching a pathname pattern.
-
-    The pattern may contain simple shell-style wildcards a la
-    fnmatch. However, unlike fnmatch, filenames starting with a
-    dot are special cases that are not matched by '*' and '?'
-    patterns.
-
-    If recursive is true, the pattern '**' will match any files and
-    zero or more directories and subdirectories.
-    """
-    return list(iglob(pathname, recursive=recursive))
-
-
-def iglob(pathname, recursive=False):
-    """Return an iterator which yields the paths matching a pathname pattern.
-
-    The pattern may contain simple shell-style wildcards a la
-    fnmatch. However, unlike fnmatch, filenames starting with a
-    dot are special cases that are not matched by '*' and '?'
-    patterns.
-
-    If recursive is true, the pattern '**' will match any files and
-    zero or more directories and subdirectories.
-    """
-    it = _iglob(pathname, recursive)
-    if recursive and _isrecursive(pathname):
-        s = next(it)  # skip empty string
-        assert not s
-    return it
-
-
-def _iglob(pathname, recursive):
-    dirname, basename = os.path.split(pathname)
-    glob_in_dir = glob2 if recursive and _isrecursive(basename) else glob1
-
-    if not has_magic(pathname):
-        if basename:
-            if os.path.lexists(pathname):
-                yield pathname
-        else:
-            # Patterns ending with a slash should match only directories
-            if os.path.isdir(dirname):
-                yield pathname
-        return
-
-    if not dirname:
-        yield from glob_in_dir(dirname, basename)
-        return
-    # `os.path.split()` returns the argument itself as a dirname if it is a
-    # drive or UNC path.  Prevent an infinite recursion if a drive or UNC path
-    # contains magic characters (i.e. r'\\?\C:').
-    if dirname != pathname and has_magic(dirname):
-        dirs = _iglob(dirname, recursive)
-    else:
-        dirs = [dirname]
-    if not has_magic(basename):
-        glob_in_dir = glob0
-    for dirname in dirs:
-        for name in glob_in_dir(dirname, basename):
-            yield os.path.join(dirname, name)
-
-
-# These 2 helper functions non-recursively glob inside a literal directory.
-# They return a list of basenames. `glob1` accepts a pattern while `glob0`
-# takes a literal basename (so it only has to check for its existence).
-
-
-def glob1(dirname, pattern):
-    if not dirname:
-        if isinstance(pattern, bytes):
-            dirname = os.curdir.encode('ASCII')
-        else:
-            dirname = os.curdir
-    try:
-        names = os.listdir(dirname)
-    except OSError:
-        return []
-    return fnmatch.filter(names, pattern)
-
-
-def glob0(dirname, basename):
-    if not basename:
-        # `os.path.split()` returns an empty basename for paths ending with a
-        # directory separator.  'q*x/' should match only directories.
-        if os.path.isdir(dirname):
-            return [basename]
-    else:
-        if os.path.lexists(os.path.join(dirname, basename)):
-            return [basename]
-    return []
-
-
-# This helper function recursively yields relative pathnames inside a literal
-# directory.
-
-
-def glob2(dirname, pattern):
-    assert _isrecursive(pattern)
-    yield pattern[:0]
-    for x in _rlistdir(dirname):
-        yield x
-
-
-# Recursively yields relative pathnames inside a literal directory.
-def _rlistdir(dirname):
-    if not dirname:
-        if isinstance(dirname, bytes):
-            dirname = os.curdir.encode('ASCII')
-        else:
-            dirname = os.curdir
-    try:
-        names = os.listdir(dirname)
-    except os.error:
-        return
-    for x in names:
-        yield x
-        path = os.path.join(dirname, x) if dirname else x
-        for y in _rlistdir(path):
-            yield os.path.join(x, y)
-
-
-magic_check = re.compile('([*?[])')
-magic_check_bytes = re.compile(b'([*?[])')
-
-
-def has_magic(s):
-    if isinstance(s, bytes):
-        match = magic_check_bytes.search(s)
-    else:
-        match = magic_check.search(s)
-    return match is not None
-
-
-def _isrecursive(pattern):
-    if isinstance(pattern, bytes):
-        return pattern == b'**'
-    else:
-        return pattern == '**'
-
-
-def escape(pathname):
-    """Escape all special characters.
-    """
-    # Escaping is done by wrapping any of "*?[" between square brackets.
-    # Metacharacters do not work in the drive part and shouldn't be escaped.
-    drive, pathname = os.path.splitdrive(pathname)
-    if isinstance(pathname, bytes):
-        pathname = magic_check_bytes.sub(br'[\1]', pathname)
-    else:
-        pathname = magic_check.sub(r'[\1]', pathname)
-    return drive + pathname
diff --git a/venv/lib/python3.11/site-packages/setuptools/gui-32.exe b/venv/lib/python3.11/site-packages/setuptools/gui-32.exe
deleted file mode 100755
index f8d3509..0000000
Binary files a/venv/lib/python3.11/site-packages/setuptools/gui-32.exe and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/setuptools/gui-64.exe b/venv/lib/python3.11/site-packages/setuptools/gui-64.exe
deleted file mode 100755
index 330c51a..0000000
Binary files a/venv/lib/python3.11/site-packages/setuptools/gui-64.exe and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/setuptools/gui-arm64.exe b/venv/lib/python3.11/site-packages/setuptools/gui-arm64.exe
deleted file mode 100755
index 5730f11..0000000
Binary files a/venv/lib/python3.11/site-packages/setuptools/gui-arm64.exe and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/setuptools/gui.exe b/venv/lib/python3.11/site-packages/setuptools/gui.exe
deleted file mode 100755
index f8d3509..0000000
Binary files a/venv/lib/python3.11/site-packages/setuptools/gui.exe and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/setuptools/installer.py b/venv/lib/python3.11/site-packages/setuptools/installer.py
deleted file mode 100755
index b7096df..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/installer.py
+++ /dev/null
@@ -1,104 +0,0 @@
-import glob
-import os
-import subprocess
-import sys
-import tempfile
-import warnings
-from distutils import log
-from distutils.errors import DistutilsError
-
-import pkg_resources
-from setuptools.wheel import Wheel
-from ._deprecation_warning import SetuptoolsDeprecationWarning
-
-
-def _fixup_find_links(find_links):
-    """Ensure find-links option end-up being a list of strings."""
-    if isinstance(find_links, str):
-        return find_links.split()
-    assert isinstance(find_links, (tuple, list))
-    return find_links
-
-
-def fetch_build_egg(dist, req):  # noqa: C901  # is too complex (16)  # FIXME
-    """Fetch an egg needed for building.
-
-    Use pip/wheel to fetch/build a wheel."""
-    warnings.warn(
-        "setuptools.installer is deprecated. Requirements should "
-        "be satisfied by a PEP 517 installer.",
-        SetuptoolsDeprecationWarning,
-    )
-    # Warn if wheel is not available
-    try:
-        pkg_resources.get_distribution('wheel')
-    except pkg_resources.DistributionNotFound:
-        dist.announce('WARNING: The wheel package is not available.', log.WARN)
-    # Ignore environment markers; if supplied, it is required.
-    req = strip_marker(req)
-    # Take easy_install options into account, but do not override relevant
-    # pip environment variables (like PIP_INDEX_URL or PIP_QUIET); they'll
-    # take precedence.
-    opts = dist.get_option_dict('easy_install')
-    if 'allow_hosts' in opts:
-        raise DistutilsError('the `allow-hosts` option is not supported '
-                             'when using pip to install requirements.')
-    quiet = 'PIP_QUIET' not in os.environ and 'PIP_VERBOSE' not in os.environ
-    if 'PIP_INDEX_URL' in os.environ:
-        index_url = None
-    elif 'index_url' in opts:
-        index_url = opts['index_url'][1]
-    else:
-        index_url = None
-    find_links = (
-        _fixup_find_links(opts['find_links'][1])[:] if 'find_links' in opts
-        else []
-    )
-    if dist.dependency_links:
-        find_links.extend(dist.dependency_links)
-    eggs_dir = os.path.realpath(dist.get_egg_cache_dir())
-    environment = pkg_resources.Environment()
-    for egg_dist in pkg_resources.find_distributions(eggs_dir):
-        if egg_dist in req and environment.can_add(egg_dist):
-            return egg_dist
-    with tempfile.TemporaryDirectory() as tmpdir:
-        cmd = [
-            sys.executable, '-m', 'pip',
-            '--disable-pip-version-check',
-            'wheel', '--no-deps',
-            '-w', tmpdir,
-        ]
-        if quiet:
-            cmd.append('--quiet')
-        if index_url is not None:
-            cmd.extend(('--index-url', index_url))
-        for link in find_links or []:
-            cmd.extend(('--find-links', link))
-        # If requirement is a PEP 508 direct URL, directly pass
-        # the URL to pip, as `req @ url` does not work on the
-        # command line.
-        cmd.append(req.url or str(req))
-        try:
-            subprocess.check_call(cmd)
-        except subprocess.CalledProcessError as e:
-            raise DistutilsError(str(e)) from e
-        wheel = Wheel(glob.glob(os.path.join(tmpdir, '*.whl'))[0])
-        dist_location = os.path.join(eggs_dir, wheel.egg_name())
-        wheel.install_as_egg(dist_location)
-        dist_metadata = pkg_resources.PathMetadata(
-            dist_location, os.path.join(dist_location, 'EGG-INFO'))
-        dist = pkg_resources.Distribution.from_filename(
-            dist_location, metadata=dist_metadata)
-        return dist
-
-
-def strip_marker(req):
-    """
-    Return a new requirement without the environment marker to avoid
-    calling pip with something like `babel; extra == "i18n"`, which
-    would always be ignored.
-    """
-    # create a copy to avoid mutating the input
-    req = pkg_resources.Requirement.parse(str(req))
-    req.marker = None
-    return req
diff --git a/venv/lib/python3.11/site-packages/setuptools/launch.py b/venv/lib/python3.11/site-packages/setuptools/launch.py
deleted file mode 100755
index 0208fdf..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/launch.py
+++ /dev/null
@@ -1,36 +0,0 @@
-"""
-Launch the Python script on the command line after
-setuptools is bootstrapped via import.
-"""
-
-# Note that setuptools gets imported implicitly by the
-# invocation of this script using python -m setuptools.launch
-
-import tokenize
-import sys
-
-
-def run():
-    """
-    Run the script in sys.argv[1] as if it had
-    been invoked naturally.
-    """
-    __builtins__
-    script_name = sys.argv[1]
-    namespace = dict(
-        __file__=script_name,
-        __name__='__main__',
-        __doc__=None,
-    )
-    sys.argv[:] = sys.argv[1:]
-
-    open_ = getattr(tokenize, 'open', open)
-    with open_(script_name) as fid:
-        script = fid.read()
-    norm_script = script.replace('\\r\\n', '\\n')
-    code = compile(norm_script, script_name, 'exec')
-    exec(code, namespace)
-
-
-if __name__ == '__main__':
-    run()
diff --git a/venv/lib/python3.11/site-packages/setuptools/logging.py b/venv/lib/python3.11/site-packages/setuptools/logging.py
deleted file mode 100755
index 0653878..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/logging.py
+++ /dev/null
@@ -1,37 +0,0 @@
-import sys
-import inspect
-import logging
-import distutils.log
-from . import monkey
-
-
-def _not_warning(record):
-    return record.levelno < logging.WARNING
-
-
-def configure():
-    """
-    Configure logging to emit warning and above to stderr
-    and everything else to stdout. This behavior is provided
-    for compatibility with distutils.log but may change in
-    the future.
-    """
-    err_handler = logging.StreamHandler()
-    err_handler.setLevel(logging.WARNING)
-    out_handler = logging.StreamHandler(sys.stdout)
-    out_handler.addFilter(_not_warning)
-    handlers = err_handler, out_handler
-    logging.basicConfig(
-        format="{message}", style='{', handlers=handlers, level=logging.DEBUG)
-    if inspect.ismodule(distutils.dist.log):
-        monkey.patch_func(set_threshold, distutils.log, 'set_threshold')
-        # For some reason `distutils.log` module is getting cached in `distutils.dist`
-        # and then loaded again when patched,
-        # implying: id(distutils.log) != id(distutils.dist.log).
-        # Make sure the same module object is used everywhere:
-        distutils.dist.log = distutils.log
-
-
-def set_threshold(level):
-    logging.root.setLevel(level*10)
-    return set_threshold.unpatched(level)
diff --git a/venv/lib/python3.11/site-packages/setuptools/monkey.py b/venv/lib/python3.11/site-packages/setuptools/monkey.py
deleted file mode 100755
index 77a7adc..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/monkey.py
+++ /dev/null
@@ -1,165 +0,0 @@
-"""
-Monkey patching of distutils.
-"""
-
-import sys
-import distutils.filelist
-import platform
-import types
-import functools
-from importlib import import_module
-import inspect
-
-import setuptools
-
-__all__ = []
-"""
-Everything is private. Contact the project team
-if you think you need this functionality.
-"""
-
-
-def _get_mro(cls):
-    """
-    Returns the bases classes for cls sorted by the MRO.
-
-    Works around an issue on Jython where inspect.getmro will not return all
-    base classes if multiple classes share the same name. Instead, this
-    function will return a tuple containing the class itself, and the contents
-    of cls.__bases__. See https://github.com/pypa/setuptools/issues/1024.
-    """
-    if platform.python_implementation() == "Jython":
-        return (cls,) + cls.__bases__
-    return inspect.getmro(cls)
-
-
-def get_unpatched(item):
-    lookup = (
-        get_unpatched_class if isinstance(item, type) else
-        get_unpatched_function if isinstance(item, types.FunctionType) else
-        lambda item: None
-    )
-    return lookup(item)
-
-
-def get_unpatched_class(cls):
-    """Protect against re-patching the distutils if reloaded
-
-    Also ensures that no other distutils extension monkeypatched the distutils
-    first.
-    """
-    external_bases = (
-        cls
-        for cls in _get_mro(cls)
-        if not cls.__module__.startswith('setuptools')
-    )
-    base = next(external_bases)
-    if not base.__module__.startswith('distutils'):
-        msg = "distutils has already been patched by %r" % cls
-        raise AssertionError(msg)
-    return base
-
-
-def patch_all():
-    # we can't patch distutils.cmd, alas
-    distutils.core.Command = setuptools.Command
-
-    has_issue_12885 = sys.version_info <= (3, 5, 3)
-
-    if has_issue_12885:
-        # fix findall bug in distutils (http://bugs.python.org/issue12885)
-        distutils.filelist.findall = setuptools.findall
-
-    needs_warehouse = (
-        (3, 4) < sys.version_info < (3, 4, 6)
-        or
-        (3, 5) < sys.version_info <= (3, 5, 3)
-    )
-
-    if needs_warehouse:
-        warehouse = 'https://upload.pypi.org/legacy/'
-        distutils.config.PyPIRCCommand.DEFAULT_REPOSITORY = warehouse
-
-    _patch_distribution_metadata()
-
-    # Install Distribution throughout the distutils
-    for module in distutils.dist, distutils.core, distutils.cmd:
-        module.Distribution = setuptools.dist.Distribution
-
-    # Install the patched Extension
-    distutils.core.Extension = setuptools.extension.Extension
-    distutils.extension.Extension = setuptools.extension.Extension
-    if 'distutils.command.build_ext' in sys.modules:
-        sys.modules['distutils.command.build_ext'].Extension = (
-            setuptools.extension.Extension
-        )
-
-    patch_for_msvc_specialized_compiler()
-
-
-def _patch_distribution_metadata():
-    """Patch write_pkg_file and read_pkg_file for higher metadata standards"""
-    for attr in ('write_pkg_file', 'read_pkg_file', 'get_metadata_version'):
-        new_val = getattr(setuptools.dist, attr)
-        setattr(distutils.dist.DistributionMetadata, attr, new_val)
-
-
-def patch_func(replacement, target_mod, func_name):
-    """
-    Patch func_name in target_mod with replacement
-
-    Important - original must be resolved by name to avoid
-    patching an already patched function.
-    """
-    original = getattr(target_mod, func_name)
-
-    # set the 'unpatched' attribute on the replacement to
-    # point to the original.
-    vars(replacement).setdefault('unpatched', original)
-
-    # replace the function in the original module
-    setattr(target_mod, func_name, replacement)
-
-
-def get_unpatched_function(candidate):
-    return getattr(candidate, 'unpatched')
-
-
-def patch_for_msvc_specialized_compiler():
-    """
-    Patch functions in distutils to use standalone Microsoft Visual C++
-    compilers.
-    """
-    # import late to avoid circular imports on Python < 3.5
-    msvc = import_module('setuptools.msvc')
-
-    if platform.system() != 'Windows':
-        # Compilers only available on Microsoft Windows
-        return
-
-    def patch_params(mod_name, func_name):
-        """
-        Prepare the parameters for patch_func to patch indicated function.
-        """
-        repl_prefix = 'msvc14_'
-        repl_name = repl_prefix + func_name.lstrip('_')
-        repl = getattr(msvc, repl_name)
-        mod = import_module(mod_name)
-        if not hasattr(mod, func_name):
-            raise ImportError(func_name)
-        return repl, mod, func_name
-
-    # Python 3.5+
-    msvc14 = functools.partial(patch_params, 'distutils._msvccompiler')
-
-    try:
-        # Patch distutils._msvccompiler._get_vc_env
-        patch_func(*msvc14('_get_vc_env'))
-    except ImportError:
-        pass
-
-    try:
-        # Patch distutils._msvccompiler.gen_lib_options for Numpy
-        patch_func(*msvc14('gen_lib_options'))
-    except ImportError:
-        pass
diff --git a/venv/lib/python3.11/site-packages/setuptools/msvc.py b/venv/lib/python3.11/site-packages/setuptools/msvc.py
deleted file mode 100755
index 5d4d775..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/msvc.py
+++ /dev/null
@@ -1,1703 +0,0 @@
-"""
-Improved support for Microsoft Visual C++ compilers.
-
-Known supported compilers:
---------------------------
-Microsoft Visual C++ 14.X:
-    Microsoft Visual C++ Build Tools 2015 (x86, x64, arm)
-    Microsoft Visual Studio Build Tools 2017 (x86, x64, arm, arm64)
-    Microsoft Visual Studio Build Tools 2019 (x86, x64, arm, arm64)
-
-This may also support compilers shipped with compatible Visual Studio versions.
-"""
-
-import json
-from io import open
-from os import listdir, pathsep
-from os.path import join, isfile, isdir, dirname
-import sys
-import contextlib
-import platform
-import itertools
-import subprocess
-import distutils.errors
-from setuptools.extern.packaging.version import LegacyVersion
-from setuptools.extern.more_itertools import unique_everseen
-
-from .monkey import get_unpatched
-
-if platform.system() == 'Windows':
-    import winreg
-    from os import environ
-else:
-    # Mock winreg and environ so the module can be imported on this platform.
-
-    class winreg:
-        HKEY_USERS = None
-        HKEY_CURRENT_USER = None
-        HKEY_LOCAL_MACHINE = None
-        HKEY_CLASSES_ROOT = None
-
-    environ = dict()
-
-
-def _msvc14_find_vc2015():
-    """Python 3.8 "distutils/_msvccompiler.py" backport"""
-    try:
-        key = winreg.OpenKey(
-            winreg.HKEY_LOCAL_MACHINE,
-            r"Software\Microsoft\VisualStudio\SxS\VC7",
-            0,
-            winreg.KEY_READ | winreg.KEY_WOW64_32KEY
-        )
-    except OSError:
-        return None, None
-
-    best_version = 0
-    best_dir = None
-    with key:
-        for i in itertools.count():
-            try:
-                v, vc_dir, vt = winreg.EnumValue(key, i)
-            except OSError:
-                break
-            if v and vt == winreg.REG_SZ and isdir(vc_dir):
-                try:
-                    version = int(float(v))
-                except (ValueError, TypeError):
-                    continue
-                if version >= 14 and version > best_version:
-                    best_version, best_dir = version, vc_dir
-    return best_version, best_dir
-
-
-def _msvc14_find_vc2017():
-    """Python 3.8 "distutils/_msvccompiler.py" backport
-
-    Returns "15, path" based on the result of invoking vswhere.exe
-    If no install is found, returns "None, None"
-
-    The version is returned to avoid unnecessarily changing the function
-    result. It may be ignored when the path is not None.
-
-    If vswhere.exe is not available, by definition, VS 2017 is not
-    installed.
-    """
-    root = environ.get("ProgramFiles(x86)") or environ.get("ProgramFiles")
-    if not root:
-        return None, None
-
-    try:
-        path = subprocess.check_output([
-            join(root, "Microsoft Visual Studio", "Installer", "vswhere.exe"),
-            "-latest",
-            "-prerelease",
-            "-requiresAny",
-            "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
-            "-requires", "Microsoft.VisualStudio.Workload.WDExpress",
-            "-property", "installationPath",
-            "-products", "*",
-        ]).decode(encoding="mbcs", errors="strict").strip()
-    except (subprocess.CalledProcessError, OSError, UnicodeDecodeError):
-        return None, None
-
-    path = join(path, "VC", "Auxiliary", "Build")
-    if isdir(path):
-        return 15, path
-
-    return None, None
-
-
-PLAT_SPEC_TO_RUNTIME = {
-    'x86': 'x86',
-    'x86_amd64': 'x64',
-    'x86_arm': 'arm',
-    'x86_arm64': 'arm64'
-}
-
-
-def _msvc14_find_vcvarsall(plat_spec):
-    """Python 3.8 "distutils/_msvccompiler.py" backport"""
-    _, best_dir = _msvc14_find_vc2017()
-    vcruntime = None
-
-    if plat_spec in PLAT_SPEC_TO_RUNTIME:
-        vcruntime_plat = PLAT_SPEC_TO_RUNTIME[plat_spec]
-    else:
-        vcruntime_plat = 'x64' if 'amd64' in plat_spec else 'x86'
-
-    if best_dir:
-        vcredist = join(best_dir, "..", "..", "redist", "MSVC", "**",
-                        vcruntime_plat, "Microsoft.VC14*.CRT",
-                        "vcruntime140.dll")
-        try:
-            import glob
-            vcruntime = glob.glob(vcredist, recursive=True)[-1]
-        except (ImportError, OSError, LookupError):
-            vcruntime = None
-
-    if not best_dir:
-        best_version, best_dir = _msvc14_find_vc2015()
-        if best_version:
-            vcruntime = join(best_dir, 'redist', vcruntime_plat,
-                             "Microsoft.VC140.CRT", "vcruntime140.dll")
-
-    if not best_dir:
-        return None, None
-
-    vcvarsall = join(best_dir, "vcvarsall.bat")
-    if not isfile(vcvarsall):
-        return None, None
-
-    if not vcruntime or not isfile(vcruntime):
-        vcruntime = None
-
-    return vcvarsall, vcruntime
-
-
-def _msvc14_get_vc_env(plat_spec):
-    """Python 3.8 "distutils/_msvccompiler.py" backport"""
-    if "DISTUTILS_USE_SDK" in environ:
-        return {
-            key.lower(): value
-            for key, value in environ.items()
-        }
-
-    vcvarsall, vcruntime = _msvc14_find_vcvarsall(plat_spec)
-    if not vcvarsall:
-        raise distutils.errors.DistutilsPlatformError(
-            "Unable to find vcvarsall.bat"
-        )
-
-    try:
-        out = subprocess.check_output(
-            'cmd /u /c "{}" {} && set'.format(vcvarsall, plat_spec),
-            stderr=subprocess.STDOUT,
-        ).decode('utf-16le', errors='replace')
-    except subprocess.CalledProcessError as exc:
-        raise distutils.errors.DistutilsPlatformError(
-            "Error executing {}".format(exc.cmd)
-        ) from exc
-
-    env = {
-        key.lower(): value
-        for key, _, value in
-        (line.partition('=') for line in out.splitlines())
-        if key and value
-    }
-
-    if vcruntime:
-        env['py_vcruntime_redist'] = vcruntime
-    return env
-
-
-def msvc14_get_vc_env(plat_spec):
-    """
-    Patched "distutils._msvccompiler._get_vc_env" for support extra
-    Microsoft Visual C++ 14.X compilers.
-
-    Set environment without use of "vcvarsall.bat".
-
-    Parameters
-    ----------
-    plat_spec: str
-        Target architecture.
-
-    Return
-    ------
-    dict
-        environment
-    """
-
-    # Always use backport from CPython 3.8
-    try:
-        return _msvc14_get_vc_env(plat_spec)
-    except distutils.errors.DistutilsPlatformError as exc:
-        _augment_exception(exc, 14.0)
-        raise
-
-
-def msvc14_gen_lib_options(*args, **kwargs):
-    """
-    Patched "distutils._msvccompiler.gen_lib_options" for fix
-    compatibility between "numpy.distutils" and "distutils._msvccompiler"
-    (for Numpy < 1.11.2)
-    """
-    if "numpy.distutils" in sys.modules:
-        import numpy as np
-        if LegacyVersion(np.__version__) < LegacyVersion('1.11.2'):
-            return np.distutils.ccompiler.gen_lib_options(*args, **kwargs)
-    return get_unpatched(msvc14_gen_lib_options)(*args, **kwargs)
-
-
-def _augment_exception(exc, version, arch=''):
-    """
-    Add details to the exception message to help guide the user
-    as to what action will resolve it.
-    """
-    # Error if MSVC++ directory not found or environment not set
-    message = exc.args[0]
-
-    if "vcvarsall" in message.lower() or "visual c" in message.lower():
-        # Special error message if MSVC++ not installed
-        tmpl = 'Microsoft Visual C++ {version:0.1f} or greater is required.'
-        message = tmpl.format(**locals())
-        msdownload = 'www.microsoft.com/download/details.aspx?id=%d'
-        if version == 9.0:
-            if arch.lower().find('ia64') > -1:
-                # For VC++ 9.0, if IA64 support is needed, redirect user
-                # to Windows SDK 7.0.
-                # Note: No download link available from Microsoft.
-                message += ' Get it with "Microsoft Windows SDK 7.0"'
-            else:
-                # For VC++ 9.0 redirect user to Vc++ for Python 2.7 :
-                # This redirection link is maintained by Microsoft.
-                # Contact vspython@microsoft.com if it needs updating.
-                message += ' Get it from http://aka.ms/vcpython27'
-        elif version == 10.0:
-            # For VC++ 10.0 Redirect user to Windows SDK 7.1
-            message += ' Get it with "Microsoft Windows SDK 7.1": '
-            message += msdownload % 8279
-        elif version >= 14.0:
-            # For VC++ 14.X Redirect user to latest Visual C++ Build Tools
-            message += (' Get it with "Microsoft C++ Build Tools": '
-                        r'https://visualstudio.microsoft.com'
-                        r'/visual-cpp-build-tools/')
-
-    exc.args = (message, )
-
-
-class PlatformInfo:
-    """
-    Current and Target Architectures information.
-
-    Parameters
-    ----------
-    arch: str
-        Target architecture.
-    """
-    current_cpu = environ.get('processor_architecture', '').lower()
-
-    def __init__(self, arch):
-        self.arch = arch.lower().replace('x64', 'amd64')
-
-    @property
-    def target_cpu(self):
-        """
-        Return Target CPU architecture.
-
-        Return
-        ------
-        str
-            Target CPU
-        """
-        return self.arch[self.arch.find('_') + 1:]
-
-    def target_is_x86(self):
-        """
-        Return True if target CPU is x86 32 bits..
-
-        Return
-        ------
-        bool
-            CPU is x86 32 bits
-        """
-        return self.target_cpu == 'x86'
-
-    def current_is_x86(self):
-        """
-        Return True if current CPU is x86 32 bits..
-
-        Return
-        ------
-        bool
-            CPU is x86 32 bits
-        """
-        return self.current_cpu == 'x86'
-
-    def current_dir(self, hidex86=False, x64=False):
-        """
-        Current platform specific subfolder.
-
-        Parameters
-        ----------
-        hidex86: bool
-            return '' and not '\x86' if architecture is x86.
-        x64: bool
-            return '\x64' and not '\amd64' if architecture is amd64.
-
-        Return
-        ------
-        str
-            subfolder: '\target', or '' (see hidex86 parameter)
-        """
-        return (
-            '' if (self.current_cpu == 'x86' and hidex86) else
-            r'\x64' if (self.current_cpu == 'amd64' and x64) else
-            r'\%s' % self.current_cpu
-        )
-
-    def target_dir(self, hidex86=False, x64=False):
-        r"""
-        Target platform specific subfolder.
-
-        Parameters
-        ----------
-        hidex86: bool
-            return '' and not '\x86' if architecture is x86.
-        x64: bool
-            return '\x64' and not '\amd64' if architecture is amd64.
-
-        Return
-        ------
-        str
-            subfolder: '\current', or '' (see hidex86 parameter)
-        """
-        return (
-            '' if (self.target_cpu == 'x86' and hidex86) else
-            r'\x64' if (self.target_cpu == 'amd64' and x64) else
-            r'\%s' % self.target_cpu
-        )
-
-    def cross_dir(self, forcex86=False):
-        r"""
-        Cross platform specific subfolder.
-
-        Parameters
-        ----------
-        forcex86: bool
-            Use 'x86' as current architecture even if current architecture is
-            not x86.
-
-        Return
-        ------
-        str
-            subfolder: '' if target architecture is current architecture,
-            '\current_target' if not.
-        """
-        current = 'x86' if forcex86 else self.current_cpu
-        return (
-            '' if self.target_cpu == current else
-            self.target_dir().replace('\\', '\\%s_' % current)
-        )
-
-
-class RegistryInfo:
-    """
-    Microsoft Visual Studio related registry information.
-
-    Parameters
-    ----------
-    platform_info: PlatformInfo
-        "PlatformInfo" instance.
-    """
-    HKEYS = (winreg.HKEY_USERS,
-             winreg.HKEY_CURRENT_USER,
-             winreg.HKEY_LOCAL_MACHINE,
-             winreg.HKEY_CLASSES_ROOT)
-
-    def __init__(self, platform_info):
-        self.pi = platform_info
-
-    @property
-    def visualstudio(self):
-        """
-        Microsoft Visual Studio root registry key.
-
-        Return
-        ------
-        str
-            Registry key
-        """
-        return 'VisualStudio'
-
-    @property
-    def sxs(self):
-        """
-        Microsoft Visual Studio SxS registry key.
-
-        Return
-        ------
-        str
-            Registry key
-        """
-        return join(self.visualstudio, 'SxS')
-
-    @property
-    def vc(self):
-        """
-        Microsoft Visual C++ VC7 registry key.
-
-        Return
-        ------
-        str
-            Registry key
-        """
-        return join(self.sxs, 'VC7')
-
-    @property
-    def vs(self):
-        """
-        Microsoft Visual Studio VS7 registry key.
-
-        Return
-        ------
-        str
-            Registry key
-        """
-        return join(self.sxs, 'VS7')
-
-    @property
-    def vc_for_python(self):
-        """
-        Microsoft Visual C++ for Python registry key.
-
-        Return
-        ------
-        str
-            Registry key
-        """
-        return r'DevDiv\VCForPython'
-
-    @property
-    def microsoft_sdk(self):
-        """
-        Microsoft SDK registry key.
-
-        Return
-        ------
-        str
-            Registry key
-        """
-        return 'Microsoft SDKs'
-
-    @property
-    def windows_sdk(self):
-        """
-        Microsoft Windows/Platform SDK registry key.
-
-        Return
-        ------
-        str
-            Registry key
-        """
-        return join(self.microsoft_sdk, 'Windows')
-
-    @property
-    def netfx_sdk(self):
-        """
-        Microsoft .NET Framework SDK registry key.
-
-        Return
-        ------
-        str
-            Registry key
-        """
-        return join(self.microsoft_sdk, 'NETFXSDK')
-
-    @property
-    def windows_kits_roots(self):
-        """
-        Microsoft Windows Kits Roots registry key.
-
-        Return
-        ------
-        str
-            Registry key
-        """
-        return r'Windows Kits\Installed Roots'
-
-    def microsoft(self, key, x86=False):
-        """
-        Return key in Microsoft software registry.
-
-        Parameters
-        ----------
-        key: str
-            Registry key path where look.
-        x86: str
-            Force x86 software registry.
-
-        Return
-        ------
-        str
-            Registry key
-        """
-        node64 = '' if self.pi.current_is_x86() or x86 else 'Wow6432Node'
-        return join('Software', node64, 'Microsoft', key)
-
-    def lookup(self, key, name):
-        """
-        Look for values in registry in Microsoft software registry.
-
-        Parameters
-        ----------
-        key: str
-            Registry key path where look.
-        name: str
-            Value name to find.
-
-        Return
-        ------
-        str
-            value
-        """
-        key_read = winreg.KEY_READ
-        openkey = winreg.OpenKey
-        closekey = winreg.CloseKey
-        ms = self.microsoft
-        for hkey in self.HKEYS:
-            bkey = None
-            try:
-                bkey = openkey(hkey, ms(key), 0, key_read)
-            except (OSError, IOError):
-                if not self.pi.current_is_x86():
-                    try:
-                        bkey = openkey(hkey, ms(key, True), 0, key_read)
-                    except (OSError, IOError):
-                        continue
-                else:
-                    continue
-            try:
-                return winreg.QueryValueEx(bkey, name)[0]
-            except (OSError, IOError):
-                pass
-            finally:
-                if bkey:
-                    closekey(bkey)
-
-
-class SystemInfo:
-    """
-    Microsoft Windows and Visual Studio related system information.
-
-    Parameters
-    ----------
-    registry_info: RegistryInfo
-        "RegistryInfo" instance.
-    vc_ver: float
-        Required Microsoft Visual C++ version.
-    """
-
-    # Variables and properties in this class use originals CamelCase variables
-    # names from Microsoft source files for more easy comparison.
-    WinDir = environ.get('WinDir', '')
-    ProgramFiles = environ.get('ProgramFiles', '')
-    ProgramFilesx86 = environ.get('ProgramFiles(x86)', ProgramFiles)
-
-    def __init__(self, registry_info, vc_ver=None):
-        self.ri = registry_info
-        self.pi = self.ri.pi
-
-        self.known_vs_paths = self.find_programdata_vs_vers()
-
-        # Except for VS15+, VC version is aligned with VS version
-        self.vs_ver = self.vc_ver = (
-            vc_ver or self._find_latest_available_vs_ver())
-
-    def _find_latest_available_vs_ver(self):
-        """
-        Find the latest VC version
-
-        Return
-        ------
-        float
-            version
-        """
-        reg_vc_vers = self.find_reg_vs_vers()
-
-        if not (reg_vc_vers or self.known_vs_paths):
-            raise distutils.errors.DistutilsPlatformError(
-                'No Microsoft Visual C++ version found')
-
-        vc_vers = set(reg_vc_vers)
-        vc_vers.update(self.known_vs_paths)
-        return sorted(vc_vers)[-1]
-
-    def find_reg_vs_vers(self):
-        """
-        Find Microsoft Visual Studio versions available in registry.
-
-        Return
-        ------
-        list of float
-            Versions
-        """
-        ms = self.ri.microsoft
-        vckeys = (self.ri.vc, self.ri.vc_for_python, self.ri.vs)
-        vs_vers = []
-        for hkey, key in itertools.product(self.ri.HKEYS, vckeys):
-            try:
-                bkey = winreg.OpenKey(hkey, ms(key), 0, winreg.KEY_READ)
-            except (OSError, IOError):
-                continue
-            with bkey:
-                subkeys, values, _ = winreg.QueryInfoKey(bkey)
-                for i in range(values):
-                    with contextlib.suppress(ValueError):
-                        ver = float(winreg.EnumValue(bkey, i)[0])
-                        if ver not in vs_vers:
-                            vs_vers.append(ver)
-                for i in range(subkeys):
-                    with contextlib.suppress(ValueError):
-                        ver = float(winreg.EnumKey(bkey, i))
-                        if ver not in vs_vers:
-                            vs_vers.append(ver)
-        return sorted(vs_vers)
-
-    def find_programdata_vs_vers(self):
-        r"""
-        Find Visual studio 2017+ versions from information in
-        "C:\ProgramData\Microsoft\VisualStudio\Packages\_Instances".
-
-        Return
-        ------
-        dict
-            float version as key, path as value.
-        """
-        vs_versions = {}
-        instances_dir = \
-            r'C:\ProgramData\Microsoft\VisualStudio\Packages\_Instances'
-
-        try:
-            hashed_names = listdir(instances_dir)
-
-        except (OSError, IOError):
-            # Directory not exists with all Visual Studio versions
-            return vs_versions
-
-        for name in hashed_names:
-            try:
-                # Get VS installation path from "state.json" file
-                state_path = join(instances_dir, name, 'state.json')
-                with open(state_path, 'rt', encoding='utf-8') as state_file:
-                    state = json.load(state_file)
-                vs_path = state['installationPath']
-
-                # Raises OSError if this VS installation does not contain VC
-                listdir(join(vs_path, r'VC\Tools\MSVC'))
-
-                # Store version and path
-                vs_versions[self._as_float_version(
-                    state['installationVersion'])] = vs_path
-
-            except (OSError, IOError, KeyError):
-                # Skip if "state.json" file is missing or bad format
-                continue
-
-        return vs_versions
-
-    @staticmethod
-    def _as_float_version(version):
-        """
-        Return a string version as a simplified float version (major.minor)
-
-        Parameters
-        ----------
-        version: str
-            Version.
-
-        Return
-        ------
-        float
-            version
-        """
-        return float('.'.join(version.split('.')[:2]))
-
-    @property
-    def VSInstallDir(self):
-        """
-        Microsoft Visual Studio directory.
-
-        Return
-        ------
-        str
-            path
-        """
-        # Default path
-        default = join(self.ProgramFilesx86,
-                       'Microsoft Visual Studio %0.1f' % self.vs_ver)
-
-        # Try to get path from registry, if fail use default path
-        return self.ri.lookup(self.ri.vs, '%0.1f' % self.vs_ver) or default
-
-    @property
-    def VCInstallDir(self):
-        """
-        Microsoft Visual C++ directory.
-
-        Return
-        ------
-        str
-            path
-        """
-        path = self._guess_vc() or self._guess_vc_legacy()
-
-        if not isdir(path):
-            msg = 'Microsoft Visual C++ directory not found'
-            raise distutils.errors.DistutilsPlatformError(msg)
-
-        return path
-
-    def _guess_vc(self):
-        """
-        Locate Visual C++ for VS2017+.
-
-        Return
-        ------
-        str
-            path
-        """
-        if self.vs_ver <= 14.0:
-            return ''
-
-        try:
-            # First search in known VS paths
-            vs_dir = self.known_vs_paths[self.vs_ver]
-        except KeyError:
-            # Else, search with path from registry
-            vs_dir = self.VSInstallDir
-
-        guess_vc = join(vs_dir, r'VC\Tools\MSVC')
-
-        # Subdir with VC exact version as name
-        try:
-            # Update the VC version with real one instead of VS version
-            vc_ver = listdir(guess_vc)[-1]
-            self.vc_ver = self._as_float_version(vc_ver)
-            return join(guess_vc, vc_ver)
-        except (OSError, IOError, IndexError):
-            return ''
-
-    def _guess_vc_legacy(self):
-        """
-        Locate Visual C++ for versions prior to 2017.
-
-        Return
-        ------
-        str
-            path
-        """
-        default = join(self.ProgramFilesx86,
-                       r'Microsoft Visual Studio %0.1f\VC' % self.vs_ver)
-
-        # Try to get "VC++ for Python" path from registry as default path
-        reg_path = join(self.ri.vc_for_python, '%0.1f' % self.vs_ver)
-        python_vc = self.ri.lookup(reg_path, 'installdir')
-        default_vc = join(python_vc, 'VC') if python_vc else default
-
-        # Try to get path from registry, if fail use default path
-        return self.ri.lookup(self.ri.vc, '%0.1f' % self.vs_ver) or default_vc
-
-    @property
-    def WindowsSdkVersion(self):
-        """
-        Microsoft Windows SDK versions for specified MSVC++ version.
-
-        Return
-        ------
-        tuple of str
-            versions
-        """
-        if self.vs_ver <= 9.0:
-            return '7.0', '6.1', '6.0a'
-        elif self.vs_ver == 10.0:
-            return '7.1', '7.0a'
-        elif self.vs_ver == 11.0:
-            return '8.0', '8.0a'
-        elif self.vs_ver == 12.0:
-            return '8.1', '8.1a'
-        elif self.vs_ver >= 14.0:
-            return '10.0', '8.1'
-
-    @property
-    def WindowsSdkLastVersion(self):
-        """
-        Microsoft Windows SDK last version.
-
-        Return
-        ------
-        str
-            version
-        """
-        return self._use_last_dir_name(join(self.WindowsSdkDir, 'lib'))
-
-    @property  # noqa: C901
-    def WindowsSdkDir(self):  # noqa: C901  # is too complex (12)  # FIXME
-        """
-        Microsoft Windows SDK directory.
-
-        Return
-        ------
-        str
-            path
-        """
-        sdkdir = ''
-        for ver in self.WindowsSdkVersion:
-            # Try to get it from registry
-            loc = join(self.ri.windows_sdk, 'v%s' % ver)
-            sdkdir = self.ri.lookup(loc, 'installationfolder')
-            if sdkdir:
-                break
-        if not sdkdir or not isdir(sdkdir):
-            # Try to get "VC++ for Python" version from registry
-            path = join(self.ri.vc_for_python, '%0.1f' % self.vc_ver)
-            install_base = self.ri.lookup(path, 'installdir')
-            if install_base:
-                sdkdir = join(install_base, 'WinSDK')
-        if not sdkdir or not isdir(sdkdir):
-            # If fail, use default new path
-            for ver in self.WindowsSdkVersion:
-                intver = ver[:ver.rfind('.')]
-                path = r'Microsoft SDKs\Windows Kits\%s' % intver
-                d = join(self.ProgramFiles, path)
-                if isdir(d):
-                    sdkdir = d
-        if not sdkdir or not isdir(sdkdir):
-            # If fail, use default old path
-            for ver in self.WindowsSdkVersion:
-                path = r'Microsoft SDKs\Windows\v%s' % ver
-                d = join(self.ProgramFiles, path)
-                if isdir(d):
-                    sdkdir = d
-        if not sdkdir:
-            # If fail, use Platform SDK
-            sdkdir = join(self.VCInstallDir, 'PlatformSDK')
-        return sdkdir
-
-    @property
-    def WindowsSDKExecutablePath(self):
-        """
-        Microsoft Windows SDK executable directory.
-
-        Return
-        ------
-        str
-            path
-        """
-        # Find WinSDK NetFx Tools registry dir name
-        if self.vs_ver <= 11.0:
-            netfxver = 35
-            arch = ''
-        else:
-            netfxver = 40
-            hidex86 = True if self.vs_ver <= 12.0 else False
-            arch = self.pi.current_dir(x64=True, hidex86=hidex86)
-        fx = 'WinSDK-NetFx%dTools%s' % (netfxver, arch.replace('\\', '-'))
-
-        # list all possibles registry paths
-        regpaths = []
-        if self.vs_ver >= 14.0:
-            for ver in self.NetFxSdkVersion:
-                regpaths += [join(self.ri.netfx_sdk, ver, fx)]
-
-        for ver in self.WindowsSdkVersion:
-            regpaths += [join(self.ri.windows_sdk, 'v%sA' % ver, fx)]
-
-        # Return installation folder from the more recent path
-        for path in regpaths:
-            execpath = self.ri.lookup(path, 'installationfolder')
-            if execpath:
-                return execpath
-
-    @property
-    def FSharpInstallDir(self):
-        """
-        Microsoft Visual F# directory.
-
-        Return
-        ------
-        str
-            path
-        """
-        path = join(self.ri.visualstudio, r'%0.1f\Setup\F#' % self.vs_ver)
-        return self.ri.lookup(path, 'productdir') or ''
-
-    @property
-    def UniversalCRTSdkDir(self):
-        """
-        Microsoft Universal CRT SDK directory.
-
-        Return
-        ------
-        str
-            path
-        """
-        # Set Kit Roots versions for specified MSVC++ version
-        vers = ('10', '81') if self.vs_ver >= 14.0 else ()
-
-        # Find path of the more recent Kit
-        for ver in vers:
-            sdkdir = self.ri.lookup(self.ri.windows_kits_roots,
-                                    'kitsroot%s' % ver)
-            if sdkdir:
-                return sdkdir or ''
-
-    @property
-    def UniversalCRTSdkLastVersion(self):
-        """
-        Microsoft Universal C Runtime SDK last version.
-
-        Return
-        ------
-        str
-            version
-        """
-        return self._use_last_dir_name(join(self.UniversalCRTSdkDir, 'lib'))
-
-    @property
-    def NetFxSdkVersion(self):
-        """
-        Microsoft .NET Framework SDK versions.
-
-        Return
-        ------
-        tuple of str
-            versions
-        """
-        # Set FxSdk versions for specified VS version
-        return (('4.7.2', '4.7.1', '4.7',
-                 '4.6.2', '4.6.1', '4.6',
-                 '4.5.2', '4.5.1', '4.5')
-                if self.vs_ver >= 14.0 else ())
-
-    @property
-    def NetFxSdkDir(self):
-        """
-        Microsoft .NET Framework SDK directory.
-
-        Return
-        ------
-        str
-            path
-        """
-        sdkdir = ''
-        for ver in self.NetFxSdkVersion:
-            loc = join(self.ri.netfx_sdk, ver)
-            sdkdir = self.ri.lookup(loc, 'kitsinstallationfolder')
-            if sdkdir:
-                break
-        return sdkdir
-
-    @property
-    def FrameworkDir32(self):
-        """
-        Microsoft .NET Framework 32bit directory.
-
-        Return
-        ------
-        str
-            path
-        """
-        # Default path
-        guess_fw = join(self.WinDir, r'Microsoft.NET\Framework')
-
-        # Try to get path from registry, if fail use default path
-        return self.ri.lookup(self.ri.vc, 'frameworkdir32') or guess_fw
-
-    @property
-    def FrameworkDir64(self):
-        """
-        Microsoft .NET Framework 64bit directory.
-
-        Return
-        ------
-        str
-            path
-        """
-        # Default path
-        guess_fw = join(self.WinDir, r'Microsoft.NET\Framework64')
-
-        # Try to get path from registry, if fail use default path
-        return self.ri.lookup(self.ri.vc, 'frameworkdir64') or guess_fw
-
-    @property
-    def FrameworkVersion32(self):
-        """
-        Microsoft .NET Framework 32bit versions.
-
-        Return
-        ------
-        tuple of str
-            versions
-        """
-        return self._find_dot_net_versions(32)
-
-    @property
-    def FrameworkVersion64(self):
-        """
-        Microsoft .NET Framework 64bit versions.
-
-        Return
-        ------
-        tuple of str
-            versions
-        """
-        return self._find_dot_net_versions(64)
-
-    def _find_dot_net_versions(self, bits):
-        """
-        Find Microsoft .NET Framework versions.
-
-        Parameters
-        ----------
-        bits: int
-            Platform number of bits: 32 or 64.
-
-        Return
-        ------
-        tuple of str
-            versions
-        """
-        # Find actual .NET version in registry
-        reg_ver = self.ri.lookup(self.ri.vc, 'frameworkver%d' % bits)
-        dot_net_dir = getattr(self, 'FrameworkDir%d' % bits)
-        ver = reg_ver or self._use_last_dir_name(dot_net_dir, 'v') or ''
-
-        # Set .NET versions for specified MSVC++ version
-        if self.vs_ver >= 12.0:
-            return ver, 'v4.0'
-        elif self.vs_ver >= 10.0:
-            return 'v4.0.30319' if ver.lower()[:2] != 'v4' else ver, 'v3.5'
-        elif self.vs_ver == 9.0:
-            return 'v3.5', 'v2.0.50727'
-        elif self.vs_ver == 8.0:
-            return 'v3.0', 'v2.0.50727'
-
-    @staticmethod
-    def _use_last_dir_name(path, prefix=''):
-        """
-        Return name of the last dir in path or '' if no dir found.
-
-        Parameters
-        ----------
-        path: str
-            Use dirs in this path
-        prefix: str
-            Use only dirs starting by this prefix
-
-        Return
-        ------
-        str
-            name
-        """
-        matching_dirs = (
-            dir_name
-            for dir_name in reversed(listdir(path))
-            if isdir(join(path, dir_name)) and
-            dir_name.startswith(prefix)
-        )
-        return next(matching_dirs, None) or ''
-
-
-class EnvironmentInfo:
-    """
-    Return environment variables for specified Microsoft Visual C++ version
-    and platform : Lib, Include, Path and libpath.
-
-    This function is compatible with Microsoft Visual C++ 9.0 to 14.X.
-
-    Script created by analysing Microsoft environment configuration files like
-    "vcvars[...].bat", "SetEnv.Cmd", "vcbuildtools.bat", ...
-
-    Parameters
-    ----------
-    arch: str
-        Target architecture.
-    vc_ver: float
-        Required Microsoft Visual C++ version. If not set, autodetect the last
-        version.
-    vc_min_ver: float
-        Minimum Microsoft Visual C++ version.
-    """
-
-    # Variables and properties in this class use originals CamelCase variables
-    # names from Microsoft source files for more easy comparison.
-
-    def __init__(self, arch, vc_ver=None, vc_min_ver=0):
-        self.pi = PlatformInfo(arch)
-        self.ri = RegistryInfo(self.pi)
-        self.si = SystemInfo(self.ri, vc_ver)
-
-        if self.vc_ver < vc_min_ver:
-            err = 'No suitable Microsoft Visual C++ version found'
-            raise distutils.errors.DistutilsPlatformError(err)
-
-    @property
-    def vs_ver(self):
-        """
-        Microsoft Visual Studio.
-
-        Return
-        ------
-        float
-            version
-        """
-        return self.si.vs_ver
-
-    @property
-    def vc_ver(self):
-        """
-        Microsoft Visual C++ version.
-
-        Return
-        ------
-        float
-            version
-        """
-        return self.si.vc_ver
-
-    @property
-    def VSTools(self):
-        """
-        Microsoft Visual Studio Tools.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        paths = [r'Common7\IDE', r'Common7\Tools']
-
-        if self.vs_ver >= 14.0:
-            arch_subdir = self.pi.current_dir(hidex86=True, x64=True)
-            paths += [r'Common7\IDE\CommonExtensions\Microsoft\TestWindow']
-            paths += [r'Team Tools\Performance Tools']
-            paths += [r'Team Tools\Performance Tools%s' % arch_subdir]
-
-        return [join(self.si.VSInstallDir, path) for path in paths]
-
-    @property
-    def VCIncludes(self):
-        """
-        Microsoft Visual C++ & Microsoft Foundation Class Includes.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        return [join(self.si.VCInstallDir, 'Include'),
-                join(self.si.VCInstallDir, r'ATLMFC\Include')]
-
-    @property
-    def VCLibraries(self):
-        """
-        Microsoft Visual C++ & Microsoft Foundation Class Libraries.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        if self.vs_ver >= 15.0:
-            arch_subdir = self.pi.target_dir(x64=True)
-        else:
-            arch_subdir = self.pi.target_dir(hidex86=True)
-        paths = ['Lib%s' % arch_subdir, r'ATLMFC\Lib%s' % arch_subdir]
-
-        if self.vs_ver >= 14.0:
-            paths += [r'Lib\store%s' % arch_subdir]
-
-        return [join(self.si.VCInstallDir, path) for path in paths]
-
-    @property
-    def VCStoreRefs(self):
-        """
-        Microsoft Visual C++ store references Libraries.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        if self.vs_ver < 14.0:
-            return []
-        return [join(self.si.VCInstallDir, r'Lib\store\references')]
-
-    @property
-    def VCTools(self):
-        """
-        Microsoft Visual C++ Tools.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        si = self.si
-        tools = [join(si.VCInstallDir, 'VCPackages')]
-
-        forcex86 = True if self.vs_ver <= 10.0 else False
-        arch_subdir = self.pi.cross_dir(forcex86)
-        if arch_subdir:
-            tools += [join(si.VCInstallDir, 'Bin%s' % arch_subdir)]
-
-        if self.vs_ver == 14.0:
-            path = 'Bin%s' % self.pi.current_dir(hidex86=True)
-            tools += [join(si.VCInstallDir, path)]
-
-        elif self.vs_ver >= 15.0:
-            host_dir = (r'bin\HostX86%s' if self.pi.current_is_x86() else
-                        r'bin\HostX64%s')
-            tools += [join(
-                si.VCInstallDir, host_dir % self.pi.target_dir(x64=True))]
-
-            if self.pi.current_cpu != self.pi.target_cpu:
-                tools += [join(
-                    si.VCInstallDir, host_dir % self.pi.current_dir(x64=True))]
-
-        else:
-            tools += [join(si.VCInstallDir, 'Bin')]
-
-        return tools
-
-    @property
-    def OSLibraries(self):
-        """
-        Microsoft Windows SDK Libraries.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        if self.vs_ver <= 10.0:
-            arch_subdir = self.pi.target_dir(hidex86=True, x64=True)
-            return [join(self.si.WindowsSdkDir, 'Lib%s' % arch_subdir)]
-
-        else:
-            arch_subdir = self.pi.target_dir(x64=True)
-            lib = join(self.si.WindowsSdkDir, 'lib')
-            libver = self._sdk_subdir
-            return [join(lib, '%sum%s' % (libver, arch_subdir))]
-
-    @property
-    def OSIncludes(self):
-        """
-        Microsoft Windows SDK Include.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        include = join(self.si.WindowsSdkDir, 'include')
-
-        if self.vs_ver <= 10.0:
-            return [include, join(include, 'gl')]
-
-        else:
-            if self.vs_ver >= 14.0:
-                sdkver = self._sdk_subdir
-            else:
-                sdkver = ''
-            return [join(include, '%sshared' % sdkver),
-                    join(include, '%sum' % sdkver),
-                    join(include, '%swinrt' % sdkver)]
-
-    @property
-    def OSLibpath(self):
-        """
-        Microsoft Windows SDK Libraries Paths.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        ref = join(self.si.WindowsSdkDir, 'References')
-        libpath = []
-
-        if self.vs_ver <= 9.0:
-            libpath += self.OSLibraries
-
-        if self.vs_ver >= 11.0:
-            libpath += [join(ref, r'CommonConfiguration\Neutral')]
-
-        if self.vs_ver >= 14.0:
-            libpath += [
-                ref,
-                join(self.si.WindowsSdkDir, 'UnionMetadata'),
-                join(
-                    ref, 'Windows.Foundation.UniversalApiContract', '1.0.0.0'),
-                join(ref, 'Windows.Foundation.FoundationContract', '1.0.0.0'),
-                join(
-                    ref, 'Windows.Networking.Connectivity.WwanContract',
-                    '1.0.0.0'),
-                join(
-                    self.si.WindowsSdkDir, 'ExtensionSDKs', 'Microsoft.VCLibs',
-                    '%0.1f' % self.vs_ver, 'References', 'CommonConfiguration',
-                    'neutral'),
-            ]
-        return libpath
-
-    @property
-    def SdkTools(self):
-        """
-        Microsoft Windows SDK Tools.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        return list(self._sdk_tools())
-
-    def _sdk_tools(self):
-        """
-        Microsoft Windows SDK Tools paths generator.
-
-        Return
-        ------
-        generator of str
-            paths
-        """
-        if self.vs_ver < 15.0:
-            bin_dir = 'Bin' if self.vs_ver <= 11.0 else r'Bin\x86'
-            yield join(self.si.WindowsSdkDir, bin_dir)
-
-        if not self.pi.current_is_x86():
-            arch_subdir = self.pi.current_dir(x64=True)
-            path = 'Bin%s' % arch_subdir
-            yield join(self.si.WindowsSdkDir, path)
-
-        if self.vs_ver in (10.0, 11.0):
-            if self.pi.target_is_x86():
-                arch_subdir = ''
-            else:
-                arch_subdir = self.pi.current_dir(hidex86=True, x64=True)
-            path = r'Bin\NETFX 4.0 Tools%s' % arch_subdir
-            yield join(self.si.WindowsSdkDir, path)
-
-        elif self.vs_ver >= 15.0:
-            path = join(self.si.WindowsSdkDir, 'Bin')
-            arch_subdir = self.pi.current_dir(x64=True)
-            sdkver = self.si.WindowsSdkLastVersion
-            yield join(path, '%s%s' % (sdkver, arch_subdir))
-
-        if self.si.WindowsSDKExecutablePath:
-            yield self.si.WindowsSDKExecutablePath
-
-    @property
-    def _sdk_subdir(self):
-        """
-        Microsoft Windows SDK version subdir.
-
-        Return
-        ------
-        str
-            subdir
-        """
-        ucrtver = self.si.WindowsSdkLastVersion
-        return ('%s\\' % ucrtver) if ucrtver else ''
-
-    @property
-    def SdkSetup(self):
-        """
-        Microsoft Windows SDK Setup.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        if self.vs_ver > 9.0:
-            return []
-
-        return [join(self.si.WindowsSdkDir, 'Setup')]
-
-    @property
-    def FxTools(self):
-        """
-        Microsoft .NET Framework Tools.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        pi = self.pi
-        si = self.si
-
-        if self.vs_ver <= 10.0:
-            include32 = True
-            include64 = not pi.target_is_x86() and not pi.current_is_x86()
-        else:
-            include32 = pi.target_is_x86() or pi.current_is_x86()
-            include64 = pi.current_cpu == 'amd64' or pi.target_cpu == 'amd64'
-
-        tools = []
-        if include32:
-            tools += [join(si.FrameworkDir32, ver)
-                      for ver in si.FrameworkVersion32]
-        if include64:
-            tools += [join(si.FrameworkDir64, ver)
-                      for ver in si.FrameworkVersion64]
-        return tools
-
-    @property
-    def NetFxSDKLibraries(self):
-        """
-        Microsoft .Net Framework SDK Libraries.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        if self.vs_ver < 14.0 or not self.si.NetFxSdkDir:
-            return []
-
-        arch_subdir = self.pi.target_dir(x64=True)
-        return [join(self.si.NetFxSdkDir, r'lib\um%s' % arch_subdir)]
-
-    @property
-    def NetFxSDKIncludes(self):
-        """
-        Microsoft .Net Framework SDK Includes.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        if self.vs_ver < 14.0 or not self.si.NetFxSdkDir:
-            return []
-
-        return [join(self.si.NetFxSdkDir, r'include\um')]
-
-    @property
-    def VsTDb(self):
-        """
-        Microsoft Visual Studio Team System Database.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        return [join(self.si.VSInstallDir, r'VSTSDB\Deploy')]
-
-    @property
-    def MSBuild(self):
-        """
-        Microsoft Build Engine.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        if self.vs_ver < 12.0:
-            return []
-        elif self.vs_ver < 15.0:
-            base_path = self.si.ProgramFilesx86
-            arch_subdir = self.pi.current_dir(hidex86=True)
-        else:
-            base_path = self.si.VSInstallDir
-            arch_subdir = ''
-
-        path = r'MSBuild\%0.1f\bin%s' % (self.vs_ver, arch_subdir)
-        build = [join(base_path, path)]
-
-        if self.vs_ver >= 15.0:
-            # Add Roslyn C# & Visual Basic Compiler
-            build += [join(base_path, path, 'Roslyn')]
-
-        return build
-
-    @property
-    def HTMLHelpWorkshop(self):
-        """
-        Microsoft HTML Help Workshop.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        if self.vs_ver < 11.0:
-            return []
-
-        return [join(self.si.ProgramFilesx86, 'HTML Help Workshop')]
-
-    @property
-    def UCRTLibraries(self):
-        """
-        Microsoft Universal C Runtime SDK Libraries.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        if self.vs_ver < 14.0:
-            return []
-
-        arch_subdir = self.pi.target_dir(x64=True)
-        lib = join(self.si.UniversalCRTSdkDir, 'lib')
-        ucrtver = self._ucrt_subdir
-        return [join(lib, '%sucrt%s' % (ucrtver, arch_subdir))]
-
-    @property
-    def UCRTIncludes(self):
-        """
-        Microsoft Universal C Runtime SDK Include.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        if self.vs_ver < 14.0:
-            return []
-
-        include = join(self.si.UniversalCRTSdkDir, 'include')
-        return [join(include, '%sucrt' % self._ucrt_subdir)]
-
-    @property
-    def _ucrt_subdir(self):
-        """
-        Microsoft Universal C Runtime SDK version subdir.
-
-        Return
-        ------
-        str
-            subdir
-        """
-        ucrtver = self.si.UniversalCRTSdkLastVersion
-        return ('%s\\' % ucrtver) if ucrtver else ''
-
-    @property
-    def FSharp(self):
-        """
-        Microsoft Visual F#.
-
-        Return
-        ------
-        list of str
-            paths
-        """
-        if 11.0 > self.vs_ver > 12.0:
-            return []
-
-        return [self.si.FSharpInstallDir]
-
-    @property
-    def VCRuntimeRedist(self):
-        """
-        Microsoft Visual C++ runtime redistributable dll.
-
-        Return
-        ------
-        str
-            path
-        """
-        vcruntime = 'vcruntime%d0.dll' % self.vc_ver
-        arch_subdir = self.pi.target_dir(x64=True).strip('\\')
-
-        # Installation prefixes candidates
-        prefixes = []
-        tools_path = self.si.VCInstallDir
-        redist_path = dirname(tools_path.replace(r'\Tools', r'\Redist'))
-        if isdir(redist_path):
-            # Redist version may not be exactly the same as tools
-            redist_path = join(redist_path, listdir(redist_path)[-1])
-            prefixes += [redist_path, join(redist_path, 'onecore')]
-
-        prefixes += [join(tools_path, 'redist')]  # VS14 legacy path
-
-        # CRT directory
-        crt_dirs = ('Microsoft.VC%d.CRT' % (self.vc_ver * 10),
-                    # Sometime store in directory with VS version instead of VC
-                    'Microsoft.VC%d.CRT' % (int(self.vs_ver) * 10))
-
-        # vcruntime path
-        for prefix, crt_dir in itertools.product(prefixes, crt_dirs):
-            path = join(prefix, arch_subdir, crt_dir, vcruntime)
-            if isfile(path):
-                return path
-
-    def return_env(self, exists=True):
-        """
-        Return environment dict.
-
-        Parameters
-        ----------
-        exists: bool
-            It True, only return existing paths.
-
-        Return
-        ------
-        dict
-            environment
-        """
-        env = dict(
-            include=self._build_paths('include',
-                                      [self.VCIncludes,
-                                       self.OSIncludes,
-                                       self.UCRTIncludes,
-                                       self.NetFxSDKIncludes],
-                                      exists),
-            lib=self._build_paths('lib',
-                                  [self.VCLibraries,
-                                   self.OSLibraries,
-                                   self.FxTools,
-                                   self.UCRTLibraries,
-                                   self.NetFxSDKLibraries],
-                                  exists),
-            libpath=self._build_paths('libpath',
-                                      [self.VCLibraries,
-                                       self.FxTools,
-                                       self.VCStoreRefs,
-                                       self.OSLibpath],
-                                      exists),
-            path=self._build_paths('path',
-                                   [self.VCTools,
-                                    self.VSTools,
-                                    self.VsTDb,
-                                    self.SdkTools,
-                                    self.SdkSetup,
-                                    self.FxTools,
-                                    self.MSBuild,
-                                    self.HTMLHelpWorkshop,
-                                    self.FSharp],
-                                   exists),
-        )
-        if self.vs_ver >= 14 and isfile(self.VCRuntimeRedist):
-            env['py_vcruntime_redist'] = self.VCRuntimeRedist
-        return env
-
-    def _build_paths(self, name, spec_path_lists, exists):
-        """
-        Given an environment variable name and specified paths,
-        return a pathsep-separated string of paths containing
-        unique, extant, directories from those paths and from
-        the environment variable. Raise an error if no paths
-        are resolved.
-
-        Parameters
-        ----------
-        name: str
-            Environment variable name
-        spec_path_lists: list of str
-            Paths
-        exists: bool
-            It True, only return existing paths.
-
-        Return
-        ------
-        str
-            Pathsep-separated paths
-        """
-        # flatten spec_path_lists
-        spec_paths = itertools.chain.from_iterable(spec_path_lists)
-        env_paths = environ.get(name, '').split(pathsep)
-        paths = itertools.chain(spec_paths, env_paths)
-        extant_paths = list(filter(isdir, paths)) if exists else paths
-        if not extant_paths:
-            msg = "%s environment variable is empty" % name.upper()
-            raise distutils.errors.DistutilsPlatformError(msg)
-        unique_paths = unique_everseen(extant_paths)
-        return pathsep.join(unique_paths)
diff --git a/venv/lib/python3.11/site-packages/setuptools/namespaces.py b/venv/lib/python3.11/site-packages/setuptools/namespaces.py
deleted file mode 100755
index 44939e1..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/namespaces.py
+++ /dev/null
@@ -1,107 +0,0 @@
-import os
-from distutils import log
-import itertools
-
-
-flatten = itertools.chain.from_iterable
-
-
-class Installer:
-
-    nspkg_ext = '-nspkg.pth'
-
-    def install_namespaces(self):
-        nsp = self._get_all_ns_packages()
-        if not nsp:
-            return
-        filename, ext = os.path.splitext(self._get_target())
-        filename += self.nspkg_ext
-        self.outputs.append(filename)
-        log.info("Installing %s", filename)
-        lines = map(self._gen_nspkg_line, nsp)
-
-        if self.dry_run:
-            # always generate the lines, even in dry run
-            list(lines)
-            return
-
-        with open(filename, 'wt') as f:
-            f.writelines(lines)
-
-    def uninstall_namespaces(self):
-        filename, ext = os.path.splitext(self._get_target())
-        filename += self.nspkg_ext
-        if not os.path.exists(filename):
-            return
-        log.info("Removing %s", filename)
-        os.remove(filename)
-
-    def _get_target(self):
-        return self.target
-
-    _nspkg_tmpl = (
-        "import sys, types, os",
-        "has_mfs = sys.version_info > (3, 5)",
-        "p = os.path.join(%(root)s, *%(pth)r)",
-        "importlib = has_mfs and __import__('importlib.util')",
-        "has_mfs and __import__('importlib.machinery')",
-        (
-            "m = has_mfs and "
-            "sys.modules.setdefault(%(pkg)r, "
-            "importlib.util.module_from_spec("
-            "importlib.machinery.PathFinder.find_spec(%(pkg)r, "
-            "[os.path.dirname(p)])))"
-        ),
-        (
-            "m = m or "
-            "sys.modules.setdefault(%(pkg)r, types.ModuleType(%(pkg)r))"
-        ),
-        "mp = (m or []) and m.__dict__.setdefault('__path__',[])",
-        "(p not in mp) and mp.append(p)",
-    )
-    "lines for the namespace installer"
-
-    _nspkg_tmpl_multi = (
-        'm and setattr(sys.modules[%(parent)r], %(child)r, m)',
-    )
-    "additional line(s) when a parent package is indicated"
-
-    def _get_root(self):
-        return "sys._getframe(1).f_locals['sitedir']"
-
-    def _gen_nspkg_line(self, pkg):
-        pth = tuple(pkg.split('.'))
-        root = self._get_root()
-        tmpl_lines = self._nspkg_tmpl
-        parent, sep, child = pkg.rpartition('.')
-        if parent:
-            tmpl_lines += self._nspkg_tmpl_multi
-        return ';'.join(tmpl_lines) % locals() + '\n'
-
-    def _get_all_ns_packages(self):
-        """Return sorted list of all package namespaces"""
-        pkgs = self.distribution.namespace_packages or []
-        return sorted(flatten(map(self._pkg_names, pkgs)))
-
-    @staticmethod
-    def _pkg_names(pkg):
-        """
-        Given a namespace package, yield the components of that
-        package.
-
-        >>> names = Installer._pkg_names('a.b.c')
-        >>> set(names) == set(['a', 'a.b', 'a.b.c'])
-        True
-        """
-        parts = pkg.split('.')
-        while parts:
-            yield '.'.join(parts)
-            parts.pop()
-
-
-class DevelopInstaller(Installer):
-    def _get_root(self):
-        return repr(str(self.egg_path))
-
-    def _get_target(self):
-        return self.egg_link
diff --git a/venv/lib/python3.11/site-packages/setuptools/package_index.py b/venv/lib/python3.11/site-packages/setuptools/package_index.py
deleted file mode 100755
index 89f59ac..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/package_index.py
+++ /dev/null
@@ -1,1181 +0,0 @@
-"""PyPI and direct package downloading."""
-
-import sys
-import subprocess
-import os
-import re
-import io
-import shutil
-import socket
-import base64
-import hashlib
-import itertools
-import warnings
-import configparser
-import html
-import http.client
-import urllib.parse
-import urllib.request
-import urllib.error
-from functools import wraps
-
-import setuptools
-from pkg_resources import (
-    CHECKOUT_DIST,
-    Distribution,
-    BINARY_DIST,
-    normalize_path,
-    SOURCE_DIST,
-    Environment,
-    find_distributions,
-    safe_name,
-    safe_version,
-    to_filename,
-    Requirement,
-    DEVELOP_DIST,
-    EGG_DIST,
-    parse_version,
-)
-from distutils import log
-from distutils.errors import DistutilsError
-from fnmatch import translate
-from setuptools.wheel import Wheel
-from setuptools.extern.more_itertools import unique_everseen
-
-
-EGG_FRAGMENT = re.compile(r'^egg=([-A-Za-z0-9_.+!]+)$')
-HREF = re.compile(r"""href\s*=\s*['"]?([^'"> ]+)""", re.I)
-PYPI_MD5 = re.compile(
-    r'([^<]+)\n\s+\(md5\)'
-)
-URL_SCHEME = re.compile('([-+.a-z0-9]{2,}):', re.I).match
-EXTENSIONS = ".tar.gz .tar.bz2 .tar .zip .tgz".split()
-
-__all__ = [
-    'PackageIndex',
-    'distros_for_url',
-    'parse_bdist_wininst',
-    'interpret_distro_name',
-]
-
-_SOCKET_TIMEOUT = 15
-
-_tmpl = "setuptools/{setuptools.__version__} Python-urllib/{py_major}"
-user_agent = _tmpl.format(
-    py_major='{}.{}'.format(*sys.version_info), setuptools=setuptools
-)
-
-
-def parse_requirement_arg(spec):
-    try:
-        return Requirement.parse(spec)
-    except ValueError as e:
-        raise DistutilsError(
-            "Not a URL, existing file, or requirement spec: %r" % (spec,)
-        ) from e
-
-
-def parse_bdist_wininst(name):
-    """Return (base,pyversion) or (None,None) for possible .exe name"""
-
-    lower = name.lower()
-    base, py_ver, plat = None, None, None
-
-    if lower.endswith('.exe'):
-        if lower.endswith('.win32.exe'):
-            base = name[:-10]
-            plat = 'win32'
-        elif lower.startswith('.win32-py', -16):
-            py_ver = name[-7:-4]
-            base = name[:-16]
-            plat = 'win32'
-        elif lower.endswith('.win-amd64.exe'):
-            base = name[:-14]
-            plat = 'win-amd64'
-        elif lower.startswith('.win-amd64-py', -20):
-            py_ver = name[-7:-4]
-            base = name[:-20]
-            plat = 'win-amd64'
-    return base, py_ver, plat
-
-
-def egg_info_for_url(url):
-    parts = urllib.parse.urlparse(url)
-    scheme, server, path, parameters, query, fragment = parts
-    base = urllib.parse.unquote(path.split('/')[-1])
-    if server == 'sourceforge.net' and base == 'download':  # XXX Yuck
-        base = urllib.parse.unquote(path.split('/')[-2])
-    if '#' in base:
-        base, fragment = base.split('#', 1)
-    return base, fragment
-
-
-def distros_for_url(url, metadata=None):
-    """Yield egg or source distribution objects that might be found at a URL"""
-    base, fragment = egg_info_for_url(url)
-    for dist in distros_for_location(url, base, metadata):
-        yield dist
-    if fragment:
-        match = EGG_FRAGMENT.match(fragment)
-        if match:
-            for dist in interpret_distro_name(
-                url, match.group(1), metadata, precedence=CHECKOUT_DIST
-            ):
-                yield dist
-
-
-def distros_for_location(location, basename, metadata=None):
-    """Yield egg or source distribution objects based on basename"""
-    if basename.endswith('.egg.zip'):
-        basename = basename[:-4]  # strip the .zip
-    if basename.endswith('.egg') and '-' in basename:
-        # only one, unambiguous interpretation
-        return [Distribution.from_location(location, basename, metadata)]
-    if basename.endswith('.whl') and '-' in basename:
-        wheel = Wheel(basename)
-        if not wheel.is_compatible():
-            return []
-        return [
-            Distribution(
-                location=location,
-                project_name=wheel.project_name,
-                version=wheel.version,
-                # Increase priority over eggs.
-                precedence=EGG_DIST + 1,
-            )
-        ]
-    if basename.endswith('.exe'):
-        win_base, py_ver, platform = parse_bdist_wininst(basename)
-        if win_base is not None:
-            return interpret_distro_name(
-                location, win_base, metadata, py_ver, BINARY_DIST, platform
-            )
-    # Try source distro extensions (.zip, .tgz, etc.)
-    #
-    for ext in EXTENSIONS:
-        if basename.endswith(ext):
-            basename = basename[: -len(ext)]
-            return interpret_distro_name(location, basename, metadata)
-    return []  # no extension matched
-
-
-def distros_for_filename(filename, metadata=None):
-    """Yield possible egg or source distribution objects based on a filename"""
-    return distros_for_location(
-        normalize_path(filename), os.path.basename(filename), metadata
-    )
-
-
-def interpret_distro_name(
-    location, basename, metadata, py_version=None, precedence=SOURCE_DIST, platform=None
-):
-    """Generate the interpretation of a source distro name
-
-    Note: if `location` is a filesystem filename, you should call
-    ``pkg_resources.normalize_path()`` on it before passing it to this
-    routine!
-    """
-
-    parts = basename.split('-')
-    if not py_version and any(re.match(r'py\d\.\d$', p) for p in parts[2:]):
-        # it is a bdist_dumb, not an sdist -- bail out
-        return
-
-    # find the pivot (p) that splits the name from the version.
-    # infer the version as the first item that has a digit.
-    for p in range(len(parts)):
-        if parts[p][:1].isdigit():
-            break
-    else:
-        p = len(parts)
-
-    yield Distribution(
-        location,
-        metadata,
-        '-'.join(parts[:p]),
-        '-'.join(parts[p:]),
-        py_version=py_version,
-        precedence=precedence,
-        platform=platform
-    )
-
-
-def unique_values(func):
-    """
-    Wrap a function returning an iterable such that the resulting iterable
-    only ever yields unique items.
-    """
-
-    @wraps(func)
-    def wrapper(*args, **kwargs):
-        return unique_everseen(func(*args, **kwargs))
-
-    return wrapper
-
-
-REL = re.compile(r"""<([^>]*\srel\s{0,10}=\s{0,10}['"]?([^'" >]+)[^>]*)>""", re.I)
-"""
-Regex for an HTML tag with 'rel="val"' attributes.
-"""
-
-
-@unique_values
-def find_external_links(url, page):
-    """Find rel="homepage" and rel="download" links in `page`, yielding URLs"""
-
-    for match in REL.finditer(page):
-        tag, rel = match.groups()
-        rels = set(map(str.strip, rel.lower().split(',')))
-        if 'homepage' in rels or 'download' in rels:
-            for match in HREF.finditer(tag):
-                yield urllib.parse.urljoin(url, htmldecode(match.group(1)))
-
-    for tag in ("Home Page", "Download URL"):
-        pos = page.find(tag)
-        if pos != -1:
-            match = HREF.search(page, pos)
-            if match:
-                yield urllib.parse.urljoin(url, htmldecode(match.group(1)))
-
-
-class ContentChecker:
-    """
-    A null content checker that defines the interface for checking content
-    """
-
-    def feed(self, block):
-        """
-        Feed a block of data to the hash.
-        """
-        return
-
-    def is_valid(self):
-        """
-        Check the hash. Return False if validation fails.
-        """
-        return True
-
-    def report(self, reporter, template):
-        """
-        Call reporter with information about the checker (hash name)
-        substituted into the template.
-        """
-        return
-
-
-class HashChecker(ContentChecker):
-    pattern = re.compile(
-        r'(?Psha1|sha224|sha384|sha256|sha512|md5)='
-        r'(?P[a-f0-9]+)'
-    )
-
-    def __init__(self, hash_name, expected):
-        self.hash_name = hash_name
-        self.hash = hashlib.new(hash_name)
-        self.expected = expected
-
-    @classmethod
-    def from_url(cls, url):
-        "Construct a (possibly null) ContentChecker from a URL"
-        fragment = urllib.parse.urlparse(url)[-1]
-        if not fragment:
-            return ContentChecker()
-        match = cls.pattern.search(fragment)
-        if not match:
-            return ContentChecker()
-        return cls(**match.groupdict())
-
-    def feed(self, block):
-        self.hash.update(block)
-
-    def is_valid(self):
-        return self.hash.hexdigest() == self.expected
-
-    def report(self, reporter, template):
-        msg = template % self.hash_name
-        return reporter(msg)
-
-
-class PackageIndex(Environment):
-    """A distribution index that scans web pages for download URLs"""
-
-    def __init__(
-        self,
-        index_url="https://pypi.org/simple/",
-        hosts=('*',),
-        ca_bundle=None,
-        verify_ssl=True,
-        *args,
-        **kw
-    ):
-        super().__init__(*args, **kw)
-        self.index_url = index_url + "/"[: not index_url.endswith('/')]
-        self.scanned_urls = {}
-        self.fetched_urls = {}
-        self.package_pages = {}
-        self.allows = re.compile('|'.join(map(translate, hosts))).match
-        self.to_scan = []
-        self.opener = urllib.request.urlopen
-
-    def add(self, dist):
-        # ignore invalid versions
-        try:
-            parse_version(dist.version)
-        except Exception:
-            return
-        return super().add(dist)
-
-    # FIXME: 'PackageIndex.process_url' is too complex (14)
-    def process_url(self, url, retrieve=False):  # noqa: C901
-        """Evaluate a URL as a possible download, and maybe retrieve it"""
-        if url in self.scanned_urls and not retrieve:
-            return
-        self.scanned_urls[url] = True
-        if not URL_SCHEME(url):
-            self.process_filename(url)
-            return
-        else:
-            dists = list(distros_for_url(url))
-            if dists:
-                if not self.url_ok(url):
-                    return
-                self.debug("Found link: %s", url)
-
-        if dists or not retrieve or url in self.fetched_urls:
-            list(map(self.add, dists))
-            return  # don't need the actual page
-
-        if not self.url_ok(url):
-            self.fetched_urls[url] = True
-            return
-
-        self.info("Reading %s", url)
-        self.fetched_urls[url] = True  # prevent multiple fetch attempts
-        tmpl = "Download error on %s: %%s -- Some packages may not be found!"
-        f = self.open_url(url, tmpl % url)
-        if f is None:
-            return
-        if isinstance(f, urllib.error.HTTPError) and f.code == 401:
-            self.info("Authentication error: %s" % f.msg)
-        self.fetched_urls[f.url] = True
-        if 'html' not in f.headers.get('content-type', '').lower():
-            f.close()  # not html, we can't process it
-            return
-
-        base = f.url  # handle redirects
-        page = f.read()
-        if not isinstance(page, str):
-            # In Python 3 and got bytes but want str.
-            if isinstance(f, urllib.error.HTTPError):
-                # Errors have no charset, assume latin1:
-                charset = 'latin-1'
-            else:
-                charset = f.headers.get_param('charset') or 'latin-1'
-            page = page.decode(charset, "ignore")
-        f.close()
-        for match in HREF.finditer(page):
-            link = urllib.parse.urljoin(base, htmldecode(match.group(1)))
-            self.process_url(link)
-        if url.startswith(self.index_url) and getattr(f, 'code', None) != 404:
-            page = self.process_index(url, page)
-
-    def process_filename(self, fn, nested=False):
-        # process filenames or directories
-        if not os.path.exists(fn):
-            self.warn("Not found: %s", fn)
-            return
-
-        if os.path.isdir(fn) and not nested:
-            path = os.path.realpath(fn)
-            for item in os.listdir(path):
-                self.process_filename(os.path.join(path, item), True)
-
-        dists = distros_for_filename(fn)
-        if dists:
-            self.debug("Found: %s", fn)
-            list(map(self.add, dists))
-
-    def url_ok(self, url, fatal=False):
-        s = URL_SCHEME(url)
-        is_file = s and s.group(1).lower() == 'file'
-        if is_file or self.allows(urllib.parse.urlparse(url)[1]):
-            return True
-        msg = (
-            "\nNote: Bypassing %s (disallowed host; see "
-            "http://bit.ly/2hrImnY for details).\n"
-        )
-        if fatal:
-            raise DistutilsError(msg % url)
-        else:
-            self.warn(msg, url)
-
-    def scan_egg_links(self, search_path):
-        dirs = filter(os.path.isdir, search_path)
-        egg_links = (
-            (path, entry)
-            for path in dirs
-            for entry in os.listdir(path)
-            if entry.endswith('.egg-link')
-        )
-        list(itertools.starmap(self.scan_egg_link, egg_links))
-
-    def scan_egg_link(self, path, entry):
-        with open(os.path.join(path, entry)) as raw_lines:
-            # filter non-empty lines
-            lines = list(filter(None, map(str.strip, raw_lines)))
-
-        if len(lines) != 2:
-            # format is not recognized; punt
-            return
-
-        egg_path, setup_path = lines
-
-        for dist in find_distributions(os.path.join(path, egg_path)):
-            dist.location = os.path.join(path, *lines)
-            dist.precedence = SOURCE_DIST
-            self.add(dist)
-
-    def _scan(self, link):
-        # Process a URL to see if it's for a package page
-        NO_MATCH_SENTINEL = None, None
-        if not link.startswith(self.index_url):
-            return NO_MATCH_SENTINEL
-
-        parts = list(map(urllib.parse.unquote, link[len(self.index_url) :].split('/')))
-        if len(parts) != 2 or '#' in parts[1]:
-            return NO_MATCH_SENTINEL
-
-        # it's a package page, sanitize and index it
-        pkg = safe_name(parts[0])
-        ver = safe_version(parts[1])
-        self.package_pages.setdefault(pkg.lower(), {})[link] = True
-        return to_filename(pkg), to_filename(ver)
-
-    def process_index(self, url, page):
-        """Process the contents of a PyPI page"""
-
-        # process an index page into the package-page index
-        for match in HREF.finditer(page):
-            try:
-                self._scan(urllib.parse.urljoin(url, htmldecode(match.group(1))))
-            except ValueError:
-                pass
-
-        pkg, ver = self._scan(url)  # ensure this page is in the page index
-        if not pkg:
-            return ""  # no sense double-scanning non-package pages
-
-        # process individual package page
-        for new_url in find_external_links(url, page):
-            # Process the found URL
-            base, frag = egg_info_for_url(new_url)
-            if base.endswith('.py') and not frag:
-                if ver:
-                    new_url += '#egg=%s-%s' % (pkg, ver)
-                else:
-                    self.need_version_info(url)
-            self.scan_url(new_url)
-
-        return PYPI_MD5.sub(
-            lambda m: '%s' % m.group(1, 3, 2), page
-        )
-
-    def need_version_info(self, url):
-        self.scan_all(
-            "Page at %s links to .py file(s) without version info; an index "
-            "scan is required.",
-            url,
-        )
-
-    def scan_all(self, msg=None, *args):
-        if self.index_url not in self.fetched_urls:
-            if msg:
-                self.warn(msg, *args)
-            self.info("Scanning index of all packages (this may take a while)")
-        self.scan_url(self.index_url)
-
-    def find_packages(self, requirement):
-        self.scan_url(self.index_url + requirement.unsafe_name + '/')
-
-        if not self.package_pages.get(requirement.key):
-            # Fall back to safe version of the name
-            self.scan_url(self.index_url + requirement.project_name + '/')
-
-        if not self.package_pages.get(requirement.key):
-            # We couldn't find the target package, so search the index page too
-            self.not_found_in_index(requirement)
-
-        for url in list(self.package_pages.get(requirement.key, ())):
-            # scan each page that might be related to the desired package
-            self.scan_url(url)
-
-    def obtain(self, requirement, installer=None):
-        self.prescan()
-        self.find_packages(requirement)
-        for dist in self[requirement.key]:
-            if dist in requirement:
-                return dist
-            self.debug("%s does not match %s", requirement, dist)
-        return super(PackageIndex, self).obtain(requirement, installer)
-
-    def check_hash(self, checker, filename, tfp):
-        """
-        checker is a ContentChecker
-        """
-        checker.report(self.debug, "Validating %%s checksum for %s" % filename)
-        if not checker.is_valid():
-            tfp.close()
-            os.unlink(filename)
-            raise DistutilsError(
-                "%s validation failed for %s; "
-                "possible download problem?"
-                % (checker.hash.name, os.path.basename(filename))
-            )
-
-    def add_find_links(self, urls):
-        """Add `urls` to the list that will be prescanned for searches"""
-        for url in urls:
-            if (
-                self.to_scan is None  # if we have already "gone online"
-                or not URL_SCHEME(url)  # or it's a local file/directory
-                or url.startswith('file:')
-                or list(distros_for_url(url))  # or a direct package link
-            ):
-                # then go ahead and process it now
-                self.scan_url(url)
-            else:
-                # otherwise, defer retrieval till later
-                self.to_scan.append(url)
-
-    def prescan(self):
-        """Scan urls scheduled for prescanning (e.g. --find-links)"""
-        if self.to_scan:
-            list(map(self.scan_url, self.to_scan))
-        self.to_scan = None  # from now on, go ahead and process immediately
-
-    def not_found_in_index(self, requirement):
-        if self[requirement.key]:  # we've seen at least one distro
-            meth, msg = self.info, "Couldn't retrieve index page for %r"
-        else:  # no distros seen for this name, might be misspelled
-            meth, msg = (
-                self.warn,
-                "Couldn't find index page for %r (maybe misspelled?)",
-            )
-        meth(msg, requirement.unsafe_name)
-        self.scan_all()
-
-    def download(self, spec, tmpdir):
-        """Locate and/or download `spec` to `tmpdir`, returning a local path
-
-        `spec` may be a ``Requirement`` object, or a string containing a URL,
-        an existing local filename, or a project/version requirement spec
-        (i.e. the string form of a ``Requirement`` object).  If it is the URL
-        of a .py file with an unambiguous ``#egg=name-version`` tag (i.e., one
-        that escapes ``-`` as ``_`` throughout), a trivial ``setup.py`` is
-        automatically created alongside the downloaded file.
-
-        If `spec` is a ``Requirement`` object or a string containing a
-        project/version requirement spec, this method returns the location of
-        a matching distribution (possibly after downloading it to `tmpdir`).
-        If `spec` is a locally existing file or directory name, it is simply
-        returned unchanged.  If `spec` is a URL, it is downloaded to a subpath
-        of `tmpdir`, and the local filename is returned.  Various errors may be
-        raised if a problem occurs during downloading.
-        """
-        if not isinstance(spec, Requirement):
-            scheme = URL_SCHEME(spec)
-            if scheme:
-                # It's a url, download it to tmpdir
-                found = self._download_url(spec, tmpdir)
-                base, fragment = egg_info_for_url(spec)
-                if base.endswith('.py'):
-                    found = self.gen_setup(found, fragment, tmpdir)
-                return found
-            elif os.path.exists(spec):
-                # Existing file or directory, just return it
-                return spec
-            else:
-                spec = parse_requirement_arg(spec)
-        return getattr(self.fetch_distribution(spec, tmpdir), 'location', None)
-
-    def fetch_distribution(  # noqa: C901  # is too complex (14)  # FIXME
-        self,
-        requirement,
-        tmpdir,
-        force_scan=False,
-        source=False,
-        develop_ok=False,
-        local_index=None,
-    ):
-        """Obtain a distribution suitable for fulfilling `requirement`
-
-        `requirement` must be a ``pkg_resources.Requirement`` instance.
-        If necessary, or if the `force_scan` flag is set, the requirement is
-        searched for in the (online) package index as well as the locally
-        installed packages.  If a distribution matching `requirement` is found,
-        the returned distribution's ``location`` is the value you would have
-        gotten from calling the ``download()`` method with the matching
-        distribution's URL or filename.  If no matching distribution is found,
-        ``None`` is returned.
-
-        If the `source` flag is set, only source distributions and source
-        checkout links will be considered.  Unless the `develop_ok` flag is
-        set, development and system eggs (i.e., those using the ``.egg-info``
-        format) will be ignored.
-        """
-        # process a Requirement
-        self.info("Searching for %s", requirement)
-        skipped = {}
-        dist = None
-
-        def find(req, env=None):
-            if env is None:
-                env = self
-            # Find a matching distribution; may be called more than once
-
-            for dist in env[req.key]:
-
-                if dist.precedence == DEVELOP_DIST and not develop_ok:
-                    if dist not in skipped:
-                        self.warn(
-                            "Skipping development or system egg: %s",
-                            dist,
-                        )
-                        skipped[dist] = 1
-                    continue
-
-                test = dist in req and (dist.precedence <= SOURCE_DIST or not source)
-                if test:
-                    loc = self.download(dist.location, tmpdir)
-                    dist.download_location = loc
-                    if os.path.exists(dist.download_location):
-                        return dist
-
-        if force_scan:
-            self.prescan()
-            self.find_packages(requirement)
-            dist = find(requirement)
-
-        if not dist and local_index is not None:
-            dist = find(requirement, local_index)
-
-        if dist is None:
-            if self.to_scan is not None:
-                self.prescan()
-            dist = find(requirement)
-
-        if dist is None and not force_scan:
-            self.find_packages(requirement)
-            dist = find(requirement)
-
-        if dist is None:
-            self.warn(
-                "No local packages or working download links found for %s%s",
-                (source and "a source distribution of " or ""),
-                requirement,
-            )
-        else:
-            self.info("Best match: %s", dist)
-            return dist.clone(location=dist.download_location)
-
-    def fetch(self, requirement, tmpdir, force_scan=False, source=False):
-        """Obtain a file suitable for fulfilling `requirement`
-
-        DEPRECATED; use the ``fetch_distribution()`` method now instead.  For
-        backward compatibility, this routine is identical but returns the
-        ``location`` of the downloaded distribution instead of a distribution
-        object.
-        """
-        dist = self.fetch_distribution(requirement, tmpdir, force_scan, source)
-        if dist is not None:
-            return dist.location
-        return None
-
-    def gen_setup(self, filename, fragment, tmpdir):
-        match = EGG_FRAGMENT.match(fragment)
-        dists = (
-            match
-            and [
-                d
-                for d in interpret_distro_name(filename, match.group(1), None)
-                if d.version
-            ]
-            or []
-        )
-
-        if len(dists) == 1:  # unambiguous ``#egg`` fragment
-            basename = os.path.basename(filename)
-
-            # Make sure the file has been downloaded to the temp dir.
-            if os.path.dirname(filename) != tmpdir:
-                dst = os.path.join(tmpdir, basename)
-                if not (os.path.exists(dst) and os.path.samefile(filename, dst)):
-                    shutil.copy2(filename, dst)
-                    filename = dst
-
-            with open(os.path.join(tmpdir, 'setup.py'), 'w') as file:
-                file.write(
-                    "from setuptools import setup\n"
-                    "setup(name=%r, version=%r, py_modules=[%r])\n"
-                    % (
-                        dists[0].project_name,
-                        dists[0].version,
-                        os.path.splitext(basename)[0],
-                    )
-                )
-            return filename
-
-        elif match:
-            raise DistutilsError(
-                "Can't unambiguously interpret project/version identifier %r; "
-                "any dashes in the name or version should be escaped using "
-                "underscores. %r" % (fragment, dists)
-            )
-        else:
-            raise DistutilsError(
-                "Can't process plain .py files without an '#egg=name-version'"
-                " suffix to enable automatic setup script generation."
-            )
-
-    dl_blocksize = 8192
-
-    def _download_to(self, url, filename):
-        self.info("Downloading %s", url)
-        # Download the file
-        fp = None
-        try:
-            checker = HashChecker.from_url(url)
-            fp = self.open_url(url)
-            if isinstance(fp, urllib.error.HTTPError):
-                raise DistutilsError(
-                    "Can't download %s: %s %s" % (url, fp.code, fp.msg)
-                )
-            headers = fp.info()
-            blocknum = 0
-            bs = self.dl_blocksize
-            size = -1
-            if "content-length" in headers:
-                # Some servers return multiple Content-Length headers :(
-                sizes = headers.get_all('Content-Length')
-                size = max(map(int, sizes))
-                self.reporthook(url, filename, blocknum, bs, size)
-            with open(filename, 'wb') as tfp:
-                while True:
-                    block = fp.read(bs)
-                    if block:
-                        checker.feed(block)
-                        tfp.write(block)
-                        blocknum += 1
-                        self.reporthook(url, filename, blocknum, bs, size)
-                    else:
-                        break
-                self.check_hash(checker, filename, tfp)
-            return headers
-        finally:
-            if fp:
-                fp.close()
-
-    def reporthook(self, url, filename, blocknum, blksize, size):
-        pass  # no-op
-
-    # FIXME:
-    def open_url(self, url, warning=None):  # noqa: C901  # is too complex (12)
-        if url.startswith('file:'):
-            return local_open(url)
-        try:
-            return open_with_auth(url, self.opener)
-        except (ValueError, http.client.InvalidURL) as v:
-            msg = ' '.join([str(arg) for arg in v.args])
-            if warning:
-                self.warn(warning, msg)
-            else:
-                raise DistutilsError('%s %s' % (url, msg)) from v
-        except urllib.error.HTTPError as v:
-            return v
-        except urllib.error.URLError as v:
-            if warning:
-                self.warn(warning, v.reason)
-            else:
-                raise DistutilsError(
-                    "Download error for %s: %s" % (url, v.reason)
-                ) from v
-        except http.client.BadStatusLine as v:
-            if warning:
-                self.warn(warning, v.line)
-            else:
-                raise DistutilsError(
-                    '%s returned a bad status line. The server might be '
-                    'down, %s' % (url, v.line)
-                ) from v
-        except (http.client.HTTPException, socket.error) as v:
-            if warning:
-                self.warn(warning, v)
-            else:
-                raise DistutilsError("Download error for %s: %s" % (url, v)) from v
-
-    def _download_url(self, url, tmpdir):
-        # Determine download filename
-        #
-        name, fragment = egg_info_for_url(url)
-        if name:
-            while '..' in name:
-                name = name.replace('..', '.').replace('\\', '_')
-        else:
-            name = "__downloaded__"  # default if URL has no path contents
-
-        if name.endswith('.egg.zip'):
-            name = name[:-4]  # strip the extra .zip before download
-
-        filename = os.path.join(tmpdir, name)
-
-        # ensure path resolves within the tmpdir
-        if not filename.startswith(str(tmpdir)):
-            raise ValueError(f"Invalid filename {filename}")
-
-        return self._download_vcs(url, filename) or self._download_other(url, filename)
-
-    @staticmethod
-    def _resolve_vcs(url):
-        """
-        >>> rvcs = PackageIndex._resolve_vcs
-        >>> rvcs('git+http://foo/bar')
-        'git'
-        >>> rvcs('hg+https://foo/bar')
-        'hg'
-        >>> rvcs('git:myhost')
-        'git'
-        >>> rvcs('hg:myhost')
-        >>> rvcs('http://foo/bar')
-        """
-        scheme = urllib.parse.urlsplit(url).scheme
-        pre, sep, post = scheme.partition('+')
-        # svn and git have their own protocol; hg does not
-        allowed = set(['svn', 'git'] + ['hg'] * bool(sep))
-        return next(iter({pre} & allowed), None)
-
-
-    def _download_vcs(self, url, spec_filename):
-        vcs = self._resolve_vcs(url)
-        if not vcs:
-            return
-        if vcs == 'svn':
-            return self._download_svn(url, spec_filename)
-
-        filename, _, _ = spec_filename.partition('#')
-        url, rev = self._vcs_split_rev_from_url(url)
-
-        self.info(f"Doing {vcs} clone from {url} to {filename}")
-        subprocess.check_call([vcs, 'clone', '--quiet', url, filename])
-
-        co_commands = dict(
-            git=[vcs, '-C', filename, 'checkout', '--quiet', rev],
-            hg=[vcs, '--cwd', filename, 'up', '-C', '-r', rev, '-q'],
-        )
-        if rev is not None:
-            self.info(f"Checking out {rev}")
-            subprocess.check_call(co_commands[vcs])
-
-        return filename
-
-    def _download_other(self, url, filename):
-        scheme = urllib.parse.urlsplit(url).scheme
-        if scheme == 'file':  # pragma: no cover
-            return urllib.request.url2pathname(urllib.parse.urlparse(url).path)
-        # raise error if not allowed
-        self.url_ok(url, True)
-        return self._attempt_download(url, filename)
-
-    def scan_url(self, url):
-        self.process_url(url, True)
-
-    def _attempt_download(self, url, filename):
-        headers = self._download_to(url, filename)
-        if 'html' in headers.get('content-type', '').lower():
-            return self._download_html(url, headers, filename)
-        else:
-            return filename
-
-    def _download_html(self, url, headers, filename):
-        file = open(filename)
-        for line in file:
-            if line.strip():
-                # Check for a subversion index page
-                if re.search(r'([^- ]+ - )?Revision \d+:', line):
-                    # it's a subversion index page:
-                    file.close()
-                    os.unlink(filename)
-                    return self._download_svn(url, filename)
-                break  # not an index page
-        file.close()
-        os.unlink(filename)
-        raise DistutilsError("Unexpected HTML page found at " + url)
-
-    def _download_svn(self, url, filename):
-        warnings.warn("SVN download support is deprecated", UserWarning)
-        url = url.split('#', 1)[0]  # remove any fragment for svn's sake
-        creds = ''
-        if url.lower().startswith('svn:') and '@' in url:
-            scheme, netloc, path, p, q, f = urllib.parse.urlparse(url)
-            if not netloc and path.startswith('//') and '/' in path[2:]:
-                netloc, path = path[2:].split('/', 1)
-                auth, host = _splituser(netloc)
-                if auth:
-                    if ':' in auth:
-                        user, pw = auth.split(':', 1)
-                        creds = " --username=%s --password=%s" % (user, pw)
-                    else:
-                        creds = " --username=" + auth
-                    netloc = host
-                    parts = scheme, netloc, url, p, q, f
-                    url = urllib.parse.urlunparse(parts)
-        self.info(f"Doing subversion checkout from {url} to {filename}")
-        subprocess.check_call(['svn', 'checkout', creds, '-q', url, filename])
-        return filename
-
-    @staticmethod
-    def _vcs_split_rev_from_url(url):
-        """
-        Given a possible VCS URL, return a clean URL and resolved revision if any.
-        >>> vsrfu = PackageIndex._vcs_split_rev_from_url
-        >>> vsrfu('git+https://github.com/pypa/setuptools@v69.0.0#egg-info=setuptools')
-        ('https://github.com/pypa/setuptools', 'v69.0.0')
-        >>> vsrfu('git+https://github.com/pypa/setuptools#egg-info=setuptools')
-        ('https://github.com/pypa/setuptools', None)
-        >>> vsrfu('http://foo/bar')
-        ('http://foo/bar', None)
-        """
-        parts = urllib.parse.urlsplit(url)
-
-        clean_scheme = parts.scheme.split('+', 1)[-1]
-
-        # Some fragment identification fails
-        no_fragment_path, _, _ = parts.path.partition('#')
-
-        pre, sep, post = no_fragment_path.rpartition('@')
-        clean_path, rev = (pre, post) if sep else (post, None)
-
-        resolved = parts._replace(
-            scheme=clean_scheme,
-            path=clean_path,
-            # discard the fragment
-            fragment='',
-        ).geturl()
-
-        return resolved, rev
-
-    def debug(self, msg, *args):
-        log.debug(msg, *args)
-
-    def info(self, msg, *args):
-        log.info(msg, *args)
-
-    def warn(self, msg, *args):
-        log.warn(msg, *args)
-
-
-# This pattern matches a character entity reference (a decimal numeric
-# references, a hexadecimal numeric reference, or a named reference).
-entity_sub = re.compile(r'&(#(\d+|x[\da-fA-F]+)|[\w.:-]+);?').sub
-
-
-def decode_entity(match):
-    what = match.group(0)
-    return html.unescape(what)
-
-
-def htmldecode(text):
-    """
-    Decode HTML entities in the given text.
-
-    >>> htmldecode(
-    ...     'https://../package_name-0.1.2.tar.gz'
-    ...     '?tokena=A&tokenb=B">package_name-0.1.2.tar.gz')
-    'https://../package_name-0.1.2.tar.gz?tokena=A&tokenb=B">package_name-0.1.2.tar.gz'
-    """
-    return entity_sub(decode_entity, text)
-
-
-def socket_timeout(timeout=15):
-    def _socket_timeout(func):
-        def _socket_timeout(*args, **kwargs):
-            old_timeout = socket.getdefaulttimeout()
-            socket.setdefaulttimeout(timeout)
-            try:
-                return func(*args, **kwargs)
-            finally:
-                socket.setdefaulttimeout(old_timeout)
-
-        return _socket_timeout
-
-    return _socket_timeout
-
-
-def _encode_auth(auth):
-    """
-    Encode auth from a URL suitable for an HTTP header.
-    >>> str(_encode_auth('username%3Apassword'))
-    'dXNlcm5hbWU6cGFzc3dvcmQ='
-
-    Long auth strings should not cause a newline to be inserted.
-    >>> long_auth = 'username:' + 'password'*10
-    >>> chr(10) in str(_encode_auth(long_auth))
-    False
-    """
-    auth_s = urllib.parse.unquote(auth)
-    # convert to bytes
-    auth_bytes = auth_s.encode()
-    encoded_bytes = base64.b64encode(auth_bytes)
-    # convert back to a string
-    encoded = encoded_bytes.decode()
-    # strip the trailing carriage return
-    return encoded.replace('\n', '')
-
-
-class Credential:
-    """
-    A username/password pair. Use like a namedtuple.
-    """
-
-    def __init__(self, username, password):
-        self.username = username
-        self.password = password
-
-    def __iter__(self):
-        yield self.username
-        yield self.password
-
-    def __str__(self):
-        return '%(username)s:%(password)s' % vars(self)
-
-
-class PyPIConfig(configparser.RawConfigParser):
-    def __init__(self):
-        """
-        Load from ~/.pypirc
-        """
-        defaults = dict.fromkeys(['username', 'password', 'repository'], '')
-        super().__init__(defaults)
-
-        rc = os.path.join(os.path.expanduser('~'), '.pypirc')
-        if os.path.exists(rc):
-            self.read(rc)
-
-    @property
-    def creds_by_repository(self):
-        sections_with_repositories = [
-            section
-            for section in self.sections()
-            if self.get(section, 'repository').strip()
-        ]
-
-        return dict(map(self._get_repo_cred, sections_with_repositories))
-
-    def _get_repo_cred(self, section):
-        repo = self.get(section, 'repository').strip()
-        return repo, Credential(
-            self.get(section, 'username').strip(),
-            self.get(section, 'password').strip(),
-        )
-
-    def find_credential(self, url):
-        """
-        If the URL indicated appears to be a repository defined in this
-        config, return the credential for that repository.
-        """
-        for repository, cred in self.creds_by_repository.items():
-            if url.startswith(repository):
-                return cred
-
-
-def open_with_auth(url, opener=urllib.request.urlopen):
-    """Open a urllib2 request, handling HTTP authentication"""
-
-    parsed = urllib.parse.urlparse(url)
-    scheme, netloc, path, params, query, frag = parsed
-
-    # Double scheme does not raise on macOS as revealed by a
-    # failing test. We would expect "nonnumeric port". Refs #20.
-    if netloc.endswith(':'):
-        raise http.client.InvalidURL("nonnumeric port: ''")
-
-    if scheme in ('http', 'https'):
-        auth, address = _splituser(netloc)
-    else:
-        auth = None
-
-    if not auth:
-        cred = PyPIConfig().find_credential(url)
-        if cred:
-            auth = str(cred)
-            info = cred.username, url
-            log.info('Authenticating as %s for %s (from .pypirc)', *info)
-
-    if auth:
-        auth = "Basic " + _encode_auth(auth)
-        parts = scheme, address, path, params, query, frag
-        new_url = urllib.parse.urlunparse(parts)
-        request = urllib.request.Request(new_url)
-        request.add_header("Authorization", auth)
-    else:
-        request = urllib.request.Request(url)
-
-    request.add_header('User-Agent', user_agent)
-    fp = opener(request)
-
-    if auth:
-        # Put authentication info back into request URL if same host,
-        # so that links found on the page will work
-        s2, h2, path2, param2, query2, frag2 = urllib.parse.urlparse(fp.url)
-        if s2 == scheme and h2 == address:
-            parts = s2, netloc, path2, param2, query2, frag2
-            fp.url = urllib.parse.urlunparse(parts)
-
-    return fp
-
-
-# copy of urllib.parse._splituser from Python 3.8
-def _splituser(host):
-    """splituser('user[:passwd]@host[:port]')
-    --> 'user[:passwd]', 'host[:port]'."""
-    user, delim, host = host.rpartition('@')
-    return (user if delim else None), host
-
-
-# adding a timeout to avoid freezing package_index
-open_with_auth = socket_timeout(_SOCKET_TIMEOUT)(open_with_auth)
-
-
-def fix_sf_url(url):
-    return url  # backward compatibility
-
-
-def local_open(url):
-    """Read a local path, with special support for directories"""
-    scheme, server, path, param, query, frag = urllib.parse.urlparse(url)
-    filename = urllib.request.url2pathname(path)
-    if os.path.isfile(filename):
-        return urllib.request.urlopen(url)
-    elif path.endswith('/') and os.path.isdir(filename):
-        files = []
-        for f in os.listdir(filename):
-            filepath = os.path.join(filename, f)
-            if f == 'index.html':
-                with open(filepath, 'r') as fp:
-                    body = fp.read()
-                break
-            elif os.path.isdir(filepath):
-                f += '/'
-            files.append('<a href="{name}">{name}</a>'.format(name=f))
-        else:
-            tmpl = (
-                "<html><head><title>{url}" "{files}"
-            )
-            body = tmpl.format(url=url, files='\n'.join(files))
-        status, message = 200, "OK"
-    else:
-        status, message, body = 404, "Path not found", "Not found"
-
-    headers = {'content-type': 'text/html'}
-    body_stream = io.StringIO(body)
-    return urllib.error.HTTPError(url, status, message, headers, body_stream)
diff --git a/venv/lib/python3.11/site-packages/setuptools/py34compat.py b/venv/lib/python3.11/site-packages/setuptools/py34compat.py
deleted file mode 100755
index 3ad9172..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/py34compat.py
+++ /dev/null
@@ -1,13 +0,0 @@
-import importlib
-
-try:
-    import importlib.util
-except ImportError:
-    pass
-
-
-try:
-    module_from_spec = importlib.util.module_from_spec
-except AttributeError:
-    def module_from_spec(spec):
-        return spec.loader.load_module(spec.name)
diff --git a/venv/lib/python3.11/site-packages/setuptools/sandbox.py b/venv/lib/python3.11/site-packages/setuptools/sandbox.py
deleted file mode 100755
index 034fc80..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/sandbox.py
+++ /dev/null
@@ -1,530 +0,0 @@
-import os
-import sys
-import tempfile
-import operator
-import functools
-import itertools
-import re
-import contextlib
-import pickle
-import textwrap
-import builtins
-
-import pkg_resources
-from distutils.errors import DistutilsError
-from pkg_resources import working_set
-
-if sys.platform.startswith('java'):
-    import org.python.modules.posix.PosixModule as _os
-else:
-    _os = sys.modules[os.name]
-try:
-    _file = file
-except NameError:
-    _file = None
-_open = open
-
-
-__all__ = [
-    "AbstractSandbox",
-    "DirectorySandbox",
-    "SandboxViolation",
-    "run_setup",
-]
-
-
-def _execfile(filename, globals, locals=None):
-    """
-    Python 3 implementation of execfile.
-    """
-    mode = 'rb'
-    with open(filename, mode) as stream:
-        script = stream.read()
-    if locals is None:
-        locals = globals
-    code = compile(script, filename, 'exec')
-    exec(code, globals, locals)
-
-
-@contextlib.contextmanager
-def save_argv(repl=None):
-    saved = sys.argv[:]
-    if repl is not None:
-        sys.argv[:] = repl
-    try:
-        yield saved
-    finally:
-        sys.argv[:] = saved
-
-
-@contextlib.contextmanager
-def save_path():
-    saved = sys.path[:]
-    try:
-        yield saved
-    finally:
-        sys.path[:] = saved
-
-
-@contextlib.contextmanager
-def override_temp(replacement):
-    """
-    Monkey-patch tempfile.tempdir with replacement, ensuring it exists
-    """
-    os.makedirs(replacement, exist_ok=True)
-
-    saved = tempfile.tempdir
-
-    tempfile.tempdir = replacement
-
-    try:
-        yield
-    finally:
-        tempfile.tempdir = saved
-
-
-@contextlib.contextmanager
-def pushd(target):
-    saved = os.getcwd()
-    os.chdir(target)
-    try:
-        yield saved
-    finally:
-        os.chdir(saved)
-
-
-class UnpickleableException(Exception):
-    """
-    An exception representing another Exception that could not be pickled.
-    """
-
-    @staticmethod
-    def dump(type, exc):
-        """
-        Always return a dumped (pickled) type and exc. If exc can't be pickled,
-        wrap it in UnpickleableException first.
-        """
-        try:
-            return pickle.dumps(type), pickle.dumps(exc)
-        except Exception:
-            # get UnpickleableException inside the sandbox
-            from setuptools.sandbox import UnpickleableException as cls
-
-            return cls.dump(cls, cls(repr(exc)))
-
-
-class ExceptionSaver:
-    """
-    A Context Manager that will save an exception, serialized, and restore it
-    later.
-    """
-
-    def __enter__(self):
-        return self
-
-    def __exit__(self, type, exc, tb):
-        if not exc:
-            return
-
-        # dump the exception
-        self._saved = UnpickleableException.dump(type, exc)
-        self._tb = tb
-
-        # suppress the exception
-        return True
-
-    def resume(self):
-        "restore and re-raise any exception"
-
-        if '_saved' not in vars(self):
-            return
-
-        type, exc = map(pickle.loads, self._saved)
-        raise exc.with_traceback(self._tb)
-
-
-@contextlib.contextmanager
-def save_modules():
-    """
-    Context in which imported modules are saved.
-
-    Translates exceptions internal to the context into the equivalent exception
-    outside the context.
-    """
-    saved = sys.modules.copy()
-    with ExceptionSaver() as saved_exc:
-        yield saved
-
-    sys.modules.update(saved)
-    # remove any modules imported since
-    del_modules = (
-        mod_name
-        for mod_name in sys.modules
-        if mod_name not in saved
-        # exclude any encodings modules. See #285
-        and not mod_name.startswith('encodings.')
-    )
-    _clear_modules(del_modules)
-
-    saved_exc.resume()
-
-
-def _clear_modules(module_names):
-    for mod_name in list(module_names):
-        del sys.modules[mod_name]
-
-
-@contextlib.contextmanager
-def save_pkg_resources_state():
-    saved = pkg_resources.__getstate__()
-    try:
-        yield saved
-    finally:
-        pkg_resources.__setstate__(saved)
-
-
-@contextlib.contextmanager
-def setup_context(setup_dir):
-    temp_dir = os.path.join(setup_dir, 'temp')
-    with save_pkg_resources_state():
-        with save_modules():
-            with save_path():
-                hide_setuptools()
-                with save_argv():
-                    with override_temp(temp_dir):
-                        with pushd(setup_dir):
-                            # ensure setuptools commands are available
-                            __import__('setuptools')
-                            yield
-
-
-_MODULES_TO_HIDE = {
-    'setuptools',
-    'distutils',
-    'pkg_resources',
-    'Cython',
-    '_distutils_hack',
-}
-
-
-def _needs_hiding(mod_name):
-    """
-    >>> _needs_hiding('setuptools')
-    True
-    >>> _needs_hiding('pkg_resources')
-    True
-    >>> _needs_hiding('setuptools_plugin')
-    False
-    >>> _needs_hiding('setuptools.__init__')
-    True
-    >>> _needs_hiding('distutils')
-    True
-    >>> _needs_hiding('os')
-    False
-    >>> _needs_hiding('Cython')
-    True
-    """
-    base_module = mod_name.split('.', 1)[0]
-    return base_module in _MODULES_TO_HIDE
-
-
-def hide_setuptools():
-    """
-    Remove references to setuptools' modules from sys.modules to allow the
-    invocation to import the most appropriate setuptools. This technique is
-    necessary to avoid issues such as #315 where setuptools upgrading itself
-    would fail to find a function declared in the metadata.
-    """
-    _distutils_hack = sys.modules.get('_distutils_hack', None)
-    if _distutils_hack is not None:
-        _distutils_hack.remove_shim()
-
-    modules = filter(_needs_hiding, sys.modules)
-    _clear_modules(modules)
-
-
-def run_setup(setup_script, args):
-    """Run a distutils setup script, sandboxed in its directory"""
-    setup_dir = os.path.abspath(os.path.dirname(setup_script))
-    with setup_context(setup_dir):
-        try:
-            sys.argv[:] = [setup_script] + list(args)
-            sys.path.insert(0, setup_dir)
-            # reset to include setup dir, w/clean callback list
-            working_set.__init__()
-            working_set.callbacks.append(lambda dist: dist.activate())
-
-            with DirectorySandbox(setup_dir):
-                ns = dict(__file__=setup_script, __name__='__main__')
-                _execfile(setup_script, ns)
-        except SystemExit as v:
-            if v.args and v.args[0]:
-                raise
-            # Normal exit, just return
-
-
-class AbstractSandbox:
-    """Wrap 'os' module and 'open()' builtin for virtualizing setup scripts"""
-
-    _active = False
-
-    def __init__(self):
-        self._attrs = [
-            name
-            for name in dir(_os)
-            if not name.startswith('_') and hasattr(self, name)
-        ]
-
-    def _copy(self, source):
-        for name in self._attrs:
-            setattr(os, name, getattr(source, name))
-
-    def __enter__(self):
-        self._copy(self)
-        if _file:
-            builtins.file = self._file
-        builtins.open = self._open
-        self._active = True
-
-    def __exit__(self, exc_type, exc_value, traceback):
-        self._active = False
-        if _file:
-            builtins.file = _file
-        builtins.open = _open
-        self._copy(_os)
-
-    def run(self, func):
-        """Run 'func' under os sandboxing"""
-        with self:
-            return func()
-
-    def _mk_dual_path_wrapper(name):
-        original = getattr(_os, name)
-
-        def wrap(self, src, dst, *args, **kw):
-            if self._active:
-                src, dst = self._remap_pair(name, src, dst, *args, **kw)
-            return original(src, dst, *args, **kw)
-
-        return wrap
-
-    for name in ["rename", "link", "symlink"]:
-        if hasattr(_os, name):
-            locals()[name] = _mk_dual_path_wrapper(name)
-
-    def _mk_single_path_wrapper(name, original=None):
-        original = original or getattr(_os, name)
-
-        def wrap(self, path, *args, **kw):
-            if self._active:
-                path = self._remap_input(name, path, *args, **kw)
-            return original(path, *args, **kw)
-
-        return wrap
-
-    if _file:
-        _file = _mk_single_path_wrapper('file', _file)
-    _open = _mk_single_path_wrapper('open', _open)
-    for name in [
-        "stat",
-        "listdir",
-        "chdir",
-        "open",
-        "chmod",
-        "chown",
-        "mkdir",
-        "remove",
-        "unlink",
-        "rmdir",
-        "utime",
-        "lchown",
-        "chroot",
-        "lstat",
-        "startfile",
-        "mkfifo",
-        "mknod",
-        "pathconf",
-        "access",
-    ]:
-        if hasattr(_os, name):
-            locals()[name] = _mk_single_path_wrapper(name)
-
-    def _mk_single_with_return(name):
-        original = getattr(_os, name)
-
-        def wrap(self, path, *args, **kw):
-            if self._active:
-                path = self._remap_input(name, path, *args, **kw)
-                return self._remap_output(name, original(path, *args, **kw))
-            return original(path, *args, **kw)
-
-        return wrap
-
-    for name in ['readlink', 'tempnam']:
-        if hasattr(_os, name):
-            locals()[name] = _mk_single_with_return(name)
-
-    def _mk_query(name):
-        original = getattr(_os, name)
-
-        def wrap(self, *args, **kw):
-            retval = original(*args, **kw)
-            if self._active:
-                return self._remap_output(name, retval)
-            return retval
-
-        return wrap
-
-    for name in ['getcwd', 'tmpnam']:
-        if hasattr(_os, name):
-            locals()[name] = _mk_query(name)
-
-    def _validate_path(self, path):
-        """Called to remap or validate any path, whether input or output"""
-        return path
-
-    def _remap_input(self, operation, path, *args, **kw):
-        """Called for path inputs"""
-        return self._validate_path(path)
-
-    def _remap_output(self, operation, path):
-        """Called for path outputs"""
-        return self._validate_path(path)
-
-    def _remap_pair(self, operation, src, dst, *args, **kw):
-        """Called for path pairs like rename, link, and symlink operations"""
-        return (
-            self._remap_input(operation + '-from', src, *args, **kw),
-            self._remap_input(operation + '-to', dst, *args, **kw),
-        )
-
-
-if hasattr(os, 'devnull'):
-    _EXCEPTIONS = [os.devnull]
-else:
-    _EXCEPTIONS = []
-
-
-class DirectorySandbox(AbstractSandbox):
-    """Restrict operations to a single subdirectory - pseudo-chroot"""
-
-    write_ops = dict.fromkeys(
-        [
-            "open",
-            "chmod",
-            "chown",
-            "mkdir",
-            "remove",
-            "unlink",
-            "rmdir",
-            "utime",
-            "lchown",
-            "chroot",
-            "mkfifo",
-            "mknod",
-            "tempnam",
-        ]
-    )
-
-    _exception_patterns = []
-    "exempt writing to paths that match the pattern"
-
-    def __init__(self, sandbox, exceptions=_EXCEPTIONS):
-        self._sandbox = os.path.normcase(os.path.realpath(sandbox))
-        self._prefix = os.path.join(self._sandbox, '')
-        self._exceptions = [
-            os.path.normcase(os.path.realpath(path)) for path in exceptions
-        ]
-        AbstractSandbox.__init__(self)
-
-    def _violation(self, operation, *args, **kw):
-        from setuptools.sandbox import SandboxViolation
-
-        raise SandboxViolation(operation, args, kw)
-
-    if _file:
-
-        def _file(self, path, mode='r', *args, **kw):
-            if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path):
-                self._violation("file", path, mode, *args, **kw)
-            return _file(path, mode, *args, **kw)
-
-    def _open(self, path, mode='r', *args, **kw):
-        if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path):
-            self._violation("open", path, mode, *args, **kw)
-        return _open(path, mode, *args, **kw)
-
-    def tmpnam(self):
-        self._violation("tmpnam")
-
-    def _ok(self, path):
-        active = self._active
-        try:
-            self._active = False
-            realpath = os.path.normcase(os.path.realpath(path))
-            return (
-                self._exempted(realpath)
-                or realpath == self._sandbox
-                or realpath.startswith(self._prefix)
-            )
-        finally:
-            self._active = active
-
-    def _exempted(self, filepath):
-        start_matches = (
-            filepath.startswith(exception) for exception in self._exceptions
-        )
-        pattern_matches = (
-            re.match(pattern, filepath) for pattern in self._exception_patterns
-        )
-        candidates = itertools.chain(start_matches, pattern_matches)
-        return any(candidates)
-
-    def _remap_input(self, operation, path, *args, **kw):
-        """Called for path inputs"""
-        if operation in self.write_ops and not self._ok(path):
-            self._violation(operation, os.path.realpath(path), *args, **kw)
-        return path
-
-    def _remap_pair(self, operation, src, dst, *args, **kw):
-        """Called for path pairs like rename, link, and symlink operations"""
-        if not self._ok(src) or not self._ok(dst):
-            self._violation(operation, src, dst, *args, **kw)
-        return (src, dst)
-
-    def open(self, file, flags, mode=0o777, *args, **kw):
-        """Called for low-level os.open()"""
-        if flags & WRITE_FLAGS and not self._ok(file):
-            self._violation("os.open", file, flags, mode, *args, **kw)
-        return _os.open(file, flags, mode, *args, **kw)
-
-
-WRITE_FLAGS = functools.reduce(
-    operator.or_,
-    [
-        getattr(_os, a, 0)
-        for a in "O_WRONLY O_RDWR O_APPEND O_CREAT O_TRUNC O_TEMPORARY".split()
-    ],
-)
-
-
-class SandboxViolation(DistutilsError):
-    """A setup script attempted to modify the filesystem outside the sandbox"""
-
-    tmpl = textwrap.dedent(
-        """
-        SandboxViolation: {cmd}{args!r} {kwargs}
-
-        The package setup script has attempted to modify files on your system
-        that are not within the EasyInstall build area, and has been aborted.
-
-        This package cannot be safely installed by EasyInstall, and may not
-        support alternate installation locations even if you run its setup
-        script by hand.  Please inform the package's author and the EasyInstall
-        maintainers to find out if a fix or workaround is available.
-        """
-    ).lstrip()
-
-    def __str__(self):
-        cmd, args, kwargs = self.args
-        return self.tmpl.format(**locals())
diff --git a/venv/lib/python3.11/site-packages/setuptools/script (dev).tmpl b/venv/lib/python3.11/site-packages/setuptools/script (dev).tmpl
deleted file mode 100755
index 39a24b0..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/script (dev).tmpl	
+++ /dev/null
@@ -1,6 +0,0 @@
-# EASY-INSTALL-DEV-SCRIPT: %(spec)r,%(script_name)r
-__requires__ = %(spec)r
-__import__('pkg_resources').require(%(spec)r)
-__file__ = %(dev_path)r
-with open(__file__) as f:
-    exec(compile(f.read(), __file__, 'exec'))
diff --git a/venv/lib/python3.11/site-packages/setuptools/script.tmpl b/venv/lib/python3.11/site-packages/setuptools/script.tmpl
deleted file mode 100755
index ff5efbc..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/script.tmpl
+++ /dev/null
@@ -1,3 +0,0 @@
-# EASY-INSTALL-SCRIPT: %(spec)r,%(script_name)r
-__requires__ = %(spec)r
-__import__('pkg_resources').run_script(%(spec)r, %(script_name)r)
diff --git a/venv/lib/python3.11/site-packages/setuptools/unicode_utils.py b/venv/lib/python3.11/site-packages/setuptools/unicode_utils.py
deleted file mode 100755
index e84e65e..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/unicode_utils.py
+++ /dev/null
@@ -1,42 +0,0 @@
-import unicodedata
-import sys
-
-
-# HFS Plus uses decomposed UTF-8
-def decompose(path):
-    if isinstance(path, str):
-        return unicodedata.normalize('NFD', path)
-    try:
-        path = path.decode('utf-8')
-        path = unicodedata.normalize('NFD', path)
-        path = path.encode('utf-8')
-    except UnicodeError:
-        pass  # Not UTF-8
-    return path
-
-
-def filesys_decode(path):
-    """
-    Ensure that the given path is decoded,
-    NONE when no expected encoding works
-    """
-
-    if isinstance(path, str):
-        return path
-
-    fs_enc = sys.getfilesystemencoding() or 'utf-8'
-    candidates = fs_enc, 'utf-8'
-
-    for enc in candidates:
-        try:
-            return path.decode(enc)
-        except UnicodeDecodeError:
-            continue
-
-
-def try_encode(string, enc):
-    "turn unicode encoding into a functional routine"
-    try:
-        return string.encode(enc)
-    except UnicodeEncodeError:
-        return None
diff --git a/venv/lib/python3.11/site-packages/setuptools/version.py b/venv/lib/python3.11/site-packages/setuptools/version.py
deleted file mode 100755
index 95e1869..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/version.py
+++ /dev/null
@@ -1,6 +0,0 @@
-import pkg_resources
-
-try:
-    __version__ = pkg_resources.get_distribution('setuptools').version
-except Exception:
-    __version__ = 'unknown'
diff --git a/venv/lib/python3.11/site-packages/setuptools/wheel.py b/venv/lib/python3.11/site-packages/setuptools/wheel.py
deleted file mode 100755
index 527ed3b..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/wheel.py
+++ /dev/null
@@ -1,222 +0,0 @@
-"""Wheels support."""
-
-import email
-import itertools
-import os
-import posixpath
-import re
-import zipfile
-import contextlib
-
-from distutils.util import get_platform
-
-import pkg_resources
-import setuptools
-from pkg_resources import parse_version
-from setuptools.extern.packaging.tags import sys_tags
-from setuptools.extern.packaging.utils import canonicalize_name
-from setuptools.command.egg_info import write_requirements
-from setuptools.archive_util import _unpack_zipfile_obj
-
-
-WHEEL_NAME = re.compile(
-    r"""^(?P.+?)-(?P\d.*?)
-    ((-(?P\d.*?))?-(?P.+?)-(?P.+?)-(?P.+?)
-    )\.whl$""",
-    re.VERBOSE).match
-
-NAMESPACE_PACKAGE_INIT = \
-    "__import__('pkg_resources').declare_namespace(__name__)\n"
-
-
-def unpack(src_dir, dst_dir):
-    '''Move everything under `src_dir` to `dst_dir`, and delete the former.'''
-    for dirpath, dirnames, filenames in os.walk(src_dir):
-        subdir = os.path.relpath(dirpath, src_dir)
-        for f in filenames:
-            src = os.path.join(dirpath, f)
-            dst = os.path.join(dst_dir, subdir, f)
-            os.renames(src, dst)
-        for n, d in reversed(list(enumerate(dirnames))):
-            src = os.path.join(dirpath, d)
-            dst = os.path.join(dst_dir, subdir, d)
-            if not os.path.exists(dst):
-                # Directory does not exist in destination,
-                # rename it and prune it from os.walk list.
-                os.renames(src, dst)
-                del dirnames[n]
-    # Cleanup.
-    for dirpath, dirnames, filenames in os.walk(src_dir, topdown=True):
-        assert not filenames
-        os.rmdir(dirpath)
-
-
-@contextlib.contextmanager
-def disable_info_traces():
-    """
-    Temporarily disable info traces.
-    """
-    from distutils import log
-    saved = log.set_threshold(log.WARN)
-    try:
-        yield
-    finally:
-        log.set_threshold(saved)
-
-
-class Wheel:
-
-    def __init__(self, filename):
-        match = WHEEL_NAME(os.path.basename(filename))
-        if match is None:
-            raise ValueError('invalid wheel name: %r' % filename)
-        self.filename = filename
-        for k, v in match.groupdict().items():
-            setattr(self, k, v)
-
-    def tags(self):
-        '''List tags (py_version, abi, platform) supported by this wheel.'''
-        return itertools.product(
-            self.py_version.split('.'),
-            self.abi.split('.'),
-            self.platform.split('.'),
-        )
-
-    def is_compatible(self):
-        '''Is the wheel is compatible with the current platform?'''
-        supported_tags = set(
-            (t.interpreter, t.abi, t.platform) for t in sys_tags())
-        return next((True for t in self.tags() if t in supported_tags), False)
-
-    def egg_name(self):
-        return pkg_resources.Distribution(
-            project_name=self.project_name, version=self.version,
-            platform=(None if self.platform == 'any' else get_platform()),
-        ).egg_name() + '.egg'
-
-    def get_dist_info(self, zf):
-        # find the correct name of the .dist-info dir in the wheel file
-        for member in zf.namelist():
-            dirname = posixpath.dirname(member)
-            if (dirname.endswith('.dist-info') and
-                    canonicalize_name(dirname).startswith(
-                        canonicalize_name(self.project_name))):
-                return dirname
-        raise ValueError("unsupported wheel format. .dist-info not found")
-
-    def install_as_egg(self, destination_eggdir):
-        '''Install wheel as an egg directory.'''
-        with zipfile.ZipFile(self.filename) as zf:
-            self._install_as_egg(destination_eggdir, zf)
-
-    def _install_as_egg(self, destination_eggdir, zf):
-        dist_basename = '%s-%s' % (self.project_name, self.version)
-        dist_info = self.get_dist_info(zf)
-        dist_data = '%s.data' % dist_basename
-        egg_info = os.path.join(destination_eggdir, 'EGG-INFO')
-
-        self._convert_metadata(zf, destination_eggdir, dist_info, egg_info)
-        self._move_data_entries(destination_eggdir, dist_data)
-        self._fix_namespace_packages(egg_info, destination_eggdir)
-
-    @staticmethod
-    def _convert_metadata(zf, destination_eggdir, dist_info, egg_info):
-        def get_metadata(name):
-            with zf.open(posixpath.join(dist_info, name)) as fp:
-                value = fp.read().decode('utf-8')
-                return email.parser.Parser().parsestr(value)
-
-        wheel_metadata = get_metadata('WHEEL')
-        # Check wheel format version is supported.
-        wheel_version = parse_version(wheel_metadata.get('Wheel-Version'))
-        wheel_v1 = (
-            parse_version('1.0') <= wheel_version < parse_version('2.0dev0')
-        )
-        if not wheel_v1:
-            raise ValueError(
-                'unsupported wheel format version: %s' % wheel_version)
-        # Extract to target directory.
-        _unpack_zipfile_obj(zf, destination_eggdir)
-        # Convert metadata.
-        dist_info = os.path.join(destination_eggdir, dist_info)
-        dist = pkg_resources.Distribution.from_location(
-            destination_eggdir, dist_info,
-            metadata=pkg_resources.PathMetadata(destination_eggdir, dist_info),
-        )
-
-        # Note: Evaluate and strip markers now,
-        # as it's difficult to convert back from the syntax:
-        # foobar; "linux" in sys_platform and extra == 'test'
-        def raw_req(req):
-            req.marker = None
-            return str(req)
-        install_requires = list(map(raw_req, dist.requires()))
-        extras_require = {
-            extra: [
-                req
-                for req in map(raw_req, dist.requires((extra,)))
-                if req not in install_requires
-            ]
-            for extra in dist.extras
-        }
-        os.rename(dist_info, egg_info)
-        os.rename(
-            os.path.join(egg_info, 'METADATA'),
-            os.path.join(egg_info, 'PKG-INFO'),
-        )
-        setup_dist = setuptools.Distribution(
-            attrs=dict(
-                install_requires=install_requires,
-                extras_require=extras_require,
-            ),
-        )
-        with disable_info_traces():
-            write_requirements(
-                setup_dist.get_command_obj('egg_info'),
-                None,
-                os.path.join(egg_info, 'requires.txt'),
-            )
-
-    @staticmethod
-    def _move_data_entries(destination_eggdir, dist_data):
-        """Move data entries to their correct location."""
-        dist_data = os.path.join(destination_eggdir, dist_data)
-        dist_data_scripts = os.path.join(dist_data, 'scripts')
-        if os.path.exists(dist_data_scripts):
-            egg_info_scripts = os.path.join(
-                destination_eggdir, 'EGG-INFO', 'scripts')
-            os.mkdir(egg_info_scripts)
-            for entry in os.listdir(dist_data_scripts):
-                # Remove bytecode, as it's not properly handled
-                # during easy_install scripts install phase.
-                if entry.endswith('.pyc'):
-                    os.unlink(os.path.join(dist_data_scripts, entry))
-                else:
-                    os.rename(
-                        os.path.join(dist_data_scripts, entry),
-                        os.path.join(egg_info_scripts, entry),
-                    )
-            os.rmdir(dist_data_scripts)
-        for subdir in filter(os.path.exists, (
-            os.path.join(dist_data, d)
-            for d in ('data', 'headers', 'purelib', 'platlib')
-        )):
-            unpack(subdir, destination_eggdir)
-        if os.path.exists(dist_data):
-            os.rmdir(dist_data)
-
-    @staticmethod
-    def _fix_namespace_packages(egg_info, destination_eggdir):
-        namespace_packages = os.path.join(
-            egg_info, 'namespace_packages.txt')
-        if os.path.exists(namespace_packages):
-            with open(namespace_packages) as fp:
-                namespace_packages = fp.read().split()
-            for mod in namespace_packages:
-                mod_dir = os.path.join(destination_eggdir, *mod.split('.'))
-                mod_init = os.path.join(mod_dir, '__init__.py')
-                if not os.path.exists(mod_dir):
-                    os.mkdir(mod_dir)
-                if not os.path.exists(mod_init):
-                    with open(mod_init, 'w') as fp:
-                        fp.write(NAMESPACE_PACKAGE_INIT)
diff --git a/venv/lib/python3.11/site-packages/setuptools/windows_support.py b/venv/lib/python3.11/site-packages/setuptools/windows_support.py
deleted file mode 100755
index 1ca64fb..0000000
--- a/venv/lib/python3.11/site-packages/setuptools/windows_support.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import platform
-
-
-def windows_only(func):
-    if platform.system() != 'Windows':
-        return lambda *args, **kwargs: None
-    return func
-
-
-@windows_only
-def hide_file(path):
-    """
-    Set the hidden attribute on a file or directory.
-
-    From http://stackoverflow.com/questions/19622133/
-
-    `path` must be text.
-    """
-    import ctypes
-    __import__('ctypes.wintypes')
-    SetFileAttributes = ctypes.windll.kernel32.SetFileAttributesW
-    SetFileAttributes.argtypes = ctypes.wintypes.LPWSTR, ctypes.wintypes.DWORD
-    SetFileAttributes.restype = ctypes.wintypes.BOOL
-
-    FILE_ATTRIBUTE_HIDDEN = 0x02
-
-    ret = SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN)
-    if not ret:
-        raise ctypes.WinError()
diff --git a/venv/lib/python3.11/site-packages/telegram/__init__.py b/venv/lib/python3.11/site-packages/telegram/__init__.py
deleted file mode 100755
index a895e60..0000000
--- a/venv/lib/python3.11/site-packages/telegram/__init__.py
+++ /dev/null
@@ -1,544 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""A library that provides a Python interface to the Telegram Bot API"""
-
-__author__ = "devs@python-telegram-bot.org"
-__all__ = (
-    "AffiliateInfo",
-    "Animation",
-    "Audio",
-    "BackgroundFill",
-    "BackgroundFillFreeformGradient",
-    "BackgroundFillGradient",
-    "BackgroundFillSolid",
-    "BackgroundType",
-    "BackgroundTypeChatTheme",
-    "BackgroundTypeFill",
-    "BackgroundTypePattern",
-    "BackgroundTypeWallpaper",
-    "Birthdate",
-    "Bot",
-    "BotCommand",
-    "BotCommandScope",
-    "BotCommandScopeAllChatAdministrators",
-    "BotCommandScopeAllGroupChats",
-    "BotCommandScopeAllPrivateChats",
-    "BotCommandScopeChat",
-    "BotCommandScopeChatAdministrators",
-    "BotCommandScopeChatMember",
-    "BotCommandScopeDefault",
-    "BotDescription",
-    "BotName",
-    "BotShortDescription",
-    "BusinessConnection",
-    "BusinessIntro",
-    "BusinessLocation",
-    "BusinessMessagesDeleted",
-    "BusinessOpeningHours",
-    "BusinessOpeningHoursInterval",
-    "CallbackGame",
-    "CallbackQuery",
-    "Chat",
-    "ChatAdministratorRights",
-    "ChatBackground",
-    "ChatBoost",
-    "ChatBoostAdded",
-    "ChatBoostRemoved",
-    "ChatBoostSource",
-    "ChatBoostSourceGiftCode",
-    "ChatBoostSourceGiveaway",
-    "ChatBoostSourcePremium",
-    "ChatBoostUpdated",
-    "ChatFullInfo",
-    "ChatInviteLink",
-    "ChatJoinRequest",
-    "ChatLocation",
-    "ChatMember",
-    "ChatMemberAdministrator",
-    "ChatMemberBanned",
-    "ChatMemberLeft",
-    "ChatMemberMember",
-    "ChatMemberOwner",
-    "ChatMemberRestricted",
-    "ChatMemberUpdated",
-    "ChatPermissions",
-    "ChatPhoto",
-    "ChatShared",
-    "ChosenInlineResult",
-    "Contact",
-    "CopyTextButton",
-    "Credentials",
-    "DataCredentials",
-    "Dice",
-    "Document",
-    "EncryptedCredentials",
-    "EncryptedPassportElement",
-    "ExternalReplyInfo",
-    "File",
-    "FileCredentials",
-    "ForceReply",
-    "ForumTopic",
-    "ForumTopicClosed",
-    "ForumTopicCreated",
-    "ForumTopicEdited",
-    "ForumTopicReopened",
-    "Game",
-    "GameHighScore",
-    "GeneralForumTopicHidden",
-    "GeneralForumTopicUnhidden",
-    "Gift",
-    "Gifts",
-    "Giveaway",
-    "GiveawayCompleted",
-    "GiveawayCreated",
-    "GiveawayWinners",
-    "IdDocumentData",
-    "InaccessibleMessage",
-    "InlineKeyboardButton",
-    "InlineKeyboardMarkup",
-    "InlineQuery",
-    "InlineQueryResult",
-    "InlineQueryResultArticle",
-    "InlineQueryResultAudio",
-    "InlineQueryResultCachedAudio",
-    "InlineQueryResultCachedDocument",
-    "InlineQueryResultCachedGif",
-    "InlineQueryResultCachedMpeg4Gif",
-    "InlineQueryResultCachedPhoto",
-    "InlineQueryResultCachedSticker",
-    "InlineQueryResultCachedVideo",
-    "InlineQueryResultCachedVoice",
-    "InlineQueryResultContact",
-    "InlineQueryResultDocument",
-    "InlineQueryResultGame",
-    "InlineQueryResultGif",
-    "InlineQueryResultLocation",
-    "InlineQueryResultMpeg4Gif",
-    "InlineQueryResultPhoto",
-    "InlineQueryResultVenue",
-    "InlineQueryResultVideo",
-    "InlineQueryResultVoice",
-    "InlineQueryResultsButton",
-    "InputContactMessageContent",
-    "InputFile",
-    "InputInvoiceMessageContent",
-    "InputLocationMessageContent",
-    "InputMedia",
-    "InputMediaAnimation",
-    "InputMediaAudio",
-    "InputMediaDocument",
-    "InputMediaPhoto",
-    "InputMediaVideo",
-    "InputMessageContent",
-    "InputPaidMedia",
-    "InputPaidMediaPhoto",
-    "InputPaidMediaVideo",
-    "InputPollOption",
-    "InputSticker",
-    "InputTextMessageContent",
-    "InputVenueMessageContent",
-    "Invoice",
-    "KeyboardButton",
-    "KeyboardButtonPollType",
-    "KeyboardButtonRequestChat",
-    "KeyboardButtonRequestUsers",
-    "LabeledPrice",
-    "LinkPreviewOptions",
-    "Location",
-    "LoginUrl",
-    "MaskPosition",
-    "MaybeInaccessibleMessage",
-    "MenuButton",
-    "MenuButtonCommands",
-    "MenuButtonDefault",
-    "MenuButtonWebApp",
-    "Message",
-    "MessageAutoDeleteTimerChanged",
-    "MessageEntity",
-    "MessageId",
-    "MessageOrigin",
-    "MessageOriginChannel",
-    "MessageOriginChat",
-    "MessageOriginHiddenUser",
-    "MessageOriginUser",
-    "MessageReactionCountUpdated",
-    "MessageReactionUpdated",
-    "OrderInfo",
-    "PaidMedia",
-    "PaidMediaInfo",
-    "PaidMediaPhoto",
-    "PaidMediaPreview",
-    "PaidMediaPurchased",
-    "PaidMediaVideo",
-    "PassportData",
-    "PassportElementError",
-    "PassportElementErrorDataField",
-    "PassportElementErrorFile",
-    "PassportElementErrorFiles",
-    "PassportElementErrorFrontSide",
-    "PassportElementErrorReverseSide",
-    "PassportElementErrorSelfie",
-    "PassportElementErrorTranslationFile",
-    "PassportElementErrorTranslationFiles",
-    "PassportElementErrorUnspecified",
-    "PassportFile",
-    "PersonalDetails",
-    "PhotoSize",
-    "Poll",
-    "PollAnswer",
-    "PollOption",
-    "PreCheckoutQuery",
-    "PreparedInlineMessage",
-    "ProximityAlertTriggered",
-    "ReactionCount",
-    "ReactionType",
-    "ReactionTypeCustomEmoji",
-    "ReactionTypeEmoji",
-    "ReactionTypePaid",
-    "RefundedPayment",
-    "ReplyKeyboardMarkup",
-    "ReplyKeyboardRemove",
-    "ReplyParameters",
-    "ResidentialAddress",
-    "RevenueWithdrawalState",
-    "RevenueWithdrawalStateFailed",
-    "RevenueWithdrawalStatePending",
-    "RevenueWithdrawalStateSucceeded",
-    "SecureData",
-    "SecureValue",
-    "SentWebAppMessage",
-    "SharedUser",
-    "ShippingAddress",
-    "ShippingOption",
-    "ShippingQuery",
-    "StarTransaction",
-    "StarTransactions",
-    "Sticker",
-    "StickerSet",
-    "Story",
-    "SuccessfulPayment",
-    "SwitchInlineQueryChosenChat",
-    "TelegramObject",
-    "TextQuote",
-    "TransactionPartner",
-    "TransactionPartnerAffiliateProgram",
-    "TransactionPartnerFragment",
-    "TransactionPartnerOther",
-    "TransactionPartnerTelegramAds",
-    "TransactionPartnerTelegramApi",
-    "TransactionPartnerUser",
-    "Update",
-    "User",
-    "UserChatBoosts",
-    "UserProfilePhotos",
-    "UsersShared",
-    "Venue",
-    "Video",
-    "VideoChatEnded",
-    "VideoChatParticipantsInvited",
-    "VideoChatScheduled",
-    "VideoChatStarted",
-    "VideoNote",
-    "Voice",
-    "WebAppData",
-    "WebAppInfo",
-    "WebhookInfo",
-    "WriteAccessAllowed",
-    "__bot_api_version__",
-    "__bot_api_version_info__",
-    "__version__",
-    "__version_info__",
-    "constants",
-    "error",
-    "helpers",
-    "request",
-    "warnings",
-)
-
-from telegram._payment.stars.startransactions import StarTransaction, StarTransactions
-from telegram._payment.stars.transactionpartner import (
-    TransactionPartner,
-    TransactionPartnerAffiliateProgram,
-    TransactionPartnerFragment,
-    TransactionPartnerOther,
-    TransactionPartnerTelegramAds,
-    TransactionPartnerTelegramApi,
-    TransactionPartnerUser,
-)
-
-from . import _version, constants, error, helpers, request, warnings
-from ._birthdate import Birthdate
-from ._bot import Bot
-from ._botcommand import BotCommand
-from ._botcommandscope import (
-    BotCommandScope,
-    BotCommandScopeAllChatAdministrators,
-    BotCommandScopeAllGroupChats,
-    BotCommandScopeAllPrivateChats,
-    BotCommandScopeChat,
-    BotCommandScopeChatAdministrators,
-    BotCommandScopeChatMember,
-    BotCommandScopeDefault,
-)
-from ._botdescription import BotDescription, BotShortDescription
-from ._botname import BotName
-from ._business import (
-    BusinessConnection,
-    BusinessIntro,
-    BusinessLocation,
-    BusinessMessagesDeleted,
-    BusinessOpeningHours,
-    BusinessOpeningHoursInterval,
-)
-from ._callbackquery import CallbackQuery
-from ._chat import Chat
-from ._chatadministratorrights import ChatAdministratorRights
-from ._chatbackground import (
-    BackgroundFill,
-    BackgroundFillFreeformGradient,
-    BackgroundFillGradient,
-    BackgroundFillSolid,
-    BackgroundType,
-    BackgroundTypeChatTheme,
-    BackgroundTypeFill,
-    BackgroundTypePattern,
-    BackgroundTypeWallpaper,
-    ChatBackground,
-)
-from ._chatboost import (
-    ChatBoost,
-    ChatBoostAdded,
-    ChatBoostRemoved,
-    ChatBoostSource,
-    ChatBoostSourceGiftCode,
-    ChatBoostSourceGiveaway,
-    ChatBoostSourcePremium,
-    ChatBoostUpdated,
-    UserChatBoosts,
-)
-from ._chatfullinfo import ChatFullInfo
-from ._chatinvitelink import ChatInviteLink
-from ._chatjoinrequest import ChatJoinRequest
-from ._chatlocation import ChatLocation
-from ._chatmember import (
-    ChatMember,
-    ChatMemberAdministrator,
-    ChatMemberBanned,
-    ChatMemberLeft,
-    ChatMemberMember,
-    ChatMemberOwner,
-    ChatMemberRestricted,
-)
-from ._chatmemberupdated import ChatMemberUpdated
-from ._chatpermissions import ChatPermissions
-from ._choseninlineresult import ChosenInlineResult
-from ._copytextbutton import CopyTextButton
-from ._dice import Dice
-from ._files.animation import Animation
-from ._files.audio import Audio
-from ._files.chatphoto import ChatPhoto
-from ._files.contact import Contact
-from ._files.document import Document
-from ._files.file import File
-from ._files.inputfile import InputFile
-from ._files.inputmedia import (
-    InputMedia,
-    InputMediaAnimation,
-    InputMediaAudio,
-    InputMediaDocument,
-    InputMediaPhoto,
-    InputMediaVideo,
-    InputPaidMedia,
-    InputPaidMediaPhoto,
-    InputPaidMediaVideo,
-)
-from ._files.inputsticker import InputSticker
-from ._files.location import Location
-from ._files.photosize import PhotoSize
-from ._files.sticker import MaskPosition, Sticker, StickerSet
-from ._files.venue import Venue
-from ._files.video import Video
-from ._files.videonote import VideoNote
-from ._files.voice import Voice
-from ._forcereply import ForceReply
-from ._forumtopic import (
-    ForumTopic,
-    ForumTopicClosed,
-    ForumTopicCreated,
-    ForumTopicEdited,
-    ForumTopicReopened,
-    GeneralForumTopicHidden,
-    GeneralForumTopicUnhidden,
-)
-from ._games.callbackgame import CallbackGame
-from ._games.game import Game
-from ._games.gamehighscore import GameHighScore
-from ._gifts import Gift, Gifts
-from ._giveaway import Giveaway, GiveawayCompleted, GiveawayCreated, GiveawayWinners
-from ._inline.inlinekeyboardbutton import InlineKeyboardButton
-from ._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
-from ._inline.inlinequery import InlineQuery
-from ._inline.inlinequeryresult import InlineQueryResult
-from ._inline.inlinequeryresultarticle import InlineQueryResultArticle
-from ._inline.inlinequeryresultaudio import InlineQueryResultAudio
-from ._inline.inlinequeryresultcachedaudio import InlineQueryResultCachedAudio
-from ._inline.inlinequeryresultcacheddocument import InlineQueryResultCachedDocument
-from ._inline.inlinequeryresultcachedgif import InlineQueryResultCachedGif
-from ._inline.inlinequeryresultcachedmpeg4gif import InlineQueryResultCachedMpeg4Gif
-from ._inline.inlinequeryresultcachedphoto import InlineQueryResultCachedPhoto
-from ._inline.inlinequeryresultcachedsticker import InlineQueryResultCachedSticker
-from ._inline.inlinequeryresultcachedvideo import InlineQueryResultCachedVideo
-from ._inline.inlinequeryresultcachedvoice import InlineQueryResultCachedVoice
-from ._inline.inlinequeryresultcontact import InlineQueryResultContact
-from ._inline.inlinequeryresultdocument import InlineQueryResultDocument
-from ._inline.inlinequeryresultgame import InlineQueryResultGame
-from ._inline.inlinequeryresultgif import InlineQueryResultGif
-from ._inline.inlinequeryresultlocation import InlineQueryResultLocation
-from ._inline.inlinequeryresultmpeg4gif import InlineQueryResultMpeg4Gif
-from ._inline.inlinequeryresultphoto import InlineQueryResultPhoto
-from ._inline.inlinequeryresultsbutton import InlineQueryResultsButton
-from ._inline.inlinequeryresultvenue import InlineQueryResultVenue
-from ._inline.inlinequeryresultvideo import InlineQueryResultVideo
-from ._inline.inlinequeryresultvoice import InlineQueryResultVoice
-from ._inline.inputcontactmessagecontent import InputContactMessageContent
-from ._inline.inputinvoicemessagecontent import InputInvoiceMessageContent
-from ._inline.inputlocationmessagecontent import InputLocationMessageContent
-from ._inline.inputmessagecontent import InputMessageContent
-from ._inline.inputtextmessagecontent import InputTextMessageContent
-from ._inline.inputvenuemessagecontent import InputVenueMessageContent
-from ._inline.preparedinlinemessage import PreparedInlineMessage
-from ._keyboardbutton import KeyboardButton
-from ._keyboardbuttonpolltype import KeyboardButtonPollType
-from ._keyboardbuttonrequest import KeyboardButtonRequestChat, KeyboardButtonRequestUsers
-from ._linkpreviewoptions import LinkPreviewOptions
-from ._loginurl import LoginUrl
-from ._menubutton import MenuButton, MenuButtonCommands, MenuButtonDefault, MenuButtonWebApp
-from ._message import InaccessibleMessage, MaybeInaccessibleMessage, Message
-from ._messageautodeletetimerchanged import MessageAutoDeleteTimerChanged
-from ._messageentity import MessageEntity
-from ._messageid import MessageId
-from ._messageorigin import (
-    MessageOrigin,
-    MessageOriginChannel,
-    MessageOriginChat,
-    MessageOriginHiddenUser,
-    MessageOriginUser,
-)
-from ._messagereactionupdated import MessageReactionCountUpdated, MessageReactionUpdated
-from ._paidmedia import (
-    PaidMedia,
-    PaidMediaInfo,
-    PaidMediaPhoto,
-    PaidMediaPreview,
-    PaidMediaPurchased,
-    PaidMediaVideo,
-)
-from ._passport.credentials import (
-    Credentials,
-    DataCredentials,
-    EncryptedCredentials,
-    FileCredentials,
-    SecureData,
-    SecureValue,
-)
-from ._passport.data import IdDocumentData, PersonalDetails, ResidentialAddress
-from ._passport.encryptedpassportelement import EncryptedPassportElement
-from ._passport.passportdata import PassportData
-from ._passport.passportelementerrors import (
-    PassportElementError,
-    PassportElementErrorDataField,
-    PassportElementErrorFile,
-    PassportElementErrorFiles,
-    PassportElementErrorFrontSide,
-    PassportElementErrorReverseSide,
-    PassportElementErrorSelfie,
-    PassportElementErrorTranslationFile,
-    PassportElementErrorTranslationFiles,
-    PassportElementErrorUnspecified,
-)
-from ._passport.passportfile import PassportFile
-from ._payment.invoice import Invoice
-from ._payment.labeledprice import LabeledPrice
-from ._payment.orderinfo import OrderInfo
-from ._payment.precheckoutquery import PreCheckoutQuery
-from ._payment.refundedpayment import RefundedPayment
-from ._payment.shippingaddress import ShippingAddress
-from ._payment.shippingoption import ShippingOption
-from ._payment.shippingquery import ShippingQuery
-from ._payment.stars.affiliateinfo import AffiliateInfo
-from ._payment.stars.revenuewithdrawalstate import (
-    RevenueWithdrawalState,
-    RevenueWithdrawalStateFailed,
-    RevenueWithdrawalStatePending,
-    RevenueWithdrawalStateSucceeded,
-)
-from ._payment.successfulpayment import SuccessfulPayment
-from ._poll import InputPollOption, Poll, PollAnswer, PollOption
-from ._proximityalerttriggered import ProximityAlertTriggered
-from ._reaction import (
-    ReactionCount,
-    ReactionType,
-    ReactionTypeCustomEmoji,
-    ReactionTypeEmoji,
-    ReactionTypePaid,
-)
-from ._reply import ExternalReplyInfo, ReplyParameters, TextQuote
-from ._replykeyboardmarkup import ReplyKeyboardMarkup
-from ._replykeyboardremove import ReplyKeyboardRemove
-from ._sentwebappmessage import SentWebAppMessage
-from ._shared import ChatShared, SharedUser, UsersShared
-from ._story import Story
-from ._switchinlinequerychosenchat import SwitchInlineQueryChosenChat
-from ._telegramobject import TelegramObject
-from ._update import Update
-from ._user import User
-from ._userprofilephotos import UserProfilePhotos
-from ._videochat import (
-    VideoChatEnded,
-    VideoChatParticipantsInvited,
-    VideoChatScheduled,
-    VideoChatStarted,
-)
-from ._webappdata import WebAppData
-from ._webappinfo import WebAppInfo
-from ._webhookinfo import WebhookInfo
-from ._writeaccessallowed import WriteAccessAllowed
-
-#: :obj:`str`: The version of the `python-telegram-bot` library as string.
-#: To get detailed information about the version number, please use :data:`__version_info__`
-#: instead.
-__version__: str = _version.__version__
-#:  :class:`typing.NamedTuple`: A tuple containing the five components of the version number:
-#:  `major`, `minor`, `micro`, `releaselevel`, and `serial`.
-#:  All values except `releaselevel` are integers.
-#:  The release level is ``'alpha'``, ``'beta'``, ``'candidate'``, or ``'final'``.
-#:  The components can also be accessed by name, so ``__version_info__[0]`` is equivalent to
-#:  ``__version_info__.major`` and so on.
-#:
-#:  .. versionadded:: 20.0
-__version_info__: _version.Version = _version.__version_info__
-#: :obj:`str`: Shortcut for :const:`telegram.constants.BOT_API_VERSION`.
-#:
-#: .. versionchanged:: 20.0
-#:    This constant was previously named ``bot_api_version``.
-__bot_api_version__: str = constants.BOT_API_VERSION
-#: :class:`typing.NamedTuple`: Shortcut for :const:`telegram.constants.BOT_API_VERSION_INFO`.
-#:
-#: .. versionadded:: 20.0
-__bot_api_version_info__: constants._BotAPIVersion = constants.BOT_API_VERSION_INFO
diff --git a/venv/lib/python3.11/site-packages/telegram/__main__.py b/venv/lib/python3.11/site-packages/telegram/__main__.py
deleted file mode 100755
index 7d291b2..0000000
--- a/venv/lib/python3.11/site-packages/telegram/__main__.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# !/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-# pylint: disable=missing-module-docstring
-# ruff: noqa: T201, D100, S603, S607
-import subprocess
-import sys
-from typing import Optional
-
-from . import __version__ as telegram_ver
-from .constants import BOT_API_VERSION
-
-
-def _git_revision() -> Optional[str]:
-    try:
-        output = subprocess.check_output(
-            ["git", "describe", "--long", "--tags"], stderr=subprocess.STDOUT
-        )
-    except (subprocess.SubprocessError, OSError):
-        return None
-    return output.decode().strip()
-
-
-def print_ver_info() -> None:
-    """Prints version information for python-telegram-bot, the Bot API and Python."""
-    git_revision = _git_revision()
-    print(f"python-telegram-bot {telegram_ver}" + (f" ({git_revision})" if git_revision else ""))
-    print(f"Bot API {BOT_API_VERSION}")
-    sys_version = sys.version.replace("\n", " ")
-    print(f"Python {sys_version}")
-
-
-def main() -> None:
-    """Prints version information for python-telegram-bot, the Bot API and Python."""
-    print_ver_info()
-
-
-if __name__ == "__main__":
-    main()
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/__init__.cpython-311.pyc
deleted file mode 100755
index b810a5d..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/__init__.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/__main__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/__main__.cpython-311.pyc
deleted file mode 100755
index b72b7a9..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/__main__.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_birthdate.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_birthdate.cpython-311.pyc
deleted file mode 100755
index f1cde27..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_birthdate.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_bot.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_bot.cpython-311.pyc
deleted file mode 100755
index 370d0fe..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_bot.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_botcommand.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_botcommand.cpython-311.pyc
deleted file mode 100755
index 1dceb84..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_botcommand.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_botcommandscope.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_botcommandscope.cpython-311.pyc
deleted file mode 100755
index 758e9cd..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_botcommandscope.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_botdescription.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_botdescription.cpython-311.pyc
deleted file mode 100755
index bf6104d..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_botdescription.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_botname.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_botname.cpython-311.pyc
deleted file mode 100755
index 5db84c6..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_botname.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_business.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_business.cpython-311.pyc
deleted file mode 100755
index 424437a..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_business.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_callbackquery.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_callbackquery.cpython-311.pyc
deleted file mode 100755
index a71b9d3..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_callbackquery.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chat.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_chat.cpython-311.pyc
deleted file mode 100755
index 8641ff5..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chat.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatadministratorrights.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatadministratorrights.cpython-311.pyc
deleted file mode 100755
index 9e80c26..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatadministratorrights.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatbackground.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatbackground.cpython-311.pyc
deleted file mode 100755
index 130b0ff..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatbackground.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatboost.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatboost.cpython-311.pyc
deleted file mode 100755
index 2c9aa83..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatboost.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatfullinfo.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatfullinfo.cpython-311.pyc
deleted file mode 100755
index 6d8829d..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatfullinfo.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatinvitelink.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatinvitelink.cpython-311.pyc
deleted file mode 100755
index d36365b..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatinvitelink.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatjoinrequest.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatjoinrequest.cpython-311.pyc
deleted file mode 100755
index bdb1254..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatjoinrequest.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatlocation.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatlocation.cpython-311.pyc
deleted file mode 100755
index b68168a..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatlocation.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatmember.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatmember.cpython-311.pyc
deleted file mode 100755
index 2ce7854..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatmember.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatmemberupdated.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatmemberupdated.cpython-311.pyc
deleted file mode 100755
index dbfd950..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatmemberupdated.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatpermissions.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatpermissions.cpython-311.pyc
deleted file mode 100755
index 319156c..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_chatpermissions.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_choseninlineresult.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_choseninlineresult.cpython-311.pyc
deleted file mode 100755
index 566eaaf..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_choseninlineresult.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_copytextbutton.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_copytextbutton.cpython-311.pyc
deleted file mode 100755
index a9b8b03..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_copytextbutton.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_dice.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_dice.cpython-311.pyc
deleted file mode 100755
index ef1865c..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_dice.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_forcereply.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_forcereply.cpython-311.pyc
deleted file mode 100755
index ac0293e..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_forcereply.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_forumtopic.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_forumtopic.cpython-311.pyc
deleted file mode 100755
index 4a1e7aa..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_forumtopic.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_gifts.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_gifts.cpython-311.pyc
deleted file mode 100755
index 15e8d20..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_gifts.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_giveaway.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_giveaway.cpython-311.pyc
deleted file mode 100755
index 8deb3fe..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_giveaway.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_keyboardbutton.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_keyboardbutton.cpython-311.pyc
deleted file mode 100755
index e3bf8e6..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_keyboardbutton.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_keyboardbuttonpolltype.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_keyboardbuttonpolltype.cpython-311.pyc
deleted file mode 100755
index 324d515..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_keyboardbuttonpolltype.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_keyboardbuttonrequest.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_keyboardbuttonrequest.cpython-311.pyc
deleted file mode 100755
index bbdf38e..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_keyboardbuttonrequest.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_linkpreviewoptions.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_linkpreviewoptions.cpython-311.pyc
deleted file mode 100755
index 3af81ca..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_linkpreviewoptions.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_loginurl.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_loginurl.cpython-311.pyc
deleted file mode 100755
index c588d59..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_loginurl.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_menubutton.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_menubutton.cpython-311.pyc
deleted file mode 100755
index 4196aa1..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_menubutton.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_message.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_message.cpython-311.pyc
deleted file mode 100755
index a054016..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_message.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_messageautodeletetimerchanged.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_messageautodeletetimerchanged.cpython-311.pyc
deleted file mode 100755
index 55f323c..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_messageautodeletetimerchanged.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_messageentity.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_messageentity.cpython-311.pyc
deleted file mode 100755
index bdef1b0..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_messageentity.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_messageid.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_messageid.cpython-311.pyc
deleted file mode 100755
index f9be475..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_messageid.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_messageorigin.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_messageorigin.cpython-311.pyc
deleted file mode 100755
index 240d948..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_messageorigin.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_messagereactionupdated.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_messagereactionupdated.cpython-311.pyc
deleted file mode 100755
index a466b46..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_messagereactionupdated.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_paidmedia.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_paidmedia.cpython-311.pyc
deleted file mode 100755
index 814f205..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_paidmedia.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_poll.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_poll.cpython-311.pyc
deleted file mode 100755
index b372dfd..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_poll.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_proximityalerttriggered.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_proximityalerttriggered.cpython-311.pyc
deleted file mode 100755
index 80c09e2..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_proximityalerttriggered.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_reaction.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_reaction.cpython-311.pyc
deleted file mode 100755
index 2481add..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_reaction.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_reply.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_reply.cpython-311.pyc
deleted file mode 100755
index 2fc010a..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_reply.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_replykeyboardmarkup.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_replykeyboardmarkup.cpython-311.pyc
deleted file mode 100755
index 68d84e0..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_replykeyboardmarkup.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_replykeyboardremove.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_replykeyboardremove.cpython-311.pyc
deleted file mode 100755
index a04a8ae..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_replykeyboardremove.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_sentwebappmessage.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_sentwebappmessage.cpython-311.pyc
deleted file mode 100755
index 234eda7..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_sentwebappmessage.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_shared.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_shared.cpython-311.pyc
deleted file mode 100755
index b3f40a7..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_shared.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_story.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_story.cpython-311.pyc
deleted file mode 100755
index 57c18ce..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_story.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_switchinlinequerychosenchat.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_switchinlinequerychosenchat.cpython-311.pyc
deleted file mode 100755
index 89b9634..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_switchinlinequerychosenchat.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_telegramobject.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_telegramobject.cpython-311.pyc
deleted file mode 100755
index 7175fe7..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_telegramobject.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_update.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_update.cpython-311.pyc
deleted file mode 100755
index a104bfa..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_update.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_user.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_user.cpython-311.pyc
deleted file mode 100755
index f756fc4..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_user.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_userprofilephotos.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_userprofilephotos.cpython-311.pyc
deleted file mode 100755
index b3ced0b..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_userprofilephotos.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_version.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_version.cpython-311.pyc
deleted file mode 100755
index 132f9cb..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_version.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_videochat.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_videochat.cpython-311.pyc
deleted file mode 100755
index ce3a02c..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_videochat.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_webappdata.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_webappdata.cpython-311.pyc
deleted file mode 100755
index e214f1a..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_webappdata.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_webappinfo.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_webappinfo.cpython-311.pyc
deleted file mode 100755
index 78c8280..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_webappinfo.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_webhookinfo.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_webhookinfo.cpython-311.pyc
deleted file mode 100755
index f2ef2df..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_webhookinfo.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/_writeaccessallowed.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/_writeaccessallowed.cpython-311.pyc
deleted file mode 100755
index 5c1f77f..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/_writeaccessallowed.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/constants.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/constants.cpython-311.pyc
deleted file mode 100755
index 790a8d0..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/constants.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/error.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/error.cpython-311.pyc
deleted file mode 100755
index 3c2933c..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/error.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/helpers.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/helpers.cpython-311.pyc
deleted file mode 100755
index fe0fdc2..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/helpers.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/__pycache__/warnings.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/__pycache__/warnings.cpython-311.pyc
deleted file mode 100755
index f5dd0a0..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/__pycache__/warnings.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_birthdate.py b/venv/lib/python3.11/site-packages/telegram/_birthdate.py
deleted file mode 100755
index 643af05..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_birthdate.py
+++ /dev/null
@@ -1,92 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram Birthday."""
-import datetime as dtm
-from typing import Optional
-
-from telegram._telegramobject import TelegramObject
-from telegram._utils.types import JSONDict
-
-
-class Birthdate(TelegramObject):
-    """
-    This object describes the birthdate of a user.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`day`, and :attr:`month` are equal.
-
-    .. versionadded:: 21.1
-
-    Args:
-        day (:obj:`int`): Day of the user's birth; 1-31.
-        month (:obj:`int`): Month of the user's birth; 1-12.
-        year (:obj:`int`, optional): Year of the user's birth.
-
-    Attributes:
-        day (:obj:`int`): Day of the user's birth; 1-31.
-        month (:obj:`int`): Month of the user's birth; 1-12.
-        year (:obj:`int`): Optional. Year of the user's birth.
-
-    """
-
-    __slots__ = ("day", "month", "year")
-
-    def __init__(
-        self,
-        day: int,
-        month: int,
-        year: Optional[int] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-
-        # Required
-        self.day: int = day
-        self.month: int = month
-        # Optional
-        self.year: Optional[int] = year
-
-        self._id_attrs = (
-            self.day,
-            self.month,
-        )
-
-        self._freeze()
-
-    def to_date(self, year: Optional[int] = None) -> dtm.date:
-        """Return the birthdate as a date object.
-
-        .. versionchanged:: 21.2
-           Now returns a :obj:`datetime.date` object instead of a :obj:`datetime.datetime` object,
-           as was originally intended.
-
-        Args:
-            year (:obj:`int`, optional): The year to use. Required, if the :attr:`year` was not
-                present.
-
-        Returns:
-            :obj:`datetime.date`: The birthdate as a date object.
-        """
-        if self.year is None and year is None:
-            raise ValueError(
-                "The `year` argument is required if the `year` attribute was not present."
-            )
-
-        return dtm.date(year or self.year, self.month, self.day)  # type: ignore[arg-type]
diff --git a/venv/lib/python3.11/site-packages/telegram/_bot.py b/venv/lib/python3.11/site-packages/telegram/_bot.py
deleted file mode 100755
index 1d684a7..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_bot.py
+++ /dev/null
@@ -1,10224 +0,0 @@
-#!/usr/bin/env python
-# pylint: disable=too-many-arguments
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram Bot."""
-
-import asyncio
-import contextlib
-import copy
-import datetime as dtm
-import pickle
-from collections.abc import Sequence
-from types import TracebackType
-from typing import (
-    TYPE_CHECKING,
-    Any,
-    Callable,
-    NoReturn,
-    Optional,
-    TypeVar,
-    Union,
-    cast,
-    no_type_check,
-)
-
-try:
-    from cryptography.hazmat.backends import default_backend
-    from cryptography.hazmat.primitives import serialization
-
-    CRYPTO_INSTALLED = True
-except ImportError:
-    default_backend = None  # type: ignore[assignment]
-    serialization = None  # type: ignore[assignment]
-    CRYPTO_INSTALLED = False
-
-from telegram._botcommand import BotCommand
-from telegram._botcommandscope import BotCommandScope
-from telegram._botdescription import BotDescription, BotShortDescription
-from telegram._botname import BotName
-from telegram._business import BusinessConnection
-from telegram._chatadministratorrights import ChatAdministratorRights
-from telegram._chatboost import UserChatBoosts
-from telegram._chatfullinfo import ChatFullInfo
-from telegram._chatinvitelink import ChatInviteLink
-from telegram._chatmember import ChatMember
-from telegram._chatpermissions import ChatPermissions
-from telegram._files.animation import Animation
-from telegram._files.audio import Audio
-from telegram._files.chatphoto import ChatPhoto
-from telegram._files.contact import Contact
-from telegram._files.document import Document
-from telegram._files.file import File
-from telegram._files.inputmedia import InputMedia, InputPaidMedia
-from telegram._files.location import Location
-from telegram._files.photosize import PhotoSize
-from telegram._files.sticker import MaskPosition, Sticker, StickerSet
-from telegram._files.venue import Venue
-from telegram._files.video import Video
-from telegram._files.videonote import VideoNote
-from telegram._files.voice import Voice
-from telegram._forumtopic import ForumTopic
-from telegram._games.gamehighscore import GameHighScore
-from telegram._gifts import Gift, Gifts
-from telegram._inline.inlinequeryresultsbutton import InlineQueryResultsButton
-from telegram._inline.preparedinlinemessage import PreparedInlineMessage
-from telegram._menubutton import MenuButton
-from telegram._message import Message
-from telegram._messageid import MessageId
-from telegram._payment.stars.startransactions import StarTransactions
-from telegram._poll import InputPollOption, Poll
-from telegram._reaction import ReactionType, ReactionTypeCustomEmoji, ReactionTypeEmoji
-from telegram._reply import ReplyParameters
-from telegram._sentwebappmessage import SentWebAppMessage
-from telegram._telegramobject import TelegramObject
-from telegram._update import Update
-from telegram._user import User
-from telegram._userprofilephotos import UserProfilePhotos
-from telegram._utils.argumentparsing import parse_lpo_and_dwpp, parse_sequence_arg
-from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue
-from telegram._utils.files import is_local_file, parse_file_input
-from telegram._utils.logging import get_logger
-from telegram._utils.repr import build_repr_with_selected_attrs
-from telegram._utils.strings import to_camel_case
-from telegram._utils.types import CorrectOptionID, FileInput, JSONDict, ODVInput, ReplyMarkup
-from telegram._utils.warnings import warn
-from telegram._webhookinfo import WebhookInfo
-from telegram.constants import InlineQueryLimit, ReactionEmoji
-from telegram.error import EndPointNotFound, InvalidToken
-from telegram.request import BaseRequest, RequestData
-from telegram.request._httpxrequest import HTTPXRequest
-from telegram.request._requestparameter import RequestParameter
-from telegram.warnings import PTBDeprecationWarning, PTBUserWarning
-
-if TYPE_CHECKING:
-    from telegram import (
-        InlineKeyboardMarkup,
-        InlineQueryResult,
-        InputFile,
-        InputMediaAudio,
-        InputMediaDocument,
-        InputMediaPhoto,
-        InputMediaVideo,
-        InputSticker,
-        LabeledPrice,
-        LinkPreviewOptions,
-        MessageEntity,
-        PassportElementError,
-        ShippingOption,
-    )
-
-BT = TypeVar("BT", bound="Bot")
-
-
-class Bot(TelegramObject, contextlib.AbstractAsyncContextManager["Bot"]):
-    """This object represents a Telegram Bot.
-
-    Instances of this class can be used as asyncio context managers, where
-
-    .. code:: python
-
-        async with bot:
-            # code
-
-    is roughly equivalent to
-
-    .. code:: python
-
-        try:
-            await bot.initialize()
-            # code
-        finally:
-            await bot.shutdown()
-
-    .. seealso:: :meth:`__aenter__` and :meth:`__aexit__`.
-
-    Note:
-        * Most bot methods have the argument ``api_kwargs`` which allows passing arbitrary keywords
-          to the Telegram API. This can be used to access new features of the API before they are
-          incorporated into PTB. The limitations to this argument are the same as the ones
-          described in :meth:`do_api_request`.
-        * Bots should not be serialized since if you for e.g. change the bots token, then your
-          serialized instance will not reflect that change. Trying to pickle a bot instance will
-          raise :exc:`pickle.PicklingError`. Trying to deepcopy a bot instance will raise
-          :exc:`TypeError`.
-
-    Examples:
-        :any:`Raw API Bot `
-
-    .. seealso:: :wiki:`Your First Bot `,
-        :wiki:`Builder Pattern `
-
-    .. versionadded:: 13.2
-        Objects of this class are comparable in terms of equality. Two objects of this class are
-        considered equal, if their :attr:`bot` is equal.
-
-    .. versionchanged:: 20.0
-
-        * Removed the deprecated methods ``kick_chat_member``, ``kickChatMember``,
-          ``get_chat_members_count`` and ``getChatMembersCount``.
-        * Removed the deprecated property ``commands``.
-        * Removed the deprecated ``defaults`` parameter. If you want to use
-          :class:`telegram.ext.Defaults`, please use the subclass :class:`telegram.ext.ExtBot`
-          instead.
-        * Attempting to pickle a bot instance will now raise :exc:`pickle.PicklingError`.
-        * Attempting to deepcopy a bot instance will now raise :exc:`TypeError`.
-        * The following are now keyword-only arguments in Bot methods:
-          ``location``, ``filename``, ``venue``, ``contact``,
-          ``{read, write, connect, pool}_timeout``, ``api_kwargs``. Use a named argument for those,
-          and notice that some positional arguments changed position as a result.
-        * For uploading files, file paths are now always accepted. If :paramref:`local_mode` is
-          :obj:`False`, the file contents will be read in binary mode and uploaded. Otherwise,
-          the file path will be passed in the
-          `file URI scheme `_.
-
-    .. versionchanged:: 20.5
-        Removed deprecated methods ``set_sticker_set_thumb`` and ``setStickerSetThumb``.
-        Use :meth:`set_sticker_set_thumbnail` and :meth:`setStickerSetThumbnail` instead.
-
-    Args:
-        token (:obj:`str`): Bot's unique authentication token.
-        base_url (:obj:`str`, optional): Telegram Bot API service URL.
-        base_file_url (:obj:`str`, optional): Telegram Bot API file URL.
-        request (:class:`telegram.request.BaseRequest`, optional): Pre initialized
-            :class:`telegram.request.BaseRequest` instances. Will be used for all bot methods
-            *except* for :meth:`get_updates`. If not passed, an instance of
-            :class:`telegram.request.HTTPXRequest` will be used.
-        get_updates_request (:class:`telegram.request.BaseRequest`, optional): Pre initialized
-            :class:`telegram.request.BaseRequest` instances. Will be used exclusively for
-            :meth:`get_updates`. If not passed, an instance of
-            :class:`telegram.request.HTTPXRequest` will be used.
-        private_key (:obj:`bytes`, optional): Private key for decryption of telegram passport data.
-        private_key_password (:obj:`bytes`, optional): Password for above private key.
-        local_mode (:obj:`bool`, optional): Set to :obj:`True`, if the :paramref:`base_url` is
-            the URI of a `Local Bot API Server `_ that runs with the ``--local`` flag. Currently, the only effect of
-            this is that files are uploaded using their local path in the
-            `file URI scheme `_.
-            Defaults to :obj:`False`.
-
-            .. versionadded:: 20.0.
-
-    .. include:: inclusions/bot_methods.rst
-
-    .. |removed_thumb_arg| replace:: Removed deprecated argument ``thumb``. Use
-        ``thumbnail`` instead.
-
-    """
-
-    # This is a class variable since we want to override the logger name in ExtBot
-    # without having to change all places where this is used
-    _LOGGER = get_logger(__name__)
-
-    __slots__ = (
-        "_base_file_url",
-        "_base_url",
-        "_bot_user",
-        "_initialized",
-        "_local_mode",
-        "_private_key",
-        "_request",
-        "_token",
-    )
-
-    def __init__(
-        self,
-        token: str,
-        base_url: str = "https://api.telegram.org/bot",
-        base_file_url: str = "https://api.telegram.org/file/bot",
-        request: Optional[BaseRequest] = None,
-        get_updates_request: Optional[BaseRequest] = None,
-        private_key: Optional[bytes] = None,
-        private_key_password: Optional[bytes] = None,
-        local_mode: bool = False,
-    ):
-        super().__init__(api_kwargs=None)
-        if not token:
-            raise InvalidToken("You must pass the token you received from https://t.me/Botfather!")
-        self._token: str = token
-
-        self._base_url: str = base_url + self._token
-        self._base_file_url: str = base_file_url + self._token
-        self._local_mode: bool = local_mode
-        self._bot_user: Optional[User] = None
-        self._private_key: Optional[bytes] = None
-        self._initialized: bool = False
-
-        self._request: tuple[BaseRequest, BaseRequest] = (
-            HTTPXRequest() if get_updates_request is None else get_updates_request,
-            HTTPXRequest() if request is None else request,
-        )
-
-        # this section is about issuing a warning when using HTTP/2 and connect to a self hosted
-        # bot api instance, which currently only supports HTTP/1.1. Checking if a custom base url
-        # is set is the best way to do that.
-
-        warning_string = ""
-
-        if (
-            isinstance(self._request[0], HTTPXRequest)
-            and self._request[0].http_version == "2"
-            and not base_url.startswith("https://api.telegram.org/bot")
-        ):
-            warning_string = "get_updates_request"
-
-        if (
-            isinstance(self._request[1], HTTPXRequest)
-            and self._request[1].http_version == "2"
-            and not base_url.startswith("https://api.telegram.org/bot")
-        ):
-            if warning_string:
-                warning_string += " and request"
-            else:
-                warning_string = "request"
-
-        if warning_string:
-            self._warn(
-                f"You set the HTTP version for the {warning_string} HTTPXRequest instance to "
-                "HTTP/2. The self hosted bot api instances only support HTTP/1.1. You should "
-                "either run a HTTP proxy in front of it which supports HTTP/2 or use HTTP/1.1.",
-                PTBUserWarning,
-                stacklevel=2,
-            )
-
-        if private_key:
-            if not CRYPTO_INSTALLED:
-                raise RuntimeError(
-                    "To use Telegram Passports, PTB must be installed via `pip install "
-                    '"python-telegram-bot[passport]"`.'
-                )
-            self._private_key = serialization.load_pem_private_key(
-                private_key, password=private_key_password, backend=default_backend()
-            )
-
-        self._freeze()
-
-    async def __aenter__(self: BT) -> BT:
-        """
-        |async_context_manager| :meth:`initializes ` the Bot.
-
-        Returns:
-            The initialized Bot instance.
-
-        Raises:
-            :exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown`
-                is called in this case.
-        """
-        try:
-            await self.initialize()
-        except Exception:
-            await self.shutdown()
-            raise
-        return self
-
-    async def __aexit__(
-        self,
-        exc_type: Optional[type[BaseException]],
-        exc_val: Optional[BaseException],
-        exc_tb: Optional[TracebackType],
-    ) -> None:
-        """|async_context_manager| :meth:`shuts down ` the Bot."""
-        # Make sure not to return `True` so that exceptions are not suppressed
-        # https://docs.python.org/3/reference/datamodel.html?#object.__aexit__
-        await self.shutdown()
-
-    def __reduce__(self) -> NoReturn:
-        """Customizes how :func:`copy.deepcopy` processes objects of this type. Bots can not
-        be pickled and this method will always raise an exception.
-
-        .. versionadded:: 20.0
-
-        Raises:
-            :exc:`pickle.PicklingError`
-        """
-        raise pickle.PicklingError("Bot objects cannot be pickled!")
-
-    def __deepcopy__(self, memodict: dict[int, object]) -> NoReturn:
-        """Customizes how :func:`copy.deepcopy` processes objects of this type. Bots can not
-        be deepcopied and this method will always raise an exception.
-
-        .. versionadded:: 20.0
-
-        Raises:
-            :exc:`TypeError`
-        """
-        raise TypeError("Bot objects cannot be deepcopied!")
-
-    def __eq__(self, other: object) -> bool:
-        """Defines equality condition for the :class:`telegram.Bot` object.
-        Two objects of this class are considered to be equal if their attributes
-        :attr:`bot` are equal.
-
-        Returns:
-            :obj:`True` if both attributes :attr:`bot` are equal. :obj:`False` otherwise.
-        """
-        if isinstance(other, Bot):
-            return self.bot == other.bot
-        return super().__eq__(other)
-
-    def __hash__(self) -> int:
-        """See :meth:`telegram.TelegramObject.__hash__`"""
-        if self._bot_user is None:
-            return super().__hash__()
-        return hash((self.bot, Bot))
-
-    def __repr__(self) -> str:
-        """Give a string representation of the bot in the form ``Bot[token=...]``.
-
-        As this class doesn't implement :meth:`object.__str__`, the default implementation
-        will be used, which is equivalent to :meth:`__repr__`.
-
-        Returns:
-            :obj:`str`
-        """
-        return build_repr_with_selected_attrs(self, token=self.token)
-
-    @property
-    def token(self) -> str:
-        """:obj:`str`: Bot's unique authentication token.
-
-        .. versionadded:: 20.0
-        """
-        return self._token
-
-    @property
-    def base_url(self) -> str:
-        """:obj:`str`: Telegram Bot API service URL, built from :paramref:`Bot.base_url` and
-        :paramref:`Bot.token`.
-
-        .. versionadded:: 20.0
-        """
-        return self._base_url
-
-    @property
-    def base_file_url(self) -> str:
-        """:obj:`str`: Telegram Bot API file URL, built from :paramref:`Bot.base_file_url` and
-        :paramref:`Bot.token`.
-
-        .. versionadded:: 20.0
-        """
-        return self._base_file_url
-
-    @property
-    def local_mode(self) -> bool:
-        """:obj:`bool`: Whether this bot is running in local mode.
-
-        .. versionadded:: 20.0
-        """
-        return self._local_mode
-
-    # Proper type hints are difficult because:
-    # 1. cryptography doesn't have a nice base class, so it would get lengthy
-    # 2. we can't import cryptography if it's not installed
-    @property
-    def private_key(self) -> Optional[Any]:
-        """Deserialized private key for decryption of telegram passport data.
-
-        .. versionadded:: 20.0
-        """
-        return self._private_key
-
-    @property
-    def request(self) -> BaseRequest:
-        """The :class:`~telegram.request.BaseRequest` object used by this bot.
-
-        Warning:
-            Requests to the Bot API are made by the various methods of this class. This attribute
-            should *not* be used manually.
-        """
-        return self._request[1]
-
-    @property
-    def bot(self) -> User:
-        """:class:`telegram.User`: User instance for the bot as returned by :meth:`get_me`.
-
-        Warning:
-            This value is the cached return value of :meth:`get_me`. If the bots profile is
-            changed during runtime, this value won't reflect the changes until :meth:`get_me` is
-            called again.
-
-        .. seealso:: :meth:`initialize`
-        """
-        if self._bot_user is None:
-            raise RuntimeError(
-                f"{self.__class__.__name__} is not properly initialized. Call "
-                f"`{self.__class__.__name__}.initialize` before accessing this property."
-            )
-        return self._bot_user
-
-    @property
-    def id(self) -> int:
-        """:obj:`int`: Unique identifier for this bot. Shortcut for the corresponding attribute of
-        :attr:`bot`.
-        """
-        return self.bot.id
-
-    @property
-    def first_name(self) -> str:
-        """:obj:`str`: Bot's first name. Shortcut for the corresponding attribute of
-        :attr:`bot`.
-        """
-        return self.bot.first_name
-
-    @property
-    def last_name(self) -> str:
-        """:obj:`str`: Optional. Bot's last name. Shortcut for the corresponding attribute of
-        :attr:`bot`.
-        """
-        return self.bot.last_name  # type: ignore
-
-    @property
-    def username(self) -> str:
-        """:obj:`str`: Bot's username. Shortcut for the corresponding attribute of
-        :attr:`bot`.
-        """
-        return self.bot.username  # type: ignore
-
-    @property
-    def link(self) -> str:
-        """:obj:`str`: Convenience property. Returns the t.me link of the bot."""
-        return f"https://t.me/{self.username}"
-
-    @property
-    def can_join_groups(self) -> bool:
-        """:obj:`bool`: Bot's :attr:`telegram.User.can_join_groups` attribute. Shortcut for the
-        corresponding attribute of :attr:`bot`.
-        """
-        return self.bot.can_join_groups  # type: ignore
-
-    @property
-    def can_read_all_group_messages(self) -> bool:
-        """:obj:`bool`: Bot's :attr:`telegram.User.can_read_all_group_messages` attribute.
-        Shortcut for the corresponding attribute of :attr:`bot`.
-        """
-        return self.bot.can_read_all_group_messages  # type: ignore
-
-    @property
-    def supports_inline_queries(self) -> bool:
-        """:obj:`bool`: Bot's :attr:`telegram.User.supports_inline_queries` attribute.
-        Shortcut for the corresponding attribute of :attr:`bot`.
-        """
-        return self.bot.supports_inline_queries  # type: ignore
-
-    @property
-    def name(self) -> str:
-        """:obj:`str`: Bot's @username. Shortcut for the corresponding attribute of :attr:`bot`."""
-        return f"@{self.username}"
-
-    @classmethod
-    def _warn(
-        cls,
-        message: Union[str, PTBUserWarning],
-        category: type[Warning] = PTBUserWarning,
-        stacklevel: int = 0,
-    ) -> None:
-        """Convenience method to issue a warning. This method is here mostly to make it easier
-        for ExtBot to add 1 level to all warning calls.
-        """
-        warn(message=message, category=category, stacklevel=stacklevel + 1)
-
-    def _parse_file_input(
-        self,
-        file_input: Union[FileInput, "TelegramObject"],
-        tg_type: Optional[type["TelegramObject"]] = None,
-        filename: Optional[str] = None,
-        attach: bool = False,
-    ) -> Union[str, "InputFile", Any]:
-        return parse_file_input(
-            file_input=file_input,
-            tg_type=tg_type,
-            filename=filename,
-            attach=attach,
-            local_mode=self._local_mode,
-        )
-
-    def _insert_defaults(self, data: dict[str, object]) -> None:
-        """This method is here to make ext.Defaults work. Because we need to be able to tell
-        e.g. `send_message(chat_id, text)` from `send_message(chat_id, text, parse_mode=None)`, the
-        default values for `parse_mode` etc are not `None` but `DEFAULT_NONE`. While this *could*
-        be done in ExtBot instead of Bot, shortcuts like `Message.reply_text` need to work for both
-        Bot and ExtBot, so they also have the `DEFAULT_NONE` default values.
-
-        This makes it necessary to convert `DefaultValue(obj)` to `obj` at some point between
-        `Message.reply_text` and the request to TG. Doing this here in a centralized manner is a
-        rather clean and minimally invasive solution, i.e. the link between tg and tg.ext is as
-        small as possible.
-        See also _insert_defaults_for_ilq
-        ExtBot overrides this method to actually insert default values.
-
-        If in the future we come up with a better way of making `Defaults` work, we can cut this
-        link as well.
-        """
-        # We
-        # 1) set the correct parse_mode for all InputMedia objects
-        # 2) replace all DefaultValue instances with the corresponding normal value.
-        for key, val in data.items():
-            # 1)
-            if isinstance(val, InputMedia):
-                # Copy object as not to edit it in-place
-                new = copy.copy(val)
-                with new._unfrozen():
-                    new.parse_mode = DefaultValue.get_value(new.parse_mode)
-                data[key] = new
-            elif (
-                key == "media"
-                and isinstance(val, Sequence)
-                and not isinstance(val[0], InputPaidMedia)
-            ):
-                # Copy objects as not to edit them in-place
-                copy_list = [copy.copy(media) for media in val]
-                for media in copy_list:
-                    with media._unfrozen():
-                        media.parse_mode = DefaultValue.get_value(media.parse_mode)
-                data[key] = copy_list
-            # 2)
-            else:
-                data[key] = DefaultValue.get_value(val)
-
-    async def _post(
-        self,
-        endpoint: str,
-        data: Optional[JSONDict] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Any:
-        # We know that the return type is Union[bool, JSONDict, list[JSONDict]], but it's hard
-        # to tell mypy which methods expects which of these return values and `Any` saves us a
-        # lot of `type: ignore` comments
-        if data is None:
-            data = {}
-
-        if api_kwargs:
-            data.update(api_kwargs)
-
-        # Insert is in-place, so no return value for data
-        self._insert_defaults(data)
-
-        # Drop any None values because Telegram doesn't handle them well
-        data = {key: value for key, value in data.items() if value is not None}
-
-        return await self._do_post(
-            endpoint=endpoint,
-            data=data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-        )
-
-    async def _do_post(
-        self,
-        endpoint: str,
-        data: JSONDict,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-    ) -> Union[bool, JSONDict, list[JSONDict]]:
-        # This also converts datetimes into timestamps.
-        # We don't do this earlier so that _insert_defaults (see above) has a chance to convert
-        # to the default timezone in case this is called by ExtBot
-        request_data = RequestData(
-            parameters=[RequestParameter.from_input(key, value) for key, value in data.items()],
-        )
-
-        request = self._request[0] if endpoint == "getUpdates" else self._request[1]
-
-        self._LOGGER.debug("Calling Bot API endpoint `%s` with parameters `%s`", endpoint, data)
-        result = await request.post(
-            url=f"{self._base_url}/{endpoint}",
-            request_data=request_data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-        )
-        self._LOGGER.debug(
-            "Call to Bot API endpoint `%s` finished with return value `%s`", endpoint, result
-        )
-
-        return result
-
-    async def _send_message(
-        self,
-        endpoint: str,
-        data: JSONDict,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        caption: Optional[str] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        link_preview_options: ODVInput["LinkPreviewOptions"] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        reply_to_message_id: Optional[int] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Any:
-        """Protected method to send or edit messages of any type.
-
-        It is here to reduce repetition of if-else closes in the different bot methods,
-        i.e. this method takes care of adding its parameters to `data` if appropriate.
-
-        Depending on the bot method, returns either `True` or the message.
-        However, it's hard to tell mypy which methods expects which of these return values and
-        using `Any` instead saves us a lot of `type: ignore` comments
-        """
-        # We don't check if (DEFAULT_)None here, so that _post is able to insert the defaults
-        # correctly, if necessary:
-        if allow_sending_without_reply is not DEFAULT_NONE and reply_parameters is not None:
-            raise ValueError(
-                "`allow_sending_without_reply` and `reply_parameters` are mutually exclusive."
-            )
-
-        if reply_to_message_id is not None and reply_parameters is not None:
-            raise ValueError(
-                "`reply_to_message_id` and `reply_parameters` are mutually exclusive."
-            )
-
-        if reply_to_message_id is not None:
-            reply_parameters = ReplyParameters(
-                message_id=reply_to_message_id,
-                allow_sending_without_reply=allow_sending_without_reply,
-            )
-
-        data.update(
-            {
-                "allow_paid_broadcast": allow_paid_broadcast,
-                "business_connection_id": business_connection_id,
-                "caption": caption,
-                "caption_entities": caption_entities,
-                "disable_notification": disable_notification,
-                "link_preview_options": link_preview_options,
-                "message_thread_id": message_thread_id,
-                "message_effect_id": message_effect_id,
-                "parse_mode": parse_mode,
-                "protect_content": protect_content,
-                "reply_markup": reply_markup,
-                "reply_parameters": reply_parameters,
-            }
-        )
-
-        result = await self._post(
-            endpoint,
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-        if result is True:
-            return result
-
-        return Message.de_json(result, self)
-
-    async def initialize(self) -> None:
-        """Initialize resources used by this class. Currently calls :meth:`get_me` to
-        cache :attr:`bot` and calls :meth:`telegram.request.BaseRequest.initialize` for
-        the request objects used by this bot.
-
-        .. seealso:: :meth:`shutdown`
-
-        .. versionadded:: 20.0
-        """
-        if self._initialized:
-            self._LOGGER.debug("This Bot is already initialized.")
-            return
-
-        await asyncio.gather(self._request[0].initialize(), self._request[1].initialize())
-        # Since the bot is to be initialized only once, we can also use it for
-        # verifying the token passed and raising an exception if it's invalid.
-        try:
-            await self.get_me()
-        except InvalidToken as exc:
-            raise InvalidToken(f"The token `{self._token}` was rejected by the server.") from exc
-        self._initialized = True
-
-    async def shutdown(self) -> None:
-        """Stop & clear resources used by this class. Currently just calls
-        :meth:`telegram.request.BaseRequest.shutdown` for the request objects used by this bot.
-
-        .. seealso:: :meth:`initialize`
-
-        .. versionadded:: 20.0
-        """
-        if not self._initialized:
-            self._LOGGER.debug("This Bot is already shut down. Returning.")
-            return
-
-        await asyncio.gather(self._request[0].shutdown(), self._request[1].shutdown())
-        self._initialized = False
-
-    async def do_api_request(
-        self,
-        endpoint: str,
-        api_kwargs: Optional[JSONDict] = None,
-        return_type: Optional[type[TelegramObject]] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-    ) -> Any:
-        """Do a request to the Telegram API.
-
-        This method is here to make it easier to use new API methods that are not yet supported
-        by this library.
-
-        Hint:
-            Since PTB does not know which arguments are passed to this method, some caution is
-            necessary in terms of PTBs utility functionalities. In particular
-
-            * passing objects of any class defined in the :mod:`telegram` module is supported
-            * when uploading files, a :class:`telegram.InputFile` must be passed as the value for
-              the corresponding argument. Passing a file path or file-like object will not work.
-              File paths will work only in combination with :paramref:`~Bot.local_mode`.
-            * when uploading files, PTB can still correctly determine that
-              a special write timeout value should be used instead of the default
-              :paramref:`telegram.request.HTTPXRequest.write_timeout`.
-            * insertion of default values specified via :class:`telegram.ext.Defaults` will not
-              work (only relevant for :class:`telegram.ext.ExtBot`).
-            * The only exception is :class:`telegram.ext.Defaults.tzinfo`, which will be correctly
-              applied to :class:`datetime.datetime` objects.
-
-        .. versionadded:: 20.8
-
-        Args:
-            endpoint (:obj:`str`): The API endpoint to use, e.g. ``getMe`` or ``get_me``.
-            api_kwargs (:obj:`dict`, optional): The keyword arguments to pass to the API call.
-                If not specified, no arguments are passed.
-            return_type (:class:`telegram.TelegramObject`, optional): If specified, the result of
-                the API call will be deserialized into an instance of this class or tuple of
-                instances of this class. If not specified, the raw result of the API call will be
-                returned.
-
-        Returns:
-            The result of the API call. If :paramref:`return_type` is not specified, this is a
-            :obj:`dict` or :obj:`bool`, otherwise an instance of :paramref:`return_type` or a
-            tuple of :paramref:`return_type`.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        if hasattr(self, endpoint):
-            self._warn(
-                (
-                    f"Please use 'Bot.{endpoint}' instead of "
-                    f"'Bot.do_api_request(\"{endpoint}\", ...)'"
-                ),
-                stacklevel=2,
-            )
-
-        camel_case_endpoint = to_camel_case(endpoint)
-        try:
-            result = await self._post(
-                camel_case_endpoint,
-                api_kwargs=api_kwargs,
-                read_timeout=read_timeout,
-                write_timeout=write_timeout,
-                connect_timeout=connect_timeout,
-                pool_timeout=pool_timeout,
-            )
-        except InvalidToken as exc:
-            # TG returns 404 Not found for
-            #   1) malformed tokens
-            #   2) correct tokens but non-existing method, e.g. api.tg.org/botTOKEN/unkonwnMethod
-            # 2) is relevant only for Bot.do_api_request, that's why we have special handling for
-            # that here rather than in BaseRequest._request_wrapper
-            if self._initialized:
-                raise EndPointNotFound(
-                    f"Endpoint '{camel_case_endpoint}' not found in Bot API"
-                ) from exc
-
-            raise InvalidToken(
-                "Either the bot token was rejected by Telegram or the endpoint "
-                f"'{camel_case_endpoint}' does not exist."
-            ) from exc
-
-        if return_type is None or isinstance(result, bool):
-            return result
-
-        if isinstance(result, list):
-            return return_type.de_list(result, self)
-        return return_type.de_json(result, self)
-
-    async def get_me(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> User:
-        """A simple method for testing your bot's auth token. Requires no parameters.
-
-        Returns:
-            :class:`telegram.User`: A :class:`telegram.User` instance representing that bot if the
-            credentials are valid, :obj:`None` otherwise.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        result = await self._post(
-            "getMe",
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-        self._bot_user = User.de_json(result, self)
-        return self._bot_user  # type: ignore[return-value]
-
-    async def send_message(
-        self,
-        chat_id: Union[int, str],
-        text: str,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        entities: Optional[Sequence["MessageEntity"]] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        message_thread_id: Optional[int] = None,
-        link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        reply_to_message_id: Optional[int] = None,
-        disable_web_page_preview: Optional[bool] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Message:
-        """Use this method to send text messages.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            text (:obj:`str`): Text of the message to be sent. Max
-                :tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters after
-                entities parsing.
-            parse_mode (:obj:`str`): |parse_mode|
-            entities (Sequence[:class:`telegram.MessageEntity`], optional): Sequence of special
-                entities that appear in message text, which can be specified instead of
-                :paramref:`parse_mode`.
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-            link_preview_options (:obj:`LinkPreviewOptions`, optional): Link preview generation
-                options for the message. Mutually exclusive with
-                :paramref:`disable_web_page_preview`.
-
-                .. versionadded:: 20.8
-
-            disable_notification (:obj:`bool`, optional): |disable_notification|
-            protect_content (:obj:`bool`, optional): |protect_content|
-
-                .. versionadded:: 13.10
-
-            reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \
-                :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional):
-                Additional interface options. An object for an inline keyboard, custom reply
-                keyboard, instructions to remove reply keyboard or to force a reply from the user.
-            message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
-
-                .. versionadded:: 20.0
-            reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
-
-                .. versionadded:: 20.8
-            business_connection_id (:obj:`str`, optional): |business_id_str|
-
-                .. versionadded:: 21.1
-            message_effect_id (:obj:`str`, optional): |message_effect_id|
-
-                .. versionadded:: 21.3
-            allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast|
-
-                .. versionadded:: 21.7
-
-        Keyword Args:
-            allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in
-                this message. Convenience parameter for setting :paramref:`link_preview_options`.
-                Mutually exclusive with :paramref:`link_preview_options`.
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`link_preview_options` replacing this
-                    argument. PTB will automatically convert this argument to that one, but
-                    for advanced options, please use :paramref:`link_preview_options` directly.
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-
-        Returns:
-            :class:`telegram.Message`: On success, the sent message is returned.
-
-        Raises:
-            :exc:`ValueError`: If both :paramref:`disable_web_page_preview` and
-                :paramref:`link_preview_options` are passed.
-            :class:`telegram.error.TelegramError`: For other errors.
-
-        """
-        data: JSONDict = {"chat_id": chat_id, "text": text, "entities": entities}
-        link_preview_options = parse_lpo_and_dwpp(disable_web_page_preview, link_preview_options)
-
-        return await self._send_message(
-            "sendMessage",
-            data,
-            reply_to_message_id=reply_to_message_id,
-            disable_notification=disable_notification,
-            reply_markup=reply_markup,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            business_connection_id=business_connection_id,
-            parse_mode=parse_mode,
-            link_preview_options=link_preview_options,
-            reply_parameters=reply_parameters,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def delete_message(
-        self,
-        chat_id: Union[str, int],
-        message_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to delete a message, including service messages, with the following
-        limitations:
-
-        - A message can only be deleted if it was sent less than 48 hours ago.
-        - Service messages about a supergroup, channel, or forum topic creation can't be deleted.
-        - A dice message in a private chat can only be deleted if it was sent more than 24
-          hours ago.
-        - Bots can delete outgoing messages in private chats, groups, and supergroups.
-        - Bots can delete incoming messages in private chats.
-        - Bots granted :attr:`~telegram.ChatMemberAdministrator.can_post_messages` permissions
-          can delete outgoing messages in channels.
-        - If the bot is an administrator of a group, it can delete any message there.
-        - If the bot has :attr:`~telegram.ChatMemberAdministrator.can_delete_messages`
-          permission in a supergroup or a channel, it can delete any message there.
-
-        ..
-            The method CallbackQuery.delete_message() will not be found when automatically
-            generating "Shortcuts" admonitions for Bot methods because it has no calls
-            to Bot methods in its return statement(s). So it is manually included in "See also".
-
-        .. seealso::
-            :meth:`telegram.CallbackQuery.delete_message` (calls :meth:`delete_message`
-            indirectly, via :meth:`telegram.Message.delete`)
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            message_id (:obj:`int`): Identifier of the message to delete.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"chat_id": chat_id, "message_id": message_id}
-        return await self._post(
-            "deleteMessage",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def delete_messages(
-        self,
-        chat_id: Union[int, str],
-        message_ids: Sequence[int],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to delete multiple messages simultaneously. If some of the specified
-        messages can't be found, they are skipped.
-
-        .. versionadded:: 20.8
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            message_ids (Sequence[:obj:`int`]): A list of
-                :tg-const:`telegram.constants.BulkRequestLimit.MIN_LIMIT`-
-                :tg-const:`telegram.constants.BulkRequestLimit.MAX_LIMIT` identifiers of messages
-                to delete. See :meth:`delete_message` for limitations on which messages can be
-                deleted.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {"chat_id": chat_id, "message_ids": message_ids}
-        return await self._post(
-            "deleteMessages",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def forward_message(
-        self,
-        chat_id: Union[int, str],
-        from_chat_id: Union[str, int],
-        message_id: int,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Message:
-        """
-        Use this method to forward messages of any kind. Service messages can't be forwarded.
-
-        Note:
-            Since the release of Bot API 5.5 it can be impossible to forward messages from
-            some chats. Use the attributes :attr:`telegram.Message.has_protected_content` and
-            :attr:`telegram.ChatFullInfo.has_protected_content` to check this.
-
-            As a workaround, it is still possible to use :meth:`copy_message`. However, this
-            behaviour is undocumented and might be changed by Telegram.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            from_chat_id (:obj:`int` | :obj:`str`): Unique identifier for the chat where the
-                original message was sent (or channel username in the format ``@channelusername``).
-            message_id (:obj:`int`): Message identifier in the chat specified in
-                :paramref:`from_chat_id`.
-            disable_notification (:obj:`bool`, optional): |disable_notification|
-            protect_content (:obj:`bool`, optional): |protect_content|
-
-                .. versionadded:: 13.10
-            message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
-
-                .. versionadded:: 20.0
-
-        Returns:
-            :class:`telegram.Message`: On success, the sent Message is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "from_chat_id": from_chat_id,
-            "message_id": message_id,
-        }
-
-        return await self._send_message(
-            "forwardMessage",
-            data,
-            disable_notification=disable_notification,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def forward_messages(
-        self,
-        chat_id: Union[int, str],
-        from_chat_id: Union[str, int],
-        message_ids: Sequence[int],
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> tuple[MessageId, ...]:
-        """
-        Use this method to forward messages of any kind. If some of the specified messages can't be
-        found or forwarded, they are skipped. Service messages and messages with protected content
-        can't be forwarded. Album grouping is kept for forwarded messages.
-
-        .. versionadded:: 20.8
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            from_chat_id (:obj:`int` | :obj:`str`): Unique identifier for the chat where the
-                original message was sent (or channel username in the format ``@channelusername``).
-            message_ids (Sequence[:obj:`int`]): A list of
-                :tg-const:`telegram.constants.BulkRequestLimit.MIN_LIMIT`-
-                :tg-const:`telegram.constants.BulkRequestLimit.MAX_LIMIT` identifiers of messages
-                in the chat :paramref:`from_chat_id` to forward. The identifiers must be specified
-                in a strictly increasing order.
-            disable_notification (:obj:`bool`, optional): |disable_notification|
-            protect_content (:obj:`bool`, optional): |protect_content|
-            message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
-
-        Returns:
-            tuple[:class:`telegram.Message`]: On success, a tuple of ``MessageId`` of sent messages
-            is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "from_chat_id": from_chat_id,
-            "message_ids": message_ids,
-            "disable_notification": disable_notification,
-            "protect_content": protect_content,
-            "message_thread_id": message_thread_id,
-        }
-
-        result = await self._post(
-            "forwardMessages",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-        return MessageId.de_list(result, self)
-
-    async def send_photo(
-        self,
-        chat_id: Union[int, str],
-        photo: Union[FileInput, "PhotoSize"],
-        caption: Optional[str] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        has_spoiler: Optional[bool] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        show_caption_above_media: Optional[bool] = None,
-        *,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        reply_to_message_id: Optional[int] = None,
-        filename: Optional[str] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Message:
-        """Use this method to send photos.
-
-        .. seealso:: :wiki:`Working with Files and Media `
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            photo (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` \
-                | :class:`pathlib.Path` | :class:`telegram.PhotoSize`): Photo to send.
-                |fileinput|
-                Lastly you can pass an existing :class:`telegram.PhotoSize` object to send.
-
-                Caution:
-                    * The photo must be at most 10MB in size.
-                    * The photo's width and height must not exceed 10000 in total.
-                    * Width and height ratio must be at most 20.
-
-                .. versionchanged:: 13.2
-                   Accept :obj:`bytes` as input.
-
-                .. versionchanged:: 20.0
-                    File paths as input is also accepted for bots *not* running in
-                    :paramref:`~telegram.Bot.local_mode`.
-            caption (:obj:`str`, optional): Photo caption (may also be used when resending photos
-                by file_id), 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH`
-                characters after entities parsing.
-            parse_mode (:obj:`str`, optional): |parse_mode|
-            caption_entities (Sequence[:class:`telegram.MessageEntity`], optional):
-                |caption_entities|
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-            disable_notification (:obj:`bool`, optional): |disable_notification|
-            protect_content (:obj:`bool`, optional): |protect_content|
-
-                .. versionadded:: 13.10
-            message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
-
-                .. versionadded:: 20.0
-
-            reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \
-                :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional):
-                Additional interface options. An object for an inline keyboard, custom reply
-                keyboard, instructions to remove reply keyboard or to force a reply from the user.
-            has_spoiler (:obj:`bool`, optional): Pass :obj:`True` if the photo needs to be covered
-                with a spoiler animation.
-
-                .. versionadded:: 20.0
-            reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
-
-                .. versionadded:: 20.8
-            business_connection_id (:obj:`str`, optional): |business_id_str|
-
-                .. versionadded:: 21.1
-            message_effect_id (:obj:`str`, optional): |message_effect_id|
-
-                .. versionadded:: 21.3
-            allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast|
-
-                .. versionadded:: 21.7
-            show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
-
-                .. versionadded:: 21.3
-
-        Keyword Args:
-            allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            filename (:obj:`str`, optional): Custom file name for the photo, when uploading a
-                new file. Convenience parameter, useful e.g. when sending files generated by the
-                :obj:`tempfile` module.
-
-                .. versionadded:: 13.1
-
-        Returns:
-            :class:`telegram.Message`: On success, the sent Message is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "photo": self._parse_file_input(photo, PhotoSize, filename=filename),
-            "has_spoiler": has_spoiler,
-            "show_caption_above_media": show_caption_above_media,
-        }
-
-        return await self._send_message(
-            "sendPhoto",
-            data,
-            reply_to_message_id=reply_to_message_id,
-            disable_notification=disable_notification,
-            reply_markup=reply_markup,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            caption=caption,
-            parse_mode=parse_mode,
-            caption_entities=caption_entities,
-            reply_parameters=reply_parameters,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_audio(
-        self,
-        chat_id: Union[int, str],
-        audio: Union[FileInput, "Audio"],
-        duration: Optional[int] = None,
-        performer: Optional[str] = None,
-        title: Optional[str] = None,
-        caption: Optional[str] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        thumbnail: Optional[FileInput] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        reply_to_message_id: Optional[int] = None,
-        filename: Optional[str] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Message:
-        """
-        Use this method to send audio files, if you want Telegram clients to display them in the
-        music player. Your audio must be in the ``.mp3`` or ``.m4a`` format.
-
-        Bots can currently send audio files of up to
-        :tg-const:`telegram.constants.FileSizeLimit.FILESIZE_UPLOAD` in size, this limit may be
-        changed in the future.
-
-        For sending voice messages, use the :meth:`send_voice` method instead.
-
-        .. seealso:: :wiki:`Working with Files and Media `
-
-        .. versionchanged:: 20.5
-            |removed_thumb_arg|
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            audio (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | \
-                :obj:`bytes` | :class:`pathlib.Path` | :class:`telegram.Audio`): Audio file to
-                send. |fileinput|
-                Lastly you can pass an existing :class:`telegram.Audio` object to send.
-
-                .. versionchanged:: 13.2
-                   Accept :obj:`bytes` as input.
-
-                .. versionchanged:: 20.0
-                    File paths as input is also accepted for bots *not* running in
-                    :paramref:`~telegram.Bot.local_mode`.
-            caption (:obj:`str`, optional): Audio caption,
-                0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
-                entities parsing.
-            parse_mode (:obj:`str`, optional): |parse_mode|
-            caption_entities (Sequence[:class:`telegram.MessageEntity`], optional):
-                |caption_entities|
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-            duration (:obj:`int`, optional): Duration of sent audio in seconds.
-            performer (:obj:`str`, optional): Performer.
-            title (:obj:`str`, optional): Track name.
-            disable_notification (:obj:`bool`, optional): |disable_notification|
-            protect_content (:obj:`bool`, optional): |protect_content|
-
-                .. versionadded:: 13.10
-            message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
-
-                .. versionadded:: 20.0
-
-            reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \
-                :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional):
-                Additional interface options. An object for an inline keyboard, custom reply
-                keyboard, instructions to remove reply keyboard or to force a reply from the user.
-            thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
-                optional): |thumbdocstring|
-
-                .. versionadded:: 20.2
-            reply_parameters (:obj:`ReplyParameters`, optional): |reply_parameters|
-
-                .. versionadded:: 20.8
-            business_connection_id (:obj:`str`, optional): |business_id_str|
-
-                .. versionadded:: 21.1
-            message_effect_id (:obj:`str`, optional): |message_effect_id|
-
-                .. versionadded:: 21.3
-            allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast|
-
-                .. versionadded:: 21.7
-
-        Keyword Args:
-            allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            filename (:obj:`str`, optional): Custom file name for the audio, when uploading a
-                new file. Convenience parameter, useful e.g. when sending files generated by the
-                :obj:`tempfile` module.
-
-                .. versionadded:: 13.1
-
-        Returns:
-            :class:`telegram.Message`: On success, the sent Message is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "audio": self._parse_file_input(audio, Audio, filename=filename),
-            "duration": duration,
-            "performer": performer,
-            "title": title,
-            "thumbnail": self._parse_file_input(thumbnail, attach=True) if thumbnail else None,
-        }
-
-        return await self._send_message(
-            "sendAudio",
-            data,
-            reply_to_message_id=reply_to_message_id,
-            disable_notification=disable_notification,
-            reply_markup=reply_markup,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            caption=caption,
-            parse_mode=parse_mode,
-            caption_entities=caption_entities,
-            reply_parameters=reply_parameters,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_document(
-        self,
-        chat_id: Union[int, str],
-        document: Union[FileInput, "Document"],
-        caption: Optional[str] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        disable_content_type_detection: Optional[bool] = None,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        thumbnail: Optional[FileInput] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        reply_to_message_id: Optional[int] = None,
-        filename: Optional[str] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Message:
-        """
-        Use this method to send general files.
-
-        Bots can currently send files of any type of up to
-        :tg-const:`telegram.constants.FileSizeLimit.FILESIZE_UPLOAD` in size, this limit may be
-        changed in the future.
-
-        .. seealso:: :wiki:`Working with Files and Media `
-
-        .. versionchanged:: 20.5
-            |removed_thumb_arg|
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            document (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | \
-                :obj:`bytes` | :class:`pathlib.Path` | :class:`telegram.Document`): File to send.
-                |fileinput|
-                Lastly you can pass an existing :class:`telegram.Document` object to send.
-
-                Note:
-                    Sending by URL will currently only work ``GIF``, ``PDF`` & ``ZIP`` files.
-
-                .. versionchanged:: 13.2
-                   Accept :obj:`bytes` as input.
-
-                .. versionchanged:: 20.0
-                    File paths as input is also accepted for bots *not* running in
-                    :paramref:`~telegram.Bot.local_mode`.
-            caption (:obj:`str`, optional): Document caption (may also be used when resending
-                documents by file_id), 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH`
-                characters after entities parsing.
-            disable_content_type_detection (:obj:`bool`, optional): Disables automatic server-side
-                content type detection for files uploaded using multipart/form-data.
-            parse_mode (:obj:`str`, optional): |parse_mode|
-            caption_entities (Sequence[:class:`telegram.MessageEntity`], optional):
-                |caption_entities|
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-            disable_notification (:obj:`bool`, optional): |disable_notification|
-            protect_content (:obj:`bool`, optional): |protect_content|
-
-                .. versionadded:: 13.10
-            message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
-
-                .. versionadded:: 20.0
-
-            reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \
-                :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional):
-                Additional interface options. An object for an inline keyboard, custom reply
-                keyboard, instructions to remove reply keyboard or to force a reply from the user.
-            thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
-                optional): |thumbdocstring|
-
-                .. versionadded:: 20.2
-            reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
-
-                .. versionadded:: 20.8
-            business_connection_id (:obj:`str`, optional): |business_id_str|
-
-                .. versionadded:: 21.1
-            message_effect_id (:obj:`str`, optional): |message_effect_id|
-
-                .. versionadded:: 21.3
-            allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast|
-
-                .. versionadded:: 21.7
-
-        Keyword Args:
-            allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            filename (:obj:`str`, optional): Custom file name for the document, when uploading a
-                new file. Convenience parameter, useful e.g. when sending files generated by the
-                :obj:`tempfile` module.
-
-        Returns:
-            :class:`telegram.Message`: On success, the sent Message is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "document": self._parse_file_input(document, Document, filename=filename),
-            "disable_content_type_detection": disable_content_type_detection,
-            "thumbnail": self._parse_file_input(thumbnail, attach=True) if thumbnail else None,
-        }
-
-        return await self._send_message(
-            "sendDocument",
-            data,
-            reply_to_message_id=reply_to_message_id,
-            disable_notification=disable_notification,
-            reply_markup=reply_markup,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            caption=caption,
-            parse_mode=parse_mode,
-            caption_entities=caption_entities,
-            reply_parameters=reply_parameters,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_sticker(
-        self,
-        chat_id: Union[int, str],
-        sticker: Union[FileInput, "Sticker"],
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        emoji: Optional[str] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        reply_to_message_id: Optional[int] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Message:
-        """
-        Use this method to send static ``.WEBP``, animated ``.TGS``, or video ``.WEBM`` stickers.
-
-        .. seealso:: :wiki:`Working with Files and Media `
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            sticker (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | \
-                :obj:`bytes` | :class:`pathlib.Path` | :class:`telegram.Sticker`): Sticker to send.
-                |fileinput| Video stickers can only be sent by a ``file_id``. Video and animated
-                stickers can't be sent via an HTTP URL.
-
-                Lastly you can pass an existing :class:`telegram.Sticker` object to send.
-
-                .. versionchanged:: 13.2
-                   Accept :obj:`bytes` as input.
-
-                .. versionchanged:: 20.0
-                    File paths as input is also accepted for bots *not* running in
-                    :paramref:`~telegram.Bot.local_mode`.
-            emoji (:obj:`str`, optional): Emoji associated with the sticker; only for just
-                uploaded stickers
-
-                .. versionadded:: 20.2
-            disable_notification (:obj:`bool`, optional): |disable_notification|
-            protect_content (:obj:`bool`, optional): |protect_content|
-
-                .. versionadded:: 13.10
-            message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
-
-                .. versionadded:: 20.0
-
-            reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \
-                :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional):
-                Additional interface options. An object for an inline keyboard, custom reply
-                keyboard, instructions to remove reply keyboard or to force a reply from the user.
-            reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
-
-                .. versionadded:: 20.8
-            business_connection_id (:obj:`str`, optional): |business_id_str|
-
-                .. versionadded:: 21.1
-            message_effect_id (:obj:`str`, optional): |message_effect_id|
-
-                .. versionadded:: 21.3
-            allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast|
-
-                .. versionadded:: 21.7
-
-        Keyword Args:
-            allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-
-        Returns:
-            :class:`telegram.Message`: On success, the sent Message is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "sticker": self._parse_file_input(sticker, Sticker),
-            "emoji": emoji,
-        }
-        return await self._send_message(
-            "sendSticker",
-            data,
-            reply_to_message_id=reply_to_message_id,
-            disable_notification=disable_notification,
-            reply_markup=reply_markup,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            reply_parameters=reply_parameters,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_video(
-        self,
-        chat_id: Union[int, str],
-        video: Union[FileInput, "Video"],
-        duration: Optional[int] = None,
-        caption: Optional[str] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        width: Optional[int] = None,
-        height: Optional[int] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        supports_streaming: Optional[bool] = None,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        has_spoiler: Optional[bool] = None,
-        thumbnail: Optional[FileInput] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        show_caption_above_media: Optional[bool] = None,
-        *,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        reply_to_message_id: Optional[int] = None,
-        filename: Optional[str] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Message:
-        """Use this method to send video files, Telegram clients support mp4 videos
-        (other formats may be sent as Document).
-
-        Bots can currently send video files of up to
-        :tg-const:`telegram.constants.FileSizeLimit.FILESIZE_UPLOAD` in size, this limit may be
-        changed in the future.
-
-        Note:
-            :paramref:`thumbnail` will be ignored for small video files, for which Telegram can
-            easily generate thumbnails. However, this behaviour is undocumented and might be
-            changed by Telegram.
-
-        .. seealso:: :wiki:`Working with Files and Media `
-
-        .. versionchanged:: 20.5
-            |removed_thumb_arg|
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            video (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` \
-                | :class:`pathlib.Path` | :class:`telegram.Video`): Video file to send.
-                |fileinput|
-                Lastly you can pass an existing :class:`telegram.Video` object to send.
-
-                .. versionchanged:: 13.2
-                   Accept :obj:`bytes` as input.
-
-                .. versionchanged:: 20.0
-                    File paths as input is also accepted for bots *not* running in
-                    :paramref:`~telegram.Bot.local_mode`.
-            duration (:obj:`int`, optional): Duration of sent video in seconds.
-            width (:obj:`int`, optional): Video width.
-            height (:obj:`int`, optional): Video height.
-            caption (:obj:`str`, optional): Video caption (may also be used when resending videos
-                by file_id), 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH`
-                characters after entities parsing.
-            parse_mode (:obj:`str`, optional): |parse_mode|
-            caption_entities (Sequence[:class:`telegram.MessageEntity`], optional):
-                |caption_entities|
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-            supports_streaming (:obj:`bool`, optional): Pass :obj:`True`, if the uploaded video is
-                suitable for streaming.
-            disable_notification (:obj:`bool`, optional): |disable_notification|
-            protect_content (:obj:`bool`, optional): |protect_content|
-
-                .. versionadded:: 13.10
-            message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
-
-                .. versionadded:: 20.0
-
-            reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \
-                :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional):
-                Additional interface options. An object for an inline keyboard, custom reply
-                keyboard, instructions to remove reply keyboard or to force a reply from the user.
-            has_spoiler (:obj:`bool`, optional): Pass :obj:`True` if the video needs to be covered
-                with a spoiler animation.
-
-                .. versionadded:: 20.0
-            thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
-                optional): |thumbdocstring|
-
-                .. versionadded:: 20.2
-            reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
-
-                .. versionadded:: 20.8
-            business_connection_id (:obj:`str`, optional): |business_id_str|
-
-                .. versionadded:: 21.1
-            message_effect_id (:obj:`str`, optional): |message_effect_id|
-
-                .. versionadded:: 21.3
-            allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast|
-
-                .. versionadded:: 21.7
-            show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
-
-                .. versionadded:: 21.3
-
-        Keyword Args:
-            allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            filename (:obj:`str`, optional): Custom file name for the video, when uploading a
-                new file. Convenience parameter, useful e.g. when sending files generated by the
-                :obj:`tempfile` module.
-
-                .. versionadded:: 13.1
-
-        Returns:
-            :class:`telegram.Message`: On success, the sent Message is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "video": self._parse_file_input(video, Video, filename=filename),
-            "duration": duration,
-            "width": width,
-            "height": height,
-            "supports_streaming": supports_streaming,
-            "thumbnail": self._parse_file_input(thumbnail, attach=True) if thumbnail else None,
-            "has_spoiler": has_spoiler,
-            "show_caption_above_media": show_caption_above_media,
-        }
-
-        return await self._send_message(
-            "sendVideo",
-            data,
-            reply_to_message_id=reply_to_message_id,
-            disable_notification=disable_notification,
-            reply_markup=reply_markup,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            caption=caption,
-            parse_mode=parse_mode,
-            caption_entities=caption_entities,
-            reply_parameters=reply_parameters,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_video_note(
-        self,
-        chat_id: Union[int, str],
-        video_note: Union[FileInput, "VideoNote"],
-        duration: Optional[int] = None,
-        length: Optional[int] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        thumbnail: Optional[FileInput] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        reply_to_message_id: Optional[int] = None,
-        filename: Optional[str] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Message:
-        """
-        As of v.4.0, Telegram clients support rounded square mp4 videos of up to 1 minute long.
-        Use this method to send video messages.
-
-        Note:
-            :paramref:`thumbnail` will be ignored for small video files, for which Telegram can
-            easily generate thumbnails. However, this behaviour is undocumented and might be
-            changed by Telegram.
-
-        .. seealso:: :wiki:`Working with Files and Media `
-
-        .. versionchanged:: 20.5
-            |removed_thumb_arg|
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            video_note (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | \
-                :obj:`bytes` | :class:`pathlib.Path` | :class:`telegram.VideoNote`): Video note
-                to send.
-                Pass a file_id as String to send a video note that exists on the Telegram
-                servers (recommended) or upload a new video using multipart/form-data.
-                |uploadinput|
-                Lastly you can pass an existing :class:`telegram.VideoNote` object to send.
-                Sending video notes by a URL is currently unsupported.
-
-                .. versionchanged:: 13.2
-                   Accept :obj:`bytes` as input.
-
-                .. versionchanged:: 20.0
-                    File paths as input is also accepted for bots *not* running in
-                    :paramref:`~telegram.Bot.local_mode`.
-            duration (:obj:`int`, optional): Duration of sent video in seconds.
-            length (:obj:`int`, optional): Video width and height, i.e. diameter of the video
-                message.
-            disable_notification (:obj:`bool`, optional): |disable_notification|
-            protect_content (:obj:`bool`, optional): |protect_content|
-
-                .. versionadded:: 13.10
-            message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
-
-                .. versionadded:: 20.0
-
-            reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \
-                :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional):
-                Additional interface options. An object for an inline keyboard, custom reply
-                keyboard, instructions to remove reply keyboard or to force a reply from the user.
-            thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
-                optional): |thumbdocstring|
-
-                .. versionadded:: 20.2
-            reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
-
-                .. versionadded:: 20.8
-            business_connection_id (:obj:`str`, optional): |business_id_str|
-
-                .. versionadded:: 21.1
-            message_effect_id (:obj:`str`, optional): |message_effect_id|
-
-                .. versionadded:: 21.3
-            allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast|
-
-                .. versionadded:: 21.7
-
-        Keyword Args:
-            allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            filename (:obj:`str`, optional): Custom file name for the video note, when uploading a
-                new file. Convenience parameter, useful e.g. when sending files generated by the
-                :obj:`tempfile` module.
-
-                .. versionadded:: 13.1
-
-        Returns:
-            :class:`telegram.Message`: On success, the sent Message is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "video_note": self._parse_file_input(video_note, VideoNote, filename=filename),
-            "duration": duration,
-            "length": length,
-            "thumbnail": self._parse_file_input(thumbnail, attach=True) if thumbnail else None,
-        }
-
-        return await self._send_message(
-            "sendVideoNote",
-            data,
-            reply_to_message_id=reply_to_message_id,
-            disable_notification=disable_notification,
-            reply_markup=reply_markup,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            reply_parameters=reply_parameters,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_animation(
-        self,
-        chat_id: Union[int, str],
-        animation: Union[FileInput, "Animation"],
-        duration: Optional[int] = None,
-        width: Optional[int] = None,
-        height: Optional[int] = None,
-        caption: Optional[str] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        has_spoiler: Optional[bool] = None,
-        thumbnail: Optional[FileInput] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        show_caption_above_media: Optional[bool] = None,
-        *,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        reply_to_message_id: Optional[int] = None,
-        filename: Optional[str] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Message:
-        """
-        Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound).
-        Bots can currently send animation files of up to
-        :tg-const:`telegram.constants.FileSizeLimit.FILESIZE_UPLOAD` in size, this limit may be
-        changed in the future.
-
-        Note:
-            :paramref:`thumbnail` will be ignored for small files, for which Telegram can easily
-            generate thumbnails. However, this behaviour is undocumented and might be changed
-            by Telegram.
-
-        .. seealso:: :wiki:`Working with Files and Media `
-
-        .. versionchanged:: 20.5
-            |removed_thumb_arg|
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            animation (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | \
-                :obj:`bytes` | :class:`pathlib.Path` | :class:`telegram.Animation`): Animation to
-                send. |fileinput|
-                Lastly you can pass an existing :class:`telegram.Animation` object to send.
-
-                .. versionchanged:: 13.2
-                   Accept :obj:`bytes` as input.
-            duration (:obj:`int`, optional): Duration of sent animation in seconds.
-            width (:obj:`int`, optional): Animation width.
-            height (:obj:`int`, optional): Animation height.
-            caption (:obj:`str`, optional): Animation caption (may also be used when resending
-                animations by file_id),
-                0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
-                entities parsing.
-            parse_mode (:obj:`str`, optional): |parse_mode|
-            caption_entities (Sequence[:class:`telegram.MessageEntity`], optional):
-                |caption_entities|
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-            disable_notification (:obj:`bool`, optional): |disable_notification|
-            protect_content (:obj:`bool`, optional): |protect_content|
-
-                .. versionadded:: 13.10
-            message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
-
-                .. versionadded:: 20.0
-
-            reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \
-                :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional):
-                Additional interface options. An object for an inline keyboard, custom reply
-                keyboard, instructions to remove reply keyboard or to force a reply from the user.
-            has_spoiler (:obj:`bool`, optional): Pass :obj:`True` if the animation needs to be
-                covered with a spoiler animation.
-
-                .. versionadded:: 20.0
-            thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
-                optional): |thumbdocstring|
-
-                .. versionadded:: 20.2
-            reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
-
-                .. versionadded:: 20.8
-            business_connection_id (:obj:`str`, optional): |business_id_str|
-
-                .. versionadded:: 21.1
-            message_effect_id (:obj:`str`, optional): |message_effect_id|
-
-                .. versionadded:: 21.3
-            allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast|
-
-                .. versionadded:: 21.7
-            show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
-
-                .. versionadded:: 21.3
-
-        Keyword Args:
-            allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            filename (:obj:`str`, optional): Custom file name for the animation, when uploading a
-                new file. Convenience parameter, useful e.g. when sending files generated by the
-                :obj:`tempfile` module.
-
-                .. versionadded:: 13.1
-
-        Returns:
-            :class:`telegram.Message`: On success, the sent Message is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "animation": self._parse_file_input(animation, Animation, filename=filename),
-            "duration": duration,
-            "width": width,
-            "height": height,
-            "thumbnail": self._parse_file_input(thumbnail, attach=True) if thumbnail else None,
-            "has_spoiler": has_spoiler,
-            "show_caption_above_media": show_caption_above_media,
-        }
-
-        return await self._send_message(
-            "sendAnimation",
-            data,
-            reply_to_message_id=reply_to_message_id,
-            disable_notification=disable_notification,
-            reply_markup=reply_markup,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            caption=caption,
-            parse_mode=parse_mode,
-            caption_entities=caption_entities,
-            reply_parameters=reply_parameters,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_voice(
-        self,
-        chat_id: Union[int, str],
-        voice: Union[FileInput, "Voice"],
-        duration: Optional[int] = None,
-        caption: Optional[str] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        reply_to_message_id: Optional[int] = None,
-        filename: Optional[str] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Message:
-        """
-        Use this method to send audio files, if you want Telegram clients to display the file
-        as a playable voice message. For this to work, your audio must be in an ``.ogg`` file
-        encoded with OPUS , or in .MP3 format, or in .M4A format (other formats may be sent as
-        :class:`~telegram.Audio` or :class:`~telegram.Document`). Bots can currently send voice
-        messages of up to :tg-const:`telegram.constants.FileSizeLimit.FILESIZE_UPLOAD` in size,
-        this limit may be changed in the future.
-
-        Note:
-            To use this method, the file must have the type :mimetype:`audio/ogg` and be no more
-            than :tg-const:`telegram.constants.FileSizeLimit.VOICE_NOTE_FILE_SIZE` in size.
-            :tg-const:`telegram.constants.FileSizeLimit.VOICE_NOTE_FILE_SIZE`-
-            :tg-const:`telegram.constants.FileSizeLimit.FILESIZE_DOWNLOAD` voice notes will be
-            sent as files.
-
-        .. seealso:: :wiki:`Working with Files and Media `
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            voice (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` \
-                | :class:`pathlib.Path` | :class:`telegram.Voice`): Voice file to send.
-                |fileinput|
-                Lastly you can pass an existing :class:`telegram.Voice` object to send.
-
-                .. versionchanged:: 13.2
-                   Accept :obj:`bytes` as input.
-
-                .. versionchanged:: 20.0
-                    File paths as input is also accepted for bots *not* running in
-                    :paramref:`~telegram.Bot.local_mode`.
-            caption (:obj:`str`, optional): Voice message caption,
-                0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
-                entities parsing.
-            parse_mode (:obj:`str`, optional): |parse_mode|
-            caption_entities (Sequence[:class:`telegram.MessageEntity`], optional):
-                |caption_entities|
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-            duration (:obj:`int`, optional): Duration of the voice message in seconds.
-            disable_notification (:obj:`bool`, optional): |disable_notification|
-            protect_content (:obj:`bool`, optional): |protect_content|
-
-                .. versionadded:: 13.10
-            message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
-
-                .. versionadded:: 20.0
-
-            reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \
-                :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional):
-                Additional interface options. An object for an inline keyboard, custom reply
-                keyboard, instructions to remove reply keyboard or to force a reply from the user.
-            reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
-
-                .. versionadded:: 20.8
-            business_connection_id (:obj:`str`, optional): |business_id_str|
-
-                .. versionadded:: 21.1
-            message_effect_id (:obj:`str`, optional): |message_effect_id|
-
-                .. versionadded:: 21.3
-            allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast|
-
-                .. versionadded:: 21.7
-
-        Keyword Args:
-            allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            filename (:obj:`str`, optional): Custom file name for the voice, when uploading a
-                new file. Convenience parameter, useful e.g. when sending files generated by the
-                :obj:`tempfile` module.
-
-                .. versionadded:: 13.1
-
-        Returns:
-            :class:`telegram.Message`: On success, the sent Message is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "voice": self._parse_file_input(voice, Voice, filename=filename),
-            "duration": duration,
-        }
-
-        return await self._send_message(
-            "sendVoice",
-            data,
-            reply_to_message_id=reply_to_message_id,
-            disable_notification=disable_notification,
-            reply_markup=reply_markup,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            caption=caption,
-            parse_mode=parse_mode,
-            caption_entities=caption_entities,
-            reply_parameters=reply_parameters,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_media_group(
-        self,
-        chat_id: Union[int, str],
-        media: Sequence[
-            Union["InputMediaAudio", "InputMediaDocument", "InputMediaPhoto", "InputMediaVideo"]
-        ],
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        reply_to_message_id: Optional[int] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-        caption: Optional[str] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-    ) -> tuple[Message, ...]:
-        """Use this method to send a group of photos, videos, documents or audios as an album.
-        Documents and audio files can be only grouped in an album with messages of the same type.
-
-        Note:
-            If you supply a :paramref:`caption` (along with either :paramref:`parse_mode` or
-            :paramref:`caption_entities`), then items in :paramref:`media` must have no captions,
-            and vice versa.
-
-        .. seealso:: :wiki:`Working with Files and Media `
-
-        .. versionchanged:: 20.0
-            Returns a tuple instead of a list.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            media (Sequence[:class:`telegram.InputMediaAudio`,\
-                :class:`telegram.InputMediaDocument`, :class:`telegram.InputMediaPhoto`,\
-                :class:`telegram.InputMediaVideo`]): An array
-                describing messages to be sent, must include
-                :tg-const:`telegram.constants.MediaGroupLimit.MIN_MEDIA_LENGTH`-
-                :tg-const:`telegram.constants.MediaGroupLimit.MAX_MEDIA_LENGTH` items.
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-            disable_notification (:obj:`bool`, optional): |disable_notification|
-            protect_content (:obj:`bool`, optional): |protect_content|
-
-                .. versionadded:: 13.10
-            message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
-
-                .. versionadded:: 20.0
-
-            reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
-
-                .. versionadded:: 20.8
-            business_connection_id (:obj:`str`, optional): |business_id_str|
-
-                .. versionadded:: 21.1
-            message_effect_id (:obj:`str`, optional): |message_effect_id|
-
-                .. versionadded:: 21.3
-            allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast|
-
-                .. versionadded:: 21.7
-
-        Keyword Args:
-            allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            caption (:obj:`str`, optional): Caption that will be added to the
-                first element of :paramref:`media`, so that it will be used as caption for the
-                whole media group.
-                Defaults to :obj:`None`.
-
-                .. versionadded:: 20.0
-            parse_mode (:obj:`str` | :obj:`None`, optional):
-                Parse mode for :paramref:`caption`.
-                See the constants in :class:`telegram.constants.ParseMode` for the
-                available modes.
-
-                .. versionadded:: 20.0
-            caption_entities (Sequence[:class:`telegram.MessageEntity`], optional):
-                List of special entities for :paramref:`caption`,
-                which can be specified instead of :paramref:`parse_mode`.
-                Defaults to :obj:`None`.
-
-                .. versionadded:: 20.0
-
-        Returns:
-            tuple[:class:`telegram.Message`]: An array of the sent Messages.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        if caption and any(
-            [
-                any(item.caption for item in media),
-                any(item.caption_entities for item in media),
-                # if parse_mode was set explicitly, even to None, error must be raised
-                any(item.parse_mode is not DEFAULT_NONE for item in media),
-            ]
-        ):
-            raise ValueError("You can only supply either group caption or media with captions.")
-
-        if caption:
-            # Copy first item (to avoid mutation of original object), apply group caption to it.
-            # This will lead to the group being shown with this caption.
-            item_to_get_caption = copy.copy(media[0])
-            with item_to_get_caption._unfrozen():
-                item_to_get_caption.caption = caption
-                if parse_mode is not DEFAULT_NONE:
-                    item_to_get_caption.parse_mode = parse_mode
-                item_to_get_caption.caption_entities = parse_sequence_arg(caption_entities)
-
-            # copy the list (just the references) to avoid mutating the original list
-            media = list(media)
-            media[0] = item_to_get_caption
-
-        if allow_sending_without_reply is not DEFAULT_NONE and reply_parameters is not None:
-            raise ValueError(
-                "`allow_sending_without_reply` and `reply_parameters` are mutually exclusive."
-            )
-
-        if reply_to_message_id is not None and reply_parameters is not None:
-            raise ValueError(
-                "`reply_to_message_id` and `reply_parameters` are mutually exclusive."
-            )
-
-        if reply_to_message_id is not None:
-            reply_parameters = ReplyParameters(
-                message_id=reply_to_message_id,
-                allow_sending_without_reply=allow_sending_without_reply,
-            )
-
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "media": media,
-            "disable_notification": disable_notification,
-            "protect_content": protect_content,
-            "message_thread_id": message_thread_id,
-            "reply_parameters": reply_parameters,
-            "business_connection_id": business_connection_id,
-            "message_effect_id": message_effect_id,
-            "allow_paid_broadcast": allow_paid_broadcast,
-        }
-
-        result = await self._post(
-            "sendMediaGroup",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-        return Message.de_list(result, self)
-
-    async def send_location(
-        self,
-        chat_id: Union[int, str],
-        latitude: Optional[float] = None,
-        longitude: Optional[float] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        live_period: Optional[int] = None,
-        horizontal_accuracy: Optional[float] = None,
-        heading: Optional[int] = None,
-        proximity_alert_radius: Optional[int] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        reply_to_message_id: Optional[int] = None,
-        location: Optional[Location] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Message:
-        """Use this method to send point on the map.
-
-        Note:
-            You can either supply a :paramref:`latitude` and :paramref:`longitude` or a
-            :paramref:`location`.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            latitude (:obj:`float`, optional): Latitude of location.
-            longitude (:obj:`float`, optional): Longitude of location.
-            horizontal_accuracy (:obj:`int`, optional): The radius of uncertainty for the location,
-                measured in meters;
-                0-:tg-const:`telegram.constants.LocationLimit.HORIZONTAL_ACCURACY`.
-            live_period (:obj:`int`, optional): Period in seconds for which the location will be
-                updated, should be between
-                :tg-const:`telegram.constants.LocationLimit.MIN_LIVE_PERIOD` and
-                :tg-const:`telegram.constants.LocationLimit.MAX_LIVE_PERIOD`, or
-                :tg-const:`telegram.constants.LocationLimit.LIVE_PERIOD_FOREVER` for live
-                locations that can be edited indefinitely.
-            heading (:obj:`int`, optional): For live locations, a direction in which the user is
-                moving, in degrees. Must be between
-                :tg-const:`telegram.constants.LocationLimit.MIN_HEADING` and
-                :tg-const:`telegram.constants.LocationLimit.MAX_HEADING` if specified.
-            proximity_alert_radius (:obj:`int`, optional): For live locations, a maximum distance
-                for proximity alerts about approaching another chat member, in meters. Must be
-                between :tg-const:`telegram.constants.LocationLimit.MIN_PROXIMITY_ALERT_RADIUS`
-                and :tg-const:`telegram.constants.LocationLimit.MAX_PROXIMITY_ALERT_RADIUS`
-                if specified.
-            disable_notification (:obj:`bool`, optional): |disable_notification|
-            protect_content (:obj:`bool`, optional): |protect_content|
-
-                .. versionadded:: 13.10
-            message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
-
-                .. versionadded:: 20.0
-
-            reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \
-                :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional):
-                Additional interface options. An object for an inline keyboard, custom reply
-                keyboard, instructions to remove reply keyboard or to force a reply from the user.
-            reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
-
-                .. versionadded:: 20.8
-            business_connection_id (:obj:`str`, optional): |business_id_str|
-
-                .. versionadded:: 21.1
-            message_effect_id (:obj:`str`, optional): |message_effect_id|
-
-                .. versionadded:: 21.3
-            allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast|
-
-                .. versionadded:: 21.7
-
-        Keyword Args:
-            allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            location (:class:`telegram.Location`, optional): The location to send.
-
-        Returns:
-            :class:`telegram.Message`: On success, the sent Message is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        if not ((latitude is not None and longitude is not None) or location):
-            raise ValueError(
-                "Either location or latitude and longitude must be passed as argument."
-            )
-
-        if not (latitude is not None or longitude is not None) ^ bool(location):
-            raise ValueError(
-                "Either location or latitude and longitude must be passed as argument. Not both."
-            )
-
-        if isinstance(location, Location):
-            latitude = location.latitude
-            longitude = location.longitude
-
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "latitude": latitude,
-            "longitude": longitude,
-            "horizontal_accuracy": horizontal_accuracy,
-            "live_period": live_period,
-            "heading": heading,
-            "proximity_alert_radius": proximity_alert_radius,
-        }
-
-        return await self._send_message(
-            "sendLocation",
-            data,
-            reply_to_message_id=reply_to_message_id,
-            disable_notification=disable_notification,
-            reply_markup=reply_markup,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            reply_parameters=reply_parameters,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def edit_message_live_location(
-        self,
-        chat_id: Optional[Union[str, int]] = None,
-        message_id: Optional[int] = None,
-        inline_message_id: Optional[str] = None,
-        latitude: Optional[float] = None,
-        longitude: Optional[float] = None,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        horizontal_accuracy: Optional[float] = None,
-        heading: Optional[int] = None,
-        proximity_alert_radius: Optional[int] = None,
-        live_period: Optional[int] = None,
-        business_connection_id: Optional[str] = None,
-        *,
-        location: Optional[Location] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Union[Message, bool]:
-        """Use this method to edit live location messages sent by the bot or via the bot
-        (for inline bots). A location can be edited until its :attr:`telegram.Location.live_period`
-        expires or editing is explicitly disabled by a call to :meth:`stop_message_live_location`.
-
-        Note:
-            You can either supply a :paramref:`latitude` and :paramref:`longitude` or a
-            :paramref:`location`.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`, optional): Required if :paramref:`inline_message_id`
-                is not specified. |chat_id_channel|
-            message_id (:obj:`int`, optional): Required if :paramref:`inline_message_id` is not
-                specified. Identifier of the message to edit.
-            inline_message_id (:obj:`str`, optional): Required if :paramref:`chat_id` and
-                :paramref:`message_id` are not specified. Identifier of the inline message.
-            latitude (:obj:`float`, optional): Latitude of location.
-            longitude (:obj:`float`, optional): Longitude of location.
-            horizontal_accuracy (:obj:`float`, optional): The radius of uncertainty for the
-                location, measured in meters;
-                0-:tg-const:`telegram.constants.LocationLimit.HORIZONTAL_ACCURACY`.
-            heading (:obj:`int`, optional): Direction in which the user is moving, in degrees. Must
-                be between :tg-const:`telegram.constants.LocationLimit.MIN_HEADING`
-                and :tg-const:`telegram.constants.LocationLimit.MAX_HEADING` if specified.
-            proximity_alert_radius (:obj:`int`, optional): Maximum distance for proximity alerts
-                about approaching another chat member, in meters. Must be between
-                :tg-const:`telegram.constants.LocationLimit.MIN_PROXIMITY_ALERT_RADIUS`
-                and :tg-const:`telegram.constants.LocationLimit.MAX_PROXIMITY_ALERT_RADIUS`
-                if specified.
-            reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for a new
-                inline keyboard.
-            live_period (:obj:`int`, optional): New period in seconds during which the location
-                can be updated, starting from the message send date. If
-                :tg-const:`telegram.constants.LocationLimit.LIVE_PERIOD_FOREVER` is specified,
-                then the location can be updated forever. Otherwise, the new value must not exceed
-                the current ``live_period`` by more than a day, and the live location expiration
-                date must remain within the next 90 days. If not specified, then ``live_period``
-                remains unchanged
-
-                .. versionadded:: 21.2.
-            business_connection_id (:obj:`str`, optional): |business_id_str_edit|
-
-                .. versionadded:: 21.4
-
-        Keyword Args:
-            location (:class:`telegram.Location`, optional): The location to send.
-
-        Returns:
-            :class:`telegram.Message`: On success, if edited message is not an inline message, the
-            edited message is returned, otherwise :obj:`True` is returned.
-        """
-        # The location parameter is a convenience functionality added by us, so enforcing the
-        # mutual exclusivity here is nothing that Telegram would handle anyway
-        if not (all([latitude, longitude]) or location):
-            raise ValueError(
-                "Either location or latitude and longitude must be passed as argument."
-            )
-        if not (latitude is not None or longitude is not None) ^ bool(location):
-            raise ValueError(
-                "Either location or latitude and longitude must be passed as argument. Not both."
-            )
-
-        if isinstance(location, Location):
-            latitude = location.latitude
-            longitude = location.longitude
-
-        data: JSONDict = {
-            "latitude": latitude,
-            "longitude": longitude,
-            "chat_id": chat_id,
-            "message_id": message_id,
-            "inline_message_id": inline_message_id,
-            "horizontal_accuracy": horizontal_accuracy,
-            "heading": heading,
-            "proximity_alert_radius": proximity_alert_radius,
-            "live_period": live_period,
-        }
-
-        return await self._send_message(
-            "editMessageLiveLocation",
-            data,
-            reply_markup=reply_markup,
-            business_connection_id=business_connection_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def stop_message_live_location(
-        self,
-        chat_id: Optional[Union[str, int]] = None,
-        message_id: Optional[int] = None,
-        inline_message_id: Optional[str] = None,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        business_connection_id: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Union[Message, bool]:
-        """Use this method to stop updating a live location message sent by the bot or via the bot
-        (for inline bots) before :paramref:`~telegram.Location.live_period` expires.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`, optional): Required if :paramref:`inline_message_id`
-                is not specified. |chat_id_channel|
-            message_id (:obj:`int`, optional): Required if :paramref:`inline_message_id` is not
-                specified. Identifier of the sent message with live location to stop.
-            inline_message_id (:obj:`str`, optional): Required if :paramref:`chat_id` and
-                :paramref:`message_id` are not specified. Identifier of the inline message.
-            reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for a new
-                inline keyboard.
-            business_connection_id (:obj:`str`, optional): |business_id_str_edit|
-
-                .. versionadded:: 21.4
-
-        Returns:
-            :class:`telegram.Message`: On success, if edited message is not an inline message, the
-            edited message is returned, otherwise :obj:`True` is returned.
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "message_id": message_id,
-            "inline_message_id": inline_message_id,
-        }
-
-        return await self._send_message(
-            "stopMessageLiveLocation",
-            data,
-            reply_markup=reply_markup,
-            business_connection_id=business_connection_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def send_venue(
-        self,
-        chat_id: Union[int, str],
-        latitude: Optional[float] = None,
-        longitude: Optional[float] = None,
-        title: Optional[str] = None,
-        address: Optional[str] = None,
-        foursquare_id: Optional[str] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        foursquare_type: Optional[str] = None,
-        google_place_id: Optional[str] = None,
-        google_place_type: Optional[str] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        reply_to_message_id: Optional[int] = None,
-        venue: Optional[Venue] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Message:
-        """Use this method to send information about a venue.
-
-        Note:
-            * You can either supply :paramref:`venue`, or :paramref:`latitude`,
-              :paramref:`longitude`, :paramref:`title` and :paramref:`address` and optionally
-              :paramref:`foursquare_id` and :paramref:`foursquare_type` or optionally
-              :paramref:`google_place_id` and :paramref:`google_place_type`.
-            * Foursquare details and Google Place details are mutually exclusive. However, this
-              behaviour is undocumented and might be changed by Telegram.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            latitude (:obj:`float`, optional): Latitude of venue.
-            longitude (:obj:`float`, optional): Longitude of venue.
-            title (:obj:`str`, optional): Name of the venue.
-            address (:obj:`str`, optional): Address of the venue.
-            foursquare_id (:obj:`str`, optional): Foursquare identifier of the venue.
-            foursquare_type (:obj:`str`, optional): Foursquare type of the venue, if known.
-                (For example, "arts_entertainment/default", "arts_entertainment/aquarium" or
-                "food/icecream".)
-            google_place_id (:obj:`str`, optional): Google Places identifier of the venue.
-            google_place_type (:obj:`str`, optional): Google Places type of the venue. (See
-                `supported types \
-                `_.)
-            disable_notification (:obj:`bool`, optional): |disable_notification|
-            protect_content (:obj:`bool`, optional): |protect_content|
-
-                .. versionadded:: 13.10
-            message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
-
-                .. versionadded:: 20.0
-
-            reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \
-                :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional):
-                Additional interface options. An object for an inline keyboard, custom reply
-                keyboard, instructions to remove reply keyboard or to force a reply from the user.
-            reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
-
-                .. versionadded:: 20.8
-            business_connection_id (:obj:`str`, optional): |business_id_str|
-
-                .. versionadded:: 21.1
-            message_effect_id (:obj:`str`, optional): |message_effect_id|
-
-                .. versionadded:: 21.3
-            allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast|
-
-                .. versionadded:: 21.7
-
-        Keyword Args:
-            allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            venue (:class:`telegram.Venue`, optional): The venue to send.
-
-        Returns:
-            :class:`telegram.Message`: On success, the sent Message is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        # The venue parameter is a convenience functionality added by us, so enforcing the
-        # mutual exclusivity here is nothing that Telegram would handle anyway
-        if not (venue or all([latitude, longitude, address, title])):
-            raise ValueError(
-                "Either venue or latitude, longitude, address and title must be "
-                "passed as arguments."
-            )
-        if not bool(venue) ^ any([latitude, longitude, address, title]):
-            raise ValueError(
-                "Either venue or latitude, longitude, address and title must be "
-                "passed as arguments. Not both."
-            )
-
-        if isinstance(venue, Venue):
-            latitude = venue.location.latitude
-            longitude = venue.location.longitude
-            address = venue.address
-            title = venue.title
-            foursquare_id = venue.foursquare_id
-            foursquare_type = venue.foursquare_type
-            google_place_id = venue.google_place_id
-            google_place_type = venue.google_place_type
-
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "latitude": latitude,
-            "longitude": longitude,
-            "address": address,
-            "title": title,
-            "foursquare_id": foursquare_id,
-            "foursquare_type": foursquare_type,
-            "google_place_id": google_place_id,
-            "google_place_type": google_place_type,
-        }
-
-        return await self._send_message(
-            "sendVenue",
-            data,
-            reply_to_message_id=reply_to_message_id,
-            disable_notification=disable_notification,
-            reply_markup=reply_markup,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            reply_parameters=reply_parameters,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_contact(
-        self,
-        chat_id: Union[int, str],
-        phone_number: Optional[str] = None,
-        first_name: Optional[str] = None,
-        last_name: Optional[str] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        vcard: Optional[str] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        reply_to_message_id: Optional[int] = None,
-        contact: Optional[Contact] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Message:
-        """Use this method to send phone contacts.
-
-        Note:
-            You can either supply :paramref:`contact` or :paramref:`phone_number` and
-            :paramref:`first_name` with optionally :paramref:`last_name` and optionally
-            :paramref:`vcard`.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            phone_number (:obj:`str`, optional): Contact's phone number.
-            first_name (:obj:`str`, optional): Contact's first name.
-            last_name (:obj:`str`, optional): Contact's last name.
-            vcard (:obj:`str`, optional): Additional data about the contact in the form of a vCard,
-                0-:tg-const:`telegram.constants.ContactLimit.VCARD` bytes.
-            disable_notification (:obj:`bool`, optional): |disable_notification|
-            protect_content (:obj:`bool`, optional): |protect_content|
-
-                .. versionadded:: 13.10
-            message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
-
-                .. versionadded:: 20.0
-
-            reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \
-                :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional):
-                Additional interface options. An object for an inline keyboard, custom reply
-                keyboard, instructions to remove reply keyboard or to force a reply from the user.
-            reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
-
-                .. versionadded:: 20.8
-            business_connection_id (:obj:`str`, optional): |business_id_str|
-
-                .. versionadded:: 21.1
-            message_effect_id (:obj:`str`, optional): |message_effect_id|
-
-                .. versionadded:: 21.3
-            allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast|
-
-                .. versionadded:: 21.7
-
-        Keyword Args:
-            allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            contact (:class:`telegram.Contact`, optional): The contact to send.
-
-        Returns:
-            :class:`telegram.Message`: On success, the sent Message is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        # The contact parameter is a convenience functionality added by us, so enforcing the
-        # mutual exclusivity here is nothing that Telegram would handle anyway
-        if (not contact) and (not all([phone_number, first_name])):
-            raise ValueError(
-                "Either contact or phone_number and first_name must be passed as arguments."
-            )
-        if not bool(contact) ^ any([phone_number, first_name]):
-            raise ValueError(
-                "Either contact or phone_number and first_name must be passed as arguments. "
-                "Not both."
-            )
-
-        if isinstance(contact, Contact):
-            phone_number = contact.phone_number
-            first_name = contact.first_name
-            last_name = contact.last_name
-            vcard = contact.vcard
-
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "phone_number": phone_number,
-            "first_name": first_name,
-            "last_name": last_name,
-            "vcard": vcard,
-        }
-
-        return await self._send_message(
-            "sendContact",
-            data,
-            reply_to_message_id=reply_to_message_id,
-            disable_notification=disable_notification,
-            reply_markup=reply_markup,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            reply_parameters=reply_parameters,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_game(
-        self,
-        chat_id: int,
-        game_short_name: str,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        reply_to_message_id: Optional[int] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Message:
-        """Use this method to send a game.
-
-        Args:
-            chat_id (:obj:`int`): Unique identifier for the target chat.
-            game_short_name (:obj:`str`): Short name of the game, serves as the unique identifier
-                for the game. Set up your games via `@BotFather `_.
-            disable_notification (:obj:`bool`, optional): |disable_notification|
-            protect_content (:obj:`bool`, optional): |protect_content|
-
-                .. versionadded:: 13.10
-            message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
-
-                .. versionadded:: 20.0
-
-            reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for a new
-                inline keyboard. If empty, one "Play game_title" button will be
-                shown. If not empty, the first button must launch the game.
-            reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
-
-                .. versionadded:: 20.8
-            business_connection_id (:obj:`str`, optional): |business_id_str|
-
-                .. versionadded:: 21.1
-            message_effect_id (:obj:`str`, optional): |message_effect_id|
-
-                .. versionadded:: 21.3
-            allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast|
-
-                .. versionadded:: 21.7
-
-        Keyword Args:
-            allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-
-        Returns:
-            :class:`telegram.Message`: On success, the sent Message is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"chat_id": chat_id, "game_short_name": game_short_name}
-
-        return await self._send_message(
-            "sendGame",
-            data,
-            reply_to_message_id=reply_to_message_id,
-            disable_notification=disable_notification,
-            reply_markup=reply_markup,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            reply_parameters=reply_parameters,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_chat_action(
-        self,
-        chat_id: Union[str, int],
-        action: str,
-        message_thread_id: Optional[int] = None,
-        business_connection_id: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method when you need to tell the user that something is happening on the bot's
-        side. The status is set for 5 seconds or less (when a message arrives from your bot,
-        Telegram clients clear its typing status). Telegram only recommends using this method when
-        a response from the bot will take a noticeable amount of time to arrive.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            action(:obj:`str`): Type of action to broadcast. Choose one, depending on what the user
-                is about to receive. For convenience look at the constants in
-                :class:`telegram.constants.ChatAction`.
-            message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
-
-                .. versionadded:: 20.0
-            business_connection_id (:obj:`str`, optional): |business_id_str|
-
-                .. versionadded:: 21.1
-
-        Returns:
-            :obj:`bool`:  On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "action": action,
-            "message_thread_id": message_thread_id,
-            "business_connection_id": business_connection_id,
-        }
-        return await self._post(
-            "sendChatAction",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    def _effective_inline_results(
-        self,
-        results: Union[
-            Sequence["InlineQueryResult"], Callable[[int], Optional[Sequence["InlineQueryResult"]]]
-        ],
-        next_offset: Optional[str] = None,
-        current_offset: Optional[str] = None,
-    ) -> tuple[Sequence["InlineQueryResult"], Optional[str]]:
-        """
-        Builds the effective results from the results input.
-        We make this a stand-alone method so tg.ext.ExtBot can wrap it.
-
-        Returns:
-            Tuple of 1. the effective results and 2. correct the next_offset
-
-        """
-        if current_offset is not None and next_offset is not None:
-            raise ValueError("`current_offset` and `next_offset` are mutually exclusive!")
-
-        if current_offset is not None:
-            # Convert the string input to integer
-            current_offset_int = 0 if not current_offset else int(current_offset)
-
-            # for now set to empty string, stating that there are no more results
-            # might change later
-            next_offset = ""
-
-            if callable(results):
-                callable_output = results(current_offset_int)
-                if not callable_output:
-                    effective_results: Sequence[InlineQueryResult] = []
-                else:
-                    effective_results = callable_output
-                    # the callback *might* return more results on the next call, so we increment
-                    # the page count
-                    next_offset = str(current_offset_int + 1)
-
-            elif len(results) > (current_offset_int + 1) * InlineQueryLimit.RESULTS:
-                # we expect more results for the next page
-                next_offset_int = current_offset_int + 1
-                next_offset = str(next_offset_int)
-                effective_results = results[
-                    current_offset_int
-                    * InlineQueryLimit.RESULTS : next_offset_int
-                    * InlineQueryLimit.RESULTS
-                ]
-            else:
-                effective_results = results[current_offset_int * InlineQueryLimit.RESULTS :]
-        else:
-            effective_results = results  # type: ignore[assignment]
-
-        return effective_results, next_offset
-
-    @no_type_check  # mypy doesn't play too well with hasattr
-    def _insert_defaults_for_ilq_results(self, res: "InlineQueryResult") -> "InlineQueryResult":
-        """The reason why this method exists is similar to the description of _insert_defaults
-        The reason why we do this in rather than in _insert_defaults is because converting
-        DEFAULT_NONE to NONE *before* calling to_dict() makes it way easier to drop None entries
-        from the json data.
-
-        Must return the correct object instead of editing in-place!
-        """
-        # Copy the objects that need modification to avoid modifying the original object
-        copied = False
-        if hasattr(res, "parse_mode"):
-            res = copy.copy(res)
-            copied = True
-            with res._unfrozen():
-                res.parse_mode = DefaultValue.get_value(res.parse_mode)
-        if hasattr(res, "input_message_content") and res.input_message_content:
-            if hasattr(res.input_message_content, "parse_mode"):
-                if not copied:
-                    res = copy.copy(res)
-                    copied = True
-
-                with res._unfrozen():
-                    res.input_message_content = copy.copy(res.input_message_content)
-                with res.input_message_content._unfrozen():
-                    res.input_message_content.parse_mode = DefaultValue.get_value(
-                        res.input_message_content.parse_mode
-                    )
-            if hasattr(res.input_message_content, "link_preview_options"):
-                if not copied:
-                    res = copy.copy(res)
-
-                with res._unfrozen():
-                    res.input_message_content = copy.copy(res.input_message_content)
-                with res.input_message_content._unfrozen():
-                    res.input_message_content.link_preview_options = DefaultValue.get_value(
-                        res.input_message_content.link_preview_options
-                    )
-
-        return res
-
-    async def answer_inline_query(
-        self,
-        inline_query_id: str,
-        results: Union[
-            Sequence["InlineQueryResult"], Callable[[int], Optional[Sequence["InlineQueryResult"]]]
-        ],
-        cache_time: Optional[int] = None,
-        is_personal: Optional[bool] = None,
-        next_offset: Optional[str] = None,
-        button: Optional[InlineQueryResultsButton] = None,
-        *,
-        current_offset: Optional[str] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to send answers to an inline query. No more than
-        :tg-const:`telegram.InlineQuery.MAX_RESULTS` results per query are allowed.
-
-        Warning:
-            In most use cases :paramref:`current_offset` should not be passed manually. Instead of
-            calling this method directly, use the shortcut :meth:`telegram.InlineQuery.answer` with
-            :paramref:`telegram.InlineQuery.answer.auto_pagination` set to :obj:`True`, which will
-            take care of passing the correct value.
-
-        .. seealso:: :wiki:`Working with Files and Media `
-
-
-        .. versionchanged:: 20.5
-           Removed deprecated arguments ``switch_pm_text`` and ``switch_pm_parameter``.
-
-        Args:
-            inline_query_id (:obj:`str`): Unique identifier for the answered query.
-            results (list[:class:`telegram.InlineQueryResult`] | Callable): A list of results for
-                the inline query. In case :paramref:`current_offset` is passed,
-                :paramref:`results` may also be
-                a callable that accepts the current page index starting from 0. It must return
-                either a list of :class:`telegram.InlineQueryResult` instances or :obj:`None` if
-                there are no more results.
-            cache_time (:obj:`int`, optional): The maximum amount of time in seconds that the
-                result of the inline query may be cached on the server. Defaults to ``300``.
-            is_personal (:obj:`bool`, optional): Pass :obj:`True`, if results may be cached on
-                the server side only for the user that sent the query. By default,
-                results may be returned to any user who sends the same query.
-            next_offset (:obj:`str`, optional): Pass the offset that a client should send in the
-                next query with the same text to receive more results. Pass an empty string if
-                there are no more results or if you don't support pagination. Offset length can't
-                exceed :tg-const:`telegram.InlineQuery.MAX_OFFSET_LENGTH` bytes.
-            button (:class:`telegram.InlineQueryResultsButton`, optional): A button to be shown
-                above the inline query results.
-
-                .. versionadded:: 20.3
-
-        Keyword Args:
-            current_offset (:obj:`str`, optional): The :attr:`telegram.InlineQuery.offset` of
-                the inline query to answer. If passed, PTB will automatically take care of
-                the pagination for you, i.e. pass the correct :paramref:`next_offset` and truncate
-                the results list/get the results from the callable you passed.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        effective_results, next_offset = self._effective_inline_results(
-            results=results, next_offset=next_offset, current_offset=current_offset
-        )
-
-        # Apply defaults
-        effective_results = [
-            self._insert_defaults_for_ilq_results(result) for result in effective_results
-        ]
-
-        data: JSONDict = {
-            "inline_query_id": inline_query_id,
-            "results": effective_results,
-            "next_offset": next_offset,
-            "cache_time": cache_time,
-            "is_personal": is_personal,
-            "button": button,
-        }
-
-        return await self._post(
-            "answerInlineQuery",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def save_prepared_inline_message(
-        self,
-        user_id: int,
-        result: "InlineQueryResult",
-        allow_user_chats: Optional[bool] = None,
-        allow_bot_chats: Optional[bool] = None,
-        allow_group_chats: Optional[bool] = None,
-        allow_channel_chats: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> PreparedInlineMessage:
-        """Stores a message that can be sent by a user of a Mini App.
-
-        .. versionadded:: 21.8
-
-        Args:
-            user_id (:obj:`int`): Unique identifier of the target user that can use the prepared
-                message.
-            result (:class:`telegram.InlineQueryResult`): The result to store.
-            allow_user_chats (:obj:`bool`, optional): Pass :obj:`True` if the message can be sent
-                to private chats with users
-            allow_bot_chats (:obj:`bool`, optional): Pass :obj:`True` if the message can be sent
-                to private chats with bots
-            allow_group_chats (:obj:`bool`, optional): Pass :obj:`True` if the message can be sent
-                to group and supergroup chats
-            allow_channel_chats (:obj:`bool`, optional): Pass :obj:`True` if the message can be
-                sent to channels
-
-        Returns:
-            :class:`telegram.PreparedInlineMessage`: On success, the prepared message is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {
-            "user_id": user_id,
-            "result": result,
-            "allow_user_chats": allow_user_chats,
-            "allow_bot_chats": allow_bot_chats,
-            "allow_group_chats": allow_group_chats,
-            "allow_channel_chats": allow_channel_chats,
-        }
-        return PreparedInlineMessage.de_json(  # type: ignore[return-value]
-            await self._post(
-                "savePreparedInlineMessage",
-                data,
-                read_timeout=read_timeout,
-                write_timeout=write_timeout,
-                connect_timeout=connect_timeout,
-                pool_timeout=pool_timeout,
-                api_kwargs=api_kwargs,
-            ),
-            self,
-        )
-
-    async def get_user_profile_photos(
-        self,
-        user_id: int,
-        offset: Optional[int] = None,
-        limit: Optional[int] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> UserProfilePhotos:
-        """Use this method to get a list of profile pictures for a user.
-
-        Args:
-            user_id (:obj:`int`): Unique identifier of the target user.
-            offset (:obj:`int`, optional): Sequential number of the first photo to be returned.
-                By default, all photos are returned.
-            limit (:obj:`int`, optional): Limits the number of photos to be retrieved. Values
-                between :tg-const:`telegram.constants.UserProfilePhotosLimit.MIN_LIMIT`-
-                :tg-const:`telegram.constants.UserProfilePhotosLimit.MAX_LIMIT` are accepted.
-                Defaults to ``100``.
-
-        Returns:
-            :class:`telegram.UserProfilePhotos`
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"user_id": user_id, "offset": offset, "limit": limit}
-
-        result = await self._post(
-            "getUserProfilePhotos",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-        return UserProfilePhotos.de_json(result, self)  # type: ignore[return-value]
-
-    async def get_file(
-        self,
-        file_id: Union[
-            str, Animation, Audio, ChatPhoto, Document, PhotoSize, Sticker, Video, VideoNote, Voice
-        ],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> File:
-        """
-        Use this method to get basic info about a file and prepare it for downloading. For the
-        moment, bots can download files of up to
-        :tg-const:`telegram.constants.FileSizeLimit.FILESIZE_DOWNLOAD` in size. The file can then
-        be e.g. downloaded with :meth:`telegram.File.download_to_drive`. It is guaranteed that
-        the link will be valid for at least 1 hour. When the link expires, a new one can be
-        requested by calling get_file again.
-
-        Note:
-            This function may not preserve the original file name and MIME type.
-            You should save the file's MIME type and name (if available) when the File object
-            is received.
-
-        .. seealso:: :wiki:`Working with Files and Media `
-
-        Args:
-            file_id (:obj:`str` | :class:`telegram.Animation` | :class:`telegram.Audio` |         \
-                     :class:`telegram.ChatPhoto` | :class:`telegram.Document` |                   \
-                     :class:`telegram.PhotoSize` | :class:`telegram.Sticker` |                    \
-                     :class:`telegram.Video` | :class:`telegram.VideoNote` |                      \
-                     :class:`telegram.Voice`):
-                Either the file identifier or an object that has a file_id attribute
-                to get file information about.
-
-        Returns:
-            :class:`telegram.File`
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        # Try to get the file_id from the object, if it fails, assume it's a string
-        with contextlib.suppress(AttributeError):
-            file_id = file_id.file_id  # type: ignore[union-attr]
-
-        data: JSONDict = {"file_id": file_id}
-
-        result = await self._post(
-            "getFile",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-        file_path = cast(dict, result).get("file_path")
-        if file_path and not is_local_file(file_path):
-            result["file_path"] = f"{self._base_file_url}/{file_path}"
-
-        return File.de_json(result, self)  # type: ignore[return-value]
-
-    async def ban_chat_member(
-        self,
-        chat_id: Union[str, int],
-        user_id: int,
-        until_date: Optional[Union[int, dtm.datetime]] = None,
-        revoke_messages: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to ban a user from a group, supergroup or a channel. In the case of
-        supergroups and channels, the user will not be able to return to the group on their own
-        using invite links, etc., unless unbanned first. The bot must be an administrator in the
-        chat for this to work and must have the appropriate admin rights.
-
-        .. versionadded:: 13.7
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target group or username
-                of the target supergroup or channel (in the format ``@channelusername``).
-            user_id (:obj:`int`): Unique identifier of the target user.
-            until_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when the user will
-                be unbanned, unix time. If user is banned for more than 366 days or less than 30
-                seconds from the current time they are considered to be banned forever. Applied
-                for supergroups and channels only.
-                |tz-naive-dtms|
-            revoke_messages (:obj:`bool`, optional): Pass :obj:`True` to delete all messages from
-                the chat for the user that is being removed. If :obj:`False`, the user will be able
-                to see messages in the group that were sent before the user was removed.
-                Always :obj:`True` for supergroups and channels.
-
-                .. versionadded:: 13.4
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "user_id": user_id,
-            "revoke_messages": revoke_messages,
-            "until_date": until_date,
-        }
-
-        return await self._post(
-            "banChatMember",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def ban_chat_sender_chat(
-        self,
-        chat_id: Union[str, int],
-        sender_chat_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to ban a channel chat in a supergroup or a channel. Until the chat is
-        unbanned, the owner of the banned chat won't be able to send messages on behalf of **any of
-        their channels**. The bot must be an administrator in the supergroup or channel for this
-        to work and must have the appropriate administrator rights.
-
-        .. versionadded:: 13.9
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target group or username
-                of the target supergroup or channel (in the format ``@channelusername``).
-            sender_chat_id (:obj:`int`): Unique identifier of the target sender chat.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"chat_id": chat_id, "sender_chat_id": sender_chat_id}
-
-        return await self._post(
-            "banChatSenderChat",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def unban_chat_member(
-        self,
-        chat_id: Union[str, int],
-        user_id: int,
-        only_if_banned: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Use this method to unban a previously kicked user in a supergroup or channel.
-
-        The user will *not* return to the group or channel automatically, but will be able to join
-        via link, etc. The bot must be an administrator for this to work. By default, this method
-        guarantees that after the call the user is not a member of the chat, but will be able to
-        join it. So if the user is a member of the chat they will also be *removed* from the chat.
-        If you don't want this, use the parameter :paramref:`only_if_banned`.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            user_id (:obj:`int`): Unique identifier of the target user.
-            only_if_banned (:obj:`bool`, optional): Do nothing if the user is not banned.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"chat_id": chat_id, "user_id": user_id, "only_if_banned": only_if_banned}
-
-        return await self._post(
-            "unbanChatMember",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def unban_chat_sender_chat(
-        self,
-        chat_id: Union[str, int],
-        sender_chat_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Use this method to unban a previously banned channel in a supergroup or channel.
-        The bot must be an administrator for this to work and must have the
-        appropriate administrator rights.
-
-        .. versionadded:: 13.9
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            sender_chat_id (:obj:`int`): Unique identifier of the target sender chat.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"chat_id": chat_id, "sender_chat_id": sender_chat_id}
-
-        return await self._post(
-            "unbanChatSenderChat",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def answer_callback_query(
-        self,
-        callback_query_id: str,
-        text: Optional[str] = None,
-        show_alert: Optional[bool] = None,
-        url: Optional[str] = None,
-        cache_time: Optional[int] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to send answers to callback queries sent from inline keyboards. The answer
-        will be displayed to the user as a notification at the top of the chat screen or as an
-        alert.
-        Alternatively, the user can be redirected to the specified Game URL. For this option to
-        work, you must first create a game for your bot via `@BotFather `_
-        and accept the terms. Otherwise, you may use links like t.me/your_bot?start=XXXX that open
-        your bot with a parameter.
-
-        Args:
-            callback_query_id (:obj:`str`): Unique identifier for the query to be answered.
-            text (:obj:`str`, optional): Text of the notification. If not specified, nothing will
-                be shown to the user, 0-:tg-const:`telegram.CallbackQuery.MAX_ANSWER_TEXT_LENGTH`
-                characters.
-            show_alert (:obj:`bool`, optional): If :obj:`True`, an alert will be shown by the
-                client instead of a notification at the top of the chat screen. Defaults to
-                :obj:`False`.
-            url (:obj:`str`, optional): URL that will be opened by the user's client. If you have
-                created a Game and accepted the conditions via
-                `@BotFather `_, specify the URL that
-                opens your game - note that this will only work if the query comes from a callback
-                game button. Otherwise, you may use links like t.me/your_bot?start=XXXX that open
-                your bot with a parameter.
-            cache_time (:obj:`int`, optional): The maximum amount of time in seconds that the
-                result of the callback query may be cached client-side. Defaults to 0.
-
-        Returns:
-            :obj:`bool` On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "callback_query_id": callback_query_id,
-            "cache_time": cache_time,
-            "text": text,
-            "show_alert": show_alert,
-            "url": url,
-        }
-
-        return await self._post(
-            "answerCallbackQuery",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def edit_message_text(
-        self,
-        text: str,
-        chat_id: Optional[Union[str, int]] = None,
-        message_id: Optional[int] = None,
-        inline_message_id: Optional[str] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        entities: Optional[Sequence["MessageEntity"]] = None,
-        link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE,
-        business_connection_id: Optional[str] = None,
-        *,
-        disable_web_page_preview: Optional[bool] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Union[Message, bool]:
-        """
-        Use this method to edit text and game messages.
-
-        Note:
-            * |editreplymarkup|
-            * |bcid_edit_time|
-
-        .. seealso:: :attr:`telegram.Game.text`
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`, optional): Required if :paramref:`inline_message_id`
-                is not specified. |chat_id_channel|
-            message_id (:obj:`int`, optional): Required if :paramref:`inline_message_id` is not
-                specified. Identifier of the message to edit.
-            inline_message_id (:obj:`str`, optional): Required if :paramref:`chat_id` and
-                :paramref:`message_id` are not specified. Identifier of the inline message.
-            text (:obj:`str`): New text of the message,
-                :tg-const:`telegram.constants.MessageLimit.MIN_TEXT_LENGTH`-
-                :tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters after
-                entities parsing.
-            parse_mode (:obj:`str`, optional): |parse_mode|
-            entities (Sequence[:class:`telegram.MessageEntity`], optional): Sequence of special
-                entities that appear in message text, which can be specified instead of
-                :paramref:`parse_mode`.
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-
-            link_preview_options (:obj:`LinkPreviewOptions`, optional): Link preview generation
-                options for the message. Mutually exclusive with
-                :paramref:`disable_web_page_preview`.
-
-                .. versionadded:: 20.8
-
-            reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for an
-                inline keyboard.
-            business_connection_id (:obj:`str`, optional): |business_id_str_edit|
-
-                .. versionadded:: 21.4
-
-        Keyword Args:
-            disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in
-                this message. Convenience parameter for setting :paramref:`link_preview_options`.
-                Mutually exclusive with :paramref:`link_preview_options`.
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`link_preview_options` replacing this
-                    argument. PTB will automatically convert this argument to that one, but
-                    for advanced options, please use :paramref:`link_preview_options` directly.
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-
-
-        Returns:
-            :class:`telegram.Message`: On success, if edited message is not an inline message, the
-            edited message is returned, otherwise :obj:`True` is returned.
-
-        Raises:
-            :exc:`ValueError`: If both :paramref:`disable_web_page_preview` and
-                :paramref:`link_preview_options` are passed.
-            :class:`telegram.error.TelegramError`: For other errors.
-
-        """
-        data: JSONDict = {
-            "text": text,
-            "chat_id": chat_id,
-            "message_id": message_id,
-            "inline_message_id": inline_message_id,
-            "entities": entities,
-        }
-
-        link_preview_options = parse_lpo_and_dwpp(disable_web_page_preview, link_preview_options)
-
-        return await self._send_message(
-            "editMessageText",
-            data,
-            reply_markup=reply_markup,
-            parse_mode=parse_mode,
-            link_preview_options=link_preview_options,
-            business_connection_id=business_connection_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def edit_message_caption(
-        self,
-        chat_id: Optional[Union[str, int]] = None,
-        message_id: Optional[int] = None,
-        inline_message_id: Optional[str] = None,
-        caption: Optional[str] = None,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        show_caption_above_media: Optional[bool] = None,
-        business_connection_id: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Union[Message, bool]:
-        """
-        Use this method to edit captions of messages.
-
-        Note:
-            * |editreplymarkup|
-            * |bcid_edit_time|
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`, optional): Required if inline_message_id is not
-                specified. |chat_id_channel|
-            message_id (:obj:`int`, optional): Required if inline_message_id is not specified.
-                Identifier of the message to edit.
-            inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not
-                specified. Identifier of the inline message.
-            caption (:obj:`str`, optional): New caption of the message,
-                0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
-                entities parsing.
-            parse_mode (:obj:`str`, optional): |parse_mode|
-            caption_entities (Sequence[:class:`telegram.MessageEntity`], optional):
-                |caption_entities|
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-            reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for an
-                inline keyboard.
-            show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
-
-                .. versionadded:: 21.3
-            business_connection_id (:obj:`str`, optional): |business_id_str_edit|
-
-                .. versionadded:: 21.4
-
-        Returns:
-            :class:`telegram.Message`: On success, if edited message is not an inline message, the
-            edited message is returned, otherwise :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "message_id": message_id,
-            "inline_message_id": inline_message_id,
-            "show_caption_above_media": show_caption_above_media,
-        }
-
-        return await self._send_message(
-            "editMessageCaption",
-            data,
-            reply_markup=reply_markup,
-            caption=caption,
-            parse_mode=parse_mode,
-            caption_entities=caption_entities,
-            business_connection_id=business_connection_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def edit_message_media(
-        self,
-        media: "InputMedia",
-        chat_id: Optional[Union[str, int]] = None,
-        message_id: Optional[int] = None,
-        inline_message_id: Optional[str] = None,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        business_connection_id: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Union[Message, bool]:
-        """
-        Use this method to edit animation, audio, document, photo, or video messages, or to add
-        media to text messages. If a message
-        is part of a message album, then it can be edited only to an audio for audio albums, only
-        to a document for document albums and to a photo or a video otherwise. When an inline
-        message is edited, a new file can't be uploaded; use a previously uploaded file via its
-        :attr:`~telegram.File.file_id` or specify a URL.
-
-        Note:
-            * |editreplymarkup|
-            * |bcid_edit_time|
-
-        .. seealso:: :wiki:`Working with Files and Media `
-
-        Args:
-            media (:class:`telegram.InputMedia`): An object for a new media content
-                of the message.
-            chat_id (:obj:`int` | :obj:`str`, optional): Required if inline_message_id is not
-                specified. |chat_id_channel|
-            message_id (:obj:`int`, optional): Required if inline_message_id is not specified.
-                Identifier of the message to edit.
-            inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not
-                specified. Identifier of the inline message.
-            reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for an
-                inline keyboard.
-            business_connection_id (:obj:`str`, optional): |business_id_str_edit|
-
-                .. versionadded:: 21.4
-
-        Returns:
-            :class:`telegram.Message`: On success, if edited message is not an inline message, the
-            edited Message is returned, otherwise :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {
-            "media": media,
-            "chat_id": chat_id,
-            "message_id": message_id,
-            "inline_message_id": inline_message_id,
-        }
-
-        return await self._send_message(
-            "editMessageMedia",
-            data,
-            reply_markup=reply_markup,
-            business_connection_id=business_connection_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def edit_message_reply_markup(
-        self,
-        chat_id: Optional[Union[str, int]] = None,
-        message_id: Optional[int] = None,
-        inline_message_id: Optional[str] = None,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        business_connection_id: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Union[Message, bool]:
-        """
-        Use this method to edit only the reply markup of messages sent by the bot or via the bot
-        (for inline bots).
-
-        Note:
-            * |editreplymarkup|
-            * |bcid_edit_time|
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`, optional): Required if inline_message_id is not
-                specified. |chat_id_channel|
-            message_id (:obj:`int`, optional): Required if inline_message_id is not specified.
-                Identifier of the message to edit.
-            inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not
-                specified. Identifier of the inline message.
-            reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for an
-                inline keyboard.
-            business_connection_id (:obj:`str`, optional): |business_id_str_edit|
-
-                .. versionadded:: 21.4
-
-        Returns:
-            :class:`telegram.Message`: On success, if edited message is not an inline message, the
-            edited message is returned, otherwise :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "message_id": message_id,
-            "inline_message_id": inline_message_id,
-        }
-
-        return await self._send_message(
-            "editMessageReplyMarkup",
-            data,
-            reply_markup=reply_markup,
-            business_connection_id=business_connection_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def get_updates(
-        self,
-        offset: Optional[int] = None,
-        limit: Optional[int] = None,
-        timeout: Optional[int] = None,  # noqa: ASYNC109
-        allowed_updates: Optional[Sequence[str]] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> tuple[Update, ...]:
-        """Use this method to receive incoming updates using long polling.
-
-        Note:
-            1. This method will not work if an outgoing webhook is set up.
-            2. In order to avoid getting duplicate updates, recalculate offset after each
-               server response.
-            3. To take full advantage of this library take a look at :class:`telegram.ext.Updater`
-
-        .. seealso:: :meth:`telegram.ext.Application.run_polling`,
-            :meth:`telegram.ext.Updater.start_polling`
-
-        .. versionchanged:: 20.0
-            Returns a tuple instead of a list.
-
-        Args:
-            offset (:obj:`int`, optional): Identifier of the first update to be returned. Must be
-                greater by one than the highest among the identifiers of previously received
-                updates. By default, updates starting with the earliest unconfirmed update are
-                returned. An update is considered confirmed as soon as this method is called with
-                an offset higher than its :attr:`telegram.Update.update_id`. The negative offset
-                can be specified to retrieve updates starting from -offset update from the end of
-                the updates queue. All previous updates will be forgotten.
-            limit (:obj:`int`, optional): Limits the number of updates to be retrieved. Values
-                between :tg-const:`telegram.constants.PollingLimit.MIN_LIMIT`-
-                :tg-const:`telegram.constants.PollingLimit.MAX_LIMIT` are accepted.
-                Defaults to ``100``.
-            timeout (:obj:`int`, optional): Timeout in seconds for long polling. Defaults to ``0``,
-                i.e. usual short polling. Should be positive, short polling should be used for
-                testing purposes only.
-            allowed_updates (Sequence[:obj:`str`]), optional): A sequence the types of
-                updates you want your bot to receive. For example, specify ["message",
-                "edited_channel_post", "callback_query"] to only receive updates of these types.
-                See :class:`telegram.Update` for a complete list of available update types.
-                Specify an empty sequence to receive all updates except
-                :attr:`telegram.Update.chat_member`, :attr:`telegram.Update.message_reaction` and
-                :attr:`telegram.Update.message_reaction_count` (default). If not specified, the
-                previous setting will be used. Please note that this parameter doesn't affect
-                updates created before the call to the get_updates, so unwanted updates may be
-                received for a short period of time.
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-
-        Returns:
-            tuple[:class:`telegram.Update`]
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "timeout": timeout,
-            "offset": offset,
-            "limit": limit,
-            "allowed_updates": allowed_updates,
-        }
-
-        # The "or 0" is needed for the case where read_timeout is None.
-        if not isinstance(read_timeout, DefaultValue):
-            arg_read_timeout: float = read_timeout or 0
-        else:
-            try:
-                arg_read_timeout = self._request[0].read_timeout or 0
-            except NotImplementedError:
-                arg_read_timeout = 2
-                self._warn(
-                    PTBDeprecationWarning(
-                        "20.7",
-                        f"The class {self._request[0].__class__.__name__} does not override "
-                        "the property `read_timeout`. Overriding this property will be mandatory "
-                        "in future versions. Using 2 seconds as fallback.",
-                    ),
-                    stacklevel=2,
-                )
-
-        # Ideally we'd use an aggressive read timeout for the polling. However,
-        # * Short polling should return within 2 seconds.
-        # * Long polling poses a different problem: the connection might have been dropped while
-        #   waiting for the server to return and there's no way of knowing the connection had been
-        #   dropped in real time.
-        result = cast(
-            list[JSONDict],
-            await self._post(
-                "getUpdates",
-                data,
-                read_timeout=arg_read_timeout + timeout if timeout else arg_read_timeout,
-                write_timeout=write_timeout,
-                connect_timeout=connect_timeout,
-                pool_timeout=pool_timeout,
-                api_kwargs=api_kwargs,
-            ),
-        )
-
-        if result:
-            self._LOGGER.debug("Getting updates: %s", [u["update_id"] for u in result])
-        else:
-            self._LOGGER.debug("No new updates found.")
-
-        try:
-            return Update.de_list(result, self)
-        except Exception as exc:
-            # This logging is in place mostly b/c we can't access the raw json data in Updater,
-            # where the exception is caught and logged again. Still, it might also be beneficial
-            # for custom usages of `get_updates`.
-            self._LOGGER.critical(
-                "Error while parsing updates! Received data was %r", result, exc_info=exc
-            )
-            raise
-
-    async def set_webhook(
-        self,
-        url: str,
-        certificate: Optional[FileInput] = None,
-        max_connections: Optional[int] = None,
-        allowed_updates: Optional[Sequence[str]] = None,
-        ip_address: Optional[str] = None,
-        drop_pending_updates: Optional[bool] = None,
-        secret_token: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to specify a url and receive incoming updates via an outgoing webhook.
-        Whenever there is an update for the bot, Telegram will send an HTTPS POST request to the
-        specified url, containing An Update. In case of an unsuccessful request,
-        Telegram will give up after a reasonable amount of attempts.
-
-        If you'd like to make sure that the Webhook was set by you, you can specify secret data in
-        the parameter :paramref:`secret_token`. If specified, the request will contain a header
-        ``X-Telegram-Bot-Api-Secret-Token`` with the secret token as content.
-
-        Note:
-            1. You will not be able to receive updates using :meth:`get_updates` for long as an
-               outgoing webhook is set up.
-            2. To use a self-signed certificate, you need to upload your public key certificate
-               using :paramref:`certificate` parameter. Please upload as
-               :class:`~telegram.InputFile`, sending a String will not work.
-            3. Ports currently supported for Webhooks:
-               :attr:`telegram.constants.SUPPORTED_WEBHOOK_PORTS`.
-
-            If you're having any trouble setting up webhooks, please check out this `guide to
-            Webhooks`_.
-
-        .. seealso:: :meth:`telegram.ext.Application.run_webhook`,
-            :meth:`telegram.ext.Updater.start_webhook`
-
-        Examples:
-            :any:`Custom Webhook Bot `
-
-        Args:
-            url (:obj:`str`): HTTPS url to send updates to. Use an empty string to remove webhook
-                integration.
-            certificate (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`):
-                Upload your public key certificate so that the root
-                certificate in use can be checked. See our :wiki:`self-signed guide\
-                ` for details.
-                |uploadinputnopath|
-            ip_address (:obj:`str`, optional): The fixed IP address which will be used to send
-                webhook requests instead of the IP address resolved through DNS.
-            max_connections (:obj:`int`, optional): Maximum allowed number of simultaneous HTTPS
-                connections to the webhook for update delivery,
-                :tg-const:`telegram.constants.WebhookLimit.MIN_CONNECTIONS_LIMIT`-
-                :tg-const:`telegram.constants.WebhookLimit.MAX_CONNECTIONS_LIMIT`.
-                Defaults to ``40``. Use lower values to limit the load on your bot's server,
-                and higher values to increase your bot's throughput.
-            allowed_updates (Sequence[:obj:`str`], optional): A sequence of the types of
-                updates you want your bot to receive. For example, specify ["message",
-                "edited_channel_post", "callback_query"] to only receive updates of these types.
-                See :class:`telegram.Update` for a complete list of available update types.
-                Specify an empty sequence to receive all updates except
-                :attr:`telegram.Update.chat_member`,
-                :attr:`telegram.Update.message_reaction`
-                and :attr:`telegram.Update.message_reaction_count` (default). If not
-                specified, the previous setting will be used. Please note that this
-                parameter doesn't affect
-                updates created before the call to the set_webhook, so unwanted update
-                may be received for a short period of time.
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-            drop_pending_updates (:obj:`bool`, optional): Pass :obj:`True` to drop all pending
-                updates.
-            secret_token (:obj:`str`, optional): A secret token to be sent in a header
-                ``X-Telegram-Bot-Api-Secret-Token`` in every webhook request,
-                :tg-const:`telegram.constants.WebhookLimit.MIN_SECRET_TOKEN_LENGTH`-
-                :tg-const:`telegram.constants.WebhookLimit.MAX_SECRET_TOKEN_LENGTH` characters.
-                Only characters ``A-Z``, ``a-z``, ``0-9``, ``_`` and ``-`` are allowed.
-                The header is useful to ensure that the request comes from a webhook set by you.
-
-                .. versionadded:: 20.0
-
-        Returns:
-            :obj:`bool` On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        .. _`guide to Webhooks`: https://core.telegram.org/bots/webhooks
-
-        """
-        data: JSONDict = {
-            "url": url,
-            "max_connections": max_connections,
-            "allowed_updates": allowed_updates,
-            "ip_address": ip_address,
-            "drop_pending_updates": drop_pending_updates,
-            "secret_token": secret_token,
-            "certificate": self._parse_file_input(certificate),  # type: ignore[arg-type]
-        }
-
-        return await self._post(
-            "setWebhook",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def delete_webhook(
-        self,
-        drop_pending_updates: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to remove webhook integration if you decide to switch back to
-        :meth:`get_updates()`.
-
-        Args:
-            drop_pending_updates (:obj:`bool`, optional): Pass :obj:`True` to drop all pending
-                updates.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data = {"drop_pending_updates": drop_pending_updates}
-
-        return await self._post(
-            "deleteWebhook",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def leave_chat(
-        self,
-        chat_id: Union[str, int],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Use this method for your bot to leave a group, supergroup or channel.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"chat_id": chat_id}
-
-        return await self._post(
-            "leaveChat",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def get_chat(
-        self,
-        chat_id: Union[str, int],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> ChatFullInfo:
-        """
-        Use this method to get up to date information about the chat (current name of the user for
-        one-on-one conversations, current username of a user, group or channel, etc.).
-
-        .. versionchanged:: 21.2
-            In accordance to Bot API 7.3, this method now returns a :class:`telegram.ChatFullInfo`.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-
-        Returns:
-            :class:`telegram.ChatFullInfo`
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"chat_id": chat_id}
-
-        result = await self._post(
-            "getChat",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-        return ChatFullInfo.de_json(result, self)  # type: ignore[return-value]
-
-    async def get_chat_administrators(
-        self,
-        chat_id: Union[str, int],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> tuple[ChatMember, ...]:
-        """
-        Use this method to get a list of administrators in a chat.
-
-        .. versionchanged:: 20.0
-            Returns a tuple instead of a list.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-
-        Returns:
-            tuple[:class:`telegram.ChatMember`]: On success, returns a tuple of ``ChatMember``
-            objects that contains information about all chat administrators except
-            other bots. If the chat is a group or a supergroup and no administrators were
-            appointed, only the creator will be returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"chat_id": chat_id}
-        result = await self._post(
-            "getChatAdministrators",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-        return ChatMember.de_list(result, self)
-
-    async def get_chat_member_count(
-        self,
-        chat_id: Union[str, int],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> int:
-        """Use this method to get the number of members in a chat.
-
-        .. versionadded:: 13.7
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-
-        Returns:
-            :obj:`int`: Number of members in the chat.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"chat_id": chat_id}
-        return await self._post(
-            "getChatMemberCount",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def get_chat_member(
-        self,
-        chat_id: Union[str, int],
-        user_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> ChatMember:
-        """Use this method to get information about a member of a chat. The method is only
-        guaranteed to work for other users if the bot is an administrator in the chat.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            user_id (:obj:`int`): Unique identifier of the target user.
-
-        Returns:
-            :class:`telegram.ChatMember`
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"chat_id": chat_id, "user_id": user_id}
-        result = await self._post(
-            "getChatMember",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-        return ChatMember.de_json(result, self)  # type: ignore[return-value]
-
-    async def set_chat_sticker_set(
-        self,
-        chat_id: Union[str, int],
-        sticker_set_name: str,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Use this method to set a new group sticker set for a supergroup.
-        The bot must be an administrator in the chat for this to work and must have the appropriate
-        admin rights. Use the field :attr:`telegram.ChatFullInfo.can_set_sticker_set` optionally
-        returned in :meth:`get_chat` requests to check if the bot can use this method.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
-            sticker_set_name (:obj:`str`): Name of the sticker set to be set as the group
-                sticker set.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-        """
-        data: JSONDict = {"chat_id": chat_id, "sticker_set_name": sticker_set_name}
-        return await self._post(
-            "setChatStickerSet",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def delete_chat_sticker_set(
-        self,
-        chat_id: Union[str, int],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Use this method to delete a group sticker set from a supergroup. The bot must be an
-        administrator in the chat for this to work and must have the appropriate admin rights.
-        Use the field :attr:`telegram.ChatFullInfo.can_set_sticker_set` optionally returned in
-        :meth:`get_chat` requests to check if the bot can use this method.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
-
-        Returns:
-             :obj:`bool`: On success, :obj:`True` is returned.
-        """
-        data: JSONDict = {"chat_id": chat_id}
-        return await self._post(
-            "deleteChatStickerSet",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def get_webhook_info(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> WebhookInfo:
-        """Use this method to get current webhook status. Requires no parameters.
-
-        If the bot is using :meth:`get_updates`, will return an object with the
-        :attr:`telegram.WebhookInfo.url` field empty.
-
-        Returns:
-            :class:`telegram.WebhookInfo`
-
-        """
-        result = await self._post(
-            "getWebhookInfo",
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-        return WebhookInfo.de_json(result, self)  # type: ignore[return-value]
-
-    async def set_game_score(
-        self,
-        user_id: int,
-        score: int,
-        chat_id: Optional[int] = None,
-        message_id: Optional[int] = None,
-        inline_message_id: Optional[str] = None,
-        force: Optional[bool] = None,
-        disable_edit_message: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Union[Message, bool]:
-        """
-        Use this method to set the score of the specified user in a game message.
-
-        .. seealso:: :attr:`telegram.Game.text`
-
-        Args:
-            user_id (:obj:`int`): User identifier.
-            score (:obj:`int`): New score, must be non-negative.
-            force (:obj:`bool`, optional): Pass :obj:`True`, if the high score is allowed to
-                decrease. This can be useful when fixing mistakes or banning cheaters.
-            disable_edit_message (:obj:`bool`, optional): Pass :obj:`True`, if the game message
-                should not be automatically edited to include the current scoreboard.
-            chat_id (:obj:`int`, optional): Required if :paramref:`inline_message_id`
-                is not specified. Unique identifier for the target chat.
-            message_id (:obj:`int`, optional): Required if :paramref:`inline_message_id` is not
-                specified. Identifier of the sent message.
-            inline_message_id (:obj:`str`, optional): Required if :paramref:`chat_id` and
-                :paramref:`message_id` are not specified. Identifier of the inline message.
-
-        Returns:
-            :class:`telegram.Message`: The edited message. If the message is not an inline message
-            , :obj:`True`.
-
-        Raises:
-            :class:`telegram.error.TelegramError`: If the new score is not greater than the user's
-                current score in the chat and :paramref:`force` is :obj:`False`.
-
-        """
-        data: JSONDict = {
-            "user_id": user_id,
-            "score": score,
-            "force": force,
-            "disable_edit_message": disable_edit_message,
-            "chat_id": chat_id,
-            "message_id": message_id,
-            "inline_message_id": inline_message_id,
-        }
-
-        return await self._send_message(
-            "setGameScore",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def get_game_high_scores(
-        self,
-        user_id: int,
-        chat_id: Optional[int] = None,
-        message_id: Optional[int] = None,
-        inline_message_id: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> tuple[GameHighScore, ...]:
-        """
-        Use this method to get data for high score tables. Will return the score of the specified
-        user and several of their neighbors in a game.
-
-        Note:
-            This method will currently return scores for the target user, plus two of their
-            closest neighbors on each side. Will also return the top three users if the user and
-            his neighbors are not among them. Please note that this behavior is subject to change.
-
-        .. versionchanged:: 20.0
-            Returns a tuple instead of a list.
-
-        Args:
-            user_id (:obj:`int`): Target user id.
-            chat_id (:obj:`int`, optional): Required if :paramref:`inline_message_id`
-                is not specified. Unique identifier for the target chat.
-            message_id (:obj:`int`, optional): Required if :paramref:`inline_message_id` is not
-                specified. Identifier of the sent message.
-            inline_message_id (:obj:`str`, optional): Required if :paramref:`chat_id` and
-                :paramref:`message_id` are not specified. Identifier of the inline message.
-
-        Returns:
-            tuple[:class:`telegram.GameHighScore`]
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "user_id": user_id,
-            "chat_id": chat_id,
-            "message_id": message_id,
-            "inline_message_id": inline_message_id,
-        }
-
-        result = await self._post(
-            "getGameHighScores",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-        return GameHighScore.de_list(result, self)
-
-    async def send_invoice(
-        self,
-        chat_id: Union[int, str],
-        title: str,
-        description: str,
-        payload: str,
-        provider_token: Optional[str],  # This arg is now optional as of Bot API 7.4
-        currency: str,
-        prices: Sequence["LabeledPrice"],
-        start_parameter: Optional[str] = None,
-        photo_url: Optional[str] = None,
-        photo_size: Optional[int] = None,
-        photo_width: Optional[int] = None,
-        photo_height: Optional[int] = None,
-        need_name: Optional[bool] = None,
-        need_phone_number: Optional[bool] = None,
-        need_email: Optional[bool] = None,
-        need_shipping_address: Optional[bool] = None,
-        is_flexible: Optional[bool] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        provider_data: Optional[Union[str, object]] = None,
-        send_phone_number_to_provider: Optional[bool] = None,
-        send_email_to_provider: Optional[bool] = None,
-        max_tip_amount: Optional[int] = None,
-        suggested_tip_amounts: Optional[Sequence[int]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        reply_to_message_id: Optional[int] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Message:
-        """Use this method to send invoices.
-
-        Warning:
-            As of API 5.2 :paramref:`start_parameter` is an optional argument and therefore the
-            order of the arguments had to be changed. Use keyword arguments to make sure that the
-            arguments are passed correctly.
-
-        .. versionchanged:: 13.5
-            As of Bot API 5.2, the parameter :paramref:`start_parameter` is optional.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            title (:obj:`str`): Product name. :tg-const:`telegram.Invoice.MIN_TITLE_LENGTH`-
-                :tg-const:`telegram.Invoice.MAX_TITLE_LENGTH` characters.
-            description (:obj:`str`): Product description.
-                :tg-const:`telegram.Invoice.MIN_DESCRIPTION_LENGTH`-
-                :tg-const:`telegram.Invoice.MAX_DESCRIPTION_LENGTH` characters.
-            payload (:obj:`str`): Bot-defined invoice payload.
-                :tg-const:`telegram.Invoice.MIN_PAYLOAD_LENGTH`-
-                :tg-const:`telegram.Invoice.MAX_PAYLOAD_LENGTH` bytes. This will not be
-                displayed to the user, use it for your internal processes.
-            provider_token (:obj:`str`): Payments provider token, obtained via
-                `@BotFather `_. Pass an empty string for payments in
-                |tg_stars|.
-
-                .. deprecated:: 21.3
-                    As of Bot API 7.4, this parameter is now optional and future versions of the
-                    library will make it optional as well.
-
-            currency (:obj:`str`): Three-letter ISO 4217 currency code, see `more on currencies
-                `_. Pass ``XTR`` for
-                payment in |tg_stars|.
-            prices (Sequence[:class:`telegram.LabeledPrice`]): Price breakdown, a sequence
-                of components (e.g. product price, tax, discount, delivery cost, delivery tax,
-                bonus, etc.). Must contain exactly one item for payment in |tg_stars|.
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-            max_tip_amount (:obj:`int`, optional): The maximum accepted amount for tips in the
-                *smallest units* of the currency (integer, **not** float/double). For example, for
-                a maximum tip of ``US$ 1.45`` pass ``max_tip_amount = 145``. See the ``exp``
-                parameter in `currencies.json
-                `_, it shows the number of
-                digits past the decimal point for each currency (2 for the majority of currencies).
-                Defaults to ``0``. Not supported for payment in |tg_stars|.
-
-                .. versionadded:: 13.5
-            suggested_tip_amounts (Sequence[:obj:`int`], optional): An array of
-                suggested amounts of tips in the *smallest units* of the currency (integer, **not**
-                float/double). At most :tg-const:`telegram.Invoice.MAX_TIP_AMOUNTS` suggested tip
-                amounts can be specified. The suggested tip amounts must be positive, passed in a
-                strictly increased order and must not exceed :paramref:`max_tip_amount`.
-
-                .. versionadded:: 13.5
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-            start_parameter (:obj:`str`, optional): Unique deep-linking parameter. If left empty,
-                *forwarded copies* of the sent message will have a *Pay* button, allowing
-                multiple users to pay directly from the forwarded message, using the same invoice.
-                If non-empty, forwarded copies of the sent message will have a *URL* button with a
-                deep link to the bot (instead of a *Pay* button), with the value used as the
-                start parameter.
-
-                .. versionchanged:: 13.5
-                    As of Bot API 5.2, this parameter is optional.
-            provider_data (:obj:`str` | :obj:`object`, optional): data about the
-                invoice, which will be shared with the payment provider. A detailed description of
-                required fields should be provided by the payment provider. When an object is
-                passed, it will be encoded as JSON.
-            photo_url (:obj:`str`, optional): URL of the product photo for the invoice. Can be a
-                photo of the goods or a marketing image for a service. People like it better when
-                they see what they are paying for.
-            photo_size (:obj:`str`, optional): Photo size.
-            photo_width (:obj:`int`, optional): Photo width.
-            photo_height (:obj:`int`, optional): Photo height.
-            need_name (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's full
-                name to complete the order. Ignored for payments in |tg_stars|.
-            need_phone_number (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's
-                phone number to complete the order. Ignored for payments in |tg_stars|.
-            need_email (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's email
-                to complete the order. Ignored for payments in |tg_stars|.
-            need_shipping_address (:obj:`bool`, optional): Pass :obj:`True`, if you require the
-                user's shipping address to complete the order. Ignored for payments in
-                |tg_stars|.
-            send_phone_number_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's
-                phone number should be sent to provider. Ignored for payments in |tg_stars|.
-            send_email_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's email
-                address should be sent to provider. Ignored for payments in |tg_stars|.
-            is_flexible (:obj:`bool`, optional): Pass :obj:`True`, if the final price depends on
-                the shipping method. Ignored for payments in |tg_stars|.
-            disable_notification (:obj:`bool`, optional): |disable_notification|
-            protect_content (:obj:`bool`, optional): |protect_content|
-
-                .. versionadded:: 13.10
-            message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
-
-                .. versionadded:: 20.0
-
-            reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for an
-                inline keyboard. If empty, one 'Pay total price' button will be
-                shown. If not empty, the first button must be a Pay button.
-            reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
-
-                .. versionadded:: 20.8
-            message_effect_id (:obj:`str`, optional): |message_effect_id|
-
-                .. versionadded:: 21.3
-            allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast|
-
-                .. versionadded:: 21.7
-
-        Keyword Args:
-            allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-
-        Returns:
-            :class:`telegram.Message`: On success, the sent Message is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "title": title,
-            "description": description,
-            "payload": payload,
-            "provider_token": provider_token,
-            "currency": currency,
-            "prices": prices,
-            "max_tip_amount": max_tip_amount,
-            "suggested_tip_amounts": suggested_tip_amounts,
-            "start_parameter": start_parameter,
-            "provider_data": provider_data,
-            "photo_url": photo_url,
-            "photo_size": photo_size,
-            "photo_width": photo_width,
-            "photo_height": photo_height,
-            "need_name": need_name,
-            "need_phone_number": need_phone_number,
-            "need_email": need_email,
-            "need_shipping_address": need_shipping_address,
-            "is_flexible": is_flexible,
-            "send_phone_number_to_provider": send_phone_number_to_provider,
-            "send_email_to_provider": send_email_to_provider,
-        }
-
-        return await self._send_message(
-            "sendInvoice",
-            data,
-            reply_to_message_id=reply_to_message_id,
-            disable_notification=disable_notification,
-            reply_markup=reply_markup,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            reply_parameters=reply_parameters,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def answer_shipping_query(
-        self,
-        shipping_query_id: str,
-        ok: bool,
-        shipping_options: Optional[Sequence["ShippingOption"]] = None,
-        error_message: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        If you sent an invoice requesting a shipping address and the parameter
-        :paramref:`send_invoice.is_flexible` was specified, the Bot API will send an
-        :class:`telegram.Update` with a :attr:`telegram.Update.shipping_query` field to the bot.
-        Use this method to reply to shipping queries.
-
-        Args:
-            shipping_query_id (:obj:`str`): Unique identifier for the query to be answered.
-            ok (:obj:`bool`): Specify :obj:`True` if delivery to the specified address is possible
-                and :obj:`False` if there are any problems (for example, if delivery to the
-                specified address is not possible).
-            shipping_options (Sequence[:class:`telegram.ShippingOption`]), optional): Required if
-                :paramref:`ok` is :obj:`True`. A sequence of available shipping options.
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-            error_message (:obj:`str`, optional): Required if :paramref:`ok` is :obj:`False`.
-                Error message in human readable form that explains why it is impossible to complete
-                the order (e.g. "Sorry, delivery to your desired address is unavailable"). Telegram
-                will display this message to the user.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "shipping_query_id": shipping_query_id,
-            "ok": ok,
-            "shipping_options": shipping_options,
-            "error_message": error_message,
-        }
-
-        return await self._post(
-            "answerShippingQuery",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def answer_pre_checkout_query(
-        self,
-        pre_checkout_query_id: str,
-        ok: bool,
-        error_message: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Once the user has confirmed their payment and shipping details, the Bot API sends the final
-        confirmation in the form of an :class:`telegram.Update` with the field
-        :attr:`telegram.Update.pre_checkout_query`. Use this method to respond to such pre-checkout
-        queries.
-
-        Note:
-            The Bot API must receive an answer within 10 seconds after the pre-checkout
-            query was sent.
-
-        Args:
-            pre_checkout_query_id (:obj:`str`): Unique identifier for the query to be answered.
-            ok (:obj:`bool`): Specify :obj:`True` if everything is alright
-                (goods are available, etc.) and the bot is ready to proceed with the order. Use
-                :obj:`False` if there are any problems.
-            error_message (:obj:`str`, optional): Required if :paramref:`ok` is :obj:`False`. Error
-                message in human readable form that explains the reason for failure to proceed with
-                the checkout (e.g. "Sorry, somebody just bought the last of our amazing black
-                T-shirts while you were busy filling out your payment details. Please choose a
-                different color or garment!"). Telegram will display this message to the user.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "pre_checkout_query_id": pre_checkout_query_id,
-            "ok": ok,
-            "error_message": error_message,
-        }
-
-        return await self._post(
-            "answerPreCheckoutQuery",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def answer_web_app_query(
-        self,
-        web_app_query_id: str,
-        result: "InlineQueryResult",
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> SentWebAppMessage:
-        """Use this method to set the result of an interaction with a Web App and send a
-        corresponding message on behalf of the user to the chat from which the query originated.
-
-        .. versionadded:: 20.0
-
-        Args:
-            web_app_query_id (:obj:`str`): Unique identifier for the query to be answered.
-            result (:class:`telegram.InlineQueryResult`): An object describing the message to be
-                sent.
-
-        Returns:
-            :class:`telegram.SentWebAppMessage`: On success, a sent
-            :class:`telegram.SentWebAppMessage` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "web_app_query_id": web_app_query_id,
-            "result": self._insert_defaults_for_ilq_results(result),
-        }
-
-        api_result = await self._post(
-            "answerWebAppQuery",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-        return SentWebAppMessage.de_json(api_result, self)  # type: ignore[return-value]
-
-    async def restrict_chat_member(
-        self,
-        chat_id: Union[str, int],
-        user_id: int,
-        permissions: ChatPermissions,
-        until_date: Optional[Union[int, dtm.datetime]] = None,
-        use_independent_chat_permissions: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to restrict a user in a supergroup. The bot must be an administrator in
-        the supergroup for this to work and must have the appropriate admin rights. Pass
-        :obj:`True` for all boolean parameters to lift restrictions from a user.
-
-        .. seealso:: :meth:`telegram.ChatPermissions.all_permissions`
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
-            user_id (:obj:`int`): Unique identifier of the target user.
-            until_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when restrictions
-                will be lifted for the user, unix time. If user is restricted for more than 366
-                days or less than 30 seconds from the current time, they are considered to be
-                restricted forever.
-                |tz-naive-dtms|
-            permissions (:class:`telegram.ChatPermissions`): An object for new user
-                permissions.
-            use_independent_chat_permissions (:obj:`bool`, optional): Pass :obj:`True` if chat
-                permissions are set independently. Otherwise, the
-                :attr:`~telegram.ChatPermissions.can_send_other_messages` and
-                :attr:`~telegram.ChatPermissions.can_add_web_page_previews` permissions will imply
-                the :attr:`~telegram.ChatPermissions.can_send_messages`,
-                :attr:`~telegram.ChatPermissions.can_send_audios`,
-                :attr:`~telegram.ChatPermissions.can_send_documents`,
-                :attr:`~telegram.ChatPermissions.can_send_photos`,
-                :attr:`~telegram.ChatPermissions.can_send_videos`,
-                :attr:`~telegram.ChatPermissions.can_send_video_notes`, and
-                :attr:`~telegram.ChatPermissions.can_send_voice_notes` permissions; the
-                :attr:`~telegram.ChatPermissions.can_send_polls` permission will imply the
-                :attr:`~telegram.ChatPermissions.can_send_messages` permission.
-
-                .. versionadded: 20.1
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "user_id": user_id,
-            "permissions": permissions,
-            "until_date": until_date,
-            "use_independent_chat_permissions": use_independent_chat_permissions,
-        }
-
-        return await self._post(
-            "restrictChatMember",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def promote_chat_member(
-        self,
-        chat_id: Union[str, int],
-        user_id: int,
-        can_change_info: Optional[bool] = None,
-        can_post_messages: Optional[bool] = None,
-        can_edit_messages: Optional[bool] = None,
-        can_delete_messages: Optional[bool] = None,
-        can_invite_users: Optional[bool] = None,
-        can_restrict_members: Optional[bool] = None,
-        can_pin_messages: Optional[bool] = None,
-        can_promote_members: Optional[bool] = None,
-        is_anonymous: Optional[bool] = None,
-        can_manage_chat: Optional[bool] = None,
-        can_manage_video_chats: Optional[bool] = None,
-        can_manage_topics: Optional[bool] = None,
-        can_post_stories: Optional[bool] = None,
-        can_edit_stories: Optional[bool] = None,
-        can_delete_stories: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to promote or demote a user in a supergroup or a channel. The bot must be
-        an administrator in the chat for this to work and must have the appropriate admin rights.
-        Pass :obj:`False` for all boolean parameters to demote a user.
-
-        .. versionchanged:: 20.0
-           The argument ``can_manage_voice_chats`` was renamed to
-           :paramref:`can_manage_video_chats` in accordance to Bot API 6.0.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            user_id (:obj:`int`): Unique identifier of the target user.
-            is_anonymous (:obj:`bool`, optional): Pass :obj:`True`, if the administrator's presence
-                in the chat is hidden.
-            can_manage_chat (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
-                access the chat event log, get boost list, see hidden supergroup and channel
-                members, report spam messages and ignore slow mode. Implied by any other
-                administrator privilege.
-
-                .. versionadded:: 13.4
-
-            can_manage_video_chats (:obj:`bool`, optional): Pass :obj:`True`, if the administrator
-                can manage video chats.
-
-                .. versionadded:: 20.0
-
-            can_change_info (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
-                change chat title, photo and other settings.
-            can_post_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
-                post messages in the channel, or access channel statistics; for channels only.
-            can_edit_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
-                edit messages of other users and can pin messages, for channels only.
-            can_delete_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
-                delete messages of other users.
-            can_invite_users (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
-                invite new users to the chat.
-            can_restrict_members (:obj:`bool`, optional): Pass :obj:`True`, if the administrator
-                can restrict, ban or unban chat members, or access supergroup statistics.
-            can_pin_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
-                pin messages, for supergroups only.
-            can_promote_members (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
-                add new administrators with a subset of their own privileges or demote
-                administrators that they have promoted, directly or indirectly
-                (promoted by administrators that were appointed by the user).
-            can_manage_topics (:obj:`bool`, optional): Pass :obj:`True`, if the user is
-                allowed to create, rename, close, and reopen forum topics; for supergroups only.
-
-                .. versionadded:: 20.0
-            can_post_stories (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
-                post stories to the chat.
-
-                .. versionadded:: 20.6
-            can_edit_stories (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
-                edit stories posted by other users, post stories to the chat page, pin chat
-                stories, and access the chat's story archive
-
-                .. versionadded:: 20.6
-            can_delete_stories (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
-                delete stories posted by other users.
-
-                .. versionadded:: 20.6
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "user_id": user_id,
-            "is_anonymous": is_anonymous,
-            "can_change_info": can_change_info,
-            "can_post_messages": can_post_messages,
-            "can_edit_messages": can_edit_messages,
-            "can_delete_messages": can_delete_messages,
-            "can_invite_users": can_invite_users,
-            "can_restrict_members": can_restrict_members,
-            "can_pin_messages": can_pin_messages,
-            "can_promote_members": can_promote_members,
-            "can_manage_chat": can_manage_chat,
-            "can_manage_video_chats": can_manage_video_chats,
-            "can_manage_topics": can_manage_topics,
-            "can_post_stories": can_post_stories,
-            "can_edit_stories": can_edit_stories,
-            "can_delete_stories": can_delete_stories,
-        }
-
-        return await self._post(
-            "promoteChatMember",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_chat_permissions(
-        self,
-        chat_id: Union[str, int],
-        permissions: ChatPermissions,
-        use_independent_chat_permissions: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to set default chat permissions for all members. The bot must be an
-        administrator in the group or a supergroup for this to work and must have the
-        :attr:`telegram.ChatMemberAdministrator.can_restrict_members` admin rights.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
-            permissions (:class:`telegram.ChatPermissions`): New default chat permissions.
-            use_independent_chat_permissions (:obj:`bool`, optional): Pass :obj:`True` if chat
-                permissions are set independently. Otherwise, the
-                :attr:`~telegram.ChatPermissions.can_send_other_messages` and
-                :attr:`~telegram.ChatPermissions.can_add_web_page_previews` permissions will imply
-                the :attr:`~telegram.ChatPermissions.can_send_messages`,
-                :attr:`~telegram.ChatPermissions.can_send_audios`,
-                :attr:`~telegram.ChatPermissions.can_send_documents`,
-                :attr:`~telegram.ChatPermissions.can_send_photos`,
-                :attr:`~telegram.ChatPermissions.can_send_videos`,
-                :attr:`~telegram.ChatPermissions.can_send_video_notes`, and
-                :attr:`~telegram.ChatPermissions.can_send_voice_notes` permissions; the
-                :attr:`~telegram.ChatPermissions.can_send_polls` permission will imply the
-                :attr:`~telegram.ChatPermissions.can_send_messages` permission.
-
-                .. versionadded: 20.1
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "permissions": permissions,
-            "use_independent_chat_permissions": use_independent_chat_permissions,
-        }
-        return await self._post(
-            "setChatPermissions",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_chat_administrator_custom_title(
-        self,
-        chat_id: Union[int, str],
-        user_id: int,
-        custom_title: str,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to set a custom title for administrators promoted by the bot in a
-        supergroup. The bot must be an administrator for this to work.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
-            user_id (:obj:`int`): Unique identifier of the target administrator.
-            custom_title (:obj:`str`): New custom title for the administrator;
-                0-:tg-const:`telegram.constants.ChatLimit.CHAT_ADMINISTRATOR_CUSTOM_TITLE_LENGTH`
-                characters, emoji are not allowed.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"chat_id": chat_id, "user_id": user_id, "custom_title": custom_title}
-
-        return await self._post(
-            "setChatAdministratorCustomTitle",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def export_chat_invite_link(
-        self,
-        chat_id: Union[str, int],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> str:
-        """
-        Use this method to generate a new primary invite link for a chat; any previously generated
-        link is revoked. The bot must be an administrator in the chat for this to work and must
-        have the appropriate admin rights.
-
-        Note:
-            Each administrator in a chat generates their own invite links. Bots can't use invite
-            links generated by other administrators. If you want your bot to work with invite
-            links, it will need to generate its own link using :meth:`export_chat_invite_link` or
-            by calling the :meth:`get_chat` method. If your bot needs to generate a new primary
-            invite link replacing its previous one, use :meth:`export_chat_invite_link` again.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-
-        Returns:
-            :obj:`str`: New invite link on success.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"chat_id": chat_id}
-        return await self._post(
-            "exportChatInviteLink",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def create_chat_invite_link(
-        self,
-        chat_id: Union[str, int],
-        expire_date: Optional[Union[int, dtm.datetime]] = None,
-        member_limit: Optional[int] = None,
-        name: Optional[str] = None,
-        creates_join_request: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> ChatInviteLink:
-        """
-        Use this method to create an additional invite link for a chat. The bot must be an
-        administrator in the chat for this to work and must have the appropriate admin rights.
-        The link can be revoked using the method :meth:`revoke_chat_invite_link`.
-
-        Note:
-            When joining *public* groups via an invite link, Telegram clients may display the
-            usual "Join" button, effectively ignoring the invite link. In particular, the parameter
-            :paramref:`creates_join_request` has no effect in this case.
-            However, this behavior is undocument and may be subject to change.
-            See `this GitHub thread `_
-            for some discussion.
-
-        .. versionadded:: 13.4
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            expire_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when the link will
-                expire. Integer input will be interpreted as Unix timestamp.
-                |tz-naive-dtms|
-            member_limit (:obj:`int`, optional): Maximum number of users that can be members of
-                the chat simultaneously after joining the chat via this invite link;
-                :tg-const:`telegram.constants.ChatInviteLinkLimit.MIN_MEMBER_LIMIT`-
-                :tg-const:`telegram.constants.ChatInviteLinkLimit.MAX_MEMBER_LIMIT`.
-            name (:obj:`str`, optional): Invite link name;
-                0-:tg-const:`telegram.constants.ChatInviteLinkLimit.NAME_LENGTH` characters.
-
-                .. versionadded:: 13.8
-            creates_join_request (:obj:`bool`, optional): :obj:`True`, if users joining the chat
-                via the link need to be approved by chat administrators.
-                If :obj:`True`, :paramref:`member_limit` can't be specified.
-
-                .. versionadded:: 13.8
-
-        Returns:
-            :class:`telegram.ChatInviteLink`
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "expire_date": expire_date,
-            "member_limit": member_limit,
-            "name": name,
-            "creates_join_request": creates_join_request,
-        }
-
-        result = await self._post(
-            "createChatInviteLink",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-        return ChatInviteLink.de_json(result, self)  # type: ignore[return-value]
-
-    async def edit_chat_invite_link(
-        self,
-        chat_id: Union[str, int],
-        invite_link: Union[str, "ChatInviteLink"],
-        expire_date: Optional[Union[int, dtm.datetime]] = None,
-        member_limit: Optional[int] = None,
-        name: Optional[str] = None,
-        creates_join_request: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> ChatInviteLink:
-        """
-        Use this method to edit a non-primary invite link created by the bot. The bot must be an
-        administrator in the chat for this to work and must have the appropriate admin rights.
-
-        Note:
-            Though not stated explicitly in the official docs, Telegram changes not only the
-            optional parameters that are explicitly passed, but also replaces all other optional
-            parameters to the default values. However, since not documented, this behaviour may
-            change unbeknown to PTB.
-
-        .. versionadded:: 13.4
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            invite_link (:obj:`str` | :class:`telegram.ChatInviteLink`): The invite link to edit.
-
-                .. versionchanged:: 20.0
-                    Now also accepts :class:`telegram.ChatInviteLink` instances.
-            expire_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when the link will
-                expire.
-                |tz-naive-dtms|
-            member_limit (:obj:`int`, optional): Maximum number of users that can be members of
-                the chat simultaneously after joining the chat via this invite link;
-                :tg-const:`telegram.constants.ChatInviteLinkLimit.MIN_MEMBER_LIMIT`-
-                :tg-const:`telegram.constants.ChatInviteLinkLimit.MAX_MEMBER_LIMIT`.
-            name (:obj:`str`, optional): Invite link name;
-                0-:tg-const:`telegram.constants.ChatInviteLinkLimit.NAME_LENGTH` characters.
-
-                .. versionadded:: 13.8
-            creates_join_request (:obj:`bool`, optional): :obj:`True`, if users joining the chat
-                via the link need to be approved by chat administrators.
-                If :obj:`True`, :paramref:`member_limit` can't be specified.
-
-                .. versionadded:: 13.8
-
-        Returns:
-            :class:`telegram.ChatInviteLink`
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        link = invite_link.invite_link if isinstance(invite_link, ChatInviteLink) else invite_link
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "invite_link": link,
-            "expire_date": expire_date,
-            "member_limit": member_limit,
-            "name": name,
-            "creates_join_request": creates_join_request,
-        }
-
-        result = await self._post(
-            "editChatInviteLink",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-        return ChatInviteLink.de_json(result, self)  # type: ignore[return-value]
-
-    async def revoke_chat_invite_link(
-        self,
-        chat_id: Union[str, int],
-        invite_link: Union[str, "ChatInviteLink"],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> ChatInviteLink:
-        """
-        Use this method to revoke an invite link created by the bot. If the primary link is
-        revoked, a new link is automatically generated. The bot must be an administrator in the
-        chat for this to work and must have the appropriate admin rights.
-
-        .. versionadded:: 13.4
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            invite_link (:obj:`str` | :class:`telegram.ChatInviteLink`): The invite link to revoke.
-
-                .. versionchanged:: 20.0
-                    Now also accepts :class:`telegram.ChatInviteLink` instances.
-
-        Returns:
-            :class:`telegram.ChatInviteLink`
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        link = invite_link.invite_link if isinstance(invite_link, ChatInviteLink) else invite_link
-        data: JSONDict = {"chat_id": chat_id, "invite_link": link}
-
-        result = await self._post(
-            "revokeChatInviteLink",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-        return ChatInviteLink.de_json(result, self)  # type: ignore[return-value]
-
-    async def approve_chat_join_request(
-        self,
-        chat_id: Union[str, int],
-        user_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Use this method to approve a chat join request.
-
-        The bot must be an administrator in the chat for this to work and must have the
-        :attr:`telegram.ChatPermissions.can_invite_users` administrator right.
-
-        .. versionadded:: 13.8
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            user_id (:obj:`int`): Unique identifier of the target user.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {"chat_id": chat_id, "user_id": user_id}
-
-        return await self._post(
-            "approveChatJoinRequest",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def decline_chat_join_request(
-        self,
-        chat_id: Union[str, int],
-        user_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Use this method to decline a chat join request.
-
-        The bot must be an administrator in the chat for this to work and must have the
-        :attr:`telegram.ChatPermissions.can_invite_users` administrator right.
-
-        .. versionadded:: 13.8
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            user_id (:obj:`int`): Unique identifier of the target user.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {"chat_id": chat_id, "user_id": user_id}
-
-        return await self._post(
-            "declineChatJoinRequest",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_chat_photo(
-        self,
-        chat_id: Union[str, int],
-        photo: FileInput,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Use this method to set a new profile photo for the chat.
-
-        Photos can't be changed for private chats. The bot must be an administrator in the chat
-        for this to work and must have the appropriate admin rights.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            photo (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path`): New chat photo.
-                |uploadinput|
-
-                .. versionchanged:: 13.2
-                   Accept :obj:`bytes` as input.
-
-                .. versionchanged:: 20.0
-                    File paths as input is also accepted for bots *not* running in
-                    :paramref:`~telegram.Bot.local_mode`.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"chat_id": chat_id, "photo": self._parse_file_input(photo)}
-        return await self._post(
-            "setChatPhoto",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def delete_chat_photo(
-        self,
-        chat_id: Union[str, int],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to delete a chat photo. Photos can't be changed for private chats. The bot
-        must be an administrator in the chat for this to work and must have the appropriate admin
-        rights.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"chat_id": chat_id}
-        return await self._post(
-            "deleteChatPhoto",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_chat_title(
-        self,
-        chat_id: Union[str, int],
-        title: str,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to change the title of a chat. Titles can't be changed for private chats.
-        The bot must be an administrator in the chat for this to work and must have the appropriate
-        admin rights.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            title (:obj:`str`): New chat title,
-                :tg-const:`telegram.constants.ChatLimit.MIN_CHAT_TITLE_LENGTH`-
-                :tg-const:`telegram.constants.ChatLimit.MAX_CHAT_TITLE_LENGTH` characters.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"chat_id": chat_id, "title": title}
-        return await self._post(
-            "setChatTitle",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_chat_description(
-        self,
-        chat_id: Union[str, int],
-        description: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to change the description of a group, a supergroup or a channel. The bot
-        must be an administrator in the chat for this to work and must have the appropriate admin
-        rights.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            description (:obj:`str`, optional): New chat description,
-                0-:tg-const:`telegram.constants.ChatLimit.CHAT_DESCRIPTION_LENGTH`
-                characters.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"chat_id": chat_id, "description": description}
-
-        return await self._post(
-            "setChatDescription",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_user_emoji_status(
-        self,
-        user_id: int,
-        emoji_status_custom_emoji_id: Optional[str] = None,
-        emoji_status_expiration_date: Optional[Union[int, dtm.datetime]] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Changes the emoji status for a given user that previously allowed the bot to manage
-        their emoji status via the Mini App method
-        `requestEmojiStatusAccess `_
-        .
-
-        .. versionadded:: 21.8
-
-        Args:
-            user_id (:obj:`int`): Unique identifier of the target user
-            emoji_status_custom_emoji_id (:obj:`str`, optional): Custom emoji identifier of the
-                emoji status to set. Pass an empty string to remove the status.
-            emoji_status_expiration_date (Union[:obj:`int`, :obj:`datetime.datetime`], optional):
-                Expiration date of the emoji status, if any, as unix timestamp or
-                :class:`datetime.datetime` object.
-                |tz-naive-dtms|
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "user_id": user_id,
-            "emoji_status_custom_emoji_id": emoji_status_custom_emoji_id,
-            "emoji_status_expiration_date": emoji_status_expiration_date,
-        }
-        return await self._post(
-            "setUserEmojiStatus",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def pin_chat_message(
-        self,
-        chat_id: Union[str, int],
-        message_id: int,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        business_connection_id: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to add a message to the list of pinned messages in a chat. If the
-        chat is not a private chat, the bot must be an administrator in the chat for this to work
-        and must have the :paramref:`~telegram.ChatAdministratorRights.can_pin_messages` admin
-        right in a supergroup or :attr:`~telegram.ChatMemberAdministrator.can_edit_messages` admin
-        right in a channel.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            message_id (:obj:`int`): Identifier of a message to pin.
-            disable_notification (:obj:`bool`, optional): Pass :obj:`True`, if it is not necessary
-                to send a notification to all chat members about the new pinned message.
-                Notifications are always disabled in channels and private chats.
-            business_connection_id (:obj:`str`, optional): Unique identifier of the business
-                connection on behalf of which the message will be pinned.
-
-                .. versionadded:: 21.5
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "message_id": message_id,
-            "disable_notification": disable_notification,
-            "business_connection_id": business_connection_id,
-        }
-
-        return await self._post(
-            "pinChatMessage",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def unpin_chat_message(
-        self,
-        chat_id: Union[str, int],
-        message_id: Optional[int] = None,
-        business_connection_id: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to remove a message from the list of pinned messages in a chat. If the
-        chat is not a private chat, the bot must be an administrator in the chat for this to work
-        and must have the :paramref:`~telegram.ChatAdministratorRights.can_pin_messages` admin
-        right in a supergroup or :attr:`~telegram.ChatMemberAdministrator.can_edit_messages` admin
-        right in a channel.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            message_id (:obj:`int`, optional): Identifier of the message to unpin. Required if
-                :paramref:`business_connection_id` is specified. If not specified,
-                the most recent pinned message (by sending date) will be unpinned.
-            business_connection_id (:obj:`str`, optional): Unique identifier of the business
-                connection on behalf of which the message will be unpinned.
-
-                .. versionadded:: 21.5
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "message_id": message_id,
-            "business_connection_id": business_connection_id,
-        }
-
-        return await self._post(
-            "unpinChatMessage",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def unpin_all_chat_messages(
-        self,
-        chat_id: Union[str, int],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to clear the list of pinned messages in a chat. If the
-        chat is not a private chat, the bot must be an administrator in the chat for this
-        to work and must have the :paramref:`~telegram.ChatAdministratorRights.can_pin_messages`
-        admin right in a supergroup or :attr:`~telegram.ChatMemberAdministrator.can_edit_messages`
-        admin right in a channel.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"chat_id": chat_id}
-        return await self._post(
-            "unpinAllChatMessages",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def get_sticker_set(
-        self,
-        name: str,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> StickerSet:
-        """Use this method to get a sticker set.
-
-        Args:
-            name (:obj:`str`): Name of the sticker set.
-
-        Returns:
-            :class:`telegram.StickerSet`
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"name": name}
-        result = await self._post(
-            "getStickerSet",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-        return StickerSet.de_json(result, self)  # type: ignore[return-value]
-
-    async def get_custom_emoji_stickers(
-        self,
-        custom_emoji_ids: Sequence[str],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> tuple[Sticker, ...]:
-        """
-        Use this method to get information about emoji stickers by their identifiers.
-
-        .. versionchanged:: 20.0
-            Returns a tuple instead of a list.
-
-        Args:
-            custom_emoji_ids (Sequence[:obj:`str`]): Sequence of custom emoji identifiers.
-                At most :tg-const:`telegram.constants.CustomEmojiStickerLimit.\
-CUSTOM_EMOJI_IDENTIFIER_LIMIT` custom emoji identifiers can be specified.
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-
-        Returns:
-            tuple[:class:`telegram.Sticker`]
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"custom_emoji_ids": custom_emoji_ids}
-        result = await self._post(
-            "getCustomEmojiStickers",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-        return Sticker.de_list(result, self)
-
-    async def upload_sticker_file(
-        self,
-        user_id: int,
-        sticker: FileInput,
-        sticker_format: str,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> File:
-        """
-        Use this method to upload a file with a sticker for later use in the
-        :meth:`create_new_sticker_set` and :meth:`add_sticker_to_set` methods (can be used multiple
-        times).
-
-        .. versionchanged:: 20.5
-           Removed deprecated parameter ``png_sticker``.
-
-        Args:
-            user_id (:obj:`int`): User identifier of sticker file owner.
-            sticker (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | \
-                :obj:`bytes` | :class:`pathlib.Path`): A file with the sticker in the
-                ``".WEBP"``, ``".PNG"``, ``".TGS"`` or ``".WEBM"``
-                format. See `here `_ for technical requirements
-                . |uploadinput|
-
-                .. versionadded:: 20.2
-
-            sticker_format (:obj:`str`): Format of the sticker. Must be one of
-                :attr:`telegram.constants.StickerFormat.STATIC`,
-                :attr:`telegram.constants.StickerFormat.ANIMATED`,
-                :attr:`telegram.constants.StickerFormat.VIDEO`.
-
-                .. versionadded:: 20.2
-
-        Returns:
-            :class:`telegram.File`: On success, the uploaded File is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "user_id": user_id,
-            "sticker": self._parse_file_input(sticker),
-            "sticker_format": sticker_format,
-        }
-        result = await self._post(
-            "uploadStickerFile",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-        return File.de_json(result, self)  # type: ignore[return-value]
-
-    async def add_sticker_to_set(
-        self,
-        user_id: int,
-        name: str,
-        sticker: "InputSticker",
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to add a new sticker to a set created by the bot. The format of the added
-        sticker must match the format of the other stickers in the set. Emoji sticker sets can have
-        up to :tg-const:`telegram.constants.StickerSetLimit.MAX_EMOJI_STICKERS` stickers. Other
-        sticker sets can have up to
-        :tg-const:`telegram.constants.StickerSetLimit.MAX_STATIC_STICKERS` stickers.
-
-        .. versionchanged:: 20.2
-            Since Bot API 6.6, the parameter :paramref:`sticker` replace the parameters
-            ``png_sticker``, ``tgs_sticker``, ``webm_sticker``, ``emojis``, and ``mask_position``.
-
-        .. versionchanged:: 20.5
-           Removed deprecated parameters ``png_sticker``, ``tgs_sticker``, ``webm_sticker``,
-           ``emojis``, and ``mask_position``.
-
-        Args:
-            user_id (:obj:`int`): User identifier of created sticker set owner.
-            name (:obj:`str`): Sticker set name.
-            sticker (:class:`telegram.InputSticker`): An object with information about the added
-                sticker. If exactly the same sticker had already been added to the set, then the
-                set isn't changed.
-
-                .. versionadded:: 20.2
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "user_id": user_id,
-            "name": name,
-            "sticker": sticker,
-        }
-
-        return await self._post(
-            "addStickerToSet",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_sticker_position_in_set(
-        self,
-        sticker: Union[str, "Sticker"],
-        position: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Use this method to move a sticker in a set created by the bot to a specific position.
-
-        Args:
-            sticker (:obj:`str` | :class:`~telegram.Sticker`): File identifier of the sticker or
-                the sticker object.
-
-                .. versionchanged:: 21.10
-                   Accepts also :class:`telegram.Sticker` instances.
-            position (:obj:`int`): New sticker position in the set, zero-based.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "sticker": sticker if isinstance(sticker, str) else sticker.file_id,
-            "position": position,
-        }
-        return await self._post(
-            "setStickerPositionInSet",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def create_new_sticker_set(
-        self,
-        user_id: int,
-        name: str,
-        title: str,
-        stickers: Sequence["InputSticker"],
-        sticker_type: Optional[str] = None,
-        needs_repainting: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to create new sticker set owned by a user.
-        The bot will be able to edit the created sticker set thus created.
-
-        .. versionchanged:: 20.0
-            The parameter ``contains_masks`` has been removed. Use :paramref:`sticker_type`
-            instead.
-
-        .. versionchanged:: 20.2
-            Since Bot API 6.6, the parameters :paramref:`stickers` and :paramref:`sticker_format`
-            replace the parameters ``png_sticker``, ``tgs_sticker``,``webm_sticker``, ``emojis``,
-            and ``mask_position``.
-
-        .. versionchanged:: 20.5
-            Removed the deprecated parameters mentioned above and adjusted the order of the
-            parameters.
-
-        .. versionremoved:: 21.2
-           Removed the deprecated parameter ``sticker_format``.
-
-        Args:
-            user_id (:obj:`int`): User identifier of created sticker set owner.
-            name (:obj:`str`): Short name of sticker set, to be used in t.me/addstickers/ URLs
-                (e.g., animals). Can contain only english letters, digits and underscores.
-                Must begin with a letter, can't contain consecutive underscores and
-                must end in "_by_".  is case insensitive.
-                :tg-const:`telegram.constants.StickerLimit.MIN_NAME_AND_TITLE`-
-                :tg-const:`telegram.constants.StickerLimit.MAX_NAME_AND_TITLE` characters.
-            title (:obj:`str`): Sticker set title,
-                :tg-const:`telegram.constants.StickerLimit.MIN_NAME_AND_TITLE`-
-                :tg-const:`telegram.constants.StickerLimit.MAX_NAME_AND_TITLE` characters.
-
-            stickers (Sequence[:class:`telegram.InputSticker`]): A sequence of
-                :tg-const:`telegram.constants.StickerSetLimit.MIN_INITIAL_STICKERS`-
-                :tg-const:`telegram.constants.StickerSetLimit.MAX_INITIAL_STICKERS` initial
-                stickers to be added to the sticker set.
-
-                .. versionadded:: 20.2
-
-            sticker_type (:obj:`str`, optional): Type of stickers in the set, pass
-                :attr:`telegram.Sticker.REGULAR` or :attr:`telegram.Sticker.MASK`, or
-                :attr:`telegram.Sticker.CUSTOM_EMOJI`. By default, a regular sticker set is created
-
-                .. versionadded:: 20.0
-
-            needs_repainting (:obj:`bool`, optional): Pass :obj:`True` if stickers in the sticker
-                set must be repainted to the color of text when used in messages, the accent color
-                if used as emoji status, white on chat photos, or another appropriate color based
-                on context; for custom emoji sticker sets only.
-
-                .. versionadded:: 20.2
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {
-            "user_id": user_id,
-            "name": name,
-            "title": title,
-            "stickers": stickers,
-            "sticker_type": sticker_type,
-            "needs_repainting": needs_repainting,
-        }
-
-        return await self._post(
-            "createNewStickerSet",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def delete_sticker_from_set(
-        self,
-        sticker: Union[str, "Sticker"],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Use this method to delete a sticker from a set created by the bot.
-
-        Args:
-            sticker (:obj:`str` | :class:`telegram.Sticker`): File identifier of the sticker or
-                the sticker object.
-
-                .. versionchanged:: 21.10
-                   Accepts also :class:`telegram.Sticker` instances.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"sticker": sticker if isinstance(sticker, str) else sticker.file_id}
-        return await self._post(
-            "deleteStickerFromSet",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def delete_sticker_set(
-        self,
-        name: str,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to delete a sticker set that was created by the bot.
-
-        .. versionadded:: 20.2
-
-        Args:
-            name (:obj:`str`): Sticker set name.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"name": name}
-        return await self._post(
-            "deleteStickerSet",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_sticker_set_thumbnail(
-        self,
-        name: str,
-        user_id: int,
-        format: str,  # pylint: disable=redefined-builtin
-        thumbnail: Optional[FileInput] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Use this method to set the thumbnail of a regular or mask sticker set. The format of the
-        thumbnail file must match the format of the stickers in the set.
-
-        .. versionadded:: 20.2
-
-        .. versionchanged:: 21.1
-            As per Bot API 7.2, the new argument :paramref:`format` will be required, and thus the
-            order of the arguments had to be changed.
-
-        Args:
-            name (:obj:`str`): Sticker set name
-            user_id (:obj:`int`): User identifier of created sticker set owner.
-            format (:obj:`str`): Format of the added sticker, must be one of
-                :tg-const:`telegram.constants.StickerFormat.STATIC` for a
-                ``.WEBP`` or ``.PNG`` image, :tg-const:`telegram.constants.StickerFormat.ANIMATED`
-                for a ``.TGS`` animation, :tg-const:`telegram.constants.StickerFormat.VIDEO` for a
-                WEBM video.
-
-                .. versionadded:: 21.1
-
-            thumbnail (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | \
-                :obj:`bytes` | :class:`pathlib.Path`, optional): A **.WEBP** or **.PNG** image
-                with the thumbnail, must
-                be up to :tg-const:`telegram.constants.StickerSetLimit.MAX_STATIC_THUMBNAIL_SIZE`
-                kilobytes in size and have width and height of exactly
-                :tg-const:`telegram.constants.StickerSetLimit.STATIC_THUMB_DIMENSIONS` px, or a
-                **.TGS** animation with the thumbnail up to
-                :tg-const:`telegram.constants.StickerSetLimit.MAX_ANIMATED_THUMBNAIL_SIZE`
-                kilobytes in size; see
-                `the docs `_ for
-                animated sticker technical requirements, or a **.WEBM** video with the thumbnail up
-                to :tg-const:`telegram.constants.StickerSetLimit.MAX_ANIMATED_THUMBNAIL_SIZE`
-                kilobytes in size; see
-                `this `_ for video sticker
-                technical requirements.
-
-                |fileinput|
-
-                Animated and video sticker set thumbnails can't be uploaded via HTTP URL. If
-                omitted, then the thumbnail is dropped and the first sticker is used as the
-                thumbnail.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "name": name,
-            "user_id": user_id,
-            "thumbnail": self._parse_file_input(thumbnail) if thumbnail else None,
-            "format": format,
-        }
-
-        return await self._post(
-            "setStickerSetThumbnail",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_sticker_set_title(
-        self,
-        name: str,
-        title: str,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to set the title of a created sticker set.
-
-        .. versionadded:: 20.2
-
-        Args:
-            name (:obj:`str`): Sticker set name.
-            title (:obj:`str`): Sticker set title,
-                :tg-const:`telegram.constants.StickerLimit.MIN_NAME_AND_TITLE`-
-                :tg-const:`telegram.constants.StickerLimit.MAX_NAME_AND_TITLE` characters.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"name": name, "title": title}
-        return await self._post(
-            "setStickerSetTitle",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_sticker_emoji_list(
-        self,
-        sticker: Union[str, "Sticker"],
-        emoji_list: Sequence[str],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to change the list of emoji assigned to a regular or custom emoji sticker.
-        The sticker must belong to a sticker set created by the bot.
-
-        .. versionadded:: 20.2
-
-        Args:
-            sticker (:obj:`str` | :class:`~telegram.Sticker`): File identifier of the sticker or
-                the sticker object.
-
-                .. versionchanged:: 21.10
-                   Accepts also :class:`telegram.Sticker` instances.
-            emoji_list (Sequence[:obj:`str`]): A sequence of
-                :tg-const:`telegram.constants.StickerLimit.MIN_STICKER_EMOJI`-
-                :tg-const:`telegram.constants.StickerLimit.MAX_STICKER_EMOJI` emoji associated with
-                the sticker.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {
-            "sticker": sticker if isinstance(sticker, str) else sticker.file_id,
-            "emoji_list": emoji_list,
-        }
-        return await self._post(
-            "setStickerEmojiList",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_sticker_keywords(
-        self,
-        sticker: Union[str, "Sticker"],
-        keywords: Optional[Sequence[str]] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to change search keywords assigned to a regular or custom emoji sticker.
-        The sticker must belong to a sticker set created by the bot.
-
-        .. versionadded:: 20.2
-
-        Args:
-            sticker (:obj:`str` | :class:`~telegram.Sticker`): File identifier of the sticker or
-                the sticker object.
-
-                .. versionchanged:: 21.10
-                   Accepts also :class:`telegram.Sticker` instances.
-            keywords (Sequence[:obj:`str`]): A sequence of
-                0-:tg-const:`telegram.constants.StickerLimit.MAX_SEARCH_KEYWORDS` search keywords
-                for the sticker with total length up to
-                :tg-const:`telegram.constants.StickerLimit.MAX_KEYWORD_LENGTH` characters.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {
-            "sticker": sticker if isinstance(sticker, str) else sticker.file_id,
-            "keywords": keywords,
-        }
-        return await self._post(
-            "setStickerKeywords",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_sticker_mask_position(
-        self,
-        sticker: Union[str, "Sticker"],
-        mask_position: Optional[MaskPosition] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to change the mask position of a mask sticker.
-        The sticker must belong to a sticker set that was created by the bot.
-
-        .. versionadded:: 20.2
-
-        Args:
-            sticker (:obj:`str` | :class:`~telegram.Sticker`): File identifier of the sticker or
-                the sticker object.
-
-                .. versionchanged:: 21.10
-                   Accepts also :class:`telegram.Sticker` instances.
-            mask_position (:class:`telegram.MaskPosition`, optional): A object with the position
-                where the mask should be placed on faces. Omit the parameter to remove the mask
-                position.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {
-            "sticker": sticker if isinstance(sticker, str) else sticker.file_id,
-            "mask_position": mask_position,
-        }
-        return await self._post(
-            "setStickerMaskPosition",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_custom_emoji_sticker_set_thumbnail(
-        self,
-        name: str,
-        custom_emoji_id: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to set the thumbnail of a custom emoji sticker set.
-
-        .. versionadded:: 20.2
-
-        Args:
-            name (:obj:`str`): Sticker set name.
-            custom_emoji_id (:obj:`str`, optional): Custom emoji identifier of a sticker from the
-                sticker set; pass an empty string to drop the thumbnail and use the first sticker
-                as the thumbnail.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"name": name, "custom_emoji_id": custom_emoji_id}
-
-        return await self._post(
-            "setCustomEmojiStickerSetThumbnail",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_passport_data_errors(
-        self,
-        user_id: int,
-        errors: Sequence["PassportElementError"],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Informs a user that some of the Telegram Passport elements they provided contains errors.
-        The user will not be able to re-submit their Passport to you until the errors are fixed
-        (the contents of the field for which you returned the error must change).
-
-        Use this if the data submitted by the user doesn't satisfy the standards your service
-        requires for any reason. For example, if a birthday date seems invalid, a submitted
-        document is blurry, a scan shows evidence of tampering, etc. Supply some details in the
-        error message to make sure the user knows how to correct the issues.
-
-        Args:
-            user_id (:obj:`int`): User identifier
-            errors (Sequence[:class:`PassportElementError`]): A Sequence describing the errors.
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"user_id": user_id, "errors": errors}
-        return await self._post(
-            "setPassportDataErrors",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def send_poll(
-        self,
-        chat_id: Union[int, str],
-        question: str,
-        options: Sequence[Union[str, "InputPollOption"]],
-        is_anonymous: Optional[bool] = None,
-        type: Optional[str] = None,  # pylint: disable=redefined-builtin
-        allows_multiple_answers: Optional[bool] = None,
-        correct_option_id: Optional[CorrectOptionID] = None,
-        is_closed: Optional[bool] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        explanation: Optional[str] = None,
-        explanation_parse_mode: ODVInput[str] = DEFAULT_NONE,
-        open_period: Optional[int] = None,
-        close_date: Optional[Union[int, dtm.datetime]] = None,
-        explanation_entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        question_parse_mode: ODVInput[str] = DEFAULT_NONE,
-        question_entities: Optional[Sequence["MessageEntity"]] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        reply_to_message_id: Optional[int] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Message:
-        """
-        Use this method to send a native poll.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            question (:obj:`str`): Poll question, :tg-const:`telegram.Poll.MIN_QUESTION_LENGTH`-
-                :tg-const:`telegram.Poll.MAX_QUESTION_LENGTH` characters.
-            options (Sequence[:obj:`str` | :class:`telegram.InputPollOption`]): Sequence of
-                :tg-const:`telegram.Poll.MIN_OPTION_NUMBER`-
-                :tg-const:`telegram.Poll.MAX_OPTION_NUMBER` answer options. Each option may either
-                be a string with
-                :tg-const:`telegram.Poll.MIN_OPTION_LENGTH`-
-                :tg-const:`telegram.Poll.MAX_OPTION_LENGTH` characters or an
-                :class:`~telegram.InputPollOption` object. Strings are converted to
-                :class:`~telegram.InputPollOption` objects automatically.
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-
-                .. versionchanged:: 21.2
-                   Bot API 7.3 adds support for :class:`~telegram.InputPollOption` objects.
-            is_anonymous (:obj:`bool`, optional): :obj:`True`, if the poll needs to be anonymous,
-                defaults to :obj:`True`.
-            type (:obj:`str`, optional): Poll type, :tg-const:`telegram.Poll.QUIZ` or
-                :tg-const:`telegram.Poll.REGULAR`, defaults to :tg-const:`telegram.Poll.REGULAR`.
-            allows_multiple_answers (:obj:`bool`, optional): :obj:`True`, if the poll allows
-                multiple answers, ignored for polls in quiz mode, defaults to :obj:`False`.
-            correct_option_id (:obj:`int`, optional): 0-based identifier of the correct answer
-                option, required for polls in quiz mode.
-            explanation (:obj:`str`, optional): Text that is shown when a user chooses an incorrect
-                answer or taps on the lamp icon in a quiz-style poll,
-                0-:tg-const:`telegram.Poll.MAX_EXPLANATION_LENGTH` characters with at most
-                :tg-const:`telegram.Poll.MAX_EXPLANATION_LINE_FEEDS` line feeds after entities
-                parsing.
-            explanation_parse_mode (:obj:`str`, optional): Mode for parsing entities in the
-                explanation. See the constants in :class:`telegram.constants.ParseMode` for the
-                available modes.
-            explanation_entities (Sequence[:class:`telegram.MessageEntity`], optional): Sequence of
-                special entities that appear in message text, which can be specified instead of
-                :paramref:`explanation_parse_mode`.
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-            open_period (:obj:`int`, optional): Amount of time in seconds the poll will be active
-                after creation, :tg-const:`telegram.Poll.MIN_OPEN_PERIOD`-
-                :tg-const:`telegram.Poll.MAX_OPEN_PERIOD`. Can't be used together with
-                :paramref:`close_date`.
-            close_date (:obj:`int` | :obj:`datetime.datetime`, optional): Point in time (Unix
-                timestamp) when the poll will be automatically closed. Must be at least
-                :tg-const:`telegram.Poll.MIN_OPEN_PERIOD` and no more than
-                :tg-const:`telegram.Poll.MAX_OPEN_PERIOD` seconds in the future.
-                Can't be used together with :paramref:`open_period`.
-                |tz-naive-dtms|
-            is_closed (:obj:`bool`, optional): Pass :obj:`True`, if the poll needs to be
-                immediately closed. This can be useful for poll preview.
-            disable_notification (:obj:`bool`, optional): |disable_notification|
-            protect_content (:obj:`bool`, optional): |protect_content|
-
-                .. versionadded:: 13.10
-            message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
-
-                .. versionadded:: 20.0
-
-            reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \
-                :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional):
-                Additional interface options. An object for an inline keyboard, custom reply
-                keyboard, instructions to remove reply keyboard or to force a reply from the user.
-            reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
-
-                .. versionadded:: 20.8
-            business_connection_id (:obj:`str`, optional): |business_id_str|
-
-                .. versionadded:: 21.1
-            question_parse_mode (:obj:`str`, optional): Mode for parsing entities in the question.
-                See the constants in :class:`telegram.constants.ParseMode` for the available modes.
-                Currently, only custom emoji entities are allowed.
-
-                .. versionadded:: 21.2
-            question_entities (Sequence[:class:`telegram.Message`], optional): Special entities
-                that appear in the poll :paramref:`question`. It can be specified instead of
-                :paramref:`question_parse_mode`.
-
-                .. versionadded:: 21.2
-            message_effect_id (:obj:`str`, optional): |message_effect_id|
-
-                .. versionadded:: 21.3
-            allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast|
-
-                .. versionadded:: 21.7
-
-        Keyword Args:
-            allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-
-        Returns:
-            :class:`telegram.Message`: On success, the sent Message is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "question": question,
-            "options": [
-                InputPollOption(option) if isinstance(option, str) else option
-                for option in options
-            ],
-            "explanation_parse_mode": explanation_parse_mode,
-            "is_anonymous": is_anonymous,
-            "type": type,
-            "allows_multiple_answers": allows_multiple_answers,
-            "correct_option_id": correct_option_id,
-            "is_closed": is_closed,
-            "explanation": explanation,
-            "explanation_entities": explanation_entities,
-            "open_period": open_period,
-            "close_date": close_date,
-            "question_parse_mode": question_parse_mode,
-            "question_entities": question_entities,
-        }
-
-        return await self._send_message(
-            "sendPoll",
-            data,
-            reply_to_message_id=reply_to_message_id,
-            disable_notification=disable_notification,
-            reply_markup=reply_markup,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            reply_parameters=reply_parameters,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def stop_poll(
-        self,
-        chat_id: Union[int, str],
-        message_id: int,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        business_connection_id: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Poll:
-        """
-        Use this method to stop a poll which was sent by the bot.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            message_id (:obj:`int`): Identifier of the original message with the poll.
-            reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for a new
-                message inline keyboard.
-            business_connection_id (:obj:`str`, optional): |business_id_str_edit|
-
-                .. versionadded:: 21.4
-
-        Returns:
-            :class:`telegram.Poll`: On success, the stopped Poll is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "message_id": message_id,
-            "reply_markup": reply_markup,
-            "business_connection_id": business_connection_id,
-        }
-
-        result = await self._post(
-            "stopPoll",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-        return Poll.de_json(result, self)  # type: ignore[return-value]
-
-    async def send_dice(
-        self,
-        chat_id: Union[int, str],
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        emoji: Optional[str] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        reply_to_message_id: Optional[int] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Message:
-        """
-        Use this method to send an animated emoji that will display a random value.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            disable_notification (:obj:`bool`, optional): |disable_notification|
-            reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \
-                :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional):
-                Additional interface options. An object for an inline keyboard, custom reply
-                keyboard, instructions to remove reply keyboard or to force a reply from the user
-            emoji (:obj:`str`, optional): Emoji on which the dice throw animation is based.
-                Currently, must be one of :class:`telegram.constants.DiceEmoji`. Dice can have
-                values
-                :tg-const:`telegram.Dice.MIN_VALUE`-:tg-const:`telegram.Dice.MAX_VALUE_BOWLING`
-                for :tg-const:`telegram.Dice.DICE`, :tg-const:`telegram.Dice.DARTS` and
-                :tg-const:`telegram.Dice.BOWLING`, values
-                :tg-const:`telegram.Dice.MIN_VALUE`-:tg-const:`telegram.Dice.MAX_VALUE_BASKETBALL`
-                for :tg-const:`telegram.Dice.BASKETBALL` and :tg-const:`telegram.Dice.FOOTBALL`,
-                and values :tg-const:`telegram.Dice.MIN_VALUE`-
-                :tg-const:`telegram.Dice.MAX_VALUE_SLOT_MACHINE`
-                for :tg-const:`telegram.Dice.SLOT_MACHINE`. Defaults to
-                :tg-const:`telegram.Dice.DICE`.
-
-                .. versionchanged:: 13.4
-                   Added the :tg-const:`telegram.Dice.BOWLING` emoji.
-            protect_content (:obj:`bool`, optional): |protect_content|
-
-                .. versionadded:: 13.10
-            message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
-
-                .. versionadded:: 20.0
-            reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
-
-                .. versionadded:: 20.8
-            business_connection_id (:obj:`str`, optional): |business_id_str|
-
-                .. versionadded:: 21.1
-            message_effect_id (:obj:`str`, optional): |message_effect_id|
-
-                .. versionadded:: 21.3
-            allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast|
-
-                .. versionadded:: 21.7
-
-        Keyword Args:
-            allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-
-
-        Returns:
-            :class:`telegram.Message`: On success, the sent Message is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"chat_id": chat_id, "emoji": emoji}
-
-        return await self._send_message(
-            "sendDice",
-            data,
-            reply_to_message_id=reply_to_message_id,
-            disable_notification=disable_notification,
-            reply_markup=reply_markup,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            reply_parameters=reply_parameters,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def get_my_default_administrator_rights(
-        self,
-        for_channels: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> ChatAdministratorRights:
-        """Use this method to get the current default administrator rights of the bot.
-
-        .. seealso:: :meth:`set_my_default_administrator_rights`
-
-        .. versionadded:: 20.0
-
-        Args:
-            for_channels (:obj:`bool`, optional): Pass :obj:`True` to get default administrator
-                rights of the bot in channels. Otherwise, default administrator rights of the bot
-                for groups and supergroups will be returned.
-
-        Returns:
-            :class:`telegram.ChatAdministratorRights`: On success.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {"for_channels": for_channels}
-
-        result = await self._post(
-            "getMyDefaultAdministratorRights",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-        return ChatAdministratorRights.de_json(result, self)  # type: ignore[return-value]
-
-    async def set_my_default_administrator_rights(
-        self,
-        rights: Optional[ChatAdministratorRights] = None,
-        for_channels: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Use this method to change the default administrator rights requested by the bot when
-        it's added as an administrator to groups or channels. These rights will be suggested to
-        users, but they are free to modify the list before adding the bot.
-
-        .. seealso:: :meth:`get_my_default_administrator_rights`
-
-        .. versionadded:: 20.0
-
-        Args:
-            rights (:class:`telegram.ChatAdministratorRights`, optional): A
-                :class:`telegram.ChatAdministratorRights` object describing new default
-                administrator
-                rights. If not specified, the default administrator rights will be cleared.
-            for_channels (:obj:`bool`, optional): Pass :obj:`True` to change the default
-                administrator rights of the bot in channels. Otherwise, the default administrator
-                rights of the bot for groups and supergroups will be changed.
-
-        Returns:
-            :obj:`bool`: Returns :obj:`True` on success.
-
-        Raises:
-            :exc:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {"rights": rights, "for_channels": for_channels}
-
-        return await self._post(
-            "setMyDefaultAdministratorRights",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def get_my_commands(
-        self,
-        scope: Optional[BotCommandScope] = None,
-        language_code: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> tuple[BotCommand, ...]:
-        """
-        Use this method to get the current list of the bot's commands for the given scope and user
-        language.
-
-        .. seealso:: :meth:`set_my_commands`, :meth:`delete_my_commands`
-
-        .. versionchanged:: 20.0
-            Returns a tuple instead of a list.
-
-        Args:
-            scope (:class:`telegram.BotCommandScope`, optional): An object,
-                describing scope of users. Defaults to :class:`telegram.BotCommandScopeDefault`.
-
-                .. versionadded:: 13.7
-
-            language_code (:obj:`str`, optional): A two-letter ISO 639-1 language code or an empty
-                string.
-
-                .. versionadded:: 13.7
-
-        Returns:
-            tuple[:class:`telegram.BotCommand`]: On success, the commands set for the bot. An empty
-            tuple is returned if commands are not set.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"scope": scope, "language_code": language_code}
-
-        result = await self._post(
-            "getMyCommands",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-        return BotCommand.de_list(result, self)
-
-    async def set_my_commands(
-        self,
-        commands: Sequence[Union[BotCommand, tuple[str, str]]],
-        scope: Optional[BotCommandScope] = None,
-        language_code: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to change the list of the bot's commands. See the
-        `Telegram docs `_ for more details about
-        bot commands.
-
-        .. seealso:: :meth:`get_my_commands`, :meth:`delete_my_commands`
-
-        Args:
-            commands (Sequence[:class:`BotCommand` | (:obj:`str`, :obj:`str`)]): A sequence
-                of bot commands to be set as the list of the bot's commands. At most
-                :tg-const:`telegram.constants.BotCommandLimit.MAX_COMMAND_NUMBER` commands can be
-                specified.
-
-                Note:
-                    If you pass in a sequence of :obj:`tuple`, the order of elements in each
-                    :obj:`tuple` must correspond to the order of positional arguments to create a
-                    :class:`BotCommand` instance.
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-            scope (:class:`telegram.BotCommandScope`, optional): An object,
-                describing scope of users for which the commands are relevant. Defaults to
-                :class:`telegram.BotCommandScopeDefault`.
-
-                .. versionadded:: 13.7
-
-            language_code (:obj:`str`, optional): A two-letter ISO 639-1 language code. If empty,
-                commands will be applied to all users from the given scope, for whose language
-                there are no dedicated commands.
-
-                .. versionadded:: 13.7
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        cmds = [c if isinstance(c, BotCommand) else BotCommand(c[0], c[1]) for c in commands]
-        data: JSONDict = {"commands": cmds, "scope": scope, "language_code": language_code}
-
-        return await self._post(
-            "setMyCommands",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def delete_my_commands(
-        self,
-        scope: Optional[BotCommandScope] = None,
-        language_code: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to delete the list of the bot's commands for the given scope and user
-        language. After deletion,
-        `higher level commands `_
-        will be shown to affected users.
-
-        .. versionadded:: 13.7
-
-        .. seealso:: :meth:`get_my_commands`, :meth:`set_my_commands`
-
-        Args:
-            scope (:class:`telegram.BotCommandScope`, optional): An object,
-                describing scope of users for which the commands are relevant. Defaults to
-                :class:`telegram.BotCommandScopeDefault`.
-            language_code (:obj:`str`, optional): A two-letter ISO 639-1 language code. If empty,
-                commands will be applied to all users from the given scope, for whose language
-                there are no dedicated commands.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {"scope": scope, "language_code": language_code}
-
-        return await self._post(
-            "deleteMyCommands",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def log_out(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to log out from the cloud Bot API server before launching the bot locally.
-        You *must* log out the bot before running it locally, otherwise there is no guarantee that
-        the bot will receive updates. After a successful call, you can immediately log in on a
-        local server, but will not be able to log in back to the cloud Bot API server for 10
-        minutes.
-
-        Returns:
-            :obj:`True`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        return await self._post(
-            "logOut",
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def close(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to close the bot instance before moving it from one local server to
-        another. You need to delete the webhook before calling this method to ensure that the bot
-        isn't launched again after server restart. The method will return error 429 in the first
-        10 minutes after the bot is launched.
-
-        Returns:
-            :obj:`True`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        return await self._post(
-            "close",
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def copy_message(
-        self,
-        chat_id: Union[int, str],
-        from_chat_id: Union[str, int],
-        message_id: int,
-        caption: Optional[str] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        show_caption_above_media: Optional[bool] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        reply_to_message_id: Optional[int] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> MessageId:
-        """Use this method to copy messages of any kind. Service messages, paid media messages,
-        giveaway messages, giveaway winners messages, and invoice messages
-        can't be copied. The method is analogous to the method :meth:`forward_message`, but the
-        copied message doesn't have a link to the original message.
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            from_chat_id (:obj:`int` | :obj:`str`): Unique identifier for the chat where the
-                original message was sent (or channel username in the format ``@channelusername``).
-            message_id (:obj:`int`): Message identifier in the chat specified in from_chat_id.
-            caption (:obj:`str`, optional): New caption for media,
-                0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
-                entities parsing. If not specified, the original caption is kept.
-            parse_mode (:obj:`str`, optional): Mode for parsing entities in the new caption. See
-                the constants in :class:`telegram.constants.ParseMode` for the available modes.
-            caption_entities (Sequence[:class:`telegram.MessageEntity`], optional):
-                |caption_entities|
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-            disable_notification (:obj:`bool`, optional): |disable_notification|
-            protect_content (:obj:`bool`, optional): |protect_content|
-
-                .. versionadded:: 13.10
-            message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
-
-                .. versionadded:: 20.0
-
-            reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \
-                :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional):
-                Additional interface options. An object for an inline keyboard, custom reply
-                keyboard, instructions to remove reply keyboard or to force a reply from the user.
-            reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
-
-                .. versionadded:: 20.8
-            show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
-
-                .. versionadded:: 21.3
-            allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast|
-
-                .. versionadded:: 21.7
-
-        Keyword Args:
-            allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-            reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-                .. versionchanged:: 20.8
-                    Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated|
-
-                .. versionchanged:: 21.0
-                    |keyword_only_arg|
-
-        Returns:
-            :class:`telegram.MessageId`: On success, the :class:`telegram.MessageId` of the sent
-                message is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        if allow_sending_without_reply is not DEFAULT_NONE and reply_parameters is not None:
-            raise ValueError(
-                "`allow_sending_without_reply` and `reply_parameters` are mutually exclusive."
-            )
-
-        if reply_to_message_id is not None and reply_parameters is not None:
-            raise ValueError(
-                "`reply_to_message_id` and `reply_parameters` are mutually exclusive."
-            )
-
-        if reply_to_message_id is not None:
-            reply_parameters = ReplyParameters(
-                message_id=reply_to_message_id,
-                allow_sending_without_reply=allow_sending_without_reply,
-            )
-
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "from_chat_id": from_chat_id,
-            "message_id": message_id,
-            "parse_mode": parse_mode,
-            "disable_notification": disable_notification,
-            "protect_content": protect_content,
-            "caption": caption,
-            "caption_entities": caption_entities,
-            "reply_markup": reply_markup,
-            "message_thread_id": message_thread_id,
-            "reply_parameters": reply_parameters,
-            "show_caption_above_media": show_caption_above_media,
-            "allow_paid_broadcast": allow_paid_broadcast,
-        }
-
-        result = await self._post(
-            "copyMessage",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-        return MessageId.de_json(result, self)  # type: ignore[return-value]
-
-    async def copy_messages(
-        self,
-        chat_id: Union[int, str],
-        from_chat_id: Union[str, int],
-        message_ids: Sequence[int],
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        remove_caption: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> tuple["MessageId", ...]:
-        """
-        Use this method to copy messages of any kind. If some of the specified messages can't be
-        found or copied, they are skipped. Service messages, paid media messages, giveaway
-        messages, giveaway winners messages, and invoice messages can't be copied. A quiz poll can
-        be copied only if the value
-        of the field :attr:`telegram.Poll.correct_option_id` is known to the bot. The method is
-        analogous to the method :meth:`forward_messages`, but the copied messages don't have a
-        link to the original message. Album grouping is kept for copied messages.
-
-        .. versionadded:: 20.8
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            from_chat_id (:obj:`int` | :obj:`str`): Unique identifier for the chat where the
-                original message was sent (or channel username in the format ``@channelusername``).
-            message_ids (Sequence[:obj:`int`]): A list of
-                :tg-const:`telegram.constants.BulkRequestLimit.MIN_LIMIT` -
-                :tg-const:`telegram.constants.BulkRequestLimit.MAX_LIMIT` identifiers of messages
-                in the chat :paramref:`from_chat_id` to copy. The identifiers must be
-                specified in a strictly increasing order.
-            disable_notification (:obj:`bool`, optional): |disable_notification|
-            protect_content (:obj:`bool`, optional): |protect_content|
-            message_thread_id (:obj:`int`, optional): |message_thread_id_arg|
-            remove_caption (:obj:`bool`, optional): Pass :obj:`True` to copy the messages without
-                their captions.
-
-        Returns:
-            tuple[:class:`telegram.MessageId`]: On success, a tuple of :class:`~telegram.MessageId`
-            of the sent messages is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "from_chat_id": from_chat_id,
-            "message_ids": message_ids,
-            "disable_notification": disable_notification,
-            "protect_content": protect_content,
-            "message_thread_id": message_thread_id,
-            "remove_caption": remove_caption,
-        }
-
-        result = await self._post(
-            "copyMessages",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-        return MessageId.de_list(result, self)
-
-    async def set_chat_menu_button(
-        self,
-        chat_id: Optional[int] = None,
-        menu_button: Optional[MenuButton] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Use this method to change the bot's menu button in a private chat, or the default menu
-        button.
-
-        .. seealso:: :meth:`get_chat_menu_button`, :meth:`telegram.Chat.get_menu_button`
-            :meth:`telegram.User.get_menu_button`
-
-        .. versionadded:: 20.0
-
-        Args:
-            chat_id (:obj:`int`, optional): Unique identifier for the target private chat. If not
-                specified, default bot's menu button will be changed
-            menu_button (:class:`telegram.MenuButton`, optional): An object for the new bot's menu
-                button. Defaults to :class:`telegram.MenuButtonDefault`.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        data: JSONDict = {"chat_id": chat_id, "menu_button": menu_button}
-
-        return await self._post(
-            "setChatMenuButton",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def get_chat_menu_button(
-        self,
-        chat_id: Optional[int] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> MenuButton:
-        """Use this method to get the current value of the bot's menu button in a private chat, or
-        the default menu button.
-
-        .. seealso:: :meth:`set_chat_menu_button`, :meth:`telegram.Chat.set_menu_button`,
-            :meth:`telegram.User.set_menu_button`
-
-        .. versionadded:: 20.0
-
-        Args:
-            chat_id (:obj:`int`, optional): Unique identifier for the target private chat. If not
-                specified, default bot's menu button will be returned.
-
-        Returns:
-            :class:`telegram.MenuButton`: On success, the current menu button is returned.
-
-        """
-        data = {"chat_id": chat_id}
-
-        result = await self._post(
-            "getChatMenuButton",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-        return MenuButton.de_json(result, bot=self)  # type: ignore[return-value]
-
-    async def create_invoice_link(
-        self,
-        title: str,
-        description: str,
-        payload: str,
-        provider_token: Optional[str],  # This arg is now optional as of Bot API 7.4
-        currency: str,
-        prices: Sequence["LabeledPrice"],
-        max_tip_amount: Optional[int] = None,
-        suggested_tip_amounts: Optional[Sequence[int]] = None,
-        provider_data: Optional[Union[str, object]] = None,
-        photo_url: Optional[str] = None,
-        photo_size: Optional[int] = None,
-        photo_width: Optional[int] = None,
-        photo_height: Optional[int] = None,
-        need_name: Optional[bool] = None,
-        need_phone_number: Optional[bool] = None,
-        need_email: Optional[bool] = None,
-        need_shipping_address: Optional[bool] = None,
-        send_phone_number_to_provider: Optional[bool] = None,
-        send_email_to_provider: Optional[bool] = None,
-        is_flexible: Optional[bool] = None,
-        subscription_period: Optional[Union[int, dtm.timedelta]] = None,
-        business_connection_id: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> str:
-        """Use this method to create a link for an invoice.
-
-        .. versionadded:: 20.0
-
-        Args:
-            business_connection_id (:obj:`str`, optional): |business_id_str|
-                For payments in |tg_stars| only.
-
-                .. versionadded:: 21.8
-            title (:obj:`str`): Product name. :tg-const:`telegram.Invoice.MIN_TITLE_LENGTH`-
-                :tg-const:`telegram.Invoice.MAX_TITLE_LENGTH` characters.
-            description (:obj:`str`): Product description.
-                :tg-const:`telegram.Invoice.MIN_DESCRIPTION_LENGTH`-
-                :tg-const:`telegram.Invoice.MAX_DESCRIPTION_LENGTH` characters.
-            payload (:obj:`str`): Bot-defined invoice payload.
-                :tg-const:`telegram.Invoice.MIN_PAYLOAD_LENGTH`-
-                :tg-const:`telegram.Invoice.MAX_PAYLOAD_LENGTH` bytes. This will not be
-                displayed to the user, use it for your internal processes.
-            provider_token (:obj:`str`): Payments provider token, obtained via
-                `@BotFather `_. Pass an empty string for payments in
-                |tg_stars|.
-
-                .. deprecated:: 21.3
-                    As of Bot API 7.4, this parameter is now optional and future versions of the
-                    library will make it optional as well.
-
-            currency (:obj:`str`): Three-letter ISO 4217 currency code, see `more on currencies
-                `_. Pass ``XTR`` for
-                payments in |tg_stars|.
-            prices (Sequence[:class:`telegram.LabeledPrice`)]: Price breakdown, a sequence
-                of components (e.g. product price, tax, discount, delivery cost, delivery tax,
-                bonus, etc.). Must contain exactly one item for payments in |tg_stars|.
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-            subscription_period (:obj:`int` | :class:`datetime.timedelta`, optional): The time the
-                subscription will be active for before the next payment, either as number of
-                seconds or as :class:`datetime.timedelta` object. The currency must be set to
-                ``“XTR”`` (Telegram Stars) if the parameter is used. Currently, it must always be
-                :tg-const:`telegram.constants.InvoiceLimit.SUBSCRIPTION_PERIOD` if specified. Any
-                number of subscriptions can be active for a given bot at the same time, including
-                multiple concurrent subscriptions from the same user. Subscription price must
-                not exceed
-                :tg-const:`telegram.constants.InvoiceLimit.SUBSCRIPTION_MAX_PRICE`
-                Telegram Stars.
-
-                .. versionadded:: 21.8
-            max_tip_amount (:obj:`int`, optional): The maximum accepted amount for tips in the
-                *smallest units* of the currency (integer, **not** float/double). For example, for
-                a maximum tip of ``US$ 1.45`` pass ``max_tip_amount = 145``. See the ``exp``
-                parameter in `currencies.json
-                `_, it shows the number of
-                digits past the decimal point for each currency (2 for the majority of currencies).
-                Defaults to ``0``. Not supported for payments in |tg_stars|.
-            suggested_tip_amounts (Sequence[:obj:`int`], optional): An array of
-                suggested amounts of tips in the *smallest units* of the currency (integer, **not**
-                float/double). At most :tg-const:`telegram.Invoice.MAX_TIP_AMOUNTS` suggested tip
-                amounts can be specified. The suggested tip amounts must be positive, passed in a
-                strictly increased order and must not exceed :paramref:`max_tip_amount`.
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-            provider_data (:obj:`str` | :obj:`object`, optional): Data about the
-                invoice, which will be shared with the payment provider. A detailed description of
-                required fields should be provided by the payment provider. When an object is
-                passed, it will be encoded as JSON.
-            photo_url (:obj:`str`, optional): URL of the product photo for the invoice. Can be a
-                photo of the goods or a marketing image for a service.
-            photo_size (:obj:`int`, optional): Photo size in bytes.
-            photo_width (:obj:`int`, optional): Photo width.
-            photo_height (:obj:`int`, optional): Photo height.
-            need_name (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's full
-                name to complete the order. Ignored for payments in |tg_stars|.
-            need_phone_number (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's
-                phone number to complete the order. Ignored for payments in |tg_stars|.
-            need_email (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's email
-                address to complete the order. Ignored for payments in |tg_stars|.
-            need_shipping_address (:obj:`bool`, optional): Pass :obj:`True`, if you require the
-                user's shipping address to complete the order. Ignored for payments in
-                |tg_stars|.
-            send_phone_number_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's
-                phone number should be sent to provider. Ignored for payments in |tg_stars|.
-            send_email_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's email
-                address should be sent to provider. Ignored for payments in |tg_stars|.
-            is_flexible (:obj:`bool`, optional): Pass :obj:`True`, if the final price depends on
-                the shipping method. Ignored for payments in |tg_stars|.
-
-        Returns:
-            :class:`str`: On success, the created invoice link is returned.
-
-        """
-        data: JSONDict = {
-            "title": title,
-            "description": description,
-            "payload": payload,
-            "provider_token": provider_token,
-            "currency": currency,
-            "prices": prices,
-            "max_tip_amount": max_tip_amount,
-            "suggested_tip_amounts": suggested_tip_amounts,
-            "provider_data": provider_data,
-            "photo_url": photo_url,
-            "photo_size": photo_size,
-            "photo_width": photo_width,
-            "photo_height": photo_height,
-            "need_name": need_name,
-            "need_phone_number": need_phone_number,
-            "need_email": need_email,
-            "need_shipping_address": need_shipping_address,
-            "is_flexible": is_flexible,
-            "send_phone_number_to_provider": send_phone_number_to_provider,
-            "send_email_to_provider": send_email_to_provider,
-            "subscription_period": (
-                subscription_period.total_seconds()
-                if isinstance(subscription_period, dtm.timedelta)
-                else subscription_period
-            ),
-            "business_connection_id": business_connection_id,
-        }
-
-        return await self._post(
-            "createInvoiceLink",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def get_forum_topic_icon_stickers(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> tuple[Sticker, ...]:
-        """Use this method to get custom emoji stickers, which can be used as a forum topic
-        icon by any user. Requires no parameters.
-
-        .. versionadded:: 20.0
-
-        Returns:
-            tuple[:class:`telegram.Sticker`]
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        result = await self._post(
-            "getForumTopicIconStickers",
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-        return Sticker.de_list(result, self)
-
-    async def create_forum_topic(
-        self,
-        chat_id: Union[str, int],
-        name: str,
-        icon_color: Optional[int] = None,
-        icon_custom_emoji_id: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> ForumTopic:
-        """
-        Use this method to create a topic in a forum supergroup chat. The bot must be
-        an administrator in the chat for this to work and must have
-        :paramref:`~telegram.ChatAdministratorRights.can_manage_topics` administrator rights.
-
-        .. versionadded:: 20.0
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
-            name (:obj:`str`): New topic name,
-                :tg-const:`telegram.constants.ForumTopicLimit.MIN_NAME_LENGTH`-
-                :tg-const:`telegram.constants.ForumTopicLimit.MAX_NAME_LENGTH` characters.
-            icon_color (:obj:`int`, optional): Color of the topic icon in RGB format. Currently,
-                must be one of :attr:`telegram.constants.ForumIconColor.BLUE`,
-                :attr:`telegram.constants.ForumIconColor.YELLOW`,
-                :attr:`telegram.constants.ForumIconColor.PURPLE`,
-                :attr:`telegram.constants.ForumIconColor.GREEN`,
-                :attr:`telegram.constants.ForumIconColor.PINK`, or
-                :attr:`telegram.constants.ForumIconColor.RED`.
-            icon_custom_emoji_id (:obj:`str`, optional): New unique identifier of the custom emoji
-                shown as the topic icon. Use :meth:`~telegram.Bot.get_forum_topic_icon_stickers`
-                to get all allowed custom emoji identifiers.
-
-        Returns:
-            :class:`telegram.ForumTopic`
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "name": name,
-            "icon_color": icon_color,
-            "icon_custom_emoji_id": icon_custom_emoji_id,
-        }
-        result = await self._post(
-            "createForumTopic",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-        return ForumTopic.de_json(result, self)  # type: ignore[return-value]
-
-    async def edit_forum_topic(
-        self,
-        chat_id: Union[str, int],
-        message_thread_id: int,
-        name: Optional[str] = None,
-        icon_custom_emoji_id: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to edit name and icon of a topic in a forum supergroup chat. The bot must
-        be an administrator in the chat for this to work and must have the
-        :paramref:`~telegram.ChatAdministratorRights.can_manage_topics` administrator rights,
-        unless it is the creator of the topic.
-
-        .. versionadded:: 20.0
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
-            message_thread_id (:obj:`int`): |message_thread_id|
-            name (:obj:`str`, optional): New topic name,
-                :tg-const:`telegram.constants.ForumTopicLimit.MIN_NAME_LENGTH`-
-                :tg-const:`telegram.constants.ForumTopicLimit.MAX_NAME_LENGTH` characters. If
-                not specified or empty, the current name of the topic will be kept.
-            icon_custom_emoji_id (:obj:`str`, optional): New unique identifier of the custom emoji
-                shown as the topic icon. Use :meth:`~telegram.Bot.get_forum_topic_icon_stickers`
-                to get all allowed custom emoji identifiers.Pass an empty string to remove the
-                icon. If not specified, the current icon will be kept.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "message_thread_id": message_thread_id,
-            "name": name,
-            "icon_custom_emoji_id": icon_custom_emoji_id,
-        }
-        return await self._post(
-            "editForumTopic",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def close_forum_topic(
-        self,
-        chat_id: Union[str, int],
-        message_thread_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to close an open topic in a forum supergroup chat. The bot must
-        be an administrator in the chat for this to work and must have
-        :paramref:`~telegram.ChatAdministratorRights.can_manage_topics` administrator rights,
-        unless it is the creator of the topic.
-
-        .. versionadded:: 20.0
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
-            message_thread_id (:obj:`int`): |message_thread_id|
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "message_thread_id": message_thread_id,
-        }
-        return await self._post(
-            "closeForumTopic",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def reopen_forum_topic(
-        self,
-        chat_id: Union[str, int],
-        message_thread_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to reopen a closed topic in a forum supergroup chat. The bot must
-        be an administrator in the chat for this to work and must have
-        :paramref:`~telegram.ChatAdministratorRights.can_manage_topics` administrator rights,
-        unless it is the creator of the topic.
-
-        .. versionadded:: 20.0
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
-            message_thread_id (:obj:`int`): |message_thread_id|
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "message_thread_id": message_thread_id,
-        }
-        return await self._post(
-            "reopenForumTopic",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def delete_forum_topic(
-        self,
-        chat_id: Union[str, int],
-        message_thread_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to delete a forum topic along with all its messages in a forum supergroup
-        chat. The bot must be an administrator in the chat for this to work and must have
-        :paramref:`~telegram.ChatAdministratorRights.can_delete_messages` administrator rights.
-
-        .. versionadded:: 20.0
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
-            message_thread_id (:obj:`int`): |message_thread_id|
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "message_thread_id": message_thread_id,
-        }
-        return await self._post(
-            "deleteForumTopic",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def unpin_all_forum_topic_messages(
-        self,
-        chat_id: Union[str, int],
-        message_thread_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to clear the list of pinned messages in a forum topic. The bot must
-        be an administrator in the chat for this to work and must have
-        :paramref:`~telegram.ChatAdministratorRights.can_pin_messages` administrator rights
-        in the supergroup.
-
-        .. versionadded:: 20.0
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
-            message_thread_id (:obj:`int`): |message_thread_id|
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "message_thread_id": message_thread_id,
-        }
-        return await self._post(
-            "unpinAllForumTopicMessages",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def unpin_all_general_forum_topic_messages(
-        self,
-        chat_id: Union[str, int],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to clear the list of pinned messages in a General forum topic. The bot must
-        be an administrator in the chat for this to work and must have
-        :paramref:`~telegram.ChatAdministratorRights.can_pin_messages` administrator rights in the
-        supergroup.
-
-        .. versionadded:: 20.5
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {"chat_id": chat_id}
-
-        return await self._post(
-            "unpinAllGeneralForumTopicMessages",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def edit_general_forum_topic(
-        self,
-        chat_id: Union[str, int],
-        name: str,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to edit the name of the 'General' topic in a forum supergroup chat. The bot
-        must be an administrator in the chat for this to work and must have the
-        :attr:`~telegram.ChatAdministratorRights.can_manage_topics` administrator rights.
-
-        .. versionadded:: 20.0
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
-            name (:obj:`str`): New topic name,
-                :tg-const:`telegram.constants.ForumTopicLimit.MIN_NAME_LENGTH`-
-                :tg-const:`telegram.constants.ForumTopicLimit.MAX_NAME_LENGTH` characters.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"chat_id": chat_id, "name": name}
-
-        return await self._post(
-            "editGeneralForumTopic",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def close_general_forum_topic(
-        self,
-        chat_id: Union[str, int],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to close an open 'General' topic in a forum supergroup chat. The bot must
-        be an administrator in the chat for this to work and must have
-        :attr:`~telegram.ChatAdministratorRights.can_manage_topics` administrator rights.
-
-        .. versionadded:: 20.0
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"chat_id": chat_id}
-
-        return await self._post(
-            "closeGeneralForumTopic",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def reopen_general_forum_topic(
-        self,
-        chat_id: Union[str, int],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to reopen a closed 'General' topic in a forum supergroup chat. The bot must
-        be an administrator in the chat for this to work and must have
-        :attr:`~telegram.ChatAdministratorRights.can_manage_topics` administrator rights.
-        The topic will be automatically unhidden if it was hidden.
-
-        .. versionadded:: 20.0
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"chat_id": chat_id}
-
-        return await self._post(
-            "reopenGeneralForumTopic",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def hide_general_forum_topic(
-        self,
-        chat_id: Union[str, int],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to hide the 'General' topic in a forum supergroup chat. The bot must
-        be an administrator in the chat for this to work and must have
-        :attr:`~telegram.ChatAdministratorRights.can_manage_topics` administrator rights.
-        The topic will be automatically closed if it was open.
-
-        .. versionadded:: 20.0
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"chat_id": chat_id}
-
-        return await self._post(
-            "hideGeneralForumTopic",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def unhide_general_forum_topic(
-        self,
-        chat_id: Union[str, int],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to unhide the 'General' topic in a forum supergroup chat. The bot must
-        be an administrator in the chat for this to work and must have
-        :attr:`~telegram.ChatAdministratorRights.can_manage_topics` administrator rights.
-
-        .. versionadded:: 20.0
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_group|
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"chat_id": chat_id}
-
-        return await self._post(
-            "unhideGeneralForumTopic",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_my_description(
-        self,
-        description: Optional[str] = None,
-        language_code: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to change the bot's description, which is shown in the chat with the bot
-        if the chat is empty.
-
-        .. versionadded:: 20.2
-
-        Args:
-            description (:obj:`str`, optional): New bot description;
-                0-:tg-const:`telegram.constants.BotDescriptionLimit.MAX_DESCRIPTION_LENGTH`
-                characters. Pass an empty string to remove the dedicated description for the given
-                language.
-            language_code (:obj:`str`, optional): A two-letter ISO 639-1 language code. If empty,
-                the description will be applied to all users for whose language there is no
-                dedicated description.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"description": description, "language_code": language_code}
-
-        return await self._post(
-            "setMyDescription",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_my_short_description(
-        self,
-        short_description: Optional[str] = None,
-        language_code: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to change the bot's short description, which is shown on the bot's profile
-        page and is sent together with the link when users share the bot.
-
-        .. versionadded:: 20.2
-
-        Args:
-            short_description (:obj:`str`, optional): New short description for the bot;
-                0-:tg-const:`telegram.constants.BotDescriptionLimit.MAX_SHORT_DESCRIPTION_LENGTH`
-                characters. Pass an empty string to remove the dedicated description for the given
-                language.
-            language_code (:obj:`str`, optional): A two-letter ISO 639-1 language code. If empty,
-                the description will be applied to all users for whose language there is no
-                dedicated description.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"short_description": short_description, "language_code": language_code}
-
-        return await self._post(
-            "setMyShortDescription",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def get_my_description(
-        self,
-        language_code: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> BotDescription:
-        """
-        Use this method to get the current bot description for the given user language.
-
-        Args:
-            language_code (:obj:`str`, optional): A two-letter ISO 639-1 language code or an empty
-                string.
-
-        Returns:
-            :class:`telegram.BotDescription`: On success, the bot description is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data = {"language_code": language_code}
-        return BotDescription.de_json(  # type: ignore[return-value]
-            await self._post(
-                "getMyDescription",
-                data,
-                read_timeout=read_timeout,
-                write_timeout=write_timeout,
-                connect_timeout=connect_timeout,
-                pool_timeout=pool_timeout,
-                api_kwargs=api_kwargs,
-            ),
-            bot=self,
-        )
-
-    async def get_my_short_description(
-        self,
-        language_code: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> BotShortDescription:
-        """
-        Use this method to get the current bot short description for the given user language.
-
-        Args:
-            language_code (:obj:`str`, optional): A two-letter ISO 639-1 language code or an empty
-                string.
-
-        Returns:
-            :class:`telegram.BotShortDescription`: On success, the bot short description is
-                returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data = {"language_code": language_code}
-        return BotShortDescription.de_json(  # type: ignore[return-value]
-            await self._post(
-                "getMyShortDescription",
-                data,
-                read_timeout=read_timeout,
-                write_timeout=write_timeout,
-                connect_timeout=connect_timeout,
-                pool_timeout=pool_timeout,
-                api_kwargs=api_kwargs,
-            ),
-            bot=self,
-        )
-
-    async def set_my_name(
-        self,
-        name: Optional[str] = None,
-        language_code: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to change the bot's name.
-
-        .. versionadded:: 20.3
-
-        Args:
-            name (:obj:`str`, optional): New bot name;
-                0-:tg-const:`telegram.constants.BotNameLimit.MAX_NAME_LENGTH`
-                characters. Pass an empty string to remove the dedicated name for the given
-                language.
-
-                Caution:
-                    If :paramref:`language_code` is not specified, a :paramref:`name` *must*
-                    be specified.
-            language_code (:obj:`str`, optional): A two-letter ISO 639-1 language code. If empty,
-                the name will be applied to all users for whose language there is no
-                dedicated name.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {"name": name, "language_code": language_code}
-
-        return await self._post(
-            "setMyName",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def get_my_name(
-        self,
-        language_code: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> BotName:
-        """
-        Use this method to get the current bot name for the given user language.
-
-        Args:
-            language_code (:obj:`str`, optional): A two-letter ISO 639-1 language code or an empty
-                string.
-
-        Returns:
-            :class:`telegram.BotName`: On success, the bot name is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data = {"language_code": language_code}
-        return BotName.de_json(  # type: ignore[return-value]
-            await self._post(
-                "getMyName",
-                data,
-                read_timeout=read_timeout,
-                write_timeout=write_timeout,
-                connect_timeout=connect_timeout,
-                pool_timeout=pool_timeout,
-                api_kwargs=api_kwargs,
-            ),
-            bot=self,
-        )
-
-    async def get_user_chat_boosts(
-        self,
-        chat_id: Union[str, int],
-        user_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> UserChatBoosts:
-        """
-        Use this method to get the list of boosts added to a chat by a user. Requires
-        administrator rights in the chat.
-
-        .. versionadded:: 20.8
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            user_id (:obj:`int`): Unique identifier of the target user.
-
-        Returns:
-            :class:`telegram.UserChatBoosts`: On success, the object containing the list of boosts
-                is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {"chat_id": chat_id, "user_id": user_id}
-        return UserChatBoosts.de_json(  # type: ignore[return-value]
-            await self._post(
-                "getUserChatBoosts",
-                data,
-                read_timeout=read_timeout,
-                write_timeout=write_timeout,
-                connect_timeout=connect_timeout,
-                pool_timeout=pool_timeout,
-                api_kwargs=api_kwargs,
-            ),
-            bot=self,
-        )
-
-    async def set_message_reaction(
-        self,
-        chat_id: Union[str, int],
-        message_id: int,
-        reaction: Optional[Union[Sequence[Union[ReactionType, str]], ReactionType, str]] = None,
-        is_big: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """
-        Use this method to change the chosen reactions on a message. Service messages can't be
-        reacted to. Automatically forwarded messages from a channel to its discussion group have
-        the same available reactions as messages in the channel. Bots can't use paid reactions.
-
-        .. versionadded:: 20.8
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            message_id (:obj:`int`): Identifier of the target message. If the message belongs to a
-                media group, the reaction is set to the first non-deleted message in the group
-                instead.
-            reaction (Sequence[:class:`telegram.ReactionType` | :obj:`str`] | \
-                :class:`telegram.ReactionType` | :obj:`str`, optional): A list of reaction
-                types to set on the message. Currently, as non-premium users, bots can set up to
-                one reaction per message. A custom emoji reaction can be used if it is either
-                already present on the message or explicitly allowed by chat administrators. Paid
-                reactions can't be used by bots.
-
-                Tip:
-                    Passed :obj:`str` values will be converted to either
-                    :class:`telegram.ReactionTypeEmoji` or
-                    :class:`telegram.ReactionTypeCustomEmoji`
-                    depending on whether they are listed in
-                    :class:`~telegram.constants.ReactionEmoji`.
-
-            is_big (:obj:`bool`, optional): Pass :obj:`True` to set the reaction with a big
-                animation.
-
-        Returns:
-            :obj:`bool` On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        allowed_reactions: set[str] = set(ReactionEmoji)
-        parsed_reaction = (
-            [
-                (
-                    entry
-                    if isinstance(entry, ReactionType)
-                    else (
-                        ReactionTypeEmoji(emoji=entry)
-                        if entry in allowed_reactions
-                        else ReactionTypeCustomEmoji(custom_emoji_id=entry)
-                    )
-                )
-                for entry in (
-                    [reaction] if isinstance(reaction, (ReactionType, str)) else reaction
-                )
-            ]
-            if reaction is not None
-            else None
-        )
-
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "message_id": message_id,
-            "reaction": parsed_reaction,
-            "is_big": is_big,
-        }
-
-        return await self._post(
-            "setMessageReaction",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def get_business_connection(
-        self,
-        business_connection_id: str,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> BusinessConnection:
-        """
-        Use this method to get information about the connection of the bot with a business account.
-
-        .. versionadded:: 21.1
-
-        Args:
-            business_connection_id (:obj:`str`): Unique identifier of the business connection.
-
-        Returns:
-            :class:`telegram.BusinessConnection`: On success, the object containing the business
-                connection information is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {"business_connection_id": business_connection_id}
-        return BusinessConnection.de_json(  # type: ignore[return-value]
-            await self._post(
-                "getBusinessConnection",
-                data,
-                read_timeout=read_timeout,
-                write_timeout=write_timeout,
-                connect_timeout=connect_timeout,
-                pool_timeout=pool_timeout,
-                api_kwargs=api_kwargs,
-            ),
-            bot=self,
-        )
-
-    async def replace_sticker_in_set(
-        self,
-        user_id: int,
-        name: str,
-        old_sticker: Union[str, "Sticker"],
-        sticker: "InputSticker",
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Use this method to replace an existing sticker in a sticker set with a new one.
-        The method is equivalent to calling :meth:`delete_sticker_from_set`,
-        then :meth:`add_sticker_to_set`, then :meth:`set_sticker_position_in_set`.
-
-        .. versionadded:: 21.1
-
-        Args:
-            user_id (:obj:`int`): User identifier of the sticker set owner.
-            name (:obj:`str`): Sticker set name.
-            old_sticker (:obj:`str` | :class:`~telegram.Sticker`): File identifier of the replaced
-                sticker or the sticker object itself.
-
-                .. versionchanged:: 21.10
-                   Accepts also :class:`telegram.Sticker` instances.
-            sticker (:class:`telegram.InputSticker`): An object with information about the added
-                sticker. If exactly the same sticker had already been added to the set, then the
-                set remains unchanged.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {
-            "user_id": user_id,
-            "name": name,
-            "old_sticker": old_sticker if isinstance(old_sticker, str) else old_sticker.file_id,
-            "sticker": sticker,
-        }
-
-        return await self._post(
-            "replaceStickerInSet",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def refund_star_payment(
-        self,
-        user_id: int,
-        telegram_payment_charge_id: str,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Refunds a successful payment in |tg_stars|.
-
-        .. versionadded:: 21.3
-
-        Args:
-            user_id (:obj:`int`): User identifier of the user whose payment will be refunded.
-            telegram_payment_charge_id (:obj:`str`): Telegram payment identifier.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "user_id": user_id,
-            "telegram_payment_charge_id": telegram_payment_charge_id,
-        }
-
-        return await self._post(
-            "refundStarPayment",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def get_star_transactions(
-        self,
-        offset: Optional[int] = None,
-        limit: Optional[int] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> StarTransactions:
-        """Returns the bot's Telegram Star transactions in chronological order.
-
-        .. versionadded:: 21.4
-
-        Args:
-            offset (:obj:`int`, optional): Number of transactions to skip in the response.
-            limit (:obj:`int`, optional): The maximum number of transactions to be retrieved.
-                Values between :tg-const:`telegram.constants.StarTransactionsLimit.MIN_LIMIT`-
-                :tg-const:`telegram.constants.StarTransactionsLimit.MAX_LIMIT` are accepted.
-                Defaults to :tg-const:`telegram.constants.StarTransactionsLimit.MAX_LIMIT`.
-
-        Returns:
-            :class:`telegram.StarTransactions`: On success.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-
-        data: JSONDict = {"offset": offset, "limit": limit}
-
-        return StarTransactions.de_json(  # type: ignore[return-value]
-            await self._post(
-                "getStarTransactions",
-                data,
-                read_timeout=read_timeout,
-                write_timeout=write_timeout,
-                connect_timeout=connect_timeout,
-                pool_timeout=pool_timeout,
-                api_kwargs=api_kwargs,
-            ),
-            bot=self,
-        )
-
-    async def edit_user_star_subscription(
-        self,
-        user_id: int,
-        telegram_payment_charge_id: str,
-        is_canceled: bool,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Allows the bot to cancel or re-enable extension of a subscription paid in Telegram
-        Stars.
-
-        .. versionadded:: 21.8
-
-        Args:
-            user_id (:obj:`int`): Identifier of the user whose subscription will be edited.
-            telegram_payment_charge_id (:obj:`str`): Telegram payment identifier for the
-                subscription.
-            is_canceled (:obj:`bool`): Pass :obj:`True` to cancel extension of the user
-                subscription; the subscription must be active up to the end of the current
-                subscription period. Pass :obj:`False` to allow the user to re-enable a
-                subscription that was previously canceled by the bot.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {
-            "user_id": user_id,
-            "telegram_payment_charge_id": telegram_payment_charge_id,
-            "is_canceled": is_canceled,
-        }
-        return await self._post(
-            "editUserStartSubscription",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def send_paid_media(
-        self,
-        chat_id: Union[str, int],
-        star_count: int,
-        media: Sequence["InputPaidMedia"],
-        caption: Optional[str] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        show_caption_above_media: Optional[bool] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        reply_markup: Optional[ReplyMarkup] = None,
-        business_connection_id: Optional[str] = None,
-        payload: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        reply_to_message_id: Optional[int] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Message:
-        """Use this method to send paid media.
-
-        .. versionadded:: 21.4
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| If the chat is a channel, all
-                Telegram Star proceeds from this media will be credited to the chat's balance.
-                Otherwise, they will be credited to the bot's balance.
-            star_count (:obj:`int`): The number of Telegram Stars that must be paid to buy access
-                to the media; :tg-const:`telegram.constants.InvoiceLimit.MIN_STAR_COUNT` -
-                :tg-const:`telegram.constants.InvoiceLimit.MAX_STAR_COUNT`.
-            media (Sequence[:class:`telegram.InputPaidMedia`]): A list describing the media to be
-                sent; up to :tg-const:`telegram.constants.MediaGroupLimit.MAX_MEDIA_LENGTH` items.
-            payload (:obj:`str`, optional): Bot-defined paid media payload,
-                0-:tg-const:`telegram.constants.InvoiceLimit.MAX_PAYLOAD_LENGTH` bytes. This will
-                not be displayed to the user, use it for your internal processes.
-
-                .. versionadded:: 21.6
-            caption (:obj:`str`, optional): Caption of the media to be sent,
-                0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters.
-            parse_mode (:obj:`str`, optional): |parse_mode|
-            caption_entities (Sequence[:class:`telegram.MessageEntity`], optional):
-                |caption_entities|
-            show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
-            disable_notification (:obj:`bool`, optional): |disable_notification|
-            protect_content (:obj:`bool`, optional): |protect_content|
-            reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters|
-            reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \
-                :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional):
-                Additional interface options. An object for an inline keyboard, custom reply
-                keyboard, instructions to remove reply keyboard or to force a reply from the user.
-            business_connection_id (:obj:`str`, optional): |business_id_str|
-
-                .. versionadded:: 21.5
-            allow_paid_broadcast (:obj:`bool`, optional): |allow_paid_broadcast|
-
-                .. versionadded:: 21.7
-
-        Keyword Args:
-            allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-            reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id|
-                Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience
-                parameter for
-
-        Returns:
-            :class:`telegram.Message`: On success, the sent message is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "star_count": star_count,
-            "media": media,
-            "show_caption_above_media": show_caption_above_media,
-            "payload": payload,
-        }
-
-        return await self._send_message(
-            "sendPaidMedia",
-            data,
-            caption=caption,
-            parse_mode=parse_mode,
-            caption_entities=caption_entities,
-            disable_notification=disable_notification,
-            protect_content=protect_content,
-            reply_parameters=reply_parameters,
-            reply_markup=reply_markup,
-            allow_sending_without_reply=allow_sending_without_reply,
-            reply_to_message_id=reply_to_message_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=business_connection_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def create_chat_subscription_invite_link(
-        self,
-        chat_id: Union[str, int],
-        subscription_period: int,
-        subscription_price: int,
-        name: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> ChatInviteLink:
-        """
-        Use this method to create a `subscription invite link `_ for a channel chat.
-        The bot must have the :attr:`~telegram.ChatPermissions.can_invite_users` administrator
-        right. The link can be edited using the :meth:`edit_chat_subscription_invite_link` or
-        revoked using the :meth:`revoke_chat_invite_link`.
-
-        .. versionadded:: 21.5
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            subscription_period (:obj:`int`): The number of seconds the subscription will be
-                active for before the next payment. Currently, it must always be
-                :tg-const:`telegram.constants.ChatSubscriptionLimit.SUBSCRIPTION_PERIOD` (30 days).
-            subscription_price (:obj:`int`): The number of Telegram Stars a user must pay initially
-                and after each subsequent subscription period to be a member of the chat;
-                :tg-const:`telegram.constants.ChatSubscriptionLimit.MIN_PRICE`-
-                :tg-const:`telegram.constants.ChatSubscriptionLimit.MAX_PRICE`.
-            name (:obj:`str`, optional): Invite link name;
-                0-:tg-const:`telegram.constants.ChatInviteLinkLimit.NAME_LENGTH` characters.
-
-        Returns:
-            :class:`telegram.ChatInviteLink`
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "subscription_period": subscription_period,
-            "subscription_price": subscription_price,
-            "name": name,
-        }
-
-        result = await self._post(
-            "createChatSubscriptionInviteLink",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-        return ChatInviteLink.de_json(result, self)  # type: ignore[return-value]
-
-    async def edit_chat_subscription_invite_link(
-        self,
-        chat_id: Union[str, int],
-        invite_link: Union[str, "ChatInviteLink"],
-        name: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> ChatInviteLink:
-        """
-        Use this method to edit a subscription invite link created by the bot. The bot must have
-        :attr:`telegram.ChatPermissions.can_invite_users` administrator right.
-
-        .. versionadded:: 21.5
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            invite_link (:obj:`str` | :obj:`telegram.ChatInviteLink`): The invite link to edit.
-            name (:obj:`str`, optional): Invite link name;
-                0-:tg-const:`telegram.constants.ChatInviteLinkLimit.NAME_LENGTH` characters.
-
-                Tip:
-                    Omitting this argument removes the name of the invite link.
-
-        Returns:
-            :class:`telegram.ChatInviteLink`
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        link = invite_link.invite_link if isinstance(invite_link, ChatInviteLink) else invite_link
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "invite_link": link,
-            "name": name,
-        }
-
-        result = await self._post(
-            "editChatSubscriptionInviteLink",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-        return ChatInviteLink.de_json(result, self)  # type: ignore[return-value]
-
-    async def get_available_gifts(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Gifts:
-        """Returns the list of gifts that can be sent by the bot to users.
-        Requires no parameters.
-
-        .. versionadded:: 21.8
-
-        Returns:
-            :class:`telegram.Gifts`
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        return Gifts.de_json(  # type: ignore[return-value]
-            await self._post(
-                "getAvailableGifts",
-                read_timeout=read_timeout,
-                write_timeout=write_timeout,
-                connect_timeout=connect_timeout,
-                pool_timeout=pool_timeout,
-                api_kwargs=api_kwargs,
-            )
-        )
-
-    async def send_gift(
-        self,
-        user_id: int,
-        gift_id: Union[str, Gift],
-        text: Optional[str] = None,
-        text_parse_mode: ODVInput[str] = DEFAULT_NONE,
-        text_entities: Optional[Sequence["MessageEntity"]] = None,
-        pay_for_upgrade: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Sends a gift to the given user.
-        The gift can't be converted to Telegram Stars by the user
-
-        .. versionadded:: 21.8
-
-        Args:
-            user_id (:obj:`int`): Unique identifier of the target user that will receive the gift
-            gift_id (:obj:`str` | :class:`~telegram.Gift`): Identifier of the gift or a
-                :class:`~telegram.Gift` object
-            text (:obj:`str`, optional): Text that will be shown along with the gift;
-                0- :tg-const:`telegram.constants.GiftLimit.MAX_TEXT_LENGTH` characters
-            text_parse_mode (:obj:`str`, optional): Mode for parsing entities.
-                See :class:`telegram.constants.ParseMode` and
-                `formatting options `__ for
-                more details. Entities other than :attr:`~MessageEntity.BOLD`,
-                :attr:`~MessageEntity.ITALIC`, :attr:`~MessageEntity.UNDERLINE`,
-                :attr:`~MessageEntity.STRIKETHROUGH`, :attr:`~MessageEntity.SPOILER`, and
-                :attr:`~MessageEntity.CUSTOM_EMOJI` are ignored.
-            text_entities (Sequence[:class:`telegram.MessageEntity`], optional): A list of special
-                entities that appear in the gift text. It can be specified instead of
-                :paramref:`text_parse_mode`. Entities other than :attr:`~MessageEntity.BOLD`,
-                :attr:`~MessageEntity.ITALIC`, :attr:`~MessageEntity.UNDERLINE`,
-                :attr:`~MessageEntity.STRIKETHROUGH`, :attr:`~MessageEntity.SPOILER`, and
-                :attr:`~MessageEntity.CUSTOM_EMOJI` are ignored.
-            pay_for_upgrade (:obj:`bool`, optional): Pass :obj:`True` to pay for the gift upgrade
-                from the bot's balance, thereby making the upgrade free for the receiver.
-
-                .. versionadded:: 21.10
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {
-            "user_id": user_id,
-            "gift_id": gift_id.id if isinstance(gift_id, Gift) else gift_id,
-            "text": text,
-            "text_parse_mode": text_parse_mode,
-            "text_entities": text_entities,
-            "pay_for_upgrade": pay_for_upgrade,
-        }
-        return await self._post(
-            "sendGift",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def verify_chat(
-        self,
-        chat_id: Union[int, str],
-        custom_description: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Verifies a chat on behalf of the organization which is represented by the bot.
-
-        .. versionadded:: 21.10
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-            custom_description (:obj:`str`, optional): Custom description for the verification;
-                0- :tg-const:`telegram.constants.VerifyLimit.MAX_TEXT_LENGTH` characters. Must be
-                empty if the organization isn't allowed to provide a custom verification
-                description.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-            "custom_description": custom_description,
-        }
-        return await self._post(
-            "verifyChat",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def verify_user(
-        self,
-        user_id: int,
-        custom_description: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Verifies a user on behalf of the organization which is represented by the bot.
-
-        .. versionadded:: 21.10
-
-        Args:
-            user_id (:obj:`int`): Unique identifier of the target user.
-            custom_description (:obj:`str`, optional): Custom description for the verification;
-                0- :tg-const:`telegram.constants.VerifyLimit.MAX_TEXT_LENGTH` characters. Must be
-                empty if the organization isn't allowed to provide a custom verification
-                description.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {
-            "user_id": user_id,
-            "custom_description": custom_description,
-        }
-        return await self._post(
-            "verifyUser",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def remove_chat_verification(
-        self,
-        chat_id: Union[int, str],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Removes verification from a chat that is currently verified on behalf of the
-        organization represented by the bot.
-
-
-
-        .. versionadded:: 21.10
-
-        Args:
-            chat_id (:obj:`int` | :obj:`str`): |chat_id_channel|
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {
-            "chat_id": chat_id,
-        }
-        return await self._post(
-            "removeChatVerification",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def remove_user_verification(
-        self,
-        user_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Removes verification from a user who is currently verified on behalf of the
-        organization represented by the bot.
-
-
-
-        .. versionadded:: 21.10
-
-        Args:
-            user_id (:obj:`int`): Unique identifier of the target user.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        data: JSONDict = {
-            "user_id": user_id,
-        }
-        return await self._post(
-            "removeUserVerification",
-            data,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    def to_dict(self, recursive: bool = True) -> JSONDict:  # noqa: ARG002
-        """See :meth:`telegram.TelegramObject.to_dict`."""
-        data: JSONDict = {"id": self.id, "username": self.username, "first_name": self.first_name}
-
-        if self.last_name:
-            data["last_name"] = self.last_name
-
-        return data
-
-    # camelCase aliases
-    getMe = get_me
-    """Alias for :meth:`get_me`"""
-    sendMessage = send_message
-    """Alias for :meth:`send_message`"""
-    deleteMessage = delete_message
-    """Alias for :meth:`delete_message`"""
-    deleteMessages = delete_messages
-    """Alias for :meth:`delete_messages`"""
-    forwardMessage = forward_message
-    """Alias for :meth:`forward_message`"""
-    forwardMessages = forward_messages
-    """Alias for :meth:`forward_messages`"""
-    sendPhoto = send_photo
-    """Alias for :meth:`send_photo`"""
-    sendAudio = send_audio
-    """Alias for :meth:`send_audio`"""
-    sendDocument = send_document
-    """Alias for :meth:`send_document`"""
-    sendSticker = send_sticker
-    """Alias for :meth:`send_sticker`"""
-    sendVideo = send_video
-    """Alias for :meth:`send_video`"""
-    sendAnimation = send_animation
-    """Alias for :meth:`send_animation`"""
-    sendVoice = send_voice
-    """Alias for :meth:`send_voice`"""
-    sendVideoNote = send_video_note
-    """Alias for :meth:`send_video_note`"""
-    sendMediaGroup = send_media_group
-    """Alias for :meth:`send_media_group`"""
-    sendLocation = send_location
-    """Alias for :meth:`send_location`"""
-    editMessageLiveLocation = edit_message_live_location
-    """Alias for :meth:`edit_message_live_location`"""
-    stopMessageLiveLocation = stop_message_live_location
-    """Alias for :meth:`stop_message_live_location`"""
-    sendVenue = send_venue
-    """Alias for :meth:`send_venue`"""
-    sendContact = send_contact
-    """Alias for :meth:`send_contact`"""
-    sendGame = send_game
-    """Alias for :meth:`send_game`"""
-    sendChatAction = send_chat_action
-    """Alias for :meth:`send_chat_action`"""
-    answerInlineQuery = answer_inline_query
-    """Alias for :meth:`answer_inline_query`"""
-    savePreparedInlineMessage = save_prepared_inline_message
-    """Alias for :meth:`save_prepared_inline_message`"""
-    getUserProfilePhotos = get_user_profile_photos
-    """Alias for :meth:`get_user_profile_photos`"""
-    getFile = get_file
-    """Alias for :meth:`get_file`"""
-    banChatMember = ban_chat_member
-    """Alias for :meth:`ban_chat_member`"""
-    banChatSenderChat = ban_chat_sender_chat
-    """Alias for :meth:`ban_chat_sender_chat`"""
-    unbanChatMember = unban_chat_member
-    """Alias for :meth:`unban_chat_member`"""
-    unbanChatSenderChat = unban_chat_sender_chat
-    """Alias for :meth:`unban_chat_sender_chat`"""
-    answerCallbackQuery = answer_callback_query
-    """Alias for :meth:`answer_callback_query`"""
-    editMessageText = edit_message_text
-    """Alias for :meth:`edit_message_text`"""
-    editMessageCaption = edit_message_caption
-    """Alias for :meth:`edit_message_caption`"""
-    editMessageMedia = edit_message_media
-    """Alias for :meth:`edit_message_media`"""
-    editMessageReplyMarkup = edit_message_reply_markup
-    """Alias for :meth:`edit_message_reply_markup`"""
-    getUpdates = get_updates
-    """Alias for :meth:`get_updates`"""
-    setWebhook = set_webhook
-    """Alias for :meth:`set_webhook`"""
-    deleteWebhook = delete_webhook
-    """Alias for :meth:`delete_webhook`"""
-    leaveChat = leave_chat
-    """Alias for :meth:`leave_chat`"""
-    getChat = get_chat
-    """Alias for :meth:`get_chat`"""
-    getChatAdministrators = get_chat_administrators
-    """Alias for :meth:`get_chat_administrators`"""
-    getChatMember = get_chat_member
-    """Alias for :meth:`get_chat_member`"""
-    setChatStickerSet = set_chat_sticker_set
-    """Alias for :meth:`set_chat_sticker_set`"""
-    deleteChatStickerSet = delete_chat_sticker_set
-    """Alias for :meth:`delete_chat_sticker_set`"""
-    getChatMemberCount = get_chat_member_count
-    """Alias for :meth:`get_chat_member_count`"""
-    getWebhookInfo = get_webhook_info
-    """Alias for :meth:`get_webhook_info`"""
-    setGameScore = set_game_score
-    """Alias for :meth:`set_game_score`"""
-    getGameHighScores = get_game_high_scores
-    """Alias for :meth:`get_game_high_scores`"""
-    sendInvoice = send_invoice
-    """Alias for :meth:`send_invoice`"""
-    answerShippingQuery = answer_shipping_query
-    """Alias for :meth:`answer_shipping_query`"""
-    answerPreCheckoutQuery = answer_pre_checkout_query
-    """Alias for :meth:`answer_pre_checkout_query`"""
-    answerWebAppQuery = answer_web_app_query
-    """Alias for :meth:`answer_web_app_query`"""
-    restrictChatMember = restrict_chat_member
-    """Alias for :meth:`restrict_chat_member`"""
-    promoteChatMember = promote_chat_member
-    """Alias for :meth:`promote_chat_member`"""
-    setChatPermissions = set_chat_permissions
-    """Alias for :meth:`set_chat_permissions`"""
-    setChatAdministratorCustomTitle = set_chat_administrator_custom_title
-    """Alias for :meth:`set_chat_administrator_custom_title`"""
-    exportChatInviteLink = export_chat_invite_link
-    """Alias for :meth:`export_chat_invite_link`"""
-    createChatInviteLink = create_chat_invite_link
-    """Alias for :meth:`create_chat_invite_link`"""
-    editChatInviteLink = edit_chat_invite_link
-    """Alias for :meth:`edit_chat_invite_link`"""
-    revokeChatInviteLink = revoke_chat_invite_link
-    """Alias for :meth:`revoke_chat_invite_link`"""
-    approveChatJoinRequest = approve_chat_join_request
-    """Alias for :meth:`approve_chat_join_request`"""
-    declineChatJoinRequest = decline_chat_join_request
-    """Alias for :meth:`decline_chat_join_request`"""
-    setChatPhoto = set_chat_photo
-    """Alias for :meth:`set_chat_photo`"""
-    deleteChatPhoto = delete_chat_photo
-    """Alias for :meth:`delete_chat_photo`"""
-    setChatTitle = set_chat_title
-    """Alias for :meth:`set_chat_title`"""
-    setChatDescription = set_chat_description
-    """Alias for :meth:`set_chat_description`"""
-    setUserEmojiStatus = set_user_emoji_status
-    """Alias for :meth:`set_user_emoji_status`"""
-    pinChatMessage = pin_chat_message
-    """Alias for :meth:`pin_chat_message`"""
-    unpinChatMessage = unpin_chat_message
-    """Alias for :meth:`unpin_chat_message`"""
-    unpinAllChatMessages = unpin_all_chat_messages
-    """Alias for :meth:`unpin_all_chat_messages`"""
-    getCustomEmojiStickers = get_custom_emoji_stickers
-    """Alias for :meth:`get_custom_emoji_stickers`"""
-    getStickerSet = get_sticker_set
-    """Alias for :meth:`get_sticker_set`"""
-    uploadStickerFile = upload_sticker_file
-    """Alias for :meth:`upload_sticker_file`"""
-    createNewStickerSet = create_new_sticker_set
-    """Alias for :meth:`create_new_sticker_set`"""
-    addStickerToSet = add_sticker_to_set
-    """Alias for :meth:`add_sticker_to_set`"""
-    setStickerPositionInSet = set_sticker_position_in_set
-    """Alias for :meth:`set_sticker_position_in_set`"""
-    deleteStickerFromSet = delete_sticker_from_set
-    """Alias for :meth:`delete_sticker_from_set`"""
-    setStickerSetThumbnail = set_sticker_set_thumbnail
-    """Alias for :meth:`set_sticker_set_thumbnail`"""
-    setPassportDataErrors = set_passport_data_errors
-    """Alias for :meth:`set_passport_data_errors`"""
-    sendPoll = send_poll
-    """Alias for :meth:`send_poll`"""
-    stopPoll = stop_poll
-    """Alias for :meth:`stop_poll`"""
-    sendDice = send_dice
-    """Alias for :meth:`send_dice`"""
-    getMyCommands = get_my_commands
-    """Alias for :meth:`get_my_commands`"""
-    setMyCommands = set_my_commands
-    """Alias for :meth:`set_my_commands`"""
-    deleteMyCommands = delete_my_commands
-    """Alias for :meth:`delete_my_commands`"""
-    logOut = log_out
-    """Alias for :meth:`log_out`"""
-    copyMessage = copy_message
-    """Alias for :meth:`copy_message`"""
-    copyMessages = copy_messages
-    """Alias for :meth:`copy_messages`"""
-    getChatMenuButton = get_chat_menu_button
-    """Alias for :meth:`get_chat_menu_button`"""
-    setChatMenuButton = set_chat_menu_button
-    """Alias for :meth:`set_chat_menu_button`"""
-    getMyDefaultAdministratorRights = get_my_default_administrator_rights
-    """Alias for :meth:`get_my_default_administrator_rights`"""
-    setMyDefaultAdministratorRights = set_my_default_administrator_rights
-    """Alias for :meth:`set_my_default_administrator_rights`"""
-    createInvoiceLink = create_invoice_link
-    """Alias for :meth:`create_invoice_link`"""
-    getForumTopicIconStickers = get_forum_topic_icon_stickers
-    """Alias for :meth:`get_forum_topic_icon_stickers`"""
-    createForumTopic = create_forum_topic
-    """Alias for :meth:`create_forum_topic`"""
-    editForumTopic = edit_forum_topic
-    """Alias for :meth:`edit_forum_topic`"""
-    closeForumTopic = close_forum_topic
-    """Alias for :meth:`close_forum_topic`"""
-    reopenForumTopic = reopen_forum_topic
-    """Alias for :meth:`reopen_forum_topic`"""
-    deleteForumTopic = delete_forum_topic
-    """Alias for :meth:`delete_forum_topic`"""
-    unpinAllForumTopicMessages = unpin_all_forum_topic_messages
-    """Alias for :meth:`unpin_all_forum_topic_messages`"""
-    editGeneralForumTopic = edit_general_forum_topic
-    """Alias for :meth:`edit_general_forum_topic`"""
-    closeGeneralForumTopic = close_general_forum_topic
-    """Alias for :meth:`close_general_forum_topic`"""
-    reopenGeneralForumTopic = reopen_general_forum_topic
-    """Alias for :meth:`reopen_general_forum_topic`"""
-    hideGeneralForumTopic = hide_general_forum_topic
-    """Alias for :meth:`hide_general_forum_topic`"""
-    unhideGeneralForumTopic = unhide_general_forum_topic
-    """Alias for :meth:`unhide_general_forum_topic`"""
-    setMyDescription = set_my_description
-    """Alias for :meth:`set_my_description`"""
-    setMyShortDescription = set_my_short_description
-    """Alias for :meth:`set_my_short_description`"""
-    getMyDescription = get_my_description
-    """Alias for :meth:`get_my_description`"""
-    getMyShortDescription = get_my_short_description
-    """Alias for :meth:`get_my_short_description`"""
-    setCustomEmojiStickerSetThumbnail = set_custom_emoji_sticker_set_thumbnail
-    """Alias for :meth:`set_custom_emoji_sticker_set_thumbnail`"""
-    setStickerSetTitle = set_sticker_set_title
-    """Alias for :meth:`set_sticker_set_title`"""
-    deleteStickerSet = delete_sticker_set
-    """Alias for :meth:`delete_sticker_set`"""
-    setStickerEmojiList = set_sticker_emoji_list
-    """Alias for :meth:`set_sticker_emoji_list`"""
-    setStickerKeywords = set_sticker_keywords
-    """Alias for :meth:`set_sticker_keywords`"""
-    setStickerMaskPosition = set_sticker_mask_position
-    """Alias for :meth:`set_sticker_mask_position`"""
-    setMyName = set_my_name
-    """Alias for :meth:`set_my_name`"""
-    getMyName = get_my_name
-    """Alias for :meth:`get_my_name`"""
-    unpinAllGeneralForumTopicMessages = unpin_all_general_forum_topic_messages
-    """Alias for :meth:`unpin_all_general_forum_topic_messages`"""
-    getUserChatBoosts = get_user_chat_boosts
-    """Alias for :meth:`get_user_chat_boosts`"""
-    setMessageReaction = set_message_reaction
-    """Alias for :meth:`set_message_reaction`"""
-    getBusinessConnection = get_business_connection
-    """Alias for :meth:`get_business_connection`"""
-    replaceStickerInSet = replace_sticker_in_set
-    """Alias for :meth:`replace_sticker_in_set`"""
-    refundStarPayment = refund_star_payment
-    """Alias for :meth:`refund_star_payment`"""
-    getStarTransactions = get_star_transactions
-    """Alias for :meth:`get_star_transactions`"""
-    editUserStarSubscription = edit_user_star_subscription
-    """Alias for :meth:`edit_user_star_subscription`"""
-    sendPaidMedia = send_paid_media
-    """Alias for :meth:`send_paid_media`"""
-    createChatSubscriptionInviteLink = create_chat_subscription_invite_link
-    """Alias for :meth:`create_chat_subscription_invite_link`"""
-    editChatSubscriptionInviteLink = edit_chat_subscription_invite_link
-    """Alias for :meth:`edit_chat_subscription_invite_link`"""
-    getAvailableGifts = get_available_gifts
-    """Alias for :meth:`get_available_gifts`"""
-    sendGift = send_gift
-    """Alias for :meth:`send_gift`"""
-    verifyChat = verify_chat
-    """Alias for :meth:`verify_chat`"""
-    verifyUser = verify_user
-    """Alias for :meth:`verify_user`"""
-    removeChatVerification = remove_chat_verification
-    """Alias for :meth:`remove_chat_verification`"""
-    removeUserVerification = remove_user_verification
-    """Alias for :meth:`remove_user_verification`"""
diff --git a/venv/lib/python3.11/site-packages/telegram/_botcommand.py b/venv/lib/python3.11/site-packages/telegram/_botcommand.py
deleted file mode 100755
index 0597408..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_botcommand.py
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram Bot Command."""
-
-from typing import Final, Optional
-
-from telegram import constants
-from telegram._telegramobject import TelegramObject
-from telegram._utils.types import JSONDict
-
-
-class BotCommand(TelegramObject):
-    """
-    This object represents a bot command.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`command` and :attr:`description` are equal.
-
-    Args:
-        command (:obj:`str`): Text of the command; :tg-const:`telegram.BotCommand.MIN_COMMAND`-
-            :tg-const:`telegram.BotCommand.MAX_COMMAND` characters. Can contain only lowercase
-            English letters, digits and underscores.
-        description (:obj:`str`): Description of the command;
-            :tg-const:`telegram.BotCommand.MIN_DESCRIPTION`-
-            :tg-const:`telegram.BotCommand.MAX_DESCRIPTION` characters.
-
-    Attributes:
-        command (:obj:`str`): Text of the command; :tg-const:`telegram.BotCommand.MIN_COMMAND`-
-            :tg-const:`telegram.BotCommand.MAX_COMMAND` characters. Can contain only lowercase
-            English letters, digits and underscores.
-        description (:obj:`str`): Description of the command;
-            :tg-const:`telegram.BotCommand.MIN_DESCRIPTION`-
-            :tg-const:`telegram.BotCommand.MAX_DESCRIPTION` characters.
-
-    """
-
-    __slots__ = ("command", "description")
-
-    def __init__(self, command: str, description: str, *, api_kwargs: Optional[JSONDict] = None):
-        super().__init__(api_kwargs=api_kwargs)
-        self.command: str = command
-        self.description: str = description
-
-        self._id_attrs = (self.command, self.description)
-
-        self._freeze()
-
-    MIN_COMMAND: Final[int] = constants.BotCommandLimit.MIN_COMMAND
-    """:const:`telegram.constants.BotCommandLimit.MIN_COMMAND`
-
-    .. versionadded:: 20.0
-    """
-    MAX_COMMAND: Final[int] = constants.BotCommandLimit.MAX_COMMAND
-    """:const:`telegram.constants.BotCommandLimit.MAX_COMMAND`
-
-    .. versionadded:: 20.0
-    """
-    MIN_DESCRIPTION: Final[int] = constants.BotCommandLimit.MIN_DESCRIPTION
-    """:const:`telegram.constants.BotCommandLimit.MIN_DESCRIPTION`
-
-    .. versionadded:: 20.0
-    """
-    MAX_DESCRIPTION: Final[int] = constants.BotCommandLimit.MAX_DESCRIPTION
-    """:const:`telegram.constants.BotCommandLimit.MAX_DESCRIPTION`
-
-    .. versionadded:: 20.0
-    """
diff --git a/venv/lib/python3.11/site-packages/telegram/_botcommandscope.py b/venv/lib/python3.11/site-packages/telegram/_botcommandscope.py
deleted file mode 100755
index 0c339a3..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_botcommandscope.py
+++ /dev/null
@@ -1,273 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-# pylint: disable=redefined-builtin
-"""This module contains objects representing Telegram bot command scopes."""
-from typing import TYPE_CHECKING, Final, Optional, Union
-
-from telegram import constants
-from telegram._telegramobject import TelegramObject
-from telegram._utils import enum
-from telegram._utils.types import JSONDict
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class BotCommandScope(TelegramObject):
-    """Base class for objects that represent the scope to which bot commands are applied.
-    Currently, the following 7 scopes are supported:
-
-    * :class:`telegram.BotCommandScopeDefault`
-    * :class:`telegram.BotCommandScopeAllPrivateChats`
-    * :class:`telegram.BotCommandScopeAllGroupChats`
-    * :class:`telegram.BotCommandScopeAllChatAdministrators`
-    * :class:`telegram.BotCommandScopeChat`
-    * :class:`telegram.BotCommandScopeChatAdministrators`
-    * :class:`telegram.BotCommandScopeChatMember`
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`type` is equal. For subclasses with additional attributes,
-    the notion of equality is overridden.
-
-    Note:
-        Please see the `official docs`_ on how Telegram determines which commands to display.
-
-    .. _`official docs`: https://core.telegram.org/bots/api#determining-list-of-commands
-
-    .. versionadded:: 13.7
-
-    Args:
-        type (:obj:`str`): Scope type.
-
-    Attributes:
-        type (:obj:`str`): Scope type.
-    """
-
-    __slots__ = ("type",)
-
-    DEFAULT: Final[str] = constants.BotCommandScopeType.DEFAULT
-    """:const:`telegram.constants.BotCommandScopeType.DEFAULT`"""
-    ALL_PRIVATE_CHATS: Final[str] = constants.BotCommandScopeType.ALL_PRIVATE_CHATS
-    """:const:`telegram.constants.BotCommandScopeType.ALL_PRIVATE_CHATS`"""
-    ALL_GROUP_CHATS: Final[str] = constants.BotCommandScopeType.ALL_GROUP_CHATS
-    """:const:`telegram.constants.BotCommandScopeType.ALL_GROUP_CHATS`"""
-    ALL_CHAT_ADMINISTRATORS: Final[str] = constants.BotCommandScopeType.ALL_CHAT_ADMINISTRATORS
-    """:const:`telegram.constants.BotCommandScopeType.ALL_CHAT_ADMINISTRATORS`"""
-    CHAT: Final[str] = constants.BotCommandScopeType.CHAT
-    """:const:`telegram.constants.BotCommandScopeType.CHAT`"""
-    CHAT_ADMINISTRATORS: Final[str] = constants.BotCommandScopeType.CHAT_ADMINISTRATORS
-    """:const:`telegram.constants.BotCommandScopeType.CHAT_ADMINISTRATORS`"""
-    CHAT_MEMBER: Final[str] = constants.BotCommandScopeType.CHAT_MEMBER
-    """:const:`telegram.constants.BotCommandScopeType.CHAT_MEMBER`"""
-
-    def __init__(self, type: str, *, api_kwargs: Optional[JSONDict] = None):
-        super().__init__(api_kwargs=api_kwargs)
-        self.type: str = enum.get_member(constants.BotCommandScopeType, type, type)
-        self._id_attrs = (self.type,)
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["BotCommandScope"]:
-        """Converts JSON data to the appropriate :class:`BotCommandScope` object, i.e. takes
-        care of selecting the correct subclass.
-
-        Args:
-            data (dict[:obj:`str`, ...]): The JSON data.
-            bot (:class:`telegram.Bot`, optional): The bot associated with this object. Defaults to
-                :obj:`None`, in which case shortcut methods will not be available.
-
-                .. versionchanged:: 21.4
-                   :paramref:`bot` is now optional and defaults to :obj:`None`
-
-        Returns:
-            The Telegram object.
-
-        """
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        _class_mapping: dict[str, type[BotCommandScope]] = {
-            cls.DEFAULT: BotCommandScopeDefault,
-            cls.ALL_PRIVATE_CHATS: BotCommandScopeAllPrivateChats,
-            cls.ALL_GROUP_CHATS: BotCommandScopeAllGroupChats,
-            cls.ALL_CHAT_ADMINISTRATORS: BotCommandScopeAllChatAdministrators,
-            cls.CHAT: BotCommandScopeChat,
-            cls.CHAT_ADMINISTRATORS: BotCommandScopeChatAdministrators,
-            cls.CHAT_MEMBER: BotCommandScopeChatMember,
-        }
-
-        if cls is BotCommandScope and data.get("type") in _class_mapping:
-            return _class_mapping[data.pop("type")].de_json(data=data, bot=bot)
-        return super().de_json(data=data, bot=bot)
-
-
-class BotCommandScopeDefault(BotCommandScope):
-    """Represents the default scope of bot commands. Default commands are used if no commands with
-    a `narrower scope`_ are specified for the user.
-
-    .. _`narrower scope`: https://core.telegram.org/bots/api#determining-list-of-commands
-
-    .. versionadded:: 13.7
-    Attributes:
-        type (:obj:`str`): Scope type :tg-const:`telegram.BotCommandScope.DEFAULT`.
-    """
-
-    __slots__ = ()
-
-    def __init__(self, *, api_kwargs: Optional[JSONDict] = None):
-        super().__init__(type=BotCommandScope.DEFAULT, api_kwargs=api_kwargs)
-        self._freeze()
-
-
-class BotCommandScopeAllPrivateChats(BotCommandScope):
-    """Represents the scope of bot commands, covering all private chats.
-
-    .. versionadded:: 13.7
-
-    Attributes:
-        type (:obj:`str`): Scope type :tg-const:`telegram.BotCommandScope.ALL_PRIVATE_CHATS`.
-    """
-
-    __slots__ = ()
-
-    def __init__(self, *, api_kwargs: Optional[JSONDict] = None):
-        super().__init__(type=BotCommandScope.ALL_PRIVATE_CHATS, api_kwargs=api_kwargs)
-        self._freeze()
-
-
-class BotCommandScopeAllGroupChats(BotCommandScope):
-    """Represents the scope of bot commands, covering all group and supergroup chats.
-
-    .. versionadded:: 13.7
-    Attributes:
-        type (:obj:`str`): Scope type :tg-const:`telegram.BotCommandScope.ALL_GROUP_CHATS`.
-    """
-
-    __slots__ = ()
-
-    def __init__(self, *, api_kwargs: Optional[JSONDict] = None):
-        super().__init__(type=BotCommandScope.ALL_GROUP_CHATS, api_kwargs=api_kwargs)
-        self._freeze()
-
-
-class BotCommandScopeAllChatAdministrators(BotCommandScope):
-    """Represents the scope of bot commands, covering all group and supergroup chat administrators.
-
-    .. versionadded:: 13.7
-    Attributes:
-        type (:obj:`str`): Scope type :tg-const:`telegram.BotCommandScope.ALL_CHAT_ADMINISTRATORS`.
-    """
-
-    __slots__ = ()
-
-    def __init__(self, *, api_kwargs: Optional[JSONDict] = None):
-        super().__init__(type=BotCommandScope.ALL_CHAT_ADMINISTRATORS, api_kwargs=api_kwargs)
-        self._freeze()
-
-
-class BotCommandScopeChat(BotCommandScope):
-    """Represents the scope of bot commands, covering a specific chat.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`type` and :attr:`chat_id` are equal.
-
-    .. versionadded:: 13.7
-
-    Args:
-        chat_id (:obj:`str` | :obj:`int`): |chat_id_group|
-
-    Attributes:
-        type (:obj:`str`): Scope type :tg-const:`telegram.BotCommandScope.CHAT`.
-        chat_id (:obj:`str` | :obj:`int`): |chat_id_group|
-    """
-
-    __slots__ = ("chat_id",)
-
-    def __init__(self, chat_id: Union[str, int], *, api_kwargs: Optional[JSONDict] = None):
-        super().__init__(type=BotCommandScope.CHAT, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.chat_id: Union[str, int] = (
-                chat_id if isinstance(chat_id, str) and chat_id.startswith("@") else int(chat_id)
-            )
-            self._id_attrs = (self.type, self.chat_id)
-
-
-class BotCommandScopeChatAdministrators(BotCommandScope):
-    """Represents the scope of bot commands, covering all administrators of a specific group or
-    supergroup chat.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`type` and :attr:`chat_id` are equal.
-
-    .. versionadded:: 13.7
-
-    Args:
-        chat_id (:obj:`str` | :obj:`int`): |chat_id_group|
-    Attributes:
-        type (:obj:`str`): Scope type :tg-const:`telegram.BotCommandScope.CHAT_ADMINISTRATORS`.
-        chat_id (:obj:`str` | :obj:`int`): |chat_id_group|
-    """
-
-    __slots__ = ("chat_id",)
-
-    def __init__(self, chat_id: Union[str, int], *, api_kwargs: Optional[JSONDict] = None):
-        super().__init__(type=BotCommandScope.CHAT_ADMINISTRATORS, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.chat_id: Union[str, int] = (
-                chat_id if isinstance(chat_id, str) and chat_id.startswith("@") else int(chat_id)
-            )
-            self._id_attrs = (self.type, self.chat_id)
-
-
-class BotCommandScopeChatMember(BotCommandScope):
-    """Represents the scope of bot commands, covering a specific member of a group or supergroup
-    chat.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`type`, :attr:`chat_id` and :attr:`user_id` are equal.
-
-    .. versionadded:: 13.7
-
-    Args:
-        chat_id (:obj:`str` | :obj:`int`): |chat_id_group|
-        user_id (:obj:`int`): Unique identifier of the target user.
-
-    Attributes:
-        type (:obj:`str`): Scope type :tg-const:`telegram.BotCommandScope.CHAT_MEMBER`.
-        chat_id (:obj:`str` | :obj:`int`): |chat_id_group|
-        user_id (:obj:`int`): Unique identifier of the target user.
-    """
-
-    __slots__ = ("chat_id", "user_id")
-
-    def __init__(
-        self, chat_id: Union[str, int], user_id: int, *, api_kwargs: Optional[JSONDict] = None
-    ):
-        super().__init__(type=BotCommandScope.CHAT_MEMBER, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.chat_id: Union[str, int] = (
-                chat_id if isinstance(chat_id, str) and chat_id.startswith("@") else int(chat_id)
-            )
-            self.user_id: int = user_id
-            self._id_attrs = (self.type, self.chat_id, self.user_id)
diff --git a/venv/lib/python3.11/site-packages/telegram/_botdescription.py b/venv/lib/python3.11/site-packages/telegram/_botdescription.py
deleted file mode 100755
index 9f53ef1..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_botdescription.py
+++ /dev/null
@@ -1,77 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains two objects that represent a Telegram bots (short) description."""
-from typing import Optional
-
-from telegram._telegramobject import TelegramObject
-from telegram._utils.types import JSONDict
-
-
-class BotDescription(TelegramObject):
-    """This object represents the bot's description.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`description` is equal.
-
-    .. versionadded:: 20.2
-
-    Args:
-        description (:obj:`str`): The bot's description.
-
-    Attributes:
-        description (:obj:`str`): The bot's description.
-
-    """
-
-    __slots__ = ("description",)
-
-    def __init__(self, description: str, *, api_kwargs: Optional[JSONDict] = None):
-        super().__init__(api_kwargs=api_kwargs)
-        self.description: str = description
-
-        self._id_attrs = (self.description,)
-
-        self._freeze()
-
-
-class BotShortDescription(TelegramObject):
-    """This object represents the bot's short description.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`short_description` is equal.
-
-    .. versionadded:: 20.2
-
-    Args:
-        short_description (:obj:`str`): The bot's short description.
-
-    Attributes:
-        short_description (:obj:`str`): The bot's short description.
-
-    """
-
-    __slots__ = ("short_description",)
-
-    def __init__(self, short_description: str, *, api_kwargs: Optional[JSONDict] = None):
-        super().__init__(api_kwargs=api_kwargs)
-        self.short_description: str = short_description
-
-        self._id_attrs = (self.short_description,)
-
-        self._freeze()
diff --git a/venv/lib/python3.11/site-packages/telegram/_botname.py b/venv/lib/python3.11/site-packages/telegram/_botname.py
deleted file mode 100755
index a297027..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_botname.py
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represent a Telegram bots name."""
-from typing import Final, Optional
-
-from telegram import constants
-from telegram._telegramobject import TelegramObject
-from telegram._utils.types import JSONDict
-
-
-class BotName(TelegramObject):
-    """This object represents the bot's name.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`name` is equal.
-
-    .. versionadded:: 20.3
-
-    Args:
-        name (:obj:`str`): The bot's name.
-
-    Attributes:
-        name (:obj:`str`): The bot's name.
-
-    """
-
-    __slots__ = ("name",)
-
-    def __init__(self, name: str, *, api_kwargs: Optional[JSONDict] = None):
-        super().__init__(api_kwargs=api_kwargs)
-        self.name: str = name
-
-        self._id_attrs = (self.name,)
-
-        self._freeze()
-
-    MAX_LENGTH: Final[int] = constants.BotNameLimit.MAX_NAME_LENGTH
-    """:const:`telegram.constants.BotNameLimit.MAX_NAME_LENGTH`"""
diff --git a/venv/lib/python3.11/site-packages/telegram/_business.py b/venv/lib/python3.11/site-packages/telegram/_business.py
deleted file mode 100755
index 412eae7..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_business.py
+++ /dev/null
@@ -1,455 +0,0 @@
-#!/usr/bin/env python
-# pylint: disable=redefined-builtin
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/]
-"""This module contains the Telegram Business related classes."""
-import datetime as dtm
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Optional
-
-from telegram._chat import Chat
-from telegram._files.location import Location
-from telegram._files.sticker import Sticker
-from telegram._telegramobject import TelegramObject
-from telegram._user import User
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
-from telegram._utils.types import JSONDict
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class BusinessConnection(TelegramObject):
-    """
-    Describes the connection of the bot with a business account.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal if their :attr:`id`, :attr:`user`, :attr:`user_chat_id`, :attr:`date`,
-    :attr:`can_reply`, and :attr:`is_enabled` are equal.
-
-    .. versionadded:: 21.1
-
-    Args:
-        id (:obj:`str`): Unique identifier of the business connection.
-        user (:class:`telegram.User`): Business account user that created the business connection.
-        user_chat_id (:obj:`int`): Identifier of a private chat with the user who created the
-            business connection.
-        date (:obj:`datetime.datetime`): Date the connection was established in Unix time.
-        can_reply (:obj:`bool`): True, if the bot can act on behalf of the business account in
-            chats that were active in the last 24 hours.
-        is_enabled (:obj:`bool`): True, if the connection is active.
-
-    Attributes:
-        id (:obj:`str`): Unique identifier of the business connection.
-        user (:class:`telegram.User`): Business account user that created the business connection.
-        user_chat_id (:obj:`int`): Identifier of a private chat with the user who created the
-            business connection.
-        date (:obj:`datetime.datetime`): Date the connection was established in Unix time.
-        can_reply (:obj:`bool`): True, if the bot can act on behalf of the business account in
-            chats that were active in the last 24 hours.
-        is_enabled (:obj:`bool`): True, if the connection is active.
-    """
-
-    __slots__ = (
-        "can_reply",
-        "date",
-        "id",
-        "is_enabled",
-        "user",
-        "user_chat_id",
-    )
-
-    def __init__(
-        self,
-        id: str,
-        user: "User",
-        user_chat_id: int,
-        date: dtm.datetime,
-        can_reply: bool,
-        is_enabled: bool,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.id: str = id
-        self.user: User = user
-        self.user_chat_id: int = user_chat_id
-        self.date: dtm.datetime = date
-        self.can_reply: bool = can_reply
-        self.is_enabled: bool = is_enabled
-
-        self._id_attrs = (
-            self.id,
-            self.user,
-            self.user_chat_id,
-            self.date,
-            self.can_reply,
-            self.is_enabled,
-        )
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["BusinessConnection"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        # Get the local timezone from the bot if it has defaults
-        loc_tzinfo = extract_tzinfo_from_defaults(bot)
-
-        data["date"] = from_timestamp(data.get("date"), tzinfo=loc_tzinfo)
-        data["user"] = User.de_json(data.get("user"), bot)
-
-        return super().de_json(data=data, bot=bot)
-
-
-class BusinessMessagesDeleted(TelegramObject):
-    """
-    This object is received when messages are deleted from a connected business account.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal if their :attr:`business_connection_id`, :attr:`message_ids`, and
-    :attr:`chat` are equal.
-
-    .. versionadded:: 21.1
-
-    Args:
-        business_connection_id (:obj:`str`): Unique identifier of the business connection.
-        chat (:class:`telegram.Chat`): Information about a chat in the business account. The bot
-            may not have access to the chat or the corresponding user.
-        message_ids (Sequence[:obj:`int`]): A list of identifiers of the deleted messages in the
-            chat of the business account.
-
-    Attributes:
-        business_connection_id (:obj:`str`): Unique identifier of the business connection.
-        chat (:class:`telegram.Chat`): Information about a chat in the business account. The bot
-            may not have access to the chat or the corresponding user.
-        message_ids (tuple[:obj:`int`]): A list of identifiers of the deleted messages in the
-            chat of the business account.
-    """
-
-    __slots__ = (
-        "business_connection_id",
-        "chat",
-        "message_ids",
-    )
-
-    def __init__(
-        self,
-        business_connection_id: str,
-        chat: Chat,
-        message_ids: Sequence[int],
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.business_connection_id: str = business_connection_id
-        self.chat: Chat = chat
-        self.message_ids: tuple[int, ...] = parse_sequence_arg(message_ids)
-
-        self._id_attrs = (
-            self.business_connection_id,
-            self.chat,
-            self.message_ids,
-        )
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["BusinessMessagesDeleted"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        data["chat"] = Chat.de_json(data.get("chat"), bot)
-
-        return super().de_json(data=data, bot=bot)
-
-
-class BusinessIntro(TelegramObject):
-    """
-    This object contains information about the start page settings of a Telegram Business account.
-
-    Objects of this class are comparable in terms of equality.
-    Two objects of this class are considered equal, if their
-    :attr:`title`, :attr:`message` and :attr:`sticker` are equal.
-
-    .. versionadded:: 21.1
-
-    Args:
-        title (:obj:`str`, optional): Title text of the business intro.
-        message (:obj:`str`, optional): Message text of the business intro.
-        sticker (:class:`telegram.Sticker`, optional): Sticker of the business intro.
-
-    Attributes:
-        title (:obj:`str`): Optional. Title text of the business intro.
-        message (:obj:`str`): Optional. Message text of the business intro.
-        sticker (:class:`telegram.Sticker`): Optional. Sticker of the business intro.
-    """
-
-    __slots__ = (
-        "message",
-        "sticker",
-        "title",
-    )
-
-    def __init__(
-        self,
-        title: Optional[str] = None,
-        message: Optional[str] = None,
-        sticker: Optional[Sticker] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.title: Optional[str] = title
-        self.message: Optional[str] = message
-        self.sticker: Optional[Sticker] = sticker
-
-        self._id_attrs = (self.title, self.message, self.sticker)
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["BusinessIntro"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        data["sticker"] = Sticker.de_json(data.get("sticker"), bot)
-
-        return super().de_json(data=data, bot=bot)
-
-
-class BusinessLocation(TelegramObject):
-    """
-    This object contains information about the location of a Telegram Business account.
-
-    Objects of this class are comparable in terms of equality.
-    Two objects of this class are considered equal, if their
-    :attr:`address` is equal.
-
-    .. versionadded:: 21.1
-
-    Args:
-        address (:obj:`str`): Address of the business.
-        location (:class:`telegram.Location`, optional): Location of the business.
-
-    Attributes:
-        address (:obj:`str`): Address of the business.
-        location (:class:`telegram.Location`): Optional. Location of the business.
-    """
-
-    __slots__ = (
-        "address",
-        "location",
-    )
-
-    def __init__(
-        self,
-        address: str,
-        location: Optional[Location] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.address: str = address
-        self.location: Optional[Location] = location
-
-        self._id_attrs = (self.address,)
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["BusinessLocation"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        data["location"] = Location.de_json(data.get("location"), bot)
-
-        return super().de_json(data=data, bot=bot)
-
-
-class BusinessOpeningHoursInterval(TelegramObject):
-    """
-    This object describes an interval of time during which a business is open.
-
-    Objects of this class are comparable in terms of equality.
-    Two objects of this class are considered equal, if their
-    :attr:`opening_minute` and :attr:`closing_minute` are equal.
-
-    .. versionadded:: 21.1
-
-    Examples:
-        A day has (24 * 60 =) 1440 minutes, a week has (7 * 1440 =) 10080 minutes.
-        Starting the the minute's sequence from Monday, example values of
-        :attr:`opening_minute`, :attr:`closing_minute` will map to the following day times:
-
-        * Monday - 8am to 8:30pm:
-            - ``opening_minute = 480`` :guilabel:`8 * 60`
-            - ``closing_minute = 1230`` :guilabel:`20 * 60 + 30`
-        * Tuesday - 24 hours:
-            - ``opening_minute = 1440`` :guilabel:`24 * 60`
-            - ``closing_minute = 2879`` :guilabel:`2 * 24 * 60 - 1`
-        * Sunday - 12am - 11:58pm:
-            - ``opening_minute = 8640`` :guilabel:`6 * 24 * 60`
-            - ``closing_minute = 10078`` :guilabel:`7 * 24 * 60 - 2`
-
-    Args:
-        opening_minute (:obj:`int`): The minute's sequence number in a week, starting on Monday,
-            marking the start of the time interval during which the business is open;
-            0 - 7 * 24 * 60.
-        closing_minute (:obj:`int`): The minute's
-            sequence number in a week, starting on Monday, marking the end of the time interval
-            during which the business is open; 0 - 8 * 24 * 60
-
-    Attributes:
-        opening_minute (:obj:`int`): The minute's sequence number in a week, starting on Monday,
-            marking the start of the time interval during which the business is open;
-            0 - 7 * 24 * 60.
-        closing_minute (:obj:`int`): The minute's
-            sequence number in a week, starting on Monday, marking the end of the time interval
-            during which the business is open; 0 - 8 * 24 * 60
-    """
-
-    __slots__ = ("_closing_time", "_opening_time", "closing_minute", "opening_minute")
-
-    def __init__(
-        self,
-        opening_minute: int,
-        closing_minute: int,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.opening_minute: int = opening_minute
-        self.closing_minute: int = closing_minute
-
-        self._opening_time: Optional[tuple[int, int, int]] = None
-        self._closing_time: Optional[tuple[int, int, int]] = None
-
-        self._id_attrs = (self.opening_minute, self.closing_minute)
-
-        self._freeze()
-
-    def _parse_minute(self, minute: int) -> tuple[int, int, int]:
-        return (minute // 1440, minute % 1440 // 60, minute % 1440 % 60)
-
-    @property
-    def opening_time(self) -> tuple[int, int, int]:
-        """Convenience attribute. A :obj:`tuple` parsed from :attr:`opening_minute`. It contains
-        the `weekday`, `hour` and `minute` in the same ranges as :attr:`datetime.datetime.weekday`,
-        :attr:`datetime.datetime.hour` and :attr:`datetime.datetime.minute`
-
-        Returns:
-            tuple[:obj:`int`, :obj:`int`, :obj:`int`]:
-        """
-        if self._opening_time is None:
-            self._opening_time = self._parse_minute(self.opening_minute)
-        return self._opening_time
-
-    @property
-    def closing_time(self) -> tuple[int, int, int]:
-        """Convenience attribute. A :obj:`tuple` parsed from :attr:`closing_minute`. It contains
-        the `weekday`, `hour` and `minute` in the same ranges as :attr:`datetime.datetime.weekday`,
-        :attr:`datetime.datetime.hour` and :attr:`datetime.datetime.minute`
-
-        Returns:
-            tuple[:obj:`int`, :obj:`int`, :obj:`int`]:
-        """
-        if self._closing_time is None:
-            self._closing_time = self._parse_minute(self.closing_minute)
-        return self._closing_time
-
-
-class BusinessOpeningHours(TelegramObject):
-    """
-    This object describes the opening hours of a business.
-
-    Objects of this class are comparable in terms of equality.
-    Two objects of this class are considered equal, if their
-    :attr:`time_zone_name` and :attr:`opening_hours` are equal.
-
-    .. versionadded:: 21.1
-
-    Args:
-        time_zone_name (:obj:`str`): Unique name of the time zone for which the opening
-            hours are defined.
-        opening_hours (Sequence[:class:`telegram.BusinessOpeningHoursInterval`]): List of
-            time intervals describing business opening hours.
-
-    Attributes:
-        time_zone_name (:obj:`str`): Unique name of the time zone for which the opening
-            hours are defined.
-        opening_hours (Sequence[:class:`telegram.BusinessOpeningHoursInterval`]): List of
-            time intervals describing business opening hours.
-    """
-
-    __slots__ = ("opening_hours", "time_zone_name")
-
-    def __init__(
-        self,
-        time_zone_name: str,
-        opening_hours: Sequence[BusinessOpeningHoursInterval],
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.time_zone_name: str = time_zone_name
-        self.opening_hours: Sequence[BusinessOpeningHoursInterval] = parse_sequence_arg(
-            opening_hours
-        )
-
-        self._id_attrs = (self.time_zone_name, self.opening_hours)
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["BusinessOpeningHours"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        data["opening_hours"] = BusinessOpeningHoursInterval.de_list(
-            data.get("opening_hours"), bot
-        )
-
-        return super().de_json(data=data, bot=bot)
diff --git a/venv/lib/python3.11/site-packages/telegram/_callbackquery.py b/venv/lib/python3.11/site-packages/telegram/_callbackquery.py
deleted file mode 100755
index 8febcca..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_callbackquery.py
+++ /dev/null
@@ -1,895 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-# pylint: disable=redefined-builtin
-"""This module contains an object that represents a Telegram CallbackQuery"""
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Final, Optional, Union
-
-from telegram import constants
-from telegram._files.location import Location
-from telegram._message import MaybeInaccessibleMessage, Message
-from telegram._telegramobject import TelegramObject
-from telegram._user import User
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.types import JSONDict, ODVInput, ReplyMarkup
-
-if TYPE_CHECKING:
-    from telegram import (
-        Bot,
-        GameHighScore,
-        InlineKeyboardMarkup,
-        InputMedia,
-        LinkPreviewOptions,
-        MessageEntity,
-        MessageId,
-        ReplyParameters,
-    )
-
-
-class CallbackQuery(TelegramObject):
-    """
-    This object represents an incoming callback query from a callback button in an inline keyboard.
-
-    If the button that originated the query was attached to a message sent by the bot, the field
-    :attr:`message` will be present. If the button was attached to a message sent via the bot (in
-    inline mode), the field :attr:`inline_message_id` will be present.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`id` is equal.
-
-    Note:
-        * In Python :keyword:`from` is a reserved word. Use :paramref:`from_user` instead.
-        * Exactly one of the fields :attr:`data` or :attr:`game_short_name` will be present.
-        * After the user presses an inline button, Telegram clients will display a progress bar
-          until you call :attr:`answer`. It is, therefore, necessary to react
-          by calling :attr:`telegram.Bot.answer_callback_query` even if no notification to the user
-          is needed (e.g., without specifying any of the optional parameters).
-        * If you're using :attr:`telegram.ext.ExtBot.callback_data_cache`, :attr:`data` may be
-          an instance
-          of :class:`telegram.ext.InvalidCallbackData`. This will be the case, if the data
-          associated with the button triggering the :class:`telegram.CallbackQuery` was already
-          deleted or if :attr:`data` was manipulated by a malicious client.
-
-          .. versionadded:: 13.6
-
-    Args:
-        id (:obj:`str`): Unique identifier for this query.
-        from_user (:class:`telegram.User`): Sender.
-        chat_instance (:obj:`str`): Global identifier, uniquely corresponding to the chat to which
-            the message with the callback button was sent. Useful for high scores in games.
-        message (:class:`telegram.MaybeInaccessibleMessage`, optional): Message sent by the bot
-            with the callback button that originated the query.
-
-            .. versionchanged:: 20.8
-               Accept objects of type :class:`telegram.MaybeInaccessibleMessage` since Bot API 7.0.
-        data (:obj:`str`, optional): Data associated with the callback button. Be aware that the
-            message, which originated the query, can contain no callback buttons with this data.
-        inline_message_id (:obj:`str`, optional): Identifier of the message sent via the bot in
-            inline mode, that originated the query.
-        game_short_name (:obj:`str`, optional): Short name of a Game to be returned, serves as
-            the unique identifier for the game.
-
-    Attributes:
-        id (:obj:`str`): Unique identifier for this query.
-        from_user (:class:`telegram.User`): Sender.
-        chat_instance (:obj:`str`): Global identifier, uniquely corresponding to the chat to which
-            the message with the callback button was sent. Useful for high scores in games.
-        message (:class:`telegram.MaybeInaccessibleMessage`): Optional. Message sent by the bot
-            with the callback button that originated the query.
-
-            .. versionchanged:: 20.8
-               Objects may be of type :class:`telegram.MaybeInaccessibleMessage` since Bot API
-               7.0.
-        data (:obj:`str` | :obj:`object`): Optional. Data associated with the callback button.
-            Be aware that the message, which originated the query, can contain no callback buttons
-            with this data.
-
-            Tip:
-                The value here is the same as the value passed in
-                :paramref:`telegram.InlineKeyboardButton.callback_data`.
-        inline_message_id (:obj:`str`): Optional. Identifier of the message sent via the bot in
-            inline mode, that originated the query.
-        game_short_name (:obj:`str`): Optional. Short name of a Game to be returned, serves as
-            the unique identifier for the game.
-
-
-    """
-
-    __slots__ = (
-        "chat_instance",
-        "data",
-        "from_user",
-        "game_short_name",
-        "id",
-        "inline_message_id",
-        "message",
-    )
-
-    def __init__(
-        self,
-        id: str,
-        from_user: User,
-        chat_instance: str,
-        message: Optional[MaybeInaccessibleMessage] = None,
-        data: Optional[str] = None,
-        inline_message_id: Optional[str] = None,
-        game_short_name: Optional[str] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        # Required
-        self.id: str = id
-        self.from_user: User = from_user
-        self.chat_instance: str = chat_instance
-        # Optionals
-        self.message: Optional[MaybeInaccessibleMessage] = message
-        self.data: Optional[str] = data
-        self.inline_message_id: Optional[str] = inline_message_id
-        self.game_short_name: Optional[str] = game_short_name
-
-        self._id_attrs = (self.id,)
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["CallbackQuery"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        data["from_user"] = User.de_json(data.pop("from", None), bot)
-        data["message"] = Message.de_json(data.get("message"), bot)
-
-        return super().de_json(data=data, bot=bot)
-
-    async def answer(
-        self,
-        text: Optional[str] = None,
-        show_alert: Optional[bool] = None,
-        url: Optional[str] = None,
-        cache_time: Optional[int] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.answer_callback_query(update.callback_query.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.answer_callback_query`.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().answer_callback_query(
-            callback_query_id=self.id,
-            text=text,
-            show_alert=show_alert,
-            url=url,
-            cache_time=cache_time,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    def _get_message(self, action: str = "edit") -> Message:
-        """Helper method to get the message for the shortcut methods. Must be called only
-        if :attr:`inline_message_id` is *not* set.
-        """
-        if not isinstance(self.message, Message):
-            raise TypeError(f"Cannot {action} an inaccessible message")
-        return self.message
-
-    async def edit_message_text(
-        self,
-        text: str,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        entities: Optional[Sequence["MessageEntity"]] = None,
-        link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE,
-        *,
-        disable_web_page_preview: Optional[bool] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Union[Message, bool]:
-        """Shortcut for either::
-
-            await update.callback_query.message.edit_text(*args, **kwargs)
-
-        or::
-
-            await bot.edit_message_text(
-                inline_message_id=update.callback_query.inline_message_id, *args, **kwargs,
-            )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.edit_message_text` and :meth:`telegram.Message.edit_text`.
-
-        .. versionchanged:: 20.8
-           Raises :exc:`TypeError` if :attr:`message` is not accessible.
-
-        Returns:
-            :class:`telegram.Message`: On success, if edited message is sent by the bot, the
-            edited Message is returned, otherwise :obj:`True` is returned.
-
-        Raises:
-            :exc:`TypeError` if :attr:`message` is not accessible.
-
-        """
-        if self.inline_message_id:
-            return await self.get_bot().edit_message_text(
-                inline_message_id=self.inline_message_id,
-                text=text,
-                parse_mode=parse_mode,
-                disable_web_page_preview=disable_web_page_preview,
-                link_preview_options=link_preview_options,
-                reply_markup=reply_markup,
-                read_timeout=read_timeout,
-                write_timeout=write_timeout,
-                connect_timeout=connect_timeout,
-                pool_timeout=pool_timeout,
-                api_kwargs=api_kwargs,
-                entities=entities,
-                chat_id=None,
-                message_id=None,
-                # inline messages can not be sent on behalf of a bcid
-                business_connection_id=None,
-            )
-        return await self._get_message().edit_text(
-            text=text,
-            parse_mode=parse_mode,
-            disable_web_page_preview=disable_web_page_preview,
-            link_preview_options=link_preview_options,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            entities=entities,
-        )
-
-    async def edit_message_caption(
-        self,
-        caption: Optional[str] = None,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        show_caption_above_media: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Union[Message, bool]:
-        """Shortcut for either::
-
-            await update.callback_query.message.edit_caption(*args, **kwargs)
-
-        or::
-
-            await bot.edit_message_caption(
-                inline_message_id=update.callback_query.inline_message_id, *args, **kwargs,
-            )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.edit_message_caption` and :meth:`telegram.Message.edit_caption`.
-
-        .. versionchanged:: 20.8
-           Raises :exc:`TypeError` if :attr:`message` is not accessible.
-
-        Returns:
-            :class:`telegram.Message`: On success, if edited message is sent by the bot, the
-            edited Message is returned, otherwise :obj:`True` is returned.
-
-        Raises:
-            :exc:`TypeError` if :attr:`message` is not accessible.
-
-        """
-        if self.inline_message_id:
-            return await self.get_bot().edit_message_caption(
-                caption=caption,
-                inline_message_id=self.inline_message_id,
-                reply_markup=reply_markup,
-                read_timeout=read_timeout,
-                write_timeout=write_timeout,
-                connect_timeout=connect_timeout,
-                pool_timeout=pool_timeout,
-                parse_mode=parse_mode,
-                api_kwargs=api_kwargs,
-                caption_entities=caption_entities,
-                chat_id=None,
-                message_id=None,
-                show_caption_above_media=show_caption_above_media,
-                # inline messages can not be sent on behalf of a bcid
-                business_connection_id=None,
-            )
-        return await self._get_message().edit_caption(
-            caption=caption,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            parse_mode=parse_mode,
-            api_kwargs=api_kwargs,
-            caption_entities=caption_entities,
-            show_caption_above_media=show_caption_above_media,
-        )
-
-    async def edit_message_reply_markup(
-        self,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Union[Message, bool]:
-        """Shortcut for either::
-
-            await update.callback_query.message.edit_reply_markup(*args, **kwargs)
-
-        or::
-
-            await bot.edit_message_reply_markup(
-                inline_message_id=update.callback_query.inline_message_id, *args, **kwargs
-            )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.edit_message_reply_markup` and
-        :meth:`telegram.Message.edit_reply_markup`.
-
-        .. versionchanged:: 20.8
-           Raises :exc:`TypeError` if :attr:`message` is not accessible.
-
-        Returns:
-            :class:`telegram.Message`: On success, if edited message is sent by the bot, the
-            edited Message is returned, otherwise :obj:`True` is returned.
-
-        Raises:
-            :exc:`TypeError` if :attr:`message` is not accessible.
-
-        """
-        if self.inline_message_id:
-            return await self.get_bot().edit_message_reply_markup(
-                reply_markup=reply_markup,
-                inline_message_id=self.inline_message_id,
-                read_timeout=read_timeout,
-                write_timeout=write_timeout,
-                connect_timeout=connect_timeout,
-                pool_timeout=pool_timeout,
-                api_kwargs=api_kwargs,
-                chat_id=None,
-                message_id=None,
-                # inline messages can not be sent on behalf of a bcid
-                business_connection_id=None,
-            )
-        return await self._get_message().edit_reply_markup(
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def edit_message_media(
-        self,
-        media: "InputMedia",
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Union[Message, bool]:
-        """Shortcut for either::
-
-            await update.callback_query.message.edit_media(*args, **kwargs)
-
-        or::
-
-            await bot.edit_message_media(
-                inline_message_id=update.callback_query.inline_message_id, *args, **kwargs
-            )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.edit_message_media` and :meth:`telegram.Message.edit_media`.
-
-        .. versionchanged:: 20.8
-           Raises :exc:`TypeError` if :attr:`message` is not accessible.
-
-        Returns:
-            :class:`telegram.Message`: On success, if edited message is not an inline message, the
-            edited Message is returned, otherwise :obj:`True` is returned.
-
-        Raises:
-            :exc:`TypeError` if :attr:`message` is not accessible.
-
-        """
-        if self.inline_message_id:
-            return await self.get_bot().edit_message_media(
-                inline_message_id=self.inline_message_id,
-                media=media,
-                reply_markup=reply_markup,
-                read_timeout=read_timeout,
-                write_timeout=write_timeout,
-                connect_timeout=connect_timeout,
-                pool_timeout=pool_timeout,
-                api_kwargs=api_kwargs,
-                chat_id=None,
-                message_id=None,
-                # inline messages can not be sent on behalf of a bcid
-                business_connection_id=None,
-            )
-        return await self._get_message().edit_media(
-            media=media,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def edit_message_live_location(
-        self,
-        latitude: Optional[float] = None,
-        longitude: Optional[float] = None,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        horizontal_accuracy: Optional[float] = None,
-        heading: Optional[int] = None,
-        proximity_alert_radius: Optional[int] = None,
-        live_period: Optional[int] = None,
-        *,
-        location: Optional[Location] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Union[Message, bool]:
-        """Shortcut for either::
-
-            await update.callback_query.message.edit_live_location(*args, **kwargs)
-
-        or::
-
-            await bot.edit_message_live_location(
-                inline_message_id=update.callback_query.inline_message_id, *args, **kwargs
-            )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.edit_message_live_location` and
-        :meth:`telegram.Message.edit_live_location`.
-
-        .. versionchanged:: 20.8
-           Raises :exc:`TypeError` if :attr:`message` is not accessible.
-
-        Returns:
-            :class:`telegram.Message`: On success, if edited message is sent by the bot, the
-            edited Message is returned, otherwise :obj:`True` is returned.
-
-        Raises:
-            :exc:`TypeError` if :attr:`message` is not accessible.
-
-        """
-        if self.inline_message_id:
-            return await self.get_bot().edit_message_live_location(
-                inline_message_id=self.inline_message_id,
-                latitude=latitude,
-                longitude=longitude,
-                location=location,
-                reply_markup=reply_markup,
-                read_timeout=read_timeout,
-                write_timeout=write_timeout,
-                connect_timeout=connect_timeout,
-                pool_timeout=pool_timeout,
-                api_kwargs=api_kwargs,
-                horizontal_accuracy=horizontal_accuracy,
-                heading=heading,
-                proximity_alert_radius=proximity_alert_radius,
-                live_period=live_period,
-                chat_id=None,
-                message_id=None,
-                # inline messages can not be sent on behalf of a bcid
-                business_connection_id=None,
-            )
-        return await self._get_message().edit_live_location(
-            latitude=latitude,
-            longitude=longitude,
-            location=location,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            horizontal_accuracy=horizontal_accuracy,
-            heading=heading,
-            proximity_alert_radius=proximity_alert_radius,
-            live_period=live_period,
-        )
-
-    async def stop_message_live_location(
-        self,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Union[Message, bool]:
-        """Shortcut for either::
-
-            await update.callback_query.message.stop_live_location(*args, **kwargs)
-
-        or::
-
-            await bot.stop_message_live_location(
-                inline_message_id=update.callback_query.inline_message_id, *args, **kwargs
-            )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.stop_message_live_location` and
-        :meth:`telegram.Message.stop_live_location`.
-
-        .. versionchanged:: 20.8
-           Raises :exc:`TypeError` if :attr:`message` is not accessible.
-
-        Returns:
-            :class:`telegram.Message`: On success, if edited message is sent by the bot, the
-            edited Message is returned, otherwise :obj:`True` is returned.
-
-        Raises:
-            :exc:`TypeError` if :attr:`message` is not accessible.
-
-        """
-        if self.inline_message_id:
-            return await self.get_bot().stop_message_live_location(
-                inline_message_id=self.inline_message_id,
-                reply_markup=reply_markup,
-                read_timeout=read_timeout,
-                write_timeout=write_timeout,
-                connect_timeout=connect_timeout,
-                pool_timeout=pool_timeout,
-                api_kwargs=api_kwargs,
-                chat_id=None,
-                message_id=None,
-                # inline messages can not be sent on behalf of a bcid
-                business_connection_id=None,
-            )
-        return await self._get_message().stop_live_location(
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_game_score(
-        self,
-        user_id: int,
-        score: int,
-        force: Optional[bool] = None,
-        disable_edit_message: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Union[Message, bool]:
-        """Shortcut for either::
-
-           await update.callback_query.message.set_game_score(*args, **kwargs)
-
-        or::
-
-            await bot.set_game_score(
-                inline_message_id=update.callback_query.inline_message_id, *args, **kwargs
-            )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.set_game_score` and :meth:`telegram.Message.set_game_score`.
-
-        .. versionchanged:: 20.8
-           Raises :exc:`TypeError` if :attr:`message` is not accessible.
-
-        Returns:
-            :class:`telegram.Message`: On success, if edited message is sent by the bot, the
-            edited Message is returned, otherwise :obj:`True` is returned.
-
-        Raises:
-            :exc:`TypeError` if :attr:`message` is not accessible.
-
-        """
-        if self.inline_message_id:
-            return await self.get_bot().set_game_score(
-                inline_message_id=self.inline_message_id,
-                user_id=user_id,
-                score=score,
-                force=force,
-                disable_edit_message=disable_edit_message,
-                read_timeout=read_timeout,
-                write_timeout=write_timeout,
-                connect_timeout=connect_timeout,
-                pool_timeout=pool_timeout,
-                api_kwargs=api_kwargs,
-                chat_id=None,
-                message_id=None,
-            )
-        return await self._get_message().set_game_score(
-            user_id=user_id,
-            score=score,
-            force=force,
-            disable_edit_message=disable_edit_message,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def get_game_high_scores(
-        self,
-        user_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> tuple["GameHighScore", ...]:
-        """Shortcut for either::
-
-            await update.callback_query.message.get_game_high_score(*args, **kwargs)
-
-        or::
-
-            await bot.get_game_high_scores(
-                inline_message_id=update.callback_query.inline_message_id, *args, **kwargs
-            )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.get_game_high_scores` and
-        :meth:`telegram.Message.get_game_high_scores`.
-
-        .. versionchanged:: 20.8
-           Raises :exc:`TypeError` if :attr:`message` is not accessible.
-
-        Returns:
-            tuple[:class:`telegram.GameHighScore`]
-
-        Raises:
-            :exc:`TypeError` if :attr:`message` is not accessible.
-
-        """
-        if self.inline_message_id:
-            return await self.get_bot().get_game_high_scores(
-                inline_message_id=self.inline_message_id,
-                user_id=user_id,
-                read_timeout=read_timeout,
-                write_timeout=write_timeout,
-                connect_timeout=connect_timeout,
-                pool_timeout=pool_timeout,
-                api_kwargs=api_kwargs,
-                chat_id=None,
-                message_id=None,
-            )
-        return await self._get_message().get_game_high_scores(
-            user_id=user_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def delete_message(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-            await update.callback_query.message.delete(*args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Message.delete`.
-
-        .. versionchanged:: 20.8
-           Raises :exc:`TypeError` if :attr:`message` is not accessible.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :exc:`TypeError` if :attr:`message` is not accessible.
-
-        """
-        return await self._get_message(action="delete").delete(
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def pin_message(
-        self,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-            await update.callback_query.message.pin(*args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Message.pin`.
-
-        .. versionchanged:: 20.8
-           Raises :exc:`TypeError` if :attr:`message` is not accessible.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :exc:`TypeError` if :attr:`message` is not accessible.
-        """
-        return await self._get_message(action="pin").pin(
-            disable_notification=disable_notification,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def unpin_message(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-            await update.callback_query.message.unpin(*args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Message.unpin`.
-
-        .. versionchanged:: 20.8
-           Raises :exc:`TypeError` if :attr:`message` is not accessible.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        Raises:
-            :exc:`TypeError` if :attr:`message` is not accessible.
-        """
-        return await self._get_message(action="unpin").unpin(
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def copy_message(
-        self,
-        chat_id: Union[int, str],
-        caption: Optional[str] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        show_caption_above_media: Optional[bool] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        reply_to_message_id: Optional[int] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "MessageId":
-        """Shortcut for::
-
-            await update.callback_query.message.copy(
-                from_chat_id=update.message.chat_id,
-                message_id=update.message.message_id,
-                *args,
-                **kwargs
-            )
-
-        For the documentation of the arguments, please see :meth:`telegram.Message.copy`.
-
-        .. versionchanged:: 20.8
-           Raises :exc:`TypeError` if :attr:`message` is not accessible.
-
-        Returns:
-            :class:`telegram.MessageId`: On success, returns the MessageId of the sent message.
-
-        Raises:
-            :exc:`TypeError` if :attr:`message` is not accessible.
-        """
-        return await self._get_message(action="copy").copy(
-            chat_id=chat_id,
-            caption=caption,
-            parse_mode=parse_mode,
-            caption_entities=caption_entities,
-            disable_notification=disable_notification,
-            reply_to_message_id=reply_to_message_id,
-            allow_sending_without_reply=allow_sending_without_reply,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            reply_parameters=reply_parameters,
-            show_caption_above_media=show_caption_above_media,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    MAX_ANSWER_TEXT_LENGTH: Final[int] = (
-        constants.CallbackQueryLimit.ANSWER_CALLBACK_QUERY_TEXT_LENGTH
-    )
-    """
-    :const:`telegram.constants.CallbackQueryLimit.ANSWER_CALLBACK_QUERY_TEXT_LENGTH`
-
-    .. versionadded:: 13.2
-    """
diff --git a/venv/lib/python3.11/site-packages/telegram/_chat.py b/venv/lib/python3.11/site-packages/telegram/_chat.py
deleted file mode 100755
index 16c1205..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_chat.py
+++ /dev/null
@@ -1,3599 +0,0 @@
-#!/usr/bin/env python
-# pylint: disable=redefined-builtin
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram Chat."""
-import datetime as dtm
-from collections.abc import Sequence
-from html import escape
-from typing import TYPE_CHECKING, Final, Optional, Union
-
-from telegram import constants
-from telegram._chatpermissions import ChatPermissions
-from telegram._forumtopic import ForumTopic
-from telegram._menubutton import MenuButton
-from telegram._reaction import ReactionType
-from telegram._telegramobject import TelegramObject
-from telegram._utils import enum
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.types import CorrectOptionID, FileInput, JSONDict, ODVInput, ReplyMarkup
-from telegram.helpers import escape_markdown
-from telegram.helpers import mention_html as helpers_mention_html
-from telegram.helpers import mention_markdown as helpers_mention_markdown
-
-if TYPE_CHECKING:
-    from telegram import (
-        Animation,
-        Audio,
-        ChatInviteLink,
-        ChatMember,
-        Contact,
-        Document,
-        Gift,
-        InlineKeyboardMarkup,
-        InputMediaAudio,
-        InputMediaDocument,
-        InputMediaPhoto,
-        InputMediaVideo,
-        InputPaidMedia,
-        InputPollOption,
-        LabeledPrice,
-        LinkPreviewOptions,
-        Location,
-        Message,
-        MessageEntity,
-        MessageId,
-        PhotoSize,
-        ReplyParameters,
-        Sticker,
-        UserChatBoosts,
-        Venue,
-        Video,
-        VideoNote,
-        Voice,
-    )
-
-
-class _ChatBase(TelegramObject):
-    """Base class for :class:`telegram.Chat` and :class:`telegram.ChatFullInfo`.
-
-    .. versionadded:: 21.3
-    """
-
-    __slots__ = ("first_name", "id", "is_forum", "last_name", "title", "type", "username")
-
-    def __init__(
-        self,
-        id: int,
-        type: str,
-        title: Optional[str] = None,
-        username: Optional[str] = None,
-        first_name: Optional[str] = None,
-        last_name: Optional[str] = None,
-        is_forum: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        # Required
-        self.id: int = id
-        self.type: str = enum.get_member(constants.ChatType, type, type)
-        # Optionals
-        self.title: Optional[str] = title
-        self.username: Optional[str] = username
-        self.first_name: Optional[str] = first_name
-        self.last_name: Optional[str] = last_name
-        self.is_forum: Optional[bool] = is_forum
-
-        self._id_attrs = (self.id,)
-
-        self._freeze()
-
-    SENDER: Final[str] = constants.ChatType.SENDER
-    """:const:`telegram.constants.ChatType.SENDER`
-
-    .. versionadded:: 13.5
-    """
-    PRIVATE: Final[str] = constants.ChatType.PRIVATE
-    """:const:`telegram.constants.ChatType.PRIVATE`"""
-    GROUP: Final[str] = constants.ChatType.GROUP
-    """:const:`telegram.constants.ChatType.GROUP`"""
-    SUPERGROUP: Final[str] = constants.ChatType.SUPERGROUP
-    """:const:`telegram.constants.ChatType.SUPERGROUP`"""
-    CHANNEL: Final[str] = constants.ChatType.CHANNEL
-    """:const:`telegram.constants.ChatType.CHANNEL`"""
-
-    @property
-    def effective_name(self) -> Optional[str]:
-        """
-        :obj:`str`: Convenience property. Gives :attr:`~Chat.title` if not :obj:`None`,
-        else :attr:`~Chat.full_name` if not :obj:`None`.
-
-        .. versionadded:: 20.1
-        """
-        if self.title is not None:
-            return self.title
-        if self.full_name is not None:
-            return self.full_name
-        return None
-
-    @property
-    def full_name(self) -> Optional[str]:
-        """
-        :obj:`str`: Convenience property. If :attr:`~Chat.first_name` is not :obj:`None`, gives
-        :attr:`~Chat.first_name` followed by (if available) :attr:`~Chat.last_name`.
-
-        Note:
-            :attr:`full_name` will always be :obj:`None`, if the chat is a (super)group or
-            channel.
-
-        .. versionadded:: 13.2
-        """
-        if not self.first_name:
-            return None
-        if self.last_name:
-            return f"{self.first_name} {self.last_name}"
-        return self.first_name
-
-    @property
-    def link(self) -> Optional[str]:
-        """:obj:`str`: Convenience property. If the chat has a :attr:`~Chat.username`, returns a
-        t.me link of the chat.
-        """
-        if self.username:
-            return f"https://t.me/{self.username}"
-        return None
-
-    def mention_markdown(self, name: Optional[str] = None) -> str:
-        """
-        Note:
-            :tg-const:`telegram.constants.ParseMode.MARKDOWN` is a legacy mode, retained by
-            Telegram for backward compatibility. You should use :meth:`mention_markdown_v2`
-            instead.
-
-        .. versionadded:: 20.0
-
-        Args:
-            name (:obj:`str`): The name used as a link for the chat. Defaults to
-                :attr:`~Chat.full_name`.
-
-        Returns:
-            :obj:`str`: The inline mention for the chat as markdown (version 1).
-
-        Raises:
-            :exc:`TypeError`: If the chat is a private chat and neither the :paramref:`name`
-                nor the :attr:`~Chat.first_name` is set, then throw an :exc:`TypeError`.
-                If the chat is a public chat and neither the :paramref:`name` nor the
-                :attr:`~Chat.title` is set, then throw an :exc:`TypeError`. If chat is a
-                private group chat, then throw an :exc:`TypeError`.
-
-        """
-        if self.type == self.PRIVATE:
-            if name:
-                return helpers_mention_markdown(self.id, name)
-            if self.full_name:
-                return helpers_mention_markdown(self.id, self.full_name)
-            raise TypeError("Can not create a mention to a private chat without first name")
-        if self.username:
-            if name:
-                return f"[{name}]({self.link})"
-            if self.title:
-                return f"[{self.title}]({self.link})"
-            raise TypeError("Can not create a mention to a public chat without title")
-        raise TypeError("Can not create a mention to a private group chat")
-
-    def mention_markdown_v2(self, name: Optional[str] = None) -> str:
-        """
-        .. versionadded:: 20.0
-
-        Args:
-            name (:obj:`str`): The name used as a link for the chat. Defaults to
-                :attr:`~Chat.full_name`.
-
-        Returns:
-            :obj:`str`: The inline mention for the chat as markdown (version 2).
-
-        Raises:
-            :exc:`TypeError`: If the chat is a private chat and neither the :paramref:`name`
-                nor the :attr:`~Chat.first_name` is set, then throw an :exc:`TypeError`.
-                If the chat is a public chat and neither the :paramref:`name` nor the
-                :attr:`~Chat.title` is set, then throw an :exc:`TypeError`. If chat is a
-                private group chat, then throw an :exc:`TypeError`.
-
-        """
-        if self.type == self.PRIVATE:
-            if name:
-                return helpers_mention_markdown(self.id, name, version=2)
-            if self.full_name:
-                return helpers_mention_markdown(self.id, self.full_name, version=2)
-            raise TypeError("Can not create a mention to a private chat without first name")
-        if self.username:
-            if name:
-                return f"[{escape_markdown(name, version=2)}]({self.link})"
-            if self.title:
-                return f"[{escape_markdown(self.title, version=2)}]({self.link})"
-            raise TypeError("Can not create a mention to a public chat without title")
-        raise TypeError("Can not create a mention to a private group chat")
-
-    def mention_html(self, name: Optional[str] = None) -> str:
-        """
-        .. versionadded:: 20.0
-
-        Args:
-            name (:obj:`str`): The name used as a link for the chat. Defaults to :attr:`full_name`.
-
-        Returns:
-            :obj:`str`: The inline mention for the chat as HTML.
-
-        Raises:
-            :exc:`TypeError`: If the chat is a private chat and neither the :paramref:`name`
-                nor the :attr:`~Chat.first_name` is set, then throw an :exc:`TypeError`.
-                If the chat is a public chat and neither the :paramref:`name` nor the
-                :attr:`~Chat.title` is set, then throw an :exc:`TypeError`.
-                If chat is a private group chat, then throw an :exc:`TypeError`.
-
-        """
-        if self.type == self.PRIVATE:
-            if name:
-                return helpers_mention_html(self.id, name)
-            if self.full_name:
-                return helpers_mention_html(self.id, self.full_name)
-            raise TypeError("Can not create a mention to a private chat without first name")
-        if self.username:
-            if name:
-                return f'{escape(name)}'
-            if self.title:
-                return f'{escape(self.title)}'
-            raise TypeError("Can not create a mention to a public chat without title")
-        raise TypeError("Can not create a mention to a private group chat")
-
-    async def leave(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.leave_chat(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.leave_chat`.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().leave_chat(
-            chat_id=self.id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def get_administrators(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> tuple["ChatMember", ...]:
-        """Shortcut for::
-
-             await bot.get_chat_administrators(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.get_chat_administrators`.
-
-        Returns:
-            tuple[:class:`telegram.ChatMember`]: A tuple of administrators in a chat. An Array of
-            :class:`telegram.ChatMember` objects that contains information about all
-            chat administrators except other bots. If the chat is a group or a supergroup
-            and no administrators were appointed, only the creator will be returned.
-
-        """
-        return await self.get_bot().get_chat_administrators(
-            chat_id=self.id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def get_member_count(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> int:
-        """Shortcut for::
-
-             await bot.get_chat_member_count(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.get_chat_member_count`.
-
-        Returns:
-            :obj:`int`
-        """
-        return await self.get_bot().get_chat_member_count(
-            chat_id=self.id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def get_member(
-        self,
-        user_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "ChatMember":
-        """Shortcut for::
-
-             await bot.get_chat_member(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.get_chat_member`.
-
-        Returns:
-            :class:`telegram.ChatMember`
-
-        """
-        return await self.get_bot().get_chat_member(
-            chat_id=self.id,
-            user_id=user_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def ban_member(
-        self,
-        user_id: int,
-        revoke_messages: Optional[bool] = None,
-        until_date: Optional[Union[int, dtm.datetime]] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.ban_chat_member(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.ban_chat_member`.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-        """
-        return await self.get_bot().ban_chat_member(
-            chat_id=self.id,
-            user_id=user_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            until_date=until_date,
-            api_kwargs=api_kwargs,
-            revoke_messages=revoke_messages,
-        )
-
-    async def ban_sender_chat(
-        self,
-        sender_chat_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.ban_chat_sender_chat(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.ban_chat_sender_chat`.
-
-        .. versionadded:: 13.9
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().ban_chat_sender_chat(
-            chat_id=self.id,
-            sender_chat_id=sender_chat_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def ban_chat(
-        self,
-        chat_id: Union[str, int],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.ban_chat_sender_chat(
-                 sender_chat_id=update.effective_chat.id, *args, **kwargs
-             )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.ban_chat_sender_chat`.
-
-        .. versionadded:: 13.9
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().ban_chat_sender_chat(
-            chat_id=chat_id,
-            sender_chat_id=self.id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def unban_sender_chat(
-        self,
-        sender_chat_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.unban_chat_sender_chat(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.unban_chat_sender_chat`.
-
-        .. versionadded:: 13.9
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().unban_chat_sender_chat(
-            chat_id=self.id,
-            sender_chat_id=sender_chat_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def unban_chat(
-        self,
-        chat_id: Union[str, int],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.unban_chat_sender_chat(
-                 sender_chat_id=update.effective_chat.id, *args, **kwargs
-             )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.unban_chat_sender_chat`.
-
-        .. versionadded:: 13.9
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().unban_chat_sender_chat(
-            chat_id=chat_id,
-            sender_chat_id=self.id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def unban_member(
-        self,
-        user_id: int,
-        only_if_banned: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.unban_chat_member(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.unban_chat_member`.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().unban_chat_member(
-            chat_id=self.id,
-            user_id=user_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            only_if_banned=only_if_banned,
-        )
-
-    async def promote_member(
-        self,
-        user_id: int,
-        can_change_info: Optional[bool] = None,
-        can_post_messages: Optional[bool] = None,
-        can_edit_messages: Optional[bool] = None,
-        can_delete_messages: Optional[bool] = None,
-        can_invite_users: Optional[bool] = None,
-        can_restrict_members: Optional[bool] = None,
-        can_pin_messages: Optional[bool] = None,
-        can_promote_members: Optional[bool] = None,
-        is_anonymous: Optional[bool] = None,
-        can_manage_chat: Optional[bool] = None,
-        can_manage_video_chats: Optional[bool] = None,
-        can_manage_topics: Optional[bool] = None,
-        can_post_stories: Optional[bool] = None,
-        can_edit_stories: Optional[bool] = None,
-        can_delete_stories: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.promote_chat_member(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.promote_chat_member`.
-
-        .. versionadded:: 13.2
-        .. versionchanged:: 20.0
-           The argument ``can_manage_voice_chats`` was renamed to
-           :paramref:`~telegram.Bot.promote_chat_member.can_manage_video_chats` in accordance to
-           Bot API 6.0.
-        .. versionchanged:: 20.6
-           The arguments `can_post_stories`, `can_edit_stories` and `can_delete_stories` were
-           added.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().promote_chat_member(
-            chat_id=self.id,
-            user_id=user_id,
-            can_change_info=can_change_info,
-            can_post_messages=can_post_messages,
-            can_edit_messages=can_edit_messages,
-            can_delete_messages=can_delete_messages,
-            can_invite_users=can_invite_users,
-            can_restrict_members=can_restrict_members,
-            can_pin_messages=can_pin_messages,
-            can_promote_members=can_promote_members,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            is_anonymous=is_anonymous,
-            can_manage_chat=can_manage_chat,
-            can_manage_video_chats=can_manage_video_chats,
-            can_manage_topics=can_manage_topics,
-            can_post_stories=can_post_stories,
-            can_edit_stories=can_edit_stories,
-            can_delete_stories=can_delete_stories,
-        )
-
-    async def restrict_member(
-        self,
-        user_id: int,
-        permissions: ChatPermissions,
-        until_date: Optional[Union[int, dtm.datetime]] = None,
-        use_independent_chat_permissions: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.restrict_chat_member(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.restrict_chat_member`.
-
-        .. versionadded:: 13.2
-
-        .. versionadded:: 20.1
-            Added :paramref:`~telegram.Bot.restrict_chat_member.use_independent_chat_permissions`.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().restrict_chat_member(
-            chat_id=self.id,
-            user_id=user_id,
-            permissions=permissions,
-            until_date=until_date,
-            use_independent_chat_permissions=use_independent_chat_permissions,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_permissions(
-        self,
-        permissions: ChatPermissions,
-        use_independent_chat_permissions: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.set_chat_permissions(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.set_chat_permissions`.
-
-        .. versionadded:: 20.1
-            Added :paramref:`~telegram.Bot.set_chat_permissions.use_independent_chat_permissions`.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().set_chat_permissions(
-            chat_id=self.id,
-            permissions=permissions,
-            use_independent_chat_permissions=use_independent_chat_permissions,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_administrator_custom_title(
-        self,
-        user_id: int,
-        custom_title: str,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.set_chat_administrator_custom_title(
-                 update.effective_chat.id, *args, **kwargs
-             )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.set_chat_administrator_custom_title`.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().set_chat_administrator_custom_title(
-            chat_id=self.id,
-            user_id=user_id,
-            custom_title=custom_title,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_photo(
-        self,
-        photo: FileInput,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.set_chat_photo(
-                 chat_id=update.effective_chat.id, *args, **kwargs
-             )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.set_chat_photo`.
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().set_chat_photo(
-            chat_id=self.id,
-            photo=photo,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def delete_photo(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.delete_chat_photo(
-                 chat_id=update.effective_chat.id, *args, **kwargs
-             )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.delete_chat_photo`.
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().delete_chat_photo(
-            chat_id=self.id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_title(
-        self,
-        title: str,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.set_chat_title(
-                 chat_id=update.effective_chat.id, *args, **kwargs
-             )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.set_chat_title`.
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().set_chat_title(
-            chat_id=self.id,
-            title=title,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_description(
-        self,
-        description: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.set_chat_description(
-                 chat_id=update.effective_chat.id, *args, **kwargs
-             )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.set_chat_description`.
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().set_chat_description(
-            chat_id=self.id,
-            description=description,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def pin_message(
-        self,
-        message_id: int,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        business_connection_id: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-              await bot.pin_chat_message(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.pin_chat_message`.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().pin_chat_message(
-            chat_id=self.id,
-            message_id=message_id,
-            disable_notification=disable_notification,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=business_connection_id,
-        )
-
-    async def unpin_message(
-        self,
-        message_id: Optional[int] = None,
-        business_connection_id: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-              await bot.unpin_chat_message(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.unpin_chat_message`.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().unpin_chat_message(
-            chat_id=self.id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            message_id=message_id,
-            business_connection_id=business_connection_id,
-        )
-
-    async def unpin_all_messages(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-              await bot.unpin_all_chat_messages(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.unpin_all_chat_messages`.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().unpin_all_chat_messages(
-            chat_id=self.id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def send_message(
-        self,
-        text: str,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        disable_web_page_preview: Optional[bool] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_message(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`.
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        return await self.get_bot().send_message(
-            chat_id=self.id,
-            text=text,
-            parse_mode=parse_mode,
-            disable_web_page_preview=disable_web_page_preview,
-            disable_notification=disable_notification,
-            reply_to_message_id=reply_to_message_id,
-            link_preview_options=link_preview_options,
-            reply_parameters=reply_parameters,
-            reply_markup=reply_markup,
-            allow_sending_without_reply=allow_sending_without_reply,
-            entities=entities,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def delete_message(
-        self,
-        message_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.delete_message(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.delete_message`.
-
-        .. versionadded:: 20.8
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().delete_message(
-            chat_id=self.id,
-            message_id=message_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def delete_messages(
-        self,
-        message_ids: Sequence[int],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.delete_messages(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.delete_messages`.
-
-        .. versionadded:: 20.8
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().delete_messages(
-            chat_id=self.id,
-            message_ids=message_ids,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def send_media_group(
-        self,
-        media: Sequence[
-            Union["InputMediaAudio", "InputMediaDocument", "InputMediaPhoto", "InputMediaVideo"]
-        ],
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-        caption: Optional[str] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-    ) -> tuple["Message", ...]:
-        """Shortcut for::
-
-             await bot.send_media_group(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_media_group`.
-
-        Returns:
-            tuple[:class:`telegram.Message`]: On success, a tuple of :class:`~telegram.Message`
-            instances that were sent is returned.
-
-        """
-        return await self.get_bot().send_media_group(
-            chat_id=self.id,
-            media=media,
-            disable_notification=disable_notification,
-            reply_to_message_id=reply_to_message_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            caption=caption,
-            parse_mode=parse_mode,
-            caption_entities=caption_entities,
-            reply_parameters=reply_parameters,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_chat_action(
-        self,
-        action: str,
-        message_thread_id: Optional[int] = None,
-        business_connection_id: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.send_chat_action(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_chat_action`.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().send_chat_action(
-            chat_id=self.id,
-            action=action,
-            message_thread_id=message_thread_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=business_connection_id,
-        )
-
-    send_action = send_chat_action
-    """Alias for :attr:`send_chat_action`"""
-
-    async def send_photo(
-        self,
-        photo: Union[FileInput, "PhotoSize"],
-        caption: Optional[str] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        has_spoiler: Optional[bool] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        show_caption_above_media: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        filename: Optional[str] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_photo(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_photo`.
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        return await self.get_bot().send_photo(
-            chat_id=self.id,
-            photo=photo,
-            caption=caption,
-            disable_notification=disable_notification,
-            reply_to_message_id=reply_to_message_id,
-            reply_parameters=reply_parameters,
-            reply_markup=reply_markup,
-            parse_mode=parse_mode,
-            allow_sending_without_reply=allow_sending_without_reply,
-            caption_entities=caption_entities,
-            filename=filename,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            has_spoiler=has_spoiler,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-            show_caption_above_media=show_caption_above_media,
-        )
-
-    async def send_contact(
-        self,
-        phone_number: Optional[str] = None,
-        first_name: Optional[str] = None,
-        last_name: Optional[str] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        vcard: Optional[str] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        contact: Optional["Contact"] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_contact(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_contact`.
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        return await self.get_bot().send_contact(
-            chat_id=self.id,
-            phone_number=phone_number,
-            first_name=first_name,
-            last_name=last_name,
-            disable_notification=disable_notification,
-            reply_to_message_id=reply_to_message_id,
-            reply_parameters=reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            contact=contact,
-            vcard=vcard,
-            api_kwargs=api_kwargs,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_audio(
-        self,
-        audio: Union[FileInput, "Audio"],
-        duration: Optional[int] = None,
-        performer: Optional[str] = None,
-        title: Optional[str] = None,
-        caption: Optional[str] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        thumbnail: Optional[FileInput] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        filename: Optional[str] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_audio(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_audio`.
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        return await self.get_bot().send_audio(
-            chat_id=self.id,
-            audio=audio,
-            duration=duration,
-            performer=performer,
-            title=title,
-            caption=caption,
-            disable_notification=disable_notification,
-            reply_to_message_id=reply_to_message_id,
-            reply_parameters=reply_parameters,
-            reply_markup=reply_markup,
-            parse_mode=parse_mode,
-            allow_sending_without_reply=allow_sending_without_reply,
-            caption_entities=caption_entities,
-            filename=filename,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            thumbnail=thumbnail,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_document(
-        self,
-        document: Union[FileInput, "Document"],
-        caption: Optional[str] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        disable_content_type_detection: Optional[bool] = None,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        thumbnail: Optional[FileInput] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        filename: Optional[str] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_document(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_document`.
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        return await self.get_bot().send_document(
-            chat_id=self.id,
-            document=document,
-            filename=filename,
-            caption=caption,
-            disable_notification=disable_notification,
-            reply_to_message_id=reply_to_message_id,
-            reply_parameters=reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            parse_mode=parse_mode,
-            thumbnail=thumbnail,
-            api_kwargs=api_kwargs,
-            disable_content_type_detection=disable_content_type_detection,
-            allow_sending_without_reply=allow_sending_without_reply,
-            caption_entities=caption_entities,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_dice(
-        self,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        emoji: Optional[str] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_dice(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_dice`.
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        return await self.get_bot().send_dice(
-            chat_id=self.id,
-            disable_notification=disable_notification,
-            reply_to_message_id=reply_to_message_id,
-            reply_parameters=reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            emoji=emoji,
-            api_kwargs=api_kwargs,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_game(
-        self,
-        game_short_name: str,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_game(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_game`.
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        return await self.get_bot().send_game(
-            chat_id=self.id,
-            game_short_name=game_short_name,
-            disable_notification=disable_notification,
-            reply_to_message_id=reply_to_message_id,
-            reply_parameters=reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_invoice(
-        self,
-        title: str,
-        description: str,
-        payload: str,
-        provider_token: Optional[str],
-        currency: str,
-        prices: Sequence["LabeledPrice"],
-        start_parameter: Optional[str] = None,
-        photo_url: Optional[str] = None,
-        photo_size: Optional[int] = None,
-        photo_width: Optional[int] = None,
-        photo_height: Optional[int] = None,
-        need_name: Optional[bool] = None,
-        need_phone_number: Optional[bool] = None,
-        need_email: Optional[bool] = None,
-        need_shipping_address: Optional[bool] = None,
-        is_flexible: Optional[bool] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        provider_data: Optional[Union[str, object]] = None,
-        send_phone_number_to_provider: Optional[bool] = None,
-        send_email_to_provider: Optional[bool] = None,
-        max_tip_amount: Optional[int] = None,
-        suggested_tip_amounts: Optional[Sequence[int]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_invoice(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_invoice`.
-
-        Warning:
-            As of API 5.2 :paramref:`start_parameter `
-            is an optional argument and therefore the
-            order of the arguments had to be changed. Use keyword arguments to make sure that the
-            arguments are passed correctly.
-
-        .. versionchanged:: 13.5
-            As of Bot API 5.2, the parameter
-            :paramref:`start_parameter ` is optional.
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        return await self.get_bot().send_invoice(
-            chat_id=self.id,
-            title=title,
-            description=description,
-            payload=payload,
-            provider_token=provider_token,
-            currency=currency,
-            prices=prices,
-            start_parameter=start_parameter,
-            photo_url=photo_url,
-            photo_size=photo_size,
-            photo_width=photo_width,
-            photo_height=photo_height,
-            need_name=need_name,
-            need_phone_number=need_phone_number,
-            need_email=need_email,
-            need_shipping_address=need_shipping_address,
-            is_flexible=is_flexible,
-            disable_notification=disable_notification,
-            reply_to_message_id=reply_to_message_id,
-            reply_markup=reply_markup,
-            provider_data=provider_data,
-            send_phone_number_to_provider=send_phone_number_to_provider,
-            send_email_to_provider=send_email_to_provider,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            allow_sending_without_reply=allow_sending_without_reply,
-            max_tip_amount=max_tip_amount,
-            suggested_tip_amounts=suggested_tip_amounts,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            reply_parameters=reply_parameters,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_location(
-        self,
-        latitude: Optional[float] = None,
-        longitude: Optional[float] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        live_period: Optional[int] = None,
-        horizontal_accuracy: Optional[float] = None,
-        heading: Optional[int] = None,
-        proximity_alert_radius: Optional[int] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        location: Optional["Location"] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_location(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_location`.
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        return await self.get_bot().send_location(
-            chat_id=self.id,
-            latitude=latitude,
-            longitude=longitude,
-            disable_notification=disable_notification,
-            reply_to_message_id=reply_to_message_id,
-            reply_parameters=reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            location=location,
-            live_period=live_period,
-            api_kwargs=api_kwargs,
-            horizontal_accuracy=horizontal_accuracy,
-            heading=heading,
-            proximity_alert_radius=proximity_alert_radius,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_animation(
-        self,
-        animation: Union[FileInput, "Animation"],
-        duration: Optional[int] = None,
-        width: Optional[int] = None,
-        height: Optional[int] = None,
-        caption: Optional[str] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        has_spoiler: Optional[bool] = None,
-        thumbnail: Optional[FileInput] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        show_caption_above_media: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        filename: Optional[str] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_animation(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_animation`.
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        return await self.get_bot().send_animation(
-            chat_id=self.id,
-            animation=animation,
-            duration=duration,
-            width=width,
-            height=height,
-            caption=caption,
-            parse_mode=parse_mode,
-            disable_notification=disable_notification,
-            reply_to_message_id=reply_to_message_id,
-            reply_parameters=reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            allow_sending_without_reply=allow_sending_without_reply,
-            caption_entities=caption_entities,
-            filename=filename,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            has_spoiler=has_spoiler,
-            thumbnail=thumbnail,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-            show_caption_above_media=show_caption_above_media,
-        )
-
-    async def send_sticker(
-        self,
-        sticker: Union[FileInput, "Sticker"],
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        emoji: Optional[str] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_sticker(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_sticker`.
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        return await self.get_bot().send_sticker(
-            chat_id=self.id,
-            sticker=sticker,
-            disable_notification=disable_notification,
-            reply_to_message_id=reply_to_message_id,
-            reply_parameters=reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            emoji=emoji,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_venue(
-        self,
-        latitude: Optional[float] = None,
-        longitude: Optional[float] = None,
-        title: Optional[str] = None,
-        address: Optional[str] = None,
-        foursquare_id: Optional[str] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        foursquare_type: Optional[str] = None,
-        google_place_id: Optional[str] = None,
-        google_place_type: Optional[str] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        venue: Optional["Venue"] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_venue(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_venue`.
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        return await self.get_bot().send_venue(
-            chat_id=self.id,
-            latitude=latitude,
-            longitude=longitude,
-            title=title,
-            address=address,
-            foursquare_id=foursquare_id,
-            disable_notification=disable_notification,
-            reply_to_message_id=reply_to_message_id,
-            reply_parameters=reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            venue=venue,
-            foursquare_type=foursquare_type,
-            api_kwargs=api_kwargs,
-            google_place_id=google_place_id,
-            google_place_type=google_place_type,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_video(
-        self,
-        video: Union[FileInput, "Video"],
-        duration: Optional[int] = None,
-        caption: Optional[str] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        width: Optional[int] = None,
-        height: Optional[int] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        supports_streaming: Optional[bool] = None,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        has_spoiler: Optional[bool] = None,
-        thumbnail: Optional[FileInput] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        show_caption_above_media: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        filename: Optional[str] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_video(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_video`.
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        return await self.get_bot().send_video(
-            chat_id=self.id,
-            video=video,
-            duration=duration,
-            caption=caption,
-            disable_notification=disable_notification,
-            reply_to_message_id=reply_to_message_id,
-            reply_parameters=reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            width=width,
-            height=height,
-            parse_mode=parse_mode,
-            supports_streaming=supports_streaming,
-            thumbnail=thumbnail,
-            api_kwargs=api_kwargs,
-            allow_sending_without_reply=allow_sending_without_reply,
-            caption_entities=caption_entities,
-            filename=filename,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            has_spoiler=has_spoiler,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-            show_caption_above_media=show_caption_above_media,
-        )
-
-    async def send_video_note(
-        self,
-        video_note: Union[FileInput, "VideoNote"],
-        duration: Optional[int] = None,
-        length: Optional[int] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        thumbnail: Optional[FileInput] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        filename: Optional[str] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_video_note(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_video_note`.
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        return await self.get_bot().send_video_note(
-            chat_id=self.id,
-            video_note=video_note,
-            duration=duration,
-            length=length,
-            disable_notification=disable_notification,
-            reply_to_message_id=reply_to_message_id,
-            reply_parameters=reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            thumbnail=thumbnail,
-            api_kwargs=api_kwargs,
-            allow_sending_without_reply=allow_sending_without_reply,
-            filename=filename,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_voice(
-        self,
-        voice: Union[FileInput, "Voice"],
-        duration: Optional[int] = None,
-        caption: Optional[str] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        filename: Optional[str] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_voice(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_voice`.
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        return await self.get_bot().send_voice(
-            chat_id=self.id,
-            voice=voice,
-            duration=duration,
-            caption=caption,
-            disable_notification=disable_notification,
-            reply_to_message_id=reply_to_message_id,
-            reply_parameters=reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            parse_mode=parse_mode,
-            api_kwargs=api_kwargs,
-            allow_sending_without_reply=allow_sending_without_reply,
-            caption_entities=caption_entities,
-            filename=filename,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            business_connection_id=business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_poll(
-        self,
-        question: str,
-        options: Sequence[Union[str, "InputPollOption"]],
-        is_anonymous: Optional[bool] = None,
-        type: Optional[str] = None,
-        allows_multiple_answers: Optional[bool] = None,
-        correct_option_id: Optional[CorrectOptionID] = None,
-        is_closed: Optional[bool] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        explanation: Optional[str] = None,
-        explanation_parse_mode: ODVInput[str] = DEFAULT_NONE,
-        open_period: Optional[int] = None,
-        close_date: Optional[Union[int, dtm.datetime]] = None,
-        explanation_entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        business_connection_id: Optional[str] = None,
-        question_parse_mode: ODVInput[str] = DEFAULT_NONE,
-        question_entities: Optional[Sequence["MessageEntity"]] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_poll(update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_poll`.
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        return await self.get_bot().send_poll(
-            chat_id=self.id,
-            question=question,
-            options=options,
-            is_anonymous=is_anonymous,
-            type=type,  # pylint=pylint,
-            allows_multiple_answers=allows_multiple_answers,
-            correct_option_id=correct_option_id,
-            is_closed=is_closed,
-            disable_notification=disable_notification,
-            reply_to_message_id=reply_to_message_id,
-            reply_parameters=reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-            explanation=explanation,
-            explanation_parse_mode=explanation_parse_mode,
-            open_period=open_period,
-            close_date=close_date,
-            api_kwargs=api_kwargs,
-            allow_sending_without_reply=allow_sending_without_reply,
-            explanation_entities=explanation_entities,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            business_connection_id=business_connection_id,
-            question_parse_mode=question_parse_mode,
-            question_entities=question_entities,
-        )
-
-    async def send_copy(
-        self,
-        from_chat_id: Union[str, int],
-        message_id: int,
-        caption: Optional[str] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        show_caption_above_media: Optional[bool] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "MessageId":
-        """Shortcut for::
-
-             await bot.copy_message(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`.
-
-        .. seealso:: :meth:`copy_message`, :meth:`send_copies`, :meth:`copy_messages`.
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        return await self.get_bot().copy_message(
-            chat_id=self.id,
-            from_chat_id=from_chat_id,
-            message_id=message_id,
-            caption=caption,
-            parse_mode=parse_mode,
-            caption_entities=caption_entities,
-            disable_notification=disable_notification,
-            reply_to_message_id=reply_to_message_id,
-            reply_parameters=reply_parameters,
-            allow_sending_without_reply=allow_sending_without_reply,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            show_caption_above_media=show_caption_above_media,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def copy_message(
-        self,
-        chat_id: Union[int, str],
-        message_id: int,
-        caption: Optional[str] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        show_caption_above_media: Optional[bool] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "MessageId":
-        """Shortcut for::
-
-             await bot.copy_message(from_chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`.
-
-        .. seealso:: :meth:`send_copy`, :meth:`send_copies`, :meth:`copy_messages`.
-
-        Returns:
-            :class:`telegram.MessageId`: On success, returns the MessageId of the sent message.
-
-        """
-        return await self.get_bot().copy_message(
-            from_chat_id=self.id,
-            chat_id=chat_id,
-            message_id=message_id,
-            caption=caption,
-            parse_mode=parse_mode,
-            caption_entities=caption_entities,
-            disable_notification=disable_notification,
-            reply_to_message_id=reply_to_message_id,
-            reply_parameters=reply_parameters,
-            allow_sending_without_reply=allow_sending_without_reply,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            show_caption_above_media=show_caption_above_media,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_copies(
-        self,
-        from_chat_id: Union[str, int],
-        message_ids: Sequence[int],
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        remove_caption: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> tuple["MessageId", ...]:
-        """Shortcut for::
-
-             await bot.copy_messages(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.copy_messages`.
-
-        .. seealso:: :meth:`copy_message`, :meth:`send_copy`, :meth:`copy_messages`.
-
-        .. versionadded:: 20.8
-
-        Returns:
-            tuple[:class:`telegram.MessageId`]: On success, a tuple of :class:`~telegram.MessageId`
-            of the sent messages is returned.
-
-        """
-        return await self.get_bot().copy_messages(
-            chat_id=self.id,
-            from_chat_id=from_chat_id,
-            message_ids=message_ids,
-            disable_notification=disable_notification,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            remove_caption=remove_caption,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def copy_messages(
-        self,
-        chat_id: Union[str, int],
-        message_ids: Sequence[int],
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        remove_caption: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> tuple["MessageId", ...]:
-        """Shortcut for::
-
-             await bot.copy_messages(from_chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.copy_messages`.
-
-        .. seealso:: :meth:`copy_message`, :meth:`send_copy`, :meth:`send_copies`.
-
-        .. versionadded:: 20.8
-
-        Returns:
-            tuple[:class:`telegram.MessageId`]: On success, a tuple of :class:`~telegram.MessageId`
-            of the sent messages is returned.
-
-        """
-        return await self.get_bot().copy_messages(
-            from_chat_id=self.id,
-            chat_id=chat_id,
-            message_ids=message_ids,
-            disable_notification=disable_notification,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            remove_caption=remove_caption,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def forward_from(
-        self,
-        from_chat_id: Union[str, int],
-        message_id: int,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.forward_message(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.forward_message`.
-
-        .. seealso:: :meth:`forward_to`, :meth:`forward_messages_from`, :meth:`forward_messages_to`
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        return await self.get_bot().forward_message(
-            chat_id=self.id,
-            from_chat_id=from_chat_id,
-            message_id=message_id,
-            disable_notification=disable_notification,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-        )
-
-    async def forward_to(
-        self,
-        chat_id: Union[int, str],
-        message_id: int,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.forward_message(from_chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.forward_message`.
-
-        .. seealso:: :meth:`forward_from`, :meth:`forward_messages_from`,
-            :meth:`forward_messages_to`
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        return await self.get_bot().forward_message(
-            from_chat_id=self.id,
-            chat_id=chat_id,
-            message_id=message_id,
-            disable_notification=disable_notification,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-        )
-
-    async def forward_messages_from(
-        self,
-        from_chat_id: Union[str, int],
-        message_ids: Sequence[int],
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> tuple["MessageId", ...]:
-        """Shortcut for::
-
-             await bot.forward_messages(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.forward_messages`.
-
-        .. seealso:: :meth:`forward_to`, :meth:`forward_from`, :meth:`forward_messages_to`.
-
-        .. versionadded:: 20.8
-
-        Returns:
-            tuple[:class:`telegram.MessageId`]: On success, a tuple of :class:`~telegram.MessageId`
-            of sent messages is returned.
-
-        """
-        return await self.get_bot().forward_messages(
-            chat_id=self.id,
-            from_chat_id=from_chat_id,
-            message_ids=message_ids,
-            disable_notification=disable_notification,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def forward_messages_to(
-        self,
-        chat_id: Union[int, str],
-        message_ids: Sequence[int],
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> tuple["MessageId", ...]:
-        """Shortcut for::
-
-             await bot.forward_messages(from_chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.forward_messages`.
-
-        .. seealso:: :meth:`forward_from`, :meth:`forward_to`, :meth:`forward_messages_from`.
-
-        .. versionadded:: 20.8
-
-        Returns:
-            tuple[:class:`telegram.MessageId`]: On success, a tuple of :class:`~telegram.MessageId`
-            of sent messages is returned.
-
-        """
-        return await self.get_bot().forward_messages(
-            from_chat_id=self.id,
-            chat_id=chat_id,
-            message_ids=message_ids,
-            disable_notification=disable_notification,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def export_invite_link(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> str:
-        """Shortcut for::
-
-             await bot.export_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.export_chat_invite_link`.
-
-        .. versionadded:: 13.4
-
-        Returns:
-            :obj:`str`: New invite link on success.
-
-        """
-        return await self.get_bot().export_chat_invite_link(
-            chat_id=self.id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def create_invite_link(
-        self,
-        expire_date: Optional[Union[int, dtm.datetime]] = None,
-        member_limit: Optional[int] = None,
-        name: Optional[str] = None,
-        creates_join_request: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "ChatInviteLink":
-        """Shortcut for::
-
-             await bot.create_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.create_chat_invite_link`.
-
-        .. versionadded:: 13.4
-
-        .. versionchanged:: 13.8
-           Edited signature according to the changes of
-           :meth:`telegram.Bot.create_chat_invite_link`.
-
-        Returns:
-            :class:`telegram.ChatInviteLink`
-
-        """
-        return await self.get_bot().create_chat_invite_link(
-            chat_id=self.id,
-            expire_date=expire_date,
-            member_limit=member_limit,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            name=name,
-            creates_join_request=creates_join_request,
-        )
-
-    async def edit_invite_link(
-        self,
-        invite_link: Union[str, "ChatInviteLink"],
-        expire_date: Optional[Union[int, dtm.datetime]] = None,
-        member_limit: Optional[int] = None,
-        name: Optional[str] = None,
-        creates_join_request: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "ChatInviteLink":
-        """Shortcut for::
-
-             await bot.edit_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.edit_chat_invite_link`.
-
-        .. versionadded:: 13.4
-
-        .. versionchanged:: 13.8
-           Edited signature according to the changes of :meth:`telegram.Bot.edit_chat_invite_link`.
-
-        Returns:
-            :class:`telegram.ChatInviteLink`
-
-        """
-        return await self.get_bot().edit_chat_invite_link(
-            chat_id=self.id,
-            invite_link=invite_link,
-            expire_date=expire_date,
-            member_limit=member_limit,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            name=name,
-            creates_join_request=creates_join_request,
-        )
-
-    async def revoke_invite_link(
-        self,
-        invite_link: Union[str, "ChatInviteLink"],
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "ChatInviteLink":
-        """Shortcut for::
-
-             await bot.revoke_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.revoke_chat_invite_link`.
-
-        .. versionadded:: 13.4
-
-        Returns:
-            :class:`telegram.ChatInviteLink`
-
-        """
-        return await self.get_bot().revoke_chat_invite_link(
-            chat_id=self.id,
-            invite_link=invite_link,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def create_subscription_invite_link(
-        self,
-        subscription_period: int,
-        subscription_price: int,
-        name: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "ChatInviteLink":
-        """Shortcut for::
-
-            await bot.create_chat_subscription_invite_link(
-                chat_id=update.effective_chat.id, *args, **kwargs
-            )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.create_chat_subscription_invite_link`.
-
-        .. versionadded:: 21.5
-
-        Returns:
-            :class:`telegram.ChatInviteLink`
-        """
-        return await self.get_bot().create_chat_subscription_invite_link(
-            chat_id=self.id,
-            subscription_period=subscription_period,
-            subscription_price=subscription_price,
-            name=name,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def edit_subscription_invite_link(
-        self,
-        invite_link: Union[str, "ChatInviteLink"],
-        name: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "ChatInviteLink":
-        """Shortcut for::
-
-            await bot.edit_chat_subscription_invite_link(
-                chat_id=update.effective_chat.id, *args, **kwargs
-            )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.edit_chat_subscription_invite_link`.
-
-        .. versionadded:: 21.5
-
-        Returns:
-            :class:`telegram.ChatInviteLink`
-
-        """
-        return await self.get_bot().edit_chat_subscription_invite_link(
-            chat_id=self.id,
-            invite_link=invite_link,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            name=name,
-        )
-
-    async def approve_join_request(
-        self,
-        user_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.approve_chat_join_request(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.approve_chat_join_request`.
-
-        .. versionadded:: 13.8
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().approve_chat_join_request(
-            chat_id=self.id,
-            user_id=user_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def decline_join_request(
-        self,
-        user_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.decline_chat_join_request(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.decline_chat_join_request`.
-
-        .. versionadded:: 13.8
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().decline_chat_join_request(
-            chat_id=self.id,
-            user_id=user_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_menu_button(
-        self,
-        menu_button: Optional[MenuButton] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.set_chat_menu_button(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.set_chat_menu_button`.
-
-        Caution:
-            Can only work, if the chat is a private chat.
-
-        .. seealso:: :meth:`get_menu_button`
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-        """
-        return await self.get_bot().set_chat_menu_button(
-            chat_id=self.id,
-            menu_button=menu_button,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def create_forum_topic(
-        self,
-        name: str,
-        icon_color: Optional[int] = None,
-        icon_custom_emoji_id: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> ForumTopic:
-        """Shortcut for::
-
-             await bot.create_forum_topic(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.create_forum_topic`.
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :class:`telegram.ForumTopic`
-        """
-        return await self.get_bot().create_forum_topic(
-            chat_id=self.id,
-            name=name,
-            icon_color=icon_color,
-            icon_custom_emoji_id=icon_custom_emoji_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def edit_forum_topic(
-        self,
-        message_thread_id: int,
-        name: Optional[str] = None,
-        icon_custom_emoji_id: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.edit_forum_topic(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.edit_forum_topic`.
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-        """
-        return await self.get_bot().edit_forum_topic(
-            chat_id=self.id,
-            message_thread_id=message_thread_id,
-            name=name,
-            icon_custom_emoji_id=icon_custom_emoji_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def close_forum_topic(
-        self,
-        message_thread_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.close_forum_topic(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.close_forum_topic`.
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-        """
-        return await self.get_bot().close_forum_topic(
-            chat_id=self.id,
-            message_thread_id=message_thread_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def reopen_forum_topic(
-        self,
-        message_thread_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.reopen_forum_topic(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.reopen_forum_topic`.
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-        """
-        return await self.get_bot().reopen_forum_topic(
-            chat_id=self.id,
-            message_thread_id=message_thread_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def delete_forum_topic(
-        self,
-        message_thread_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.delete_forum_topic(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.delete_forum_topic`.
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-        """
-        return await self.get_bot().delete_forum_topic(
-            chat_id=self.id,
-            message_thread_id=message_thread_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def unpin_all_forum_topic_messages(
-        self,
-        message_thread_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.unpin_all_forum_topic_messages(chat_id=update.effective_chat.id,
-                *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.unpin_all_forum_topic_messages`.
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-        """
-        return await self.get_bot().unpin_all_forum_topic_messages(
-            chat_id=self.id,
-            message_thread_id=message_thread_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def unpin_all_general_forum_topic_messages(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.unpin_all_general_forum_topic_messages(chat_id=update.effective_chat.id,
-                *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.unpin_all_general_forum_topic_messages`.
-
-        .. versionadded:: 20.5
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-        """
-        return await self.get_bot().unpin_all_general_forum_topic_messages(
-            chat_id=self.id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def edit_general_forum_topic(
-        self,
-        name: str,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.edit_general_forum_topic(
-                chat_id=update.effective_chat.id, *args, **kwargs
-             )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.edit_general_forum_topic`.
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-        """
-        return await self.get_bot().edit_general_forum_topic(
-            chat_id=self.id,
-            name=name,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def close_general_forum_topic(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.close_general_forum_topic(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.close_general_forum_topic`.
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-        """
-        return await self.get_bot().close_general_forum_topic(
-            chat_id=self.id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def reopen_general_forum_topic(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.reopen_general_forum_topic(
-                chat_id=update.effective_chat.id, *args, **kwargs
-             )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.reopen_general_forum_topic`.
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-        """
-        return await self.get_bot().reopen_general_forum_topic(
-            chat_id=self.id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def hide_general_forum_topic(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.hide_general_forum_topic(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.hide_general_forum_topic`.
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-        """
-        return await self.get_bot().hide_general_forum_topic(
-            chat_id=self.id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def unhide_general_forum_topic(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.unhide_general_forum_topic (
-                chat_id=update.effective_chat.id, *args, **kwargs
-             )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.unhide_general_forum_topic`.
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-        """
-        return await self.get_bot().unhide_general_forum_topic(
-            chat_id=self.id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def get_menu_button(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> MenuButton:
-        """Shortcut for::
-
-             await bot.get_chat_menu_button(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.get_chat_menu_button`.
-
-        Caution:
-            Can only work, if the chat is a private chat.
-
-        .. seealso:: :meth:`set_menu_button`
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :class:`telegram.MenuButton`: On success, the current menu button is returned.
-        """
-        return await self.get_bot().get_chat_menu_button(
-            chat_id=self.id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def get_user_chat_boosts(
-        self,
-        user_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "UserChatBoosts":
-        """Shortcut for::
-
-             await bot.get_user_chat_boosts(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.get_user_chat_boosts`.
-
-        .. versionadded:: 20.8
-
-        Returns:
-            :class:`telegram.UserChatBoosts`: On success, returns the boosts applied in the chat.
-        """
-        return await self.get_bot().get_user_chat_boosts(
-            chat_id=self.id,
-            user_id=user_id,
-            api_kwargs=api_kwargs,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-        )
-
-    async def set_message_reaction(
-        self,
-        message_id: int,
-        reaction: Optional[Union[Sequence[Union[ReactionType, str]], ReactionType, str]] = None,
-        is_big: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.set_message_reaction(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.set_message_reaction`.
-
-        .. versionadded:: 20.8
-
-        Returns:
-            :obj:`bool` On success, :obj:`True` is returned.
-        """
-        return await self.get_bot().set_message_reaction(
-            chat_id=self.id,
-            message_id=message_id,
-            reaction=reaction,
-            is_big=is_big,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def send_paid_media(
-        self,
-        star_count: int,
-        media: Sequence["InputPaidMedia"],
-        caption: Optional[str] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        show_caption_above_media: Optional[bool] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        reply_markup: Optional[ReplyMarkup] = None,
-        business_connection_id: Optional[str] = None,
-        payload: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        reply_to_message_id: Optional[int] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_paid_media(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.send_paid_media`.
-
-        .. versionadded:: 21.4
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-        """
-        return await self.get_bot().send_paid_media(
-            chat_id=self.id,
-            star_count=star_count,
-            media=media,
-            caption=caption,
-            parse_mode=parse_mode,
-            caption_entities=caption_entities,
-            show_caption_above_media=show_caption_above_media,
-            disable_notification=disable_notification,
-            protect_content=protect_content,
-            reply_parameters=reply_parameters,
-            reply_markup=reply_markup,
-            allow_sending_without_reply=allow_sending_without_reply,
-            reply_to_message_id=reply_to_message_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=business_connection_id,
-            payload=payload,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def send_gift(
-        self,
-        gift_id: Union[str, "Gift"],
-        text: Optional[str] = None,
-        text_parse_mode: ODVInput[str] = DEFAULT_NONE,
-        text_entities: Optional[Sequence["MessageEntity"]] = None,
-        pay_for_upgrade: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.send_gift(user_id=update.effective_chat.id, *args, **kwargs )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_gift`.
-
-        Caution:
-            Can only work, if the chat is a private chat, see :attr:`type`.
-
-        .. versionadded:: 21.8
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-        """
-        return await self.get_bot().send_gift(
-            user_id=self.id,
-            gift_id=gift_id,
-            text=text,
-            text_parse_mode=text_parse_mode,
-            text_entities=text_entities,
-            pay_for_upgrade=pay_for_upgrade,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def verify(
-        self,
-        custom_description: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.verify_chat(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.verify_chat`.
-
-        .. versionadded:: 21.10
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-        """
-        return await self.get_bot().verify_chat(
-            chat_id=self.id,
-            custom_description=custom_description,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def remove_verification(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.remove_chat_verification(chat_id=update.effective_chat.id, *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.remove_chat_verification`.
-
-        .. versionadded:: 21.10
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-        """
-        return await self.get_bot().remove_chat_verification(
-            chat_id=self.id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-
-class Chat(_ChatBase):
-    """This object represents a chat.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`id` is equal.
-
-    .. versionchanged:: 20.0
-
-        * Removed the deprecated methods ``kick_member`` and ``get_members_count``.
-        * The following are now keyword-only arguments in Bot methods:
-          ``location``, ``filename``, ``contact``, ``{read, write, connect, pool}_timeout``,
-          ``api_kwargs``. Use a named argument for those,
-          and notice that some positional arguments changed position as a result.
-
-    .. versionchanged:: 20.0
-        Removed the attribute ``all_members_are_administrators``. As long as Telegram provides
-        this field for backwards compatibility, it is available through
-        :attr:`~telegram.TelegramObject.api_kwargs`.
-
-    .. versionchanged:: 21.3
-        As per Bot API 7.3, most of the arguments and attributes of this class have now moved to
-        :class:`telegram.ChatFullInfo`.
-
-    Args:
-        id (:obj:`int`): Unique identifier for this chat.
-        type (:obj:`str`): Type of chat, can be either :attr:`PRIVATE`, :attr:`GROUP`,
-            :attr:`SUPERGROUP` or :attr:`CHANNEL`.
-        title (:obj:`str`, optional): Title, for supergroups, channels and group chats.
-        username (:obj:`str`, optional): Username, for private chats, supergroups and channels if
-            available.
-        first_name (:obj:`str`, optional): First name of the other party in a private chat.
-        last_name (:obj:`str`, optional): Last name of the other party in a private chat.
-        is_forum (:obj:`bool`, optional): :obj:`True`, if the supergroup chat is a forum
-            (has topics_ enabled).
-
-            .. versionadded:: 20.0
-
-    Attributes:
-        id (:obj:`int`): Unique identifier for this chat.
-        type (:obj:`str`): Type of chat, can be either :attr:`PRIVATE`, :attr:`GROUP`,
-            :attr:`SUPERGROUP` or :attr:`CHANNEL`.
-        title (:obj:`str`): Optional. Title, for supergroups, channels and group chats.
-        username (:obj:`str`): Optional. Username, for private chats, supergroups and channels if
-            available.
-        first_name (:obj:`str`): Optional. First name of the other party in a private chat.
-        last_name (:obj:`str`): Optional. Last name of the other party in a private chat.
-        is_forum (:obj:`bool`): Optional. :obj:`True`, if the supergroup chat is a forum
-            (has topics_ enabled).
-
-            .. versionadded:: 20.0
-
-    .. _topics: https://telegram.org/blog/topics-in-groups-collectible-usernames#topics-in-groups
-    """
-
-    __slots__ = ()
diff --git a/venv/lib/python3.11/site-packages/telegram/_chatadministratorrights.py b/venv/lib/python3.11/site-packages/telegram/_chatadministratorrights.py
deleted file mode 100755
index 6b6c437..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_chatadministratorrights.py
+++ /dev/null
@@ -1,247 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the class which represents a Telegram ChatAdministratorRights."""
-from typing import Optional
-
-from telegram._telegramobject import TelegramObject
-from telegram._utils.types import JSONDict
-
-
-class ChatAdministratorRights(TelegramObject):
-    """Represents the rights of an administrator in a chat.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`is_anonymous`, :attr:`can_manage_chat`,
-    :attr:`can_delete_messages`, :attr:`can_manage_video_chats`, :attr:`can_restrict_members`,
-    :attr:`can_promote_members`, :attr:`can_change_info`, :attr:`can_invite_users`,
-    :attr:`can_post_messages`, :attr:`can_edit_messages`, :attr:`can_pin_messages`,
-    :attr:`can_manage_topics`, :attr:`can_post_stories`, :attr:`can_delete_stories`, and
-    :attr:`can_edit_stories` are equal.
-
-    .. versionadded:: 20.0
-
-    .. versionchanged:: 20.0
-        :attr:`can_manage_topics` is considered as well when comparing objects of
-        this type in terms of equality.
-
-    .. versionchanged:: 20.6
-        :attr:`can_post_stories`, :attr:`can_edit_stories`, and :attr:`can_delete_stories` are
-        considered as well when comparing objects of this type in terms of equality.
-
-    .. versionchanged:: 21.1
-        As of this version, :attr:`can_post_stories`, :attr:`can_edit_stories`,
-        and :attr:`can_delete_stories` is now required. Thus, the order of arguments had to be
-        changed.
-
-    Args:
-        is_anonymous (:obj:`bool`): :obj:`True`, if the user's presence in the chat is hidden.
-        can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator can access the chat event
-            log, get boost list, see hidden supergroup and channel members, report spam messages
-            and ignore slow mode. Implied by any other administrator privilege.
-        can_delete_messages (:obj:`bool`): :obj:`True`, if the administrator can delete messages of
-            other users.
-        can_manage_video_chats (:obj:`bool`): :obj:`True`, if the administrator can manage video
-            chats.
-        can_restrict_members (:obj:`bool`): :obj:`True`, if the administrator can restrict, ban or
-            unban chat members, or access supergroup statistics.
-        can_promote_members (:obj:`bool`): :obj:`True`, if the administrator can add new
-            administrators with a subset of their own privileges or demote administrators
-            that they have promoted, directly or indirectly (promoted by administrators that
-            were appointed by the user).
-        can_change_info (:obj:`bool`): :obj:`True`, if the user is allowed to change the chat title
-            , photo and other settings.
-        can_invite_users (:obj:`bool`): :obj:`True`, if the user is allowed to invite new users to
-            the chat.
-        can_post_messages (:obj:`bool`, optional): :obj:`True`, if the administrator can post
-            messages in the channel, or access channel statistics; for channels only.
-        can_edit_messages (:obj:`bool`, optional): :obj:`True`, if the administrator can edit
-            messages of other users and can pin messages; for channels only.
-        can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to pin
-            messages; for groups and supergroups only.
-        can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post
-            stories to the chat.
-
-            .. versionadded:: 20.6
-            .. versionchanged:: 21.0
-                |non_optional_story_argument|
-        can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted
-            by other users, post stories to the chat page, pin chat stories, and access the chat's
-            story archive
-
-            .. versionadded:: 20.6
-            .. versionchanged:: 21.0
-                |non_optional_story_argument|
-        can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete
-            stories posted by other users.
-
-            .. versionadded:: 20.6
-            .. versionchanged:: 21.0
-                |non_optional_story_argument|
-        can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed
-            to create, rename, close, and reopen forum topics; for supergroups only.
-
-            .. versionadded:: 20.0
-
-    Attributes:
-        is_anonymous (:obj:`bool`): :obj:`True`, if the user's presence in the chat is hidden.
-        can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator can access the chat event
-            log, get boost list, see hidden supergroup and channel members, report spam messages
-            and ignore slow mode. Implied by any other administrator privilege.
-        can_delete_messages (:obj:`bool`): :obj:`True`, if the administrator can delete messages of
-            other users.
-        can_manage_video_chats (:obj:`bool`): :obj:`True`, if the administrator can manage video
-            chats.
-        can_restrict_members (:obj:`bool`): :obj:`True`, if the administrator can restrict, ban or
-            unban chat members, or access supergroup statistics.
-        can_promote_members (:obj:`bool`): :obj:`True`, if the administrator can add new
-            administrators with a subset of their own privileges or demote administrators that he
-            has promoted, directly or indirectly (promoted by administrators that were appointed by
-            the user.)
-        can_change_info (:obj:`bool`): :obj:`True`, if the user is allowed to change the chat title
-            ,photo and other settings.
-        can_invite_users (:obj:`bool`): :obj:`True`, if the user is allowed to invite new users to
-            the chat.
-        can_post_messages (:obj:`bool`): Optional. :obj:`True`, if the administrator can post
-            messages in the channel, or access channel statistics; for channels only.
-        can_edit_messages (:obj:`bool`): Optional. :obj:`True`, if the administrator can edit
-            messages of other users and can pin messages; for channels only.
-        can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to pin
-            messages; for groups and supergroups only.
-        can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post
-            stories to the chat.
-
-            .. versionadded:: 20.6
-            .. versionchanged:: 21.0
-                |non_optional_story_argument|
-        can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted
-            by other users, post stories to the chat page, pin chat stories, and access the chat's
-            story archive
-
-            .. versionadded:: 20.6
-            .. versionchanged:: 21.0
-                |non_optional_story_argument|
-        can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete
-            stories posted by other users.
-
-            .. versionadded:: 20.6
-            .. versionchanged:: 21.0
-                |non_optional_story_argument|
-        can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed
-            to create, rename, close, and reopen forum topics; for supergroups only.
-
-            .. versionadded:: 20.0
-    """
-
-    __slots__ = (
-        "can_change_info",
-        "can_delete_messages",
-        "can_delete_stories",
-        "can_edit_messages",
-        "can_edit_stories",
-        "can_invite_users",
-        "can_manage_chat",
-        "can_manage_topics",
-        "can_manage_video_chats",
-        "can_pin_messages",
-        "can_post_messages",
-        "can_post_stories",
-        "can_promote_members",
-        "can_restrict_members",
-        "is_anonymous",
-    )
-
-    def __init__(
-        self,
-        is_anonymous: bool,
-        can_manage_chat: bool,
-        can_delete_messages: bool,
-        can_manage_video_chats: bool,
-        can_restrict_members: bool,
-        can_promote_members: bool,
-        can_change_info: bool,
-        can_invite_users: bool,
-        can_post_stories: bool,
-        can_edit_stories: bool,
-        can_delete_stories: bool,
-        can_post_messages: Optional[bool] = None,
-        can_edit_messages: Optional[bool] = None,
-        can_pin_messages: Optional[bool] = None,
-        can_manage_topics: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> None:
-        super().__init__(api_kwargs=api_kwargs)
-        # Required
-        self.is_anonymous: bool = is_anonymous
-        self.can_manage_chat: bool = can_manage_chat
-        self.can_delete_messages: bool = can_delete_messages
-        self.can_manage_video_chats: bool = can_manage_video_chats
-        self.can_restrict_members: bool = can_restrict_members
-        self.can_promote_members: bool = can_promote_members
-        self.can_change_info: bool = can_change_info
-        self.can_invite_users: bool = can_invite_users
-        self.can_post_stories: bool = can_post_stories
-        self.can_edit_stories: bool = can_edit_stories
-        self.can_delete_stories: bool = can_delete_stories
-        # Optionals
-        self.can_post_messages: Optional[bool] = can_post_messages
-        self.can_edit_messages: Optional[bool] = can_edit_messages
-        self.can_pin_messages: Optional[bool] = can_pin_messages
-        self.can_manage_topics: Optional[bool] = can_manage_topics
-
-        self._id_attrs = (
-            self.is_anonymous,
-            self.can_manage_chat,
-            self.can_delete_messages,
-            self.can_manage_video_chats,
-            self.can_restrict_members,
-            self.can_promote_members,
-            self.can_change_info,
-            self.can_invite_users,
-            self.can_post_messages,
-            self.can_edit_messages,
-            self.can_pin_messages,
-            self.can_manage_topics,
-            self.can_post_stories,
-            self.can_edit_stories,
-            self.can_delete_stories,
-        )
-
-        self._freeze()
-
-    @classmethod
-    def all_rights(cls) -> "ChatAdministratorRights":
-        """
-        This method returns the :class:`ChatAdministratorRights` object with all attributes set to
-        :obj:`True`. This is e.g. useful when changing the bot's default administrator rights with
-        :meth:`telegram.Bot.set_my_default_administrator_rights`.
-
-        .. versionadded:: 20.0
-        """
-        return cls(*(True,) * len(cls.__slots__))
-
-    @classmethod
-    def no_rights(cls) -> "ChatAdministratorRights":
-        """
-        This method returns the :class:`ChatAdministratorRights` object with all attributes set to
-        :obj:`False`.
-
-        .. versionadded:: 20.0
-        """
-        return cls(*(False,) * len(cls.__slots__))
diff --git a/venv/lib/python3.11/site-packages/telegram/_chatbackground.py b/venv/lib/python3.11/site-packages/telegram/_chatbackground.py
deleted file mode 100755
index 4d41e55..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_chatbackground.py
+++ /dev/null
@@ -1,547 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains objects related to chat backgrounds."""
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Final, Optional
-
-from telegram import constants
-from telegram._files.document import Document
-from telegram._telegramobject import TelegramObject
-from telegram._utils import enum
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.types import JSONDict
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class BackgroundFill(TelegramObject):
-    """Base class for Telegram BackgroundFill Objects. It can be one of:
-
-    * :class:`telegram.BackgroundFillSolid`
-    * :class:`telegram.BackgroundFillGradient`
-    * :class:`telegram.BackgroundFillFreeformGradient`
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`type` is equal.
-
-    .. versionadded:: 21.2
-
-    Args:
-        type (:obj:`str`): Type of the background fill. Can be one of:
-            :attr:`~telegram.BackgroundFill.SOLID`, :attr:`~telegram.BackgroundFill.GRADIENT`
-            or :attr:`~telegram.BackgroundFill.FREEFORM_GRADIENT`.
-
-    Attributes:
-        type (:obj:`str`): Type of the background fill. Can be one of:
-            :attr:`~telegram.BackgroundFill.SOLID`, :attr:`~telegram.BackgroundFill.GRADIENT`
-            or :attr:`~telegram.BackgroundFill.FREEFORM_GRADIENT`.
-    """
-
-    __slots__ = ("type",)
-
-    SOLID: Final[constants.BackgroundFillType] = constants.BackgroundFillType.SOLID
-    """:const:`telegram.constants.BackgroundFillType.SOLID`"""
-    GRADIENT: Final[constants.BackgroundFillType] = constants.BackgroundFillType.GRADIENT
-    """:const:`telegram.constants.BackgroundFillType.GRADIENT`"""
-    FREEFORM_GRADIENT: Final[constants.BackgroundFillType] = (
-        constants.BackgroundFillType.FREEFORM_GRADIENT
-    )
-    """:const:`telegram.constants.BackgroundFillType.FREEFORM_GRADIENT`"""
-
-    def __init__(
-        self,
-        type: str,  # pylint: disable=redefined-builtin
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        # Required by all subclasses
-        self.type: str = enum.get_member(constants.BackgroundFillType, type, type)
-
-        self._id_attrs = (self.type,)
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["BackgroundFill"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        _class_mapping: dict[str, type[BackgroundFill]] = {
-            cls.SOLID: BackgroundFillSolid,
-            cls.GRADIENT: BackgroundFillGradient,
-            cls.FREEFORM_GRADIENT: BackgroundFillFreeformGradient,
-        }
-
-        if cls is BackgroundFill and data.get("type") in _class_mapping:
-            return _class_mapping[data.pop("type")].de_json(data=data, bot=bot)
-
-        return super().de_json(data=data, bot=bot)
-
-
-class BackgroundFillSolid(BackgroundFill):
-    """
-    The background is filled using the selected color.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`color` is equal.
-
-    .. versionadded:: 21.2
-
-    Args:
-        color (:obj:`int`): The color of the background fill in the `RGB24` format.
-
-    Attributes:
-        type (:obj:`str`): Type of the background fill. Always
-            :attr:`~telegram.BackgroundFill.SOLID`.
-        color (:obj:`int`): The color of the background fill in the `RGB24` format.
-    """
-
-    __slots__ = ("color",)
-
-    def __init__(
-        self,
-        color: int,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(type=self.SOLID, api_kwargs=api_kwargs)
-
-        with self._unfrozen():
-            self.color: int = color
-
-            self._id_attrs = (self.color,)
-
-
-class BackgroundFillGradient(BackgroundFill):
-    """
-    The background is a gradient fill.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`top_color`, :attr:`bottom_color`
-    and :attr:`rotation_angle` are equal.
-
-    .. versionadded:: 21.2
-
-    Args:
-        top_color (:obj:`int`): Top color of the gradient in the `RGB24` format.
-        bottom_color (:obj:`int`): Bottom color of the gradient in the `RGB24` format.
-        rotation_angle (:obj:`int`): Clockwise rotation angle of the background
-            fill in degrees;
-            0-:tg-const:`telegram.constants.BackgroundFillLimit.MAX_ROTATION_ANGLE`.
-
-
-    Attributes:
-        type (:obj:`str`): Type of the background fill. Always
-            :attr:`~telegram.BackgroundFill.GRADIENT`.
-        top_color (:obj:`int`): Top color of the gradient in the `RGB24` format.
-        bottom_color (:obj:`int`): Bottom color of the gradient in the `RGB24` format.
-        rotation_angle (:obj:`int`): Clockwise rotation angle of the background
-            fill in degrees;
-            0-:tg-const:`telegram.constants.BackgroundFillLimit.MAX_ROTATION_ANGLE`.
-    """
-
-    __slots__ = ("bottom_color", "rotation_angle", "top_color")
-
-    def __init__(
-        self,
-        top_color: int,
-        bottom_color: int,
-        rotation_angle: int,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(type=self.GRADIENT, api_kwargs=api_kwargs)
-
-        with self._unfrozen():
-            self.top_color: int = top_color
-            self.bottom_color: int = bottom_color
-            self.rotation_angle: int = rotation_angle
-
-            self._id_attrs = (self.top_color, self.bottom_color, self.rotation_angle)
-
-
-class BackgroundFillFreeformGradient(BackgroundFill):
-    """
-    The background is a freeform gradient that rotates after every message in the chat.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`colors` is equal.
-
-    .. versionadded:: 21.2
-
-    Args:
-        colors (Sequence[:obj:`int`]): A list of the 3 or 4 base colors that are used to
-            generate the freeform gradient in the `RGB24` format
-
-    Attributes:
-        type (:obj:`str`): Type of the background fill. Always
-            :attr:`~telegram.BackgroundFill.FREEFORM_GRADIENT`.
-        colors (Sequence[:obj:`int`]): A list of the 3 or 4 base colors that are used to
-            generate the freeform gradient in the `RGB24` format
-    """
-
-    __slots__ = ("colors",)
-
-    def __init__(
-        self,
-        colors: Sequence[int],
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(type=self.FREEFORM_GRADIENT, api_kwargs=api_kwargs)
-
-        with self._unfrozen():
-            self.colors: tuple[int, ...] = parse_sequence_arg(colors)
-
-            self._id_attrs = (self.colors,)
-
-
-class BackgroundType(TelegramObject):
-    """Base class for Telegram BackgroundType Objects. It can be one of:
-
-    * :class:`telegram.BackgroundTypeFill`
-    * :class:`telegram.BackgroundTypeWallpaper`
-    * :class:`telegram.BackgroundTypePattern`
-    * :class:`telegram.BackgroundTypeChatTheme`.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`type` is equal.
-
-    .. versionadded:: 21.2
-
-    Args:
-        type (:obj:`str`): Type of the background. Can be one of:
-            :attr:`~telegram.BackgroundType.FILL`, :attr:`~telegram.BackgroundType.WALLPAPER`
-            :attr:`~telegram.BackgroundType.PATTERN` or
-            :attr:`~telegram.BackgroundType.CHAT_THEME`.
-
-    Attributes:
-        type (:obj:`str`): Type of the background. Can be one of:
-            :attr:`~telegram.BackgroundType.FILL`, :attr:`~telegram.BackgroundType.WALLPAPER`
-            :attr:`~telegram.BackgroundType.PATTERN` or
-            :attr:`~telegram.BackgroundType.CHAT_THEME`.
-
-    """
-
-    __slots__ = ("type",)
-
-    FILL: Final[constants.BackgroundTypeType] = constants.BackgroundTypeType.FILL
-    """:const:`telegram.constants.BackgroundTypeType.FILL`"""
-    WALLPAPER: Final[constants.BackgroundTypeType] = constants.BackgroundTypeType.WALLPAPER
-    """:const:`telegram.constants.BackgroundTypeType.WALLPAPER`"""
-    PATTERN: Final[constants.BackgroundTypeType] = constants.BackgroundTypeType.PATTERN
-    """:const:`telegram.constants.BackgroundTypeType.PATTERN`"""
-    CHAT_THEME: Final[constants.BackgroundTypeType] = constants.BackgroundTypeType.CHAT_THEME
-    """:const:`telegram.constants.BackgroundTypeType.CHAT_THEME`"""
-
-    def __init__(
-        self,
-        type: str,  # pylint: disable=redefined-builtin
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        # Required by all subclasses
-        self.type: str = enum.get_member(constants.BackgroundTypeType, type, type)
-
-        self._id_attrs = (self.type,)
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["BackgroundType"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        _class_mapping: dict[str, type[BackgroundType]] = {
-            cls.FILL: BackgroundTypeFill,
-            cls.WALLPAPER: BackgroundTypeWallpaper,
-            cls.PATTERN: BackgroundTypePattern,
-            cls.CHAT_THEME: BackgroundTypeChatTheme,
-        }
-
-        if cls is BackgroundType and data.get("type") in _class_mapping:
-            return _class_mapping[data.pop("type")].de_json(data=data, bot=bot)
-
-        if "fill" in data:
-            data["fill"] = BackgroundFill.de_json(data.get("fill"), bot)
-
-        if "document" in data:
-            data["document"] = Document.de_json(data.get("document"), bot)
-
-        return super().de_json(data=data, bot=bot)
-
-
-class BackgroundTypeFill(BackgroundType):
-    """
-    The background is automatically filled based on the selected colors.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`fill` and :attr:`dark_theme_dimming` are equal.
-
-    .. versionadded:: 21.2
-
-    Args:
-        fill (:class:`telegram.BackgroundFill`): The background fill.
-        dark_theme_dimming (:obj:`int`): Dimming of the background in dark themes, as a
-            percentage;
-            0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_DIMMING`.
-
-    Attributes:
-        type (:obj:`str`): Type of the background. Always
-            :attr:`~telegram.BackgroundType.FILL`.
-        fill (:class:`telegram.BackgroundFill`): The background fill.
-        dark_theme_dimming (:obj:`int`): Dimming of the background in dark themes, as a
-            percentage;
-            0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_DIMMING`.
-    """
-
-    __slots__ = ("dark_theme_dimming", "fill")
-
-    def __init__(
-        self,
-        fill: BackgroundFill,
-        dark_theme_dimming: int,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(type=self.FILL, api_kwargs=api_kwargs)
-
-        with self._unfrozen():
-            self.fill: BackgroundFill = fill
-            self.dark_theme_dimming: int = dark_theme_dimming
-
-            self._id_attrs = (self.fill, self.dark_theme_dimming)
-
-
-class BackgroundTypeWallpaper(BackgroundType):
-    """
-    The background is a wallpaper in the `JPEG` format.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`document` and :attr:`dark_theme_dimming` are equal.
-
-    .. versionadded:: 21.2
-
-    Args:
-        document (:class:`telegram.Document`): Document with the wallpaper
-        dark_theme_dimming (:obj:`int`): Dimming of the background in dark themes, as a
-            percentage;
-            0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_DIMMING`.
-        is_blurred (:obj:`bool`, optional): :obj:`True`, if the wallpaper is downscaled to fit
-            in a 450x450 square and then box-blurred with radius 12
-        is_moving (:obj:`bool`, optional): :obj:`True`, if the background moves slightly
-            when the device is tilted
-
-    Attributes:
-        type (:obj:`str`): Type of the background. Always
-            :attr:`~telegram.BackgroundType.WALLPAPER`.
-        document (:class:`telegram.Document`): Document with the wallpaper
-        dark_theme_dimming (:obj:`int`): Dimming of the background in dark themes, as a
-            percentage;
-            0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_DIMMING`.
-        is_blurred (:obj:`bool`): Optional. :obj:`True`, if the wallpaper is downscaled to fit
-            in a 450x450 square and then box-blurred with radius 12
-        is_moving (:obj:`bool`): Optional. :obj:`True`, if the background moves slightly
-            when the device is tilted
-    """
-
-    __slots__ = ("dark_theme_dimming", "document", "is_blurred", "is_moving")
-
-    def __init__(
-        self,
-        document: Document,
-        dark_theme_dimming: int,
-        is_blurred: Optional[bool] = None,
-        is_moving: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(type=self.WALLPAPER, api_kwargs=api_kwargs)
-
-        with self._unfrozen():
-            # Required
-            self.document: Document = document
-            self.dark_theme_dimming: int = dark_theme_dimming
-            # Optionals
-            self.is_blurred: Optional[bool] = is_blurred
-            self.is_moving: Optional[bool] = is_moving
-
-            self._id_attrs = (self.document, self.dark_theme_dimming)
-
-
-class BackgroundTypePattern(BackgroundType):
-    """
-    The background is a `PNG` or `TGV` (gzipped subset of `SVG` with `MIME` type
-    `"application/x-tgwallpattern"`) pattern to be combined with the background fill
-    chosen by the user.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`document` and :attr:`fill` and :attr:`intensity` are equal.
-
-    .. versionadded:: 21.2
-
-    Args:
-        document (:class:`telegram.Document`): Document with the pattern.
-        fill (:class:`telegram.BackgroundFill`): The background fill that is combined with
-            the pattern.
-        intensity (:obj:`int`): Intensity of the pattern when it is shown above the filled
-            background;
-            0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_INTENSITY`.
-        is_inverted (:obj:`int`, optional): :obj:`True`, if the background fill must be applied
-            only to the pattern itself. All other pixels are black in this case. For dark
-            themes only.
-        is_moving (:obj:`bool`, optional): :obj:`True`, if the background moves slightly
-            when the device is tilted.
-
-    Attributes:
-        type (:obj:`str`): Type of the background. Always
-            :attr:`~telegram.BackgroundType.PATTERN`.
-        document (:class:`telegram.Document`): Document with the pattern.
-        fill (:class:`telegram.BackgroundFill`): The background fill that is combined with
-            the pattern.
-        intensity (:obj:`int`): Intensity of the pattern when it is shown above the filled
-            background;
-            0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_INTENSITY`.
-        is_inverted (:obj:`int`): Optional. :obj:`True`, if the background fill must be applied
-            only to the pattern itself. All other pixels are black in this case. For dark
-            themes only.
-        is_moving (:obj:`bool`): Optional. :obj:`True`, if the background moves slightly
-            when the device is tilted.
-    """
-
-    __slots__ = (
-        "document",
-        "fill",
-        "intensity",
-        "is_inverted",
-        "is_moving",
-    )
-
-    def __init__(
-        self,
-        document: Document,
-        fill: BackgroundFill,
-        intensity: int,
-        is_inverted: Optional[bool] = None,
-        is_moving: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(type=self.PATTERN, api_kwargs=api_kwargs)
-
-        with self._unfrozen():
-            # Required
-            self.document: Document = document
-            self.fill: BackgroundFill = fill
-            self.intensity: int = intensity
-            # Optionals
-            self.is_inverted: Optional[bool] = is_inverted
-            self.is_moving: Optional[bool] = is_moving
-
-            self._id_attrs = (self.document, self.fill, self.intensity)
-
-
-class BackgroundTypeChatTheme(BackgroundType):
-    """
-    The background is taken directly from a built-in chat theme.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`theme_name` is equal.
-
-    .. versionadded:: 21.2
-
-    Args:
-        theme_name (:obj:`str`): Name of the chat theme, which is usually an emoji.
-
-    Attributes:
-        type (:obj:`str`): Type of the background. Always
-            :attr:`~telegram.BackgroundType.CHAT_THEME`.
-        theme_name (:obj:`str`): Name of the chat theme, which is usually an emoji.
-    """
-
-    __slots__ = ("theme_name",)
-
-    def __init__(
-        self,
-        theme_name: str,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(type=self.CHAT_THEME, api_kwargs=api_kwargs)
-
-        with self._unfrozen():
-            self.theme_name: str = theme_name
-
-            self._id_attrs = (self.theme_name,)
-
-
-class ChatBackground(TelegramObject):
-    """
-    This object represents a chat background.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`type` is  equal.
-
-    .. versionadded:: 21.2
-
-    Args:
-        type (:class:`telegram.BackgroundType`): Type of the background.
-
-    Attributes:
-        type (:class:`telegram.BackgroundType`): Type of the background.
-    """
-
-    __slots__ = ("type",)
-
-    def __init__(
-        self,
-        type: BackgroundType,  # pylint: disable=redefined-builtin
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.type: BackgroundType = type
-
-        self._id_attrs = (self.type,)
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["ChatBackground"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        data["type"] = BackgroundType.de_json(data.get("type"), bot)
-
-        return super().de_json(data=data, bot=bot)
diff --git a/venv/lib/python3.11/site-packages/telegram/_chatboost.py b/venv/lib/python3.11/site-packages/telegram/_chatboost.py
deleted file mode 100755
index 6f45a27..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_chatboost.py
+++ /dev/null
@@ -1,464 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram ChatBoosts."""
-import datetime as dtm
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Final, Optional
-
-from telegram import constants
-from telegram._chat import Chat
-from telegram._telegramobject import TelegramObject
-from telegram._user import User
-from telegram._utils import enum
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
-from telegram._utils.types import JSONDict
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class ChatBoostAdded(TelegramObject):
-    """
-    This object represents a service message about a user boosting a chat.
-
-    Objects of this class are comparable in terms of equality.
-    Two objects of this class are considered equal, if their
-    :attr:`boost_count` are equal.
-
-    .. versionadded:: 21.0
-
-    Args:
-        boost_count (:obj:`int`): Number of boosts added by the user.
-
-    Attributes:
-        boost_count (:obj:`int`): Number of boosts added by the user.
-
-    """
-
-    __slots__ = ("boost_count",)
-
-    def __init__(
-        self,
-        boost_count: int,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> None:
-        super().__init__(api_kwargs=api_kwargs)
-        self.boost_count: int = boost_count
-        self._id_attrs = (self.boost_count,)
-
-        self._freeze()
-
-
-class ChatBoostSource(TelegramObject):
-    """
-    Base class for Telegram ChatBoostSource objects. It can be one of:
-
-    * :class:`telegram.ChatBoostSourcePremium`
-    * :class:`telegram.ChatBoostSourceGiftCode`
-    * :class:`telegram.ChatBoostSourceGiveaway`
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`source` is equal.
-
-    .. versionadded:: 20.8
-
-    Args:
-        source (:obj:`str`): The source of the chat boost. Can be one of:
-            :attr:`~telegram.ChatBoostSource.PREMIUM`, :attr:`~telegram.ChatBoostSource.GIFT_CODE`,
-            or :attr:`~telegram.ChatBoostSource.GIVEAWAY`.
-
-    Attributes:
-        source (:obj:`str`): The source of the chat boost. Can be one of:
-            :attr:`~telegram.ChatBoostSource.PREMIUM`, :attr:`~telegram.ChatBoostSource.GIFT_CODE`,
-            or :attr:`~telegram.ChatBoostSource.GIVEAWAY`.
-    """
-
-    __slots__ = ("source",)
-
-    PREMIUM: Final[str] = constants.ChatBoostSources.PREMIUM
-    """:const:`telegram.constants.ChatBoostSources.PREMIUM`"""
-    GIFT_CODE: Final[str] = constants.ChatBoostSources.GIFT_CODE
-    """:const:`telegram.constants.ChatBoostSources.GIFT_CODE`"""
-    GIVEAWAY: Final[str] = constants.ChatBoostSources.GIVEAWAY
-    """:const:`telegram.constants.ChatBoostSources.GIVEAWAY`"""
-
-    def __init__(self, source: str, *, api_kwargs: Optional[JSONDict] = None):
-        super().__init__(api_kwargs=api_kwargs)
-
-        # Required by all subclasses:
-        self.source: str = enum.get_member(constants.ChatBoostSources, source, source)
-
-        self._id_attrs = (self.source,)
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["ChatBoostSource"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        _class_mapping: dict[str, type[ChatBoostSource]] = {
-            cls.PREMIUM: ChatBoostSourcePremium,
-            cls.GIFT_CODE: ChatBoostSourceGiftCode,
-            cls.GIVEAWAY: ChatBoostSourceGiveaway,
-        }
-
-        if cls is ChatBoostSource and data.get("source") in _class_mapping:
-            return _class_mapping[data.pop("source")].de_json(data=data, bot=bot)
-
-        if "user" in data:
-            data["user"] = User.de_json(data.get("user"), bot)
-
-        return super().de_json(data=data, bot=bot)
-
-
-class ChatBoostSourcePremium(ChatBoostSource):
-    """
-    The boost was obtained by subscribing to Telegram Premium or by gifting a Telegram Premium
-    subscription to another user.
-
-    .. versionadded:: 20.8
-
-    Args:
-        user (:class:`telegram.User`): User that boosted the chat.
-
-    Attributes:
-        source (:obj:`str`): The source of the chat boost. Always
-            :attr:`~telegram.ChatBoostSource.PREMIUM`.
-        user (:class:`telegram.User`): User that boosted the chat.
-    """
-
-    __slots__ = ("user",)
-
-    def __init__(self, user: User, *, api_kwargs: Optional[JSONDict] = None):
-        super().__init__(source=self.PREMIUM, api_kwargs=api_kwargs)
-
-        with self._unfrozen():
-            self.user: User = user
-
-
-class ChatBoostSourceGiftCode(ChatBoostSource):
-    """
-    The boost was obtained by the creation of Telegram Premium gift codes to boost a chat. Each
-    such code boosts the chat 4 times for the duration of the corresponding Telegram Premium
-    subscription.
-
-    .. versionadded:: 20.8
-
-    Args:
-        user (:class:`telegram.User`): User for which the gift code was created.
-
-    Attributes:
-        source (:obj:`str`): The source of the chat boost. Always
-            :attr:`~telegram.ChatBoostSource.GIFT_CODE`.
-        user (:class:`telegram.User`): User for which the gift code was created.
-    """
-
-    __slots__ = ("user",)
-
-    def __init__(self, user: User, *, api_kwargs: Optional[JSONDict] = None):
-        super().__init__(source=self.GIFT_CODE, api_kwargs=api_kwargs)
-
-        with self._unfrozen():
-            self.user: User = user
-
-
-class ChatBoostSourceGiveaway(ChatBoostSource):
-    """
-    The boost was obtained by the creation of a Telegram Premium giveaway or a Telegram Star.
-    This boosts the chat 4 times for the duration of the corresponding Telegram Premium
-    subscription for Telegram Premium giveaways and :attr:`prize_star_count` / 500 times for
-    one year for Telegram Star giveaways.
-
-    .. versionadded:: 20.8
-
-    Args:
-        giveaway_message_id (:obj:`int`): Identifier of a message in the chat with the giveaway;
-            the message could have been deleted already. May be 0 if the message isn't sent yet.
-        user (:class:`telegram.User`, optional): User that won the prize in the giveaway if any;
-            for Telegram Premium giveaways only.
-        prize_star_count (:obj:`int`, optional): The number of Telegram Stars to be split between
-            giveaway winners; for Telegram Star giveaways only.
-
-            .. versionadded:: 21.6
-        is_unclaimed (:obj:`bool`, optional): :obj:`True`, if the giveaway was completed, but
-            there was no user to win the prize.
-
-    Attributes:
-        source (:obj:`str`): Source of the boost. Always
-            :attr:`~telegram.ChatBoostSource.GIVEAWAY`.
-        giveaway_message_id (:obj:`int`): Identifier of a message in the chat with the giveaway;
-            the message could have been deleted already. May be 0 if the message isn't sent yet.
-        user (:class:`telegram.User`): Optional. User that won the prize in the giveaway if any.
-        prize_star_count (:obj:`int`): Optional. The number of Telegram Stars to be split between
-            giveaway winners; for Telegram Star giveaways only.
-
-            .. versionadded:: 21.6
-        is_unclaimed (:obj:`bool`): Optional. :obj:`True`, if the giveaway was completed, but
-            there was no user to win the prize.
-    """
-
-    __slots__ = ("giveaway_message_id", "is_unclaimed", "prize_star_count", "user")
-
-    def __init__(
-        self,
-        giveaway_message_id: int,
-        user: Optional[User] = None,
-        is_unclaimed: Optional[bool] = None,
-        prize_star_count: Optional[int] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(source=self.GIVEAWAY, api_kwargs=api_kwargs)
-
-        with self._unfrozen():
-            self.giveaway_message_id: int = giveaway_message_id
-            self.user: Optional[User] = user
-            self.prize_star_count: Optional[int] = prize_star_count
-            self.is_unclaimed: Optional[bool] = is_unclaimed
-
-
-class ChatBoost(TelegramObject):
-    """
-    This object contains information about a chat boost.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`boost_id`, :attr:`add_date`, :attr:`expiration_date`,
-    and :attr:`source` are equal.
-
-    .. versionadded:: 20.8
-
-    Args:
-        boost_id (:obj:`str`): Unique identifier of the boost.
-        add_date (:obj:`datetime.datetime`): Point in time when the chat was boosted.
-        expiration_date (:obj:`datetime.datetime`): Point in time when the boost
-            will automatically expire, unless the booster's Telegram Premium subscription is
-            prolonged.
-        source (:class:`telegram.ChatBoostSource`): Source of the added boost.
-
-    Attributes:
-        boost_id (:obj:`str`): Unique identifier of the boost.
-        add_date (:obj:`datetime.datetime`): Point in time when the chat was boosted.
-            |datetime_localization|
-        expiration_date (:obj:`datetime.datetime`): Point in time when the boost
-            will automatically expire, unless the booster's Telegram Premium subscription is
-            prolonged. |datetime_localization|
-        source (:class:`telegram.ChatBoostSource`): Source of the added boost.
-    """
-
-    __slots__ = ("add_date", "boost_id", "expiration_date", "source")
-
-    def __init__(
-        self,
-        boost_id: str,
-        add_date: dtm.datetime,
-        expiration_date: dtm.datetime,
-        source: ChatBoostSource,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-
-        self.boost_id: str = boost_id
-        self.add_date: dtm.datetime = add_date
-        self.expiration_date: dtm.datetime = expiration_date
-        self.source: ChatBoostSource = source
-
-        self._id_attrs = (self.boost_id, self.add_date, self.expiration_date, self.source)
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["ChatBoost"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        data["source"] = ChatBoostSource.de_json(data.get("source"), bot)
-        loc_tzinfo = extract_tzinfo_from_defaults(bot)
-        data["add_date"] = from_timestamp(data["add_date"], tzinfo=loc_tzinfo)
-        data["expiration_date"] = from_timestamp(data["expiration_date"], tzinfo=loc_tzinfo)
-
-        return super().de_json(data=data, bot=bot)
-
-
-class ChatBoostUpdated(TelegramObject):
-    """This object represents a boost added to a chat or changed.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`chat`, and :attr:`boost` are equal.
-
-    .. versionadded:: 20.8
-
-    Args:
-        chat (:class:`telegram.Chat`): Chat which was boosted.
-        boost (:class:`telegram.ChatBoost`): Information about the chat boost.
-
-    Attributes:
-        chat (:class:`telegram.Chat`): Chat which was boosted.
-        boost (:class:`telegram.ChatBoost`): Information about the chat boost.
-    """
-
-    __slots__ = ("boost", "chat")
-
-    def __init__(
-        self,
-        chat: Chat,
-        boost: ChatBoost,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-
-        self.chat: Chat = chat
-        self.boost: ChatBoost = boost
-
-        self._id_attrs = (self.chat.id, self.boost)
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["ChatBoostUpdated"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        data["chat"] = Chat.de_json(data.get("chat"), bot)
-        data["boost"] = ChatBoost.de_json(data.get("boost"), bot)
-
-        return super().de_json(data=data, bot=bot)
-
-
-class ChatBoostRemoved(TelegramObject):
-    """
-    This object represents a boost removed from a chat.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`chat`, :attr:`boost_id`, :attr:`remove_date`, and
-    :attr:`source` are equal.
-
-    Args:
-        chat (:class:`telegram.Chat`): Chat which was boosted.
-        boost_id (:obj:`str`): Unique identifier of the boost.
-        remove_date (:obj:`datetime.datetime`): Point in time when the boost was removed.
-        source (:class:`telegram.ChatBoostSource`): Source of the removed boost.
-
-    Attributes:
-        chat (:class:`telegram.Chat`): Chat which was boosted.
-        boost_id (:obj:`str`): Unique identifier of the boost.
-        remove_date (:obj:`datetime.datetime`): Point in time when the boost was removed.
-            |datetime_localization|
-        source (:class:`telegram.ChatBoostSource`): Source of the removed boost.
-    """
-
-    __slots__ = ("boost_id", "chat", "remove_date", "source")
-
-    def __init__(
-        self,
-        chat: Chat,
-        boost_id: str,
-        remove_date: dtm.datetime,
-        source: ChatBoostSource,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-
-        self.chat: Chat = chat
-        self.boost_id: str = boost_id
-        self.remove_date: dtm.datetime = remove_date
-        self.source: ChatBoostSource = source
-
-        self._id_attrs = (self.chat, self.boost_id, self.remove_date, self.source)
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["ChatBoostRemoved"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        data["chat"] = Chat.de_json(data.get("chat"), bot)
-        data["source"] = ChatBoostSource.de_json(data.get("source"), bot)
-        loc_tzinfo = extract_tzinfo_from_defaults(bot)
-        data["remove_date"] = from_timestamp(data["remove_date"], tzinfo=loc_tzinfo)
-
-        return super().de_json(data=data, bot=bot)
-
-
-class UserChatBoosts(TelegramObject):
-    """This object represents a list of boosts added to a chat by a user.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`boosts` are equal.
-
-    .. versionadded:: 20.8
-
-    Args:
-        boosts (Sequence[:class:`telegram.ChatBoost`]): List of boosts added to the chat by the
-            user.
-
-    Attributes:
-        boosts (tuple[:class:`telegram.ChatBoost`]): List of boosts added to the chat by the user.
-    """
-
-    __slots__ = ("boosts",)
-
-    def __init__(
-        self,
-        boosts: Sequence[ChatBoost],
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-
-        self.boosts: tuple[ChatBoost, ...] = parse_sequence_arg(boosts)
-
-        self._id_attrs = (self.boosts,)
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["UserChatBoosts"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        data["boosts"] = ChatBoost.de_list(data.get("boosts"), bot)
-
-        return super().de_json(data=data, bot=bot)
diff --git a/venv/lib/python3.11/site-packages/telegram/_chatfullinfo.py b/venv/lib/python3.11/site-packages/telegram/_chatfullinfo.py
deleted file mode 100755
index ebf8e8e..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_chatfullinfo.py
+++ /dev/null
@@ -1,552 +0,0 @@
-#!/usr/bin/env python
-# pylint: disable=redefined-builtin
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram ChatFullInfo."""
-import datetime as dtm
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Optional
-
-from telegram._birthdate import Birthdate
-from telegram._chat import Chat, _ChatBase
-from telegram._chatlocation import ChatLocation
-from telegram._chatpermissions import ChatPermissions
-from telegram._files.chatphoto import ChatPhoto
-from telegram._reaction import ReactionType
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
-from telegram._utils.types import JSONDict
-
-if TYPE_CHECKING:
-    from telegram import Bot, BusinessIntro, BusinessLocation, BusinessOpeningHours, Message
-
-
-class ChatFullInfo(_ChatBase):
-    """
-    This object contains full information about a chat.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`~telegram.Chat.id` is equal.
-
-    .. versionadded:: 21.2
-
-    .. versionchanged:: 21.3
-        Explicit support for all shortcut methods known from :class:`telegram.Chat` on this
-        object. Previously those were only available because this class inherited from
-        :class:`telegram.Chat`.
-
-    Args:
-        id (:obj:`int`): Unique identifier for this chat.
-        type (:obj:`str`): Type of chat, can be either :attr:`PRIVATE`, :attr:`GROUP`,
-            :attr:`SUPERGROUP` or :attr:`CHANNEL`.
-        accent_color_id (:obj:`int`, optional): Identifier of the
-            :class:`accent color ` for the chat name and
-            backgrounds of the chat photo, reply header, and link preview. See `accent colors`_
-            for more details.
-
-            .. versionadded:: 20.8
-        max_reaction_count (:obj:`int`): The maximum number of reactions that can be set on a
-            message in the chat.
-
-            .. versionadded:: 21.2
-        title (:obj:`str`, optional): Title, for supergroups, channels and group chats.
-        username (:obj:`str`, optional): Username, for private chats, supergroups and channels if
-            available.
-        first_name (:obj:`str`, optional): First name of the other party in a private chat.
-        last_name (:obj:`str`, optional): Last name of the other party in a private chat.
-        is_forum (:obj:`bool`, optional): :obj:`True`, if the supergroup chat is a forum
-            (has topics_ enabled).
-
-            .. versionadded:: 20.0
-        photo (:class:`telegram.ChatPhoto`, optional): Chat photo.
-        active_usernames (Sequence[:obj:`str`], optional):  If set, the list of all `active chat
-            usernames `_; for private chats, supergroups and channels.
-
-            .. versionadded:: 20.0
-        birthdate (:class:`telegram.Birthdate`, optional): For private chats,
-            the date of birth of the user.
-
-            .. versionadded:: 21.1
-        business_intro (:class:`telegram.BusinessIntro`, optional): For private chats with
-            business accounts, the intro of the business.
-
-            .. versionadded:: 21.1
-        business_location (:class:`telegram.BusinessLocation`, optional): For private chats with
-            business accounts, the location of the business.
-
-            .. versionadded:: 21.1
-        business_opening_hours (:class:`telegram.BusinessOpeningHours`, optional): For private
-            chats with business accounts, the opening hours of the business.
-
-            .. versionadded:: 21.1
-        personal_chat (:class:`telegram.Chat`, optional): For private chats, the personal channel
-            of the user.
-
-            .. versionadded:: 21.1
-        available_reactions (Sequence[:class:`telegram.ReactionType`], optional): List of available
-            reactions allowed in the chat. If omitted, then all of
-            :const:`telegram.constants.ReactionEmoji` are allowed.
-
-            .. versionadded:: 20.8
-        background_custom_emoji_id (:obj:`str`, optional): Custom emoji identifier of emoji chosen
-            by the chat for the reply header and link preview background.
-
-            .. versionadded:: 20.8
-        profile_accent_color_id (:obj:`int`, optional): Identifier of the
-            :class:`accent color ` for the chat's profile
-            background. See profile `accent colors`_ for more details.
-
-            .. versionadded:: 20.8
-        profile_background_custom_emoji_id (:obj:`str`, optional): Custom emoji identifier of
-            the emoji chosen by the chat for its profile background.
-
-            .. versionadded:: 20.8
-        emoji_status_custom_emoji_id (:obj:`str`, optional): Custom emoji identifier of emoji
-            status of the chat or the other party in a private chat.
-
-            .. versionadded:: 20.0
-        emoji_status_expiration_date (:class:`datetime.datetime`, optional): Expiration date of
-            emoji status of the chat or the other party in a private chat, as a datetime object,
-            if any.
-
-            |datetime_localization|
-
-            .. versionadded:: 20.5
-        bio (:obj:`str`, optional): Bio of the other party in a private chat.
-        has_private_forwards (:obj:`bool`, optional): :obj:`True`, if privacy settings of the other
-            party in the private chat allows to use ``tg://user?id=`` links only in chats
-            with the user.
-
-            .. versionadded:: 13.9
-        has_restricted_voice_and_video_messages (:obj:`bool`, optional): :obj:`True`, if the
-            privacy settings of the other party restrict sending voice and video note messages
-            in the private chat.
-
-            .. versionadded:: 20.0
-        join_to_send_messages (:obj:`bool`, optional): :obj:`True`, if users need to join the
-            supergroup before they can send messages.
-
-            .. versionadded:: 20.0
-        join_by_request (:obj:`bool`, optional): :obj:`True`, if all users directly joining the
-            supergroup without using an invite link need to be approved by supergroup
-            administrators.
-
-            .. versionadded:: 20.0
-        description (:obj:`str`, optional): Description, for groups, supergroups and channel chats.
-        invite_link (:obj:`str`, optional): Primary invite link, for groups, supergroups and
-            channel.
-        pinned_message (:class:`telegram.Message`, optional): The most recent pinned message
-            (by sending date).
-        permissions (:class:`telegram.ChatPermissions`): Optional. Default chat member permissions,
-            for groups and supergroups.
-        slow_mode_delay (:obj:`int`, optional): For supergroups, the minimum allowed delay between
-            consecutive messages sent by each unprivileged user.
-        unrestrict_boost_count (:obj:`int`, optional): For supergroups, the minimum number of
-            boosts that a non-administrator user needs to add in order to ignore slow mode and chat
-            permissions.
-
-            .. versionadded:: 21.0
-        message_auto_delete_time (:obj:`int`, optional): The time after which all messages sent to
-            the chat will be automatically deleted; in seconds.
-
-            .. versionadded:: 13.4
-        has_aggressive_anti_spam_enabled (:obj:`bool`, optional): :obj:`True`, if aggressive
-            anti-spam checks are enabled in the supergroup. The field is only available to chat
-            administrators.
-
-            .. versionadded:: 20.0
-        has_hidden_members (:obj:`bool`, optional): :obj:`True`, if non-administrators can only
-            get the list of bots and administrators in the chat.
-
-            .. versionadded:: 20.0
-        has_protected_content (:obj:`bool`, optional): :obj:`True`, if messages from the chat can't
-            be forwarded to other chats.
-
-            .. versionadded:: 13.9
-        has_visible_history (:obj:`bool`, optional): :obj:`True`, if new chat members will have
-            access to old messages; available only to chat administrators.
-
-            .. versionadded:: 20.8
-        sticker_set_name (:obj:`str`, optional): For supergroups, name of group sticker set.
-        can_set_sticker_set (:obj:`bool`, optional): :obj:`True`, if the bot can change group the
-            sticker set.
-        custom_emoji_sticker_set_name (:obj:`str`, optional): For supergroups, the name of the
-            group's custom emoji sticker set. Custom emoji from this set can be used by all users
-            and bots in the group.
-
-            .. versionadded:: 21.0
-        linked_chat_id (:obj:`int`, optional): Unique identifier for the linked chat, i.e. the
-            discussion group identifier for a channel and vice versa; for supergroups and channel
-            chats.
-        location (:class:`telegram.ChatLocation`, optional): For supergroups, the location to which
-            the supergroup is connected.
-        can_send_paid_media (:obj:`bool`, optional): :obj:`True`, if paid media messages can be
-            sent or forwarded to the channel chat. The field is available only for channel chats.
-
-            .. versionadded:: 21.4
-
-    Attributes:
-        id (:obj:`int`): Unique identifier for this chat.
-        type (:obj:`str`): Type of chat, can be either :attr:`PRIVATE`, :attr:`GROUP`,
-            :attr:`SUPERGROUP` or :attr:`CHANNEL`.
-        accent_color_id (:obj:`int`): Optional. Identifier of the
-            :class:`accent color ` for the chat name and
-            backgrounds of the chat photo, reply header, and link preview. See `accent colors`_
-            for more details.
-
-            .. versionadded:: 20.8
-        max_reaction_count (:obj:`int`): The maximum number of reactions that can be set on a
-            message in the chat.
-
-            .. versionadded:: 21.2
-        title (:obj:`str`, optional): Title, for supergroups, channels and group chats.
-        username (:obj:`str`, optional): Username, for private chats, supergroups and channels if
-            available.
-        first_name (:obj:`str`, optional): First name of the other party in a private chat.
-        last_name (:obj:`str`, optional): Last name of the other party in a private chat.
-        is_forum (:obj:`bool`, optional): :obj:`True`, if the supergroup chat is a forum
-            (has topics_ enabled).
-
-            .. versionadded:: 20.0
-        photo (:class:`telegram.ChatPhoto`): Optional. Chat photo.
-        active_usernames (tuple[:obj:`str`]): Optional. If set, the list of all `active chat
-            usernames `_; for private chats, supergroups and channels.
-
-            This list is empty if the chat has no active usernames or this chat instance was not
-            obtained via :meth:`~telegram.Bot.get_chat`.
-
-            .. versionadded:: 20.0
-        birthdate (:class:`telegram.Birthdate`): Optional. For private chats,
-            the date of birth of the user.
-
-            .. versionadded:: 21.1
-        business_intro (:class:`telegram.BusinessIntro`): Optional. For private chats with
-            business accounts, the intro of the business.
-
-            .. versionadded:: 21.1
-        business_location (:class:`telegram.BusinessLocation`): Optional. For private chats with
-            business accounts, the location of the business.
-
-            .. versionadded:: 21.1
-        business_opening_hours (:class:`telegram.BusinessOpeningHours`): Optional. For private
-            chats with business accounts, the opening hours of the business.
-
-            .. versionadded:: 21.1
-        personal_chat (:class:`telegram.Chat`): Optional. For private chats, the personal channel
-            of the user.
-
-            .. versionadded:: 21.1
-        available_reactions (tuple[:class:`telegram.ReactionType`]): Optional. List of available
-            reactions allowed in the chat. If omitted, then all of
-            :const:`telegram.constants.ReactionEmoji` are allowed.
-
-            .. versionadded:: 20.8
-        background_custom_emoji_id (:obj:`str`): Optional. Custom emoji identifier of emoji chosen
-            by the chat for the reply header and link preview background.
-
-            .. versionadded:: 20.8
-        profile_accent_color_id (:obj:`int`): Optional. Identifier of the
-            :class:`accent color ` for the chat's profile
-            background. See profile `accent colors`_ for more details.
-
-            .. versionadded:: 20.8
-        profile_background_custom_emoji_id (:obj:`str`): Optional. Custom emoji identifier of
-            the emoji chosen by the chat for its profile background.
-
-            .. versionadded:: 20.8
-        emoji_status_custom_emoji_id (:obj:`str`): Optional. Custom emoji identifier of emoji
-            status of the chat or the other party in a private chat.
-
-            .. versionadded:: 20.0
-        emoji_status_expiration_date (:class:`datetime.datetime`): Optional. Expiration date of
-            emoji status of the chat or the other party in a private chat, as a datetime object,
-            if any.
-
-            |datetime_localization|
-
-            .. versionadded:: 20.5
-        bio (:obj:`str`): Optional. Bio of the other party in a private chat.
-        has_private_forwards (:obj:`bool`): Optional. :obj:`True`, if privacy settings of the other
-            party in the private chat allows to use ``tg://user?id=`` links only in chats
-            with the user.
-
-            .. versionadded:: 13.9
-        has_restricted_voice_and_video_messages (:obj:`bool`): Optional. :obj:`True`, if the
-            privacy settings of the other party restrict sending voice and video note messages
-            in the private chat.
-
-            .. versionadded:: 20.0
-        join_to_send_messages (:obj:`bool`): Optional. :obj:`True`, if users need to join
-            the supergroup before they can send messages.
-
-            .. versionadded:: 20.0
-        join_by_request (:obj:`bool`): Optional. :obj:`True`, if all users directly joining the
-            supergroup without using an invite link need to be approved by supergroup
-            administrators.
-
-            .. versionadded:: 20.0
-        description (:obj:`str`): Optional. Description, for groups, supergroups and channel chats.
-        invite_link (:obj:`str`): Optional. Primary invite link, for groups, supergroups and
-            channel.
-        pinned_message (:class:`telegram.Message`): Optional. The most recent pinned message
-            (by sending date).
-        permissions (:class:`telegram.ChatPermissions`): Optional. Default chat member permissions,
-            for groups and supergroups.
-        slow_mode_delay (:obj:`int`): Optional. For supergroups, the minimum allowed delay between
-            consecutive messages sent by each unprivileged user.
-        unrestrict_boost_count (:obj:`int`): Optional. For supergroups, the minimum number of
-            boosts that a non-administrator user needs to add in order to ignore slow mode and chat
-            permissions.
-
-            .. versionadded:: 21.0
-        message_auto_delete_time (:obj:`int`): Optional. The time after which all messages sent to
-            the chat will be automatically deleted; in seconds.
-
-            .. versionadded:: 13.4
-        has_aggressive_anti_spam_enabled (:obj:`bool`): Optional. :obj:`True`, if aggressive
-            anti-spam checks are enabled in the supergroup. The field is only available to chat
-            administrators.
-
-            .. versionadded:: 20.0
-        has_hidden_members (:obj:`bool`): Optional. :obj:`True`, if non-administrators can only
-            get the list of bots and administrators in the chat.
-
-            .. versionadded:: 20.0
-        has_protected_content (:obj:`bool`): Optional. :obj:`True`, if messages from the chat can't
-            be forwarded to other chats.
-
-            .. versionadded:: 13.9
-        has_visible_history (:obj:`bool`): Optional. :obj:`True`, if new chat members will have
-            access to old messages; available only to chat administrators.
-
-            .. versionadded:: 20.8
-        sticker_set_name (:obj:`str`): Optional. For supergroups, name of Group sticker set.
-        can_set_sticker_set (:obj:`bool`): Optional. :obj:`True`, if the bot can change group the
-            sticker set.
-        custom_emoji_sticker_set_name (:obj:`str`): Optional. For supergroups, the name of the
-            group's custom emoji sticker set. Custom emoji from this set can be used by all users
-            and bots in the group.
-
-            .. versionadded:: 21.0
-        linked_chat_id (:obj:`int`): Optional. Unique identifier for the linked chat, i.e. the
-            discussion group identifier for a channel and vice versa; for supergroups and channel
-            chats.
-        location (:class:`telegram.ChatLocation`): Optional. For supergroups, the location to which
-            the supergroup is connected.
-        can_send_paid_media (:obj:`bool`): Optional. :obj:`True`, if paid media messages can be
-            sent or forwarded to the channel chat. The field is available only for channel chats.
-
-            .. versionadded:: 21.4
-
-    .. _accent colors: https://core.telegram.org/bots/api#accent-colors
-    .. _topics: https://telegram.org/blog/topics-in-groups-collectible-usernames#topics-in-groups
-    """
-
-    __slots__ = (
-        "accent_color_id",
-        "active_usernames",
-        "available_reactions",
-        "background_custom_emoji_id",
-        "bio",
-        "birthdate",
-        "business_intro",
-        "business_location",
-        "business_opening_hours",
-        "can_send_paid_media",
-        "can_set_sticker_set",
-        "custom_emoji_sticker_set_name",
-        "description",
-        "emoji_status_custom_emoji_id",
-        "emoji_status_expiration_date",
-        "has_aggressive_anti_spam_enabled",
-        "has_hidden_members",
-        "has_private_forwards",
-        "has_protected_content",
-        "has_restricted_voice_and_video_messages",
-        "has_visible_history",
-        "invite_link",
-        "join_by_request",
-        "join_to_send_messages",
-        "linked_chat_id",
-        "location",
-        "max_reaction_count",
-        "message_auto_delete_time",
-        "permissions",
-        "personal_chat",
-        "photo",
-        "pinned_message",
-        "profile_accent_color_id",
-        "profile_background_custom_emoji_id",
-        "slow_mode_delay",
-        "sticker_set_name",
-        "unrestrict_boost_count",
-    )
-
-    def __init__(
-        self,
-        id: int,
-        type: str,
-        accent_color_id: int,
-        max_reaction_count: int,
-        title: Optional[str] = None,
-        username: Optional[str] = None,
-        first_name: Optional[str] = None,
-        last_name: Optional[str] = None,
-        is_forum: Optional[bool] = None,
-        photo: Optional[ChatPhoto] = None,
-        active_usernames: Optional[Sequence[str]] = None,
-        birthdate: Optional[Birthdate] = None,
-        business_intro: Optional["BusinessIntro"] = None,
-        business_location: Optional["BusinessLocation"] = None,
-        business_opening_hours: Optional["BusinessOpeningHours"] = None,
-        personal_chat: Optional["Chat"] = None,
-        available_reactions: Optional[Sequence[ReactionType]] = None,
-        background_custom_emoji_id: Optional[str] = None,
-        profile_accent_color_id: Optional[int] = None,
-        profile_background_custom_emoji_id: Optional[str] = None,
-        emoji_status_custom_emoji_id: Optional[str] = None,
-        emoji_status_expiration_date: Optional[dtm.datetime] = None,
-        bio: Optional[str] = None,
-        has_private_forwards: Optional[bool] = None,
-        has_restricted_voice_and_video_messages: Optional[bool] = None,
-        join_to_send_messages: Optional[bool] = None,
-        join_by_request: Optional[bool] = None,
-        description: Optional[str] = None,
-        invite_link: Optional[str] = None,
-        pinned_message: Optional["Message"] = None,
-        permissions: Optional[ChatPermissions] = None,
-        slow_mode_delay: Optional[int] = None,
-        unrestrict_boost_count: Optional[int] = None,
-        message_auto_delete_time: Optional[int] = None,
-        has_aggressive_anti_spam_enabled: Optional[bool] = None,
-        has_hidden_members: Optional[bool] = None,
-        has_protected_content: Optional[bool] = None,
-        has_visible_history: Optional[bool] = None,
-        sticker_set_name: Optional[str] = None,
-        can_set_sticker_set: Optional[bool] = None,
-        custom_emoji_sticker_set_name: Optional[str] = None,
-        linked_chat_id: Optional[int] = None,
-        location: Optional[ChatLocation] = None,
-        can_send_paid_media: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(
-            id=id,
-            type=type,
-            title=title,
-            username=username,
-            first_name=first_name,
-            last_name=last_name,
-            is_forum=is_forum,
-            api_kwargs=api_kwargs,
-        )
-
-        # Required and unique to this class-
-        with self._unfrozen():
-            self.max_reaction_count: int = max_reaction_count
-            self.photo: Optional[ChatPhoto] = photo
-            self.bio: Optional[str] = bio
-            self.has_private_forwards: Optional[bool] = has_private_forwards
-            self.description: Optional[str] = description
-            self.invite_link: Optional[str] = invite_link
-            self.pinned_message: Optional[Message] = pinned_message
-            self.permissions: Optional[ChatPermissions] = permissions
-            self.slow_mode_delay: Optional[int] = slow_mode_delay
-            self.message_auto_delete_time: Optional[int] = (
-                int(message_auto_delete_time) if message_auto_delete_time is not None else None
-            )
-            self.has_protected_content: Optional[bool] = has_protected_content
-            self.has_visible_history: Optional[bool] = has_visible_history
-            self.sticker_set_name: Optional[str] = sticker_set_name
-            self.can_set_sticker_set: Optional[bool] = can_set_sticker_set
-            self.linked_chat_id: Optional[int] = linked_chat_id
-            self.location: Optional[ChatLocation] = location
-            self.join_to_send_messages: Optional[bool] = join_to_send_messages
-            self.join_by_request: Optional[bool] = join_by_request
-            self.has_restricted_voice_and_video_messages: Optional[bool] = (
-                has_restricted_voice_and_video_messages
-            )
-            self.active_usernames: tuple[str, ...] = parse_sequence_arg(active_usernames)
-            self.emoji_status_custom_emoji_id: Optional[str] = emoji_status_custom_emoji_id
-            self.emoji_status_expiration_date: Optional[dtm.datetime] = (
-                emoji_status_expiration_date
-            )
-            self.has_aggressive_anti_spam_enabled: Optional[bool] = (
-                has_aggressive_anti_spam_enabled
-            )
-            self.has_hidden_members: Optional[bool] = has_hidden_members
-            self.available_reactions: Optional[tuple[ReactionType, ...]] = parse_sequence_arg(
-                available_reactions
-            )
-            self.accent_color_id: Optional[int] = accent_color_id
-            self.background_custom_emoji_id: Optional[str] = background_custom_emoji_id
-            self.profile_accent_color_id: Optional[int] = profile_accent_color_id
-            self.profile_background_custom_emoji_id: Optional[str] = (
-                profile_background_custom_emoji_id
-            )
-            self.unrestrict_boost_count: Optional[int] = unrestrict_boost_count
-            self.custom_emoji_sticker_set_name: Optional[str] = custom_emoji_sticker_set_name
-            self.birthdate: Optional[Birthdate] = birthdate
-            self.personal_chat: Optional[Chat] = personal_chat
-            self.business_intro: Optional[BusinessIntro] = business_intro
-            self.business_location: Optional[BusinessLocation] = business_location
-            self.business_opening_hours: Optional[BusinessOpeningHours] = business_opening_hours
-            self.can_send_paid_media: Optional[bool] = can_send_paid_media
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["ChatFullInfo"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        # Get the local timezone from the bot if it has defaults
-        loc_tzinfo = extract_tzinfo_from_defaults(bot)
-
-        data["emoji_status_expiration_date"] = from_timestamp(
-            data.get("emoji_status_expiration_date"), tzinfo=loc_tzinfo
-        )
-
-        data["photo"] = ChatPhoto.de_json(data.get("photo"), bot)
-
-        from telegram import (  # pylint: disable=import-outside-toplevel
-            BusinessIntro,
-            BusinessLocation,
-            BusinessOpeningHours,
-            Message,
-        )
-
-        data["pinned_message"] = Message.de_json(data.get("pinned_message"), bot)
-        data["permissions"] = ChatPermissions.de_json(data.get("permissions"), bot)
-        data["location"] = ChatLocation.de_json(data.get("location"), bot)
-        data["available_reactions"] = ReactionType.de_list(data.get("available_reactions"), bot)
-        data["birthdate"] = Birthdate.de_json(data.get("birthdate"), bot)
-        data["personal_chat"] = Chat.de_json(data.get("personal_chat"), bot)
-        data["business_intro"] = BusinessIntro.de_json(data.get("business_intro"), bot)
-        data["business_location"] = BusinessLocation.de_json(data.get("business_location"), bot)
-        data["business_opening_hours"] = BusinessOpeningHours.de_json(
-            data.get("business_opening_hours"), bot
-        )
-
-        return super().de_json(data=data, bot=bot)
diff --git a/venv/lib/python3.11/site-packages/telegram/_chatinvitelink.py b/venv/lib/python3.11/site-packages/telegram/_chatinvitelink.py
deleted file mode 100755
index b806724..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_chatinvitelink.py
+++ /dev/null
@@ -1,195 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents an invite link for a chat."""
-import datetime as dtm
-from typing import TYPE_CHECKING, Optional
-
-from telegram._telegramobject import TelegramObject
-from telegram._user import User
-from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
-from telegram._utils.types import JSONDict
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class ChatInviteLink(TelegramObject):
-    """This object represents an invite link for a chat.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`invite_link`, :attr:`creator`, :attr:`creates_join_request`,
-    :attr:`is_primary` and :attr:`is_revoked` are equal.
-
-    .. versionadded:: 13.4
-    .. versionchanged:: 20.0
-
-       * The argument & attribute :attr:`creates_join_request` is now required to comply with the
-         Bot API.
-       * Comparing objects of this class now also takes :attr:`creates_join_request` into account.
-
-    Args:
-        invite_link (:obj:`str`): The invite link.
-        creator (:class:`telegram.User`): Creator of the link.
-        creates_join_request (:obj:`bool`): :obj:`True`, if users joining the chat via
-            the link need to be approved by chat administrators.
-
-            .. versionadded:: 13.8
-        is_primary (:obj:`bool`): :obj:`True`, if the link is primary.
-        is_revoked (:obj:`bool`): :obj:`True`, if the link is revoked.
-        expire_date (:class:`datetime.datetime`, optional): Date when the link will expire or
-            has been expired.
-
-            .. versionchanged:: 20.3
-                |datetime_localization|
-        member_limit (:obj:`int`, optional): Maximum number of users that can be members of the
-            chat simultaneously after joining the chat via this invite link;
-            :tg-const:`telegram.constants.ChatInviteLinkLimit.MIN_MEMBER_LIMIT`-
-            :tg-const:`telegram.constants.ChatInviteLinkLimit.MAX_MEMBER_LIMIT`.
-        name (:obj:`str`, optional): Invite link name.
-            0-:tg-const:`telegram.constants.ChatInviteLinkLimit.NAME_LENGTH` characters.
-
-            .. versionadded:: 13.8
-        pending_join_request_count (:obj:`int`, optional): Number of pending join requests
-            created using this link.
-
-            .. versionadded:: 13.8
-        subscription_period (:obj:`int`, optional): The number of seconds the subscription will be
-            active for before the next payment.
-
-            .. versionadded:: 21.5
-        subscription_price (:obj:`int`, optional): The amount of Telegram Stars a user must pay
-            initially and after each subsequent subscription period to be a member of the chat
-            using the link.
-
-            .. versionadded:: 21.5
-
-    Attributes:
-        invite_link (:obj:`str`): The invite link. If the link was created by another chat
-            administrator, then the second part of the link will be replaced with ``'…'``.
-        creator (:class:`telegram.User`): Creator of the link.
-        creates_join_request (:obj:`bool`): :obj:`True`, if users joining the chat via
-            the link need to be approved by chat administrators.
-
-            .. versionadded:: 13.8
-        is_primary (:obj:`bool`): :obj:`True`, if the link is primary.
-        is_revoked (:obj:`bool`): :obj:`True`, if the link is revoked.
-        expire_date (:class:`datetime.datetime`): Optional. Date when the link will expire or
-            has been expired.
-
-            .. versionchanged:: 20.3
-                |datetime_localization|
-        member_limit (:obj:`int`): Optional. Maximum number of users that can be members
-            of the chat simultaneously after joining the chat via this invite link;
-            :tg-const:`telegram.constants.ChatInviteLinkLimit.MIN_MEMBER_LIMIT`-
-            :tg-const:`telegram.constants.ChatInviteLinkLimit.MAX_MEMBER_LIMIT`.
-        name (:obj:`str`): Optional. Invite link name.
-            0-:tg-const:`telegram.constants.ChatInviteLinkLimit.NAME_LENGTH` characters.
-
-            .. versionadded:: 13.8
-        pending_join_request_count (:obj:`int`): Optional. Number of pending join requests
-            created using this link.
-
-            .. versionadded:: 13.8
-        subscription_period (:obj:`int`): Optional. The number of seconds the subscription will be
-            active for before the next payment.
-
-            .. versionadded:: 21.5
-        subscription_price (:obj:`int`): Optional. The amount of Telegram Stars a user must pay
-            initially and after each subsequent subscription period to be a member of the chat
-            using the link.
-
-            .. versionadded:: 21.5
-
-    """
-
-    __slots__ = (
-        "creates_join_request",
-        "creator",
-        "expire_date",
-        "invite_link",
-        "is_primary",
-        "is_revoked",
-        "member_limit",
-        "name",
-        "pending_join_request_count",
-        "subscription_period",
-        "subscription_price",
-    )
-
-    def __init__(
-        self,
-        invite_link: str,
-        creator: User,
-        creates_join_request: bool,
-        is_primary: bool,
-        is_revoked: bool,
-        expire_date: Optional[dtm.datetime] = None,
-        member_limit: Optional[int] = None,
-        name: Optional[str] = None,
-        pending_join_request_count: Optional[int] = None,
-        subscription_period: Optional[int] = None,
-        subscription_price: Optional[int] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        # Required
-        self.invite_link: str = invite_link
-        self.creator: User = creator
-        self.creates_join_request: bool = creates_join_request
-        self.is_primary: bool = is_primary
-        self.is_revoked: bool = is_revoked
-
-        # Optionals
-        self.expire_date: Optional[dtm.datetime] = expire_date
-        self.member_limit: Optional[int] = member_limit
-        self.name: Optional[str] = name
-        self.pending_join_request_count: Optional[int] = (
-            int(pending_join_request_count) if pending_join_request_count is not None else None
-        )
-        self.subscription_period: Optional[int] = subscription_period
-        self.subscription_price: Optional[int] = subscription_price
-
-        self._id_attrs = (
-            self.invite_link,
-            self.creates_join_request,
-            self.creator,
-            self.is_primary,
-            self.is_revoked,
-        )
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["ChatInviteLink"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        # Get the local timezone from the bot if it has defaults
-        loc_tzinfo = extract_tzinfo_from_defaults(bot)
-
-        data["creator"] = User.de_json(data.get("creator"), bot)
-        data["expire_date"] = from_timestamp(data.get("expire_date", None), tzinfo=loc_tzinfo)
-
-        return super().de_json(data=data, bot=bot)
diff --git a/venv/lib/python3.11/site-packages/telegram/_chatjoinrequest.py b/venv/lib/python3.11/site-packages/telegram/_chatjoinrequest.py
deleted file mode 100755
index 8730552..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_chatjoinrequest.py
+++ /dev/null
@@ -1,213 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram ChatJoinRequest."""
-import datetime as dtm
-from typing import TYPE_CHECKING, Optional
-
-from telegram._chat import Chat
-from telegram._chatinvitelink import ChatInviteLink
-from telegram._telegramobject import TelegramObject
-from telegram._user import User
-from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.types import JSONDict, ODVInput
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class ChatJoinRequest(TelegramObject):
-    """This object represents a join request sent to a chat.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`chat`, :attr:`from_user` and :attr:`date` are equal.
-
-    Note:
-        * Since Bot API 5.5, bots are allowed to contact users who sent a join request to a chat
-          where the bot is an administrator with the
-          :attr:`~telegram.ChatMemberAdministrator.can_invite_users` administrator right - even
-          if the user never interacted with the bot before.
-        * Telegram does not guarantee that :attr:`from_user.id ` coincides with the
-          ``chat_id`` of the user. Please use :attr:`user_chat_id` to contact the user in
-          response to their join request.
-
-    .. versionadded:: 13.8
-    .. versionchanged:: 20.1
-       In Bot API 6.5 the argument :paramref:`user_chat_id` was added, which changes the position
-       of the optional arguments :paramref:`bio` and :paramref:`invite_link`.
-
-    Args:
-        chat (:class:`telegram.Chat`): Chat to which the request was sent.
-        from_user (:class:`telegram.User`): User that sent the join request.
-        date (:class:`datetime.datetime`): Date the request was sent.
-
-            .. versionchanged:: 20.3
-                |datetime_localization|
-        user_chat_id (:obj:`int`): Identifier of a private chat with the user who sent the join
-            request. This number may have more than 32 significant bits and some programming
-            languages may have difficulty/silent defects in interpreting it. But it has at most 52
-            significant bits, so a 64-bit integer or double-precision float type are safe for
-            storing this identifier. The bot can use this identifier for 5 minutes to send messages
-            until the join request is processed, assuming no other administrator contacted the
-            user.
-
-            .. versionadded:: 20.1
-        bio (:obj:`str`, optional): Bio of the user.
-        invite_link (:class:`telegram.ChatInviteLink`, optional): Chat invite link that was used
-            by the user to send the join request.
-
-    Attributes:
-        chat (:class:`telegram.Chat`): Chat to which the request was sent.
-        from_user (:class:`telegram.User`): User that sent the join request.
-        date (:class:`datetime.datetime`): Date the request was sent.
-
-            .. versionchanged:: 20.3
-                |datetime_localization|
-        user_chat_id (:obj:`int`): Identifier of a private chat with the user who sent the join
-            request. This number may have more than 32 significant bits and some programming
-            languages may have difficulty/silent defects in interpreting it. But it has at most 52
-            significant bits, so a 64-bit integer or double-precision float type are safe for
-            storing this identifier. The bot can use this identifier for 24 hours to send messages
-            until the join request is processed, assuming no other administrator contacted the
-            user.
-
-            .. versionadded:: 20.1
-        bio (:obj:`str`): Optional. Bio of the user.
-        invite_link (:class:`telegram.ChatInviteLink`): Optional. Chat invite link that was used
-            by the user to send the join request.
-
-            Note:
-                When a user joins a *public* group via an invite link, this attribute may not
-                be present. However, this behavior is undocument and may be subject to change.
-                See `this GitHub thread `_
-                for some discussion.
-
-    """
-
-    __slots__ = ("bio", "chat", "date", "from_user", "invite_link", "user_chat_id")
-
-    def __init__(
-        self,
-        chat: Chat,
-        from_user: User,
-        date: dtm.datetime,
-        user_chat_id: int,
-        bio: Optional[str] = None,
-        invite_link: Optional[ChatInviteLink] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        # Required
-        self.chat: Chat = chat
-        self.from_user: User = from_user
-        self.date: dtm.datetime = date
-        self.user_chat_id: int = user_chat_id
-
-        # Optionals
-        self.bio: Optional[str] = bio
-        self.invite_link: Optional[ChatInviteLink] = invite_link
-
-        self._id_attrs = (self.chat, self.from_user, self.date)
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["ChatJoinRequest"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        # Get the local timezone from the bot if it has defaults
-        loc_tzinfo = extract_tzinfo_from_defaults(bot)
-
-        data["chat"] = Chat.de_json(data.get("chat"), bot)
-        data["from_user"] = User.de_json(data.pop("from", None), bot)
-        data["date"] = from_timestamp(data.get("date", None), tzinfo=loc_tzinfo)
-        data["invite_link"] = ChatInviteLink.de_json(data.get("invite_link"), bot)
-
-        return super().de_json(data=data, bot=bot)
-
-    async def approve(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-            await bot.approve_chat_join_request(
-                chat_id=update.effective_chat.id, user_id=update.effective_user.id, *args, **kwargs
-            )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.approve_chat_join_request`.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().approve_chat_join_request(
-            chat_id=self.chat.id,
-            user_id=self.from_user.id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def decline(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-            await bot.decline_chat_join_request(
-                chat_id=update.effective_chat.id, user_id=update.effective_user.id, *args, **kwargs
-            )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.decline_chat_join_request`.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().decline_chat_join_request(
-            chat_id=self.chat.id,
-            user_id=self.from_user.id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
diff --git a/venv/lib/python3.11/site-packages/telegram/_chatlocation.py b/venv/lib/python3.11/site-packages/telegram/_chatlocation.py
deleted file mode 100755
index 7e22722..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_chatlocation.py
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a location to which a chat is connected."""
-
-from typing import TYPE_CHECKING, Final, Optional
-
-from telegram import constants
-from telegram._files.location import Location
-from telegram._telegramobject import TelegramObject
-from telegram._utils.types import JSONDict
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class ChatLocation(TelegramObject):
-    """This object represents a location to which a chat is connected.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`location` is equal.
-
-    Args:
-        location (:class:`telegram.Location`): The location to which the supergroup is connected.
-            Can't be a live location.
-        address (:obj:`str`): Location address;
-            :tg-const:`telegram.ChatLocation.MIN_ADDRESS`-
-            :tg-const:`telegram.ChatLocation.MAX_ADDRESS` characters, as defined by the chat owner.
-    Attributes:
-        location (:class:`telegram.Location`): The location to which the supergroup is connected.
-            Can't be a live location.
-        address (:obj:`str`): Location address;
-            :tg-const:`telegram.ChatLocation.MIN_ADDRESS`-
-            :tg-const:`telegram.ChatLocation.MAX_ADDRESS` characters, as defined by the chat owner.
-
-    """
-
-    __slots__ = ("address", "location")
-
-    def __init__(
-        self,
-        location: Location,
-        address: str,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.location: Location = location
-        self.address: str = address
-
-        self._id_attrs = (self.location,)
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["ChatLocation"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        data["location"] = Location.de_json(data.get("location"), bot)
-
-        return super().de_json(data=data, bot=bot)
-
-    MIN_ADDRESS: Final[int] = constants.LocationLimit.MIN_CHAT_LOCATION_ADDRESS
-    """:const:`telegram.constants.LocationLimit.MIN_CHAT_LOCATION_ADDRESS`
-
-    .. versionadded:: 20.0
-    """
-    MAX_ADDRESS: Final[int] = constants.LocationLimit.MAX_CHAT_LOCATION_ADDRESS
-    """:const:`telegram.constants.LocationLimit.MAX_CHAT_LOCATION_ADDRESS`
-
-    .. versionadded:: 20.0
-    """
diff --git a/venv/lib/python3.11/site-packages/telegram/_chatmember.py b/venv/lib/python3.11/site-packages/telegram/_chatmember.py
deleted file mode 100755
index 85fd2e9..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_chatmember.py
+++ /dev/null
@@ -1,665 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram ChatMember."""
-
-import datetime as dtm
-from typing import TYPE_CHECKING, Final, Optional
-
-from telegram import constants
-from telegram._telegramobject import TelegramObject
-from telegram._user import User
-from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
-from telegram._utils.types import JSONDict
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class ChatMember(TelegramObject):
-    """Base class for Telegram ChatMember Objects.
-    Currently, the following 6 types of chat members are supported:
-
-    * :class:`telegram.ChatMemberOwner`
-    * :class:`telegram.ChatMemberAdministrator`
-    * :class:`telegram.ChatMemberMember`
-    * :class:`telegram.ChatMemberRestricted`
-    * :class:`telegram.ChatMemberLeft`
-    * :class:`telegram.ChatMemberBanned`
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`user` and :attr:`status` are equal.
-
-    Examples:
-        :any:`Chat Member Bot `
-
-    .. versionchanged:: 20.0
-
-        * As of Bot API 5.3, :class:`ChatMember` is nothing but the base class for the subclasses
-          listed above and is no longer returned directly by :meth:`~telegram.Bot.get_chat`.
-          Therefore, most of the arguments and attributes were removed and you should no longer
-          use :class:`ChatMember` directly.
-        * The constant ``ChatMember.CREATOR`` was replaced by :attr:`~telegram.ChatMember.OWNER`
-        * The constant ``ChatMember.KICKED`` was replaced by :attr:`~telegram.ChatMember.BANNED`
-
-    Args:
-        user (:class:`telegram.User`): Information about the user.
-        status (:obj:`str`): The member's status in the chat. Can be
-            :attr:`~telegram.ChatMember.ADMINISTRATOR`, :attr:`~telegram.ChatMember.OWNER`,
-            :attr:`~telegram.ChatMember.BANNED`, :attr:`~telegram.ChatMember.LEFT`,
-            :attr:`~telegram.ChatMember.MEMBER` or :attr:`~telegram.ChatMember.RESTRICTED`.
-
-    Attributes:
-        user (:class:`telegram.User`): Information about the user.
-        status (:obj:`str`): The member's status in the chat. Can be
-            :attr:`~telegram.ChatMember.ADMINISTRATOR`, :attr:`~telegram.ChatMember.OWNER`,
-            :attr:`~telegram.ChatMember.BANNED`, :attr:`~telegram.ChatMember.LEFT`,
-            :attr:`~telegram.ChatMember.MEMBER` or :attr:`~telegram.ChatMember.RESTRICTED`.
-
-    """
-
-    __slots__ = ("status", "user")
-
-    ADMINISTRATOR: Final[str] = constants.ChatMemberStatus.ADMINISTRATOR
-    """:const:`telegram.constants.ChatMemberStatus.ADMINISTRATOR`"""
-    OWNER: Final[str] = constants.ChatMemberStatus.OWNER
-    """:const:`telegram.constants.ChatMemberStatus.OWNER`"""
-    BANNED: Final[str] = constants.ChatMemberStatus.BANNED
-    """:const:`telegram.constants.ChatMemberStatus.BANNED`"""
-    LEFT: Final[str] = constants.ChatMemberStatus.LEFT
-    """:const:`telegram.constants.ChatMemberStatus.LEFT`"""
-    MEMBER: Final[str] = constants.ChatMemberStatus.MEMBER
-    """:const:`telegram.constants.ChatMemberStatus.MEMBER`"""
-    RESTRICTED: Final[str] = constants.ChatMemberStatus.RESTRICTED
-    """:const:`telegram.constants.ChatMemberStatus.RESTRICTED`"""
-
-    def __init__(
-        self,
-        user: User,
-        status: str,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        # Required by all subclasses
-        self.user: User = user
-        self.status: str = status
-
-        self._id_attrs = (self.user, self.status)
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["ChatMember"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        _class_mapping: dict[str, type[ChatMember]] = {
-            cls.OWNER: ChatMemberOwner,
-            cls.ADMINISTRATOR: ChatMemberAdministrator,
-            cls.MEMBER: ChatMemberMember,
-            cls.RESTRICTED: ChatMemberRestricted,
-            cls.LEFT: ChatMemberLeft,
-            cls.BANNED: ChatMemberBanned,
-        }
-
-        if cls is ChatMember and data.get("status") in _class_mapping:
-            return _class_mapping[data.pop("status")].de_json(data=data, bot=bot)
-
-        data["user"] = User.de_json(data.get("user"), bot)
-        if "until_date" in data:
-            # Get the local timezone from the bot if it has defaults
-            loc_tzinfo = extract_tzinfo_from_defaults(bot)
-
-            data["until_date"] = from_timestamp(data["until_date"], tzinfo=loc_tzinfo)
-
-        # This is a deprecated field that TG still returns for backwards compatibility
-        # Let's filter it out to speed up the de-json process
-        if cls is ChatMemberRestricted and data.get("can_send_media_messages") is not None:
-            api_kwargs = {"can_send_media_messages": data.pop("can_send_media_messages")}
-            return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs)
-
-        return super().de_json(data=data, bot=bot)
-
-
-class ChatMemberOwner(ChatMember):
-    """
-    Represents a chat member that owns the chat
-    and has all administrator privileges.
-
-    .. versionadded:: 13.7
-
-    Args:
-        user (:class:`telegram.User`): Information about the user.
-        is_anonymous (:obj:`bool`): :obj:`True`, if the
-            user's presence in the chat is hidden.
-        custom_title (:obj:`str`, optional): Custom title for this user.
-
-    Attributes:
-        status (:obj:`str`): The member's status in the chat,
-            always :tg-const:`telegram.ChatMember.OWNER`.
-        user (:class:`telegram.User`): Information about the user.
-        is_anonymous (:obj:`bool`): :obj:`True`, if the user's
-            presence in the chat is hidden.
-        custom_title (:obj:`str`): Optional. Custom title for
-            this user.
-    """
-
-    __slots__ = ("custom_title", "is_anonymous")
-
-    def __init__(
-        self,
-        user: User,
-        is_anonymous: bool,
-        custom_title: Optional[str] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(status=ChatMember.OWNER, user=user, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.is_anonymous: bool = is_anonymous
-            self.custom_title: Optional[str] = custom_title
-
-
-class ChatMemberAdministrator(ChatMember):
-    """
-    Represents a chat member that has some additional privileges.
-
-    .. versionadded:: 13.7
-    .. versionchanged:: 20.0
-
-       * Argument and attribute ``can_manage_voice_chats`` were renamed to
-         :paramref:`can_manage_video_chats` and  :attr:`can_manage_video_chats` in accordance to
-         Bot API 6.0.
-       * The argument :paramref:`can_manage_topics` was added, which changes the position of the
-         optional argument :paramref:`custom_title`.
-
-    .. versionchanged:: 21.1
-        As of this version, :attr:`can_post_stories`, :attr:`can_edit_stories`,
-        and :attr:`can_delete_stories` is now required. Thus, the order of arguments had to be
-        changed.
-
-    Args:
-        user (:class:`telegram.User`): Information about the user.
-        can_be_edited (:obj:`bool`): :obj:`True`, if the bot
-            is allowed to edit administrator privileges of that user.
-        is_anonymous (:obj:`bool`): :obj:`True`, if the  user's
-            presence in the chat is hidden.
-        can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator can access the chat event
-            log, get boost list, see hidden supergroup and channel members, report spam messages
-            and ignore slow mode. Implied by any other administrator privilege.
-        can_delete_messages (:obj:`bool`): :obj:`True`, if the
-            administrator can delete messages of other users.
-        can_manage_video_chats (:obj:`bool`): :obj:`True`, if the
-            administrator can manage video chats.
-
-            .. versionadded:: 20.0
-        can_restrict_members (:obj:`bool`): :obj:`True`, if the
-            administrator can restrict, ban or unban chat members.
-        can_promote_members (:obj:`bool`): :obj:`True`, if the administrator
-            can add new administrators with a subset of his own privileges or demote
-            administrators that he has promoted, directly or indirectly (promoted by
-            administrators that were appointed by the user).
-        can_change_info (:obj:`bool`): :obj:`True`, if the user can change
-            the chat title, photo and other settings.
-        can_invite_users (:obj:`bool`): :obj:`True`, if the user can invite
-            new users to the chat.
-        can_post_messages (:obj:`bool`, optional): :obj:`True`, if the
-            administrator can post messages in the channel, or access channel statistics;
-            for channels only.
-        can_edit_messages (:obj:`bool`, optional): :obj:`True`, if the
-            administrator can edit messages of other users and can pin
-            messages; for channels only.
-        can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed
-            to pin messages; for groups and supergroups only.
-        can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post
-            stories to the chat.
-
-            .. versionadded:: 20.6
-            .. versionchanged:: 21.0
-                |non_optional_story_argument|
-        can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted
-            by other users, post stories to the chat page, pin chat stories, and access the chat's
-            story archive
-
-            .. versionadded:: 20.6
-            .. versionchanged:: 21.0
-                |non_optional_story_argument|
-        can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete
-            stories posted by other users.
-
-            .. versionadded:: 20.6
-            .. versionchanged:: 21.0
-                |non_optional_story_argument|
-        can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed
-            to create, rename, close, and reopen forum topics; for supergroups only.
-
-            .. versionadded:: 20.0
-        custom_title (:obj:`str`, optional): Custom title for this user.
-
-    Attributes:
-        status (:obj:`str`): The member's status in the chat,
-            always :tg-const:`telegram.ChatMember.ADMINISTRATOR`.
-        user (:class:`telegram.User`): Information about the user.
-        can_be_edited (:obj:`bool`): :obj:`True`, if the bot
-            is allowed to edit administrator privileges of that user.
-        is_anonymous (:obj:`bool`): :obj:`True`, if the  user's
-            presence in the chat is hidden.
-        can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator can access the chat event
-            log, get boost list, see hidden supergroup and channel members, report spam messages
-            and ignore slow mode. Implied by any other administrator privilege.
-        can_delete_messages (:obj:`bool`): :obj:`True`, if the
-            administrator can delete messages of other users.
-        can_manage_video_chats (:obj:`bool`): :obj:`True`, if the
-            administrator can manage video chats.
-
-            .. versionadded:: 20.0
-        can_restrict_members (:obj:`bool`): :obj:`True`, if the
-            administrator can restrict, ban or unban chat members, or access supergroup statistics.
-        can_promote_members (:obj:`bool`): :obj:`True`, if the administrator can add new
-            administrators with a subset of their own privileges or demote administrators
-            that they have promoted, directly or indirectly (promoted by administrators that
-            were appointed by the user).
-        can_change_info (:obj:`bool`): :obj:`True`, if the user can change
-            the chat title, photo and other settings.
-        can_invite_users (:obj:`bool`): :obj:`True`, if the user can invite
-            new users to the chat.
-        can_post_messages (:obj:`bool`): Optional. :obj:`True`, if the
-            administrator can post messages in the channel or access channel statistics;
-            for channels only.
-        can_edit_messages (:obj:`bool`): Optional. :obj:`True`, if the
-            administrator can edit messages of other users and can pin
-            messages; for channels only.
-        can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed
-            to pin messages; for groups and supergroups only.
-        can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post
-            stories to the chat.
-
-            .. versionadded:: 20.6
-            .. versionchanged:: 21.0
-                |non_optional_story_argument|
-        can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted
-            by other users, post stories to the chat page, pin chat stories, and access the chat's
-            story archive
-
-            .. versionadded:: 20.6
-            .. versionchanged:: 21.0
-                |non_optional_story_argument|
-        can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete
-            stories posted by other users.
-
-            .. versionadded:: 20.6
-            .. versionchanged:: 21.0
-                |non_optional_story_argument|
-        can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed
-            to create, rename, close, and reopen forum topics; for supergroups only
-
-            .. versionadded:: 20.0
-        custom_title (:obj:`str`): Optional. Custom title for this user.
-    """
-
-    __slots__ = (
-        "can_be_edited",
-        "can_change_info",
-        "can_delete_messages",
-        "can_delete_stories",
-        "can_edit_messages",
-        "can_edit_stories",
-        "can_invite_users",
-        "can_manage_chat",
-        "can_manage_topics",
-        "can_manage_video_chats",
-        "can_pin_messages",
-        "can_post_messages",
-        "can_post_stories",
-        "can_promote_members",
-        "can_restrict_members",
-        "custom_title",
-        "is_anonymous",
-    )
-
-    def __init__(
-        self,
-        user: User,
-        can_be_edited: bool,
-        is_anonymous: bool,
-        can_manage_chat: bool,
-        can_delete_messages: bool,
-        can_manage_video_chats: bool,
-        can_restrict_members: bool,
-        can_promote_members: bool,
-        can_change_info: bool,
-        can_invite_users: bool,
-        can_post_stories: bool,
-        can_edit_stories: bool,
-        can_delete_stories: bool,
-        can_post_messages: Optional[bool] = None,
-        can_edit_messages: Optional[bool] = None,
-        can_pin_messages: Optional[bool] = None,
-        can_manage_topics: Optional[bool] = None,
-        custom_title: Optional[str] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(status=ChatMember.ADMINISTRATOR, user=user, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.can_be_edited: bool = can_be_edited
-            self.is_anonymous: bool = is_anonymous
-            self.can_manage_chat: bool = can_manage_chat
-            self.can_delete_messages: bool = can_delete_messages
-            self.can_manage_video_chats: bool = can_manage_video_chats
-            self.can_restrict_members: bool = can_restrict_members
-            self.can_promote_members: bool = can_promote_members
-            self.can_change_info: bool = can_change_info
-            self.can_invite_users: bool = can_invite_users
-            self.can_post_stories: bool = can_post_stories
-            self.can_edit_stories: bool = can_edit_stories
-            self.can_delete_stories: bool = can_delete_stories
-            # Optionals
-            self.can_post_messages: Optional[bool] = can_post_messages
-            self.can_edit_messages: Optional[bool] = can_edit_messages
-            self.can_pin_messages: Optional[bool] = can_pin_messages
-            self.can_manage_topics: Optional[bool] = can_manage_topics
-            self.custom_title: Optional[str] = custom_title
-
-
-class ChatMemberMember(ChatMember):
-    """
-    Represents a chat member that has no additional
-    privileges or restrictions.
-
-    .. versionadded:: 13.7
-
-    Args:
-        user (:class:`telegram.User`): Information about the user.
-        until_date (:class:`datetime.datetime`, optional): Date when the user's subscription will
-            expire.
-
-            .. versionadded:: 21.5
-
-    Attributes:
-        status (:obj:`str`): The member's status in the chat,
-            always :tg-const:`telegram.ChatMember.MEMBER`.
-        user (:class:`telegram.User`): Information about the user.
-        until_date (:class:`datetime.datetime`): Optional. Date when the user's subscription will
-            expire.
-
-            .. versionadded:: 21.5
-
-    """
-
-    __slots__ = ("until_date",)
-
-    def __init__(
-        self,
-        user: User,
-        until_date: Optional[dtm.datetime] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(status=ChatMember.MEMBER, user=user, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.until_date: Optional[dtm.datetime] = until_date
-
-
-class ChatMemberRestricted(ChatMember):
-    """
-    Represents a chat member that is under certain restrictions
-    in the chat. Supergroups only.
-
-    .. versionadded:: 13.7
-    .. versionchanged:: 20.0
-       All arguments were made positional and their order was changed.
-       The argument can_manage_topics was added.
-
-    .. versionchanged:: 20.5
-      Removed deprecated argument and attribute ``can_send_media_messages``.
-
-    Args:
-        user (:class:`telegram.User`): Information about the user.
-        is_member (:obj:`bool`): :obj:`True`, if the user is a
-            member of the chat at the moment of the request.
-        can_change_info (:obj:`bool`): :obj:`True`, if the user can change
-            the chat title, photo and other settings.
-        can_invite_users (:obj:`bool`): :obj:`True`, if the user can invite
-            new users to the chat.
-        can_pin_messages (:obj:`bool`): :obj:`True`, if the user is allowed
-            to pin messages; groups and supergroups only.
-        can_send_messages (:obj:`bool`): :obj:`True`, if the user is allowed
-            to send text messages, contacts, invoices, locations and venues.
-        can_send_polls (:obj:`bool`): :obj:`True`, if the user is allowed
-            to send polls.
-        can_send_other_messages (:obj:`bool`): :obj:`True`, if the user is allowed
-            to send animations, games, stickers and use inline bots.
-        can_add_web_page_previews (:obj:`bool`): :obj:`True`, if the user is
-           allowed to add web page previews to their messages.
-        can_manage_topics (:obj:`bool`): :obj:`True`, if the user is allowed to create
-            forum topics.
-
-            .. versionadded:: 20.0
-        until_date (:class:`datetime.datetime`): Date when restrictions
-           will be lifted for this user.
-
-            .. versionchanged:: 20.3
-                |datetime_localization|
-        can_send_audios (:obj:`bool`): :obj:`True`, if the user is allowed to send audios.
-
-            .. versionadded:: 20.1
-        can_send_documents (:obj:`bool`): :obj:`True`, if the user is allowed to send documents.
-
-            .. versionadded:: 20.1
-        can_send_photos (:obj:`bool`): :obj:`True`, if the user is allowed to send photos.
-
-            .. versionadded:: 20.1
-        can_send_videos (:obj:`bool`): :obj:`True`, if the user is allowed to send videos.
-
-            .. versionadded:: 20.1
-        can_send_video_notes (:obj:`bool`): :obj:`True`, if the user is allowed to send video
-            notes.
-
-            .. versionadded:: 20.1
-        can_send_voice_notes (:obj:`bool`): :obj:`True`, if the user is allowed to send voice
-            notes.
-
-            .. versionadded:: 20.1
-
-    Attributes:
-        status (:obj:`str`): The member's status in the chat,
-            always :tg-const:`telegram.ChatMember.RESTRICTED`.
-        user (:class:`telegram.User`): Information about the user.
-        is_member (:obj:`bool`): :obj:`True`, if the user is a
-            member of the chat at the moment of the request.
-        can_change_info (:obj:`bool`): :obj:`True`, if the user can change
-            the chat title, photo and other settings.
-        can_invite_users (:obj:`bool`): :obj:`True`, if the user can invite
-            new users to the chat.
-        can_pin_messages (:obj:`bool`): :obj:`True`, if the user is allowed
-            to pin messages; groups and supergroups only.
-        can_send_messages (:obj:`bool`): :obj:`True`, if the user is allowed
-            to send text messages, contacts, locations and venues.
-        can_send_polls (:obj:`bool`): :obj:`True`, if the user is allowed
-            to send polls.
-        can_send_other_messages (:obj:`bool`): :obj:`True`, if the user is allowed
-            to send animations, games, stickers and use inline bots.
-        can_add_web_page_previews (:obj:`bool`): :obj:`True`, if the user is
-           allowed to add web page previews to their messages.
-        can_manage_topics (:obj:`bool`): :obj:`True`, if the user is allowed to create
-            forum topics.
-
-            .. versionadded:: 20.0
-        until_date (:class:`datetime.datetime`): Date when restrictions
-           will be lifted for this user.
-
-            .. versionchanged:: 20.3
-                |datetime_localization|
-        can_send_audios (:obj:`bool`): :obj:`True`, if the user is allowed to send audios.
-
-            .. versionadded:: 20.1
-        can_send_documents (:obj:`bool`): :obj:`True`, if the user is allowed to send documents.
-
-            .. versionadded:: 20.1
-        can_send_photos (:obj:`bool`): :obj:`True`, if the user is allowed to send photos.
-
-            .. versionadded:: 20.1
-        can_send_videos (:obj:`bool`): :obj:`True`, if the user is allowed to send videos.
-
-            .. versionadded:: 20.1
-        can_send_video_notes (:obj:`bool`): :obj:`True`, if the user is allowed to send video
-            notes.
-
-            .. versionadded:: 20.1
-        can_send_voice_notes (:obj:`bool`): :obj:`True`, if the user is allowed to send voice
-            notes.
-
-            .. versionadded:: 20.1
-
-    """
-
-    __slots__ = (
-        "can_add_web_page_previews",
-        "can_change_info",
-        "can_invite_users",
-        "can_manage_topics",
-        "can_pin_messages",
-        "can_send_audios",
-        "can_send_documents",
-        "can_send_messages",
-        "can_send_other_messages",
-        "can_send_photos",
-        "can_send_polls",
-        "can_send_video_notes",
-        "can_send_videos",
-        "can_send_voice_notes",
-        "is_member",
-        "until_date",
-    )
-
-    def __init__(
-        self,
-        user: User,
-        is_member: bool,
-        can_change_info: bool,
-        can_invite_users: bool,
-        can_pin_messages: bool,
-        can_send_messages: bool,
-        can_send_polls: bool,
-        can_send_other_messages: bool,
-        can_add_web_page_previews: bool,
-        can_manage_topics: bool,
-        until_date: dtm.datetime,
-        can_send_audios: bool,
-        can_send_documents: bool,
-        can_send_photos: bool,
-        can_send_videos: bool,
-        can_send_video_notes: bool,
-        can_send_voice_notes: bool,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(status=ChatMember.RESTRICTED, user=user, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.is_member: bool = is_member
-            self.can_change_info: bool = can_change_info
-            self.can_invite_users: bool = can_invite_users
-            self.can_pin_messages: bool = can_pin_messages
-            self.can_send_messages: bool = can_send_messages
-            self.can_send_polls: bool = can_send_polls
-            self.can_send_other_messages: bool = can_send_other_messages
-            self.can_add_web_page_previews: bool = can_add_web_page_previews
-            self.can_manage_topics: bool = can_manage_topics
-            self.until_date: dtm.datetime = until_date
-            self.can_send_audios: bool = can_send_audios
-            self.can_send_documents: bool = can_send_documents
-            self.can_send_photos: bool = can_send_photos
-            self.can_send_videos: bool = can_send_videos
-            self.can_send_video_notes: bool = can_send_video_notes
-            self.can_send_voice_notes: bool = can_send_voice_notes
-
-
-class ChatMemberLeft(ChatMember):
-    """
-    Represents a chat member that isn't currently a member of the chat,
-    but may join it themselves.
-
-    .. versionadded:: 13.7
-
-    Args:
-        user (:class:`telegram.User`): Information about the user.
-
-    Attributes:
-        status (:obj:`str`): The member's status in the chat,
-            always :tg-const:`telegram.ChatMember.LEFT`.
-        user (:class:`telegram.User`): Information about the user.
-    """
-
-    __slots__ = ()
-
-    def __init__(
-        self,
-        user: User,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(status=ChatMember.LEFT, user=user, api_kwargs=api_kwargs)
-        self._freeze()
-
-
-class ChatMemberBanned(ChatMember):
-    """
-    Represents a chat member that was banned in the chat and
-    can't return to the chat or view chat messages.
-
-    .. versionadded:: 13.7
-
-    Args:
-        user (:class:`telegram.User`): Information about the user.
-        until_date (:class:`datetime.datetime`): Date when restrictions
-           will be lifted for this user.
-
-            .. versionchanged:: 20.3
-                |datetime_localization|
-
-    Attributes:
-        status (:obj:`str`): The member's status in the chat,
-            always :tg-const:`telegram.ChatMember.BANNED`.
-        user (:class:`telegram.User`): Information about the user.
-        until_date (:class:`datetime.datetime`): Date when restrictions
-           will be lifted for this user.
-
-            .. versionchanged:: 20.3
-                |datetime_localization|
-
-    """
-
-    __slots__ = ("until_date",)
-
-    def __init__(
-        self,
-        user: User,
-        until_date: dtm.datetime,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(status=ChatMember.BANNED, user=user, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.until_date: dtm.datetime = until_date
diff --git a/venv/lib/python3.11/site-packages/telegram/_chatmemberupdated.py b/venv/lib/python3.11/site-packages/telegram/_chatmemberupdated.py
deleted file mode 100755
index ca6822f..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_chatmemberupdated.py
+++ /dev/null
@@ -1,217 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram ChatMemberUpdated."""
-import datetime as dtm
-from typing import TYPE_CHECKING, Optional, Union
-
-from telegram._chat import Chat
-from telegram._chatinvitelink import ChatInviteLink
-from telegram._chatmember import ChatMember
-from telegram._telegramobject import TelegramObject
-from telegram._user import User
-from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
-from telegram._utils.types import JSONDict
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class ChatMemberUpdated(TelegramObject):
-    """This object represents changes in the status of a chat member.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`chat`, :attr:`from_user`, :attr:`date`,
-    :attr:`old_chat_member` and :attr:`new_chat_member` are equal.
-
-    .. versionadded:: 13.4
-
-    Note:
-        In Python :keyword:`from` is a reserved word. Use :paramref:`from_user` instead.
-
-    Examples:
-        :any:`Chat Member Bot `
-
-    Args:
-        chat (:class:`telegram.Chat`): Chat the user belongs to.
-        from_user (:class:`telegram.User`): Performer of the action, which resulted in the change.
-        date (:class:`datetime.datetime`): Date the change was done in Unix time. Converted to
-            :class:`datetime.datetime`.
-
-            .. versionchanged:: 20.3
-                |datetime_localization|
-        old_chat_member (:class:`telegram.ChatMember`): Previous information about the chat member.
-        new_chat_member (:class:`telegram.ChatMember`): New information about the chat member.
-        invite_link (:class:`telegram.ChatInviteLink`, optional): Chat invite link, which was used
-            by the user to join the chat. For joining by invite link events only.
-        via_chat_folder_invite_link (:obj:`bool`, optional): :obj:`True`, if the user joined the
-            chat via a chat folder invite link
-
-            .. versionadded:: 20.3
-        via_join_request (:obj:`bool`, optional): :obj:`True`, if the user joined the chat after
-            sending a direct join request without using an invite link and being approved by
-            an administrator
-
-            .. versionadded:: 21.2
-
-    Attributes:
-        chat (:class:`telegram.Chat`): Chat the user belongs to.
-        from_user (:class:`telegram.User`): Performer of the action, which resulted in the change.
-        date (:class:`datetime.datetime`): Date the change was done in Unix time. Converted to
-            :class:`datetime.datetime`.
-
-            .. versionchanged:: 20.3
-                |datetime_localization|
-        old_chat_member (:class:`telegram.ChatMember`): Previous information about the chat member.
-        new_chat_member (:class:`telegram.ChatMember`): New information about the chat member.
-        invite_link (:class:`telegram.ChatInviteLink`): Optional. Chat invite link, which was used
-            by the user to join the chat. For joining by invite link events only.
-        via_chat_folder_invite_link (:obj:`bool`): Optional. :obj:`True`, if the user joined the
-            chat via a chat folder invite link
-
-            .. versionadded:: 20.3
-        via_join_request (:obj:`bool`): Optional. :obj:`True`, if the user joined the chat after
-            sending a direct join request without using an invite link and being approved
-            by an administrator
-
-            .. versionadded:: 21.2
-
-    """
-
-    __slots__ = (
-        "chat",
-        "date",
-        "from_user",
-        "invite_link",
-        "new_chat_member",
-        "old_chat_member",
-        "via_chat_folder_invite_link",
-        "via_join_request",
-    )
-
-    def __init__(
-        self,
-        chat: Chat,
-        from_user: User,
-        date: dtm.datetime,
-        old_chat_member: ChatMember,
-        new_chat_member: ChatMember,
-        invite_link: Optional[ChatInviteLink] = None,
-        via_chat_folder_invite_link: Optional[bool] = None,
-        via_join_request: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        # Required
-        self.chat: Chat = chat
-        self.from_user: User = from_user
-        self.date: dtm.datetime = date
-        self.old_chat_member: ChatMember = old_chat_member
-        self.new_chat_member: ChatMember = new_chat_member
-        self.via_chat_folder_invite_link: Optional[bool] = via_chat_folder_invite_link
-
-        # Optionals
-        self.invite_link: Optional[ChatInviteLink] = invite_link
-        self.via_join_request: Optional[bool] = via_join_request
-
-        self._id_attrs = (
-            self.chat,
-            self.from_user,
-            self.date,
-            self.old_chat_member,
-            self.new_chat_member,
-        )
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["ChatMemberUpdated"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        # Get the local timezone from the bot if it has defaults
-        loc_tzinfo = extract_tzinfo_from_defaults(bot)
-
-        data["chat"] = Chat.de_json(data.get("chat"), bot)
-        data["from_user"] = User.de_json(data.pop("from", None), bot)
-        data["date"] = from_timestamp(data.get("date"), tzinfo=loc_tzinfo)
-        data["old_chat_member"] = ChatMember.de_json(data.get("old_chat_member"), bot)
-        data["new_chat_member"] = ChatMember.de_json(data.get("new_chat_member"), bot)
-        data["invite_link"] = ChatInviteLink.de_json(data.get("invite_link"), bot)
-
-        return super().de_json(data=data, bot=bot)
-
-    def _get_attribute_difference(self, attribute: str) -> tuple[object, object]:
-        try:
-            old = self.old_chat_member[attribute]
-        except KeyError:
-            old = None
-
-        try:
-            new = self.new_chat_member[attribute]
-        except KeyError:
-            new = None
-
-        return old, new
-
-    def difference(
-        self,
-    ) -> dict[
-        str,
-        tuple[Union[str, bool, dtm.datetime, User], Union[str, bool, dtm.datetime, User]],
-    ]:
-        """Computes the difference between :attr:`old_chat_member` and :attr:`new_chat_member`.
-
-        Example:
-            .. code:: pycon
-
-                >>> chat_member_updated.difference()
-                {'custom_title': ('old title', 'new title')}
-
-        Note:
-            To determine, if the :attr:`telegram.ChatMember.user` attribute has changed, *every*
-            attribute of the user will be checked.
-
-        .. versionadded:: 13.5
-
-        Returns:
-            dict[:obj:`str`, tuple[:class:`object`, :class:`object`]]: A dictionary mapping
-            attribute names to tuples of the form ``(old_value, new_value)``
-        """
-        # we first get the names of the attributes that have changed
-        # user.to_dict() is unhashable, so that needs some special casing further down
-        old_dict = self.old_chat_member.to_dict()
-        old_user_dict = old_dict.pop("user")
-        new_dict = self.new_chat_member.to_dict()
-        new_user_dict = new_dict.pop("user")
-
-        # Generator for speed: we only need to iterate over it once
-        # we can't directly use the values from old_dict ^ new_dict b/c that set is unordered
-        attributes = (entry[0] for entry in set(old_dict.items()) ^ set(new_dict.items()))
-
-        result = {attribute: self._get_attribute_difference(attribute) for attribute in attributes}
-        if old_user_dict != new_user_dict:
-            result["user"] = (self.old_chat_member.user, self.new_chat_member.user)
-
-        return result  # type: ignore[return-value]
diff --git a/venv/lib/python3.11/site-packages/telegram/_chatpermissions.py b/venv/lib/python3.11/site-packages/telegram/_chatpermissions.py
deleted file mode 100755
index a7b1b10..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_chatpermissions.py
+++ /dev/null
@@ -1,249 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram ChatPermission."""
-from typing import TYPE_CHECKING, Optional
-
-from telegram._telegramobject import TelegramObject
-from telegram._utils.types import JSONDict
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class ChatPermissions(TelegramObject):
-    """Describes actions that a non-administrator user is allowed to take in a chat.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`can_send_messages`,
-    :attr:`can_send_polls`, :attr:`can_send_other_messages`, :attr:`can_add_web_page_previews`,
-    :attr:`can_change_info`, :attr:`can_invite_users`, :attr:`can_pin_messages`,
-    :attr:`can_send_audios`, :attr:`can_send_documents`, :attr:`can_send_photos`,
-    :attr:`can_send_videos`, :attr:`can_send_video_notes`, :attr:`can_send_voice_notes`, and
-    :attr:`can_manage_topics` are equal.
-
-    .. versionchanged:: 20.0
-        :attr:`can_manage_topics` is considered as well when comparing objects of
-        this type in terms of equality.
-    .. versionchanged:: 20.5
-
-        * :attr:`can_send_audios`, :attr:`can_send_documents`, :attr:`can_send_photos`,
-          :attr:`can_send_videos`, :attr:`can_send_video_notes` and :attr:`can_send_voice_notes`
-          are considered as well when comparing objects of this type in terms of equality.
-        * Removed deprecated argument and attribute ``can_send_media_messages``.
-
-
-    Note:
-        Though not stated explicitly in the official docs, Telegram changes not only the
-        permissions that are set, but also sets all the others to :obj:`False`. However, since not
-        documented, this behavior may change unbeknown to PTB.
-
-    Args:
-        can_send_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to send text
-            messages, contacts, locations and venues.
-        can_send_polls (:obj:`bool`, optional): :obj:`True`, if the user is allowed to send polls.
-        can_send_other_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to
-            send animations, games, stickers and use inline bots.
-        can_add_web_page_previews (:obj:`bool`, optional): :obj:`True`, if the user is allowed to
-            add web page previews to their messages.
-        can_change_info (:obj:`bool`, optional): :obj:`True`, if the user is allowed to change the
-            chat title, photo and other settings. Ignored in public supergroups.
-        can_invite_users (:obj:`bool`, optional): :obj:`True`, if the user is allowed to invite new
-            users to the chat.
-        can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to pin
-            messages. Ignored in public supergroups.
-        can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed
-            to create forum topics. If omitted defaults to the value of
-            :attr:`can_pin_messages`.
-
-            .. versionadded:: 20.0
-        can_send_audios (:obj:`bool`): :obj:`True`, if the user is allowed to send audios.
-
-            .. versionadded:: 20.1
-        can_send_documents (:obj:`bool`): :obj:`True`, if the user is allowed to send documents.
-
-            .. versionadded:: 20.1
-        can_send_photos (:obj:`bool`): :obj:`True`, if the user is allowed to send photos.
-
-            .. versionadded:: 20.1
-        can_send_videos (:obj:`bool`): :obj:`True`, if the user is allowed to send videos.
-
-            .. versionadded:: 20.1
-        can_send_video_notes (:obj:`bool`): :obj:`True`, if the user is allowed to send video
-            notes.
-
-            .. versionadded:: 20.1
-        can_send_voice_notes (:obj:`bool`): :obj:`True`, if the user is allowed to send voice
-            notes.
-
-            .. versionadded:: 20.1
-
-    Attributes:
-        can_send_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to send text
-            messages, contacts, locations and venues.
-        can_send_polls (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to send polls,
-            implies :attr:`can_send_messages`.
-        can_send_other_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to
-            send animations, games, stickers and use inline bots.
-        can_add_web_page_previews (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to
-            add web page previews to their messages.
-        can_change_info (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to change the
-            chat title, photo and other settings. Ignored in public supergroups.
-        can_invite_users (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to invite
-            new users to the chat.
-        can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to pin
-            messages. Ignored in public supergroups.
-        can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed
-            to create forum topics. If omitted defaults to the value of
-            :attr:`can_pin_messages`.
-
-            .. versionadded:: 20.0
-        can_send_audios (:obj:`bool`): :obj:`True`, if the user is allowed to send audios.
-
-            .. versionadded:: 20.1
-        can_send_documents (:obj:`bool`): :obj:`True`, if the user is allowed to send documents.
-
-            .. versionadded:: 20.1
-        can_send_photos (:obj:`bool`): :obj:`True`, if the user is allowed to send photos.
-
-            .. versionadded:: 20.1
-        can_send_videos (:obj:`bool`): :obj:`True`, if the user is allowed to send videos.
-
-            .. versionadded:: 20.1
-        can_send_video_notes (:obj:`bool`): :obj:`True`, if the user is allowed to send video
-            notes.
-
-            .. versionadded:: 20.1
-        can_send_voice_notes (:obj:`bool`): :obj:`True`, if the user is allowed to send voice
-            notes.
-
-            .. versionadded:: 20.1
-
-    """
-
-    __slots__ = (
-        "can_add_web_page_previews",
-        "can_change_info",
-        "can_invite_users",
-        "can_manage_topics",
-        "can_pin_messages",
-        "can_send_audios",
-        "can_send_documents",
-        "can_send_messages",
-        "can_send_other_messages",
-        "can_send_photos",
-        "can_send_polls",
-        "can_send_video_notes",
-        "can_send_videos",
-        "can_send_voice_notes",
-    )
-
-    def __init__(
-        self,
-        can_send_messages: Optional[bool] = None,
-        can_send_polls: Optional[bool] = None,
-        can_send_other_messages: Optional[bool] = None,
-        can_add_web_page_previews: Optional[bool] = None,
-        can_change_info: Optional[bool] = None,
-        can_invite_users: Optional[bool] = None,
-        can_pin_messages: Optional[bool] = None,
-        can_manage_topics: Optional[bool] = None,
-        can_send_audios: Optional[bool] = None,
-        can_send_documents: Optional[bool] = None,
-        can_send_photos: Optional[bool] = None,
-        can_send_videos: Optional[bool] = None,
-        can_send_video_notes: Optional[bool] = None,
-        can_send_voice_notes: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        # Required
-        self.can_send_messages: Optional[bool] = can_send_messages
-        self.can_send_polls: Optional[bool] = can_send_polls
-        self.can_send_other_messages: Optional[bool] = can_send_other_messages
-        self.can_add_web_page_previews: Optional[bool] = can_add_web_page_previews
-        self.can_change_info: Optional[bool] = can_change_info
-        self.can_invite_users: Optional[bool] = can_invite_users
-        self.can_pin_messages: Optional[bool] = can_pin_messages
-        self.can_manage_topics: Optional[bool] = can_manage_topics
-        self.can_send_audios: Optional[bool] = can_send_audios
-        self.can_send_documents: Optional[bool] = can_send_documents
-        self.can_send_photos: Optional[bool] = can_send_photos
-        self.can_send_videos: Optional[bool] = can_send_videos
-        self.can_send_video_notes: Optional[bool] = can_send_video_notes
-        self.can_send_voice_notes: Optional[bool] = can_send_voice_notes
-
-        self._id_attrs = (
-            self.can_send_messages,
-            self.can_send_polls,
-            self.can_send_other_messages,
-            self.can_add_web_page_previews,
-            self.can_change_info,
-            self.can_invite_users,
-            self.can_pin_messages,
-            self.can_manage_topics,
-            self.can_send_audios,
-            self.can_send_documents,
-            self.can_send_photos,
-            self.can_send_videos,
-            self.can_send_video_notes,
-            self.can_send_voice_notes,
-        )
-
-        self._freeze()
-
-    @classmethod
-    def all_permissions(cls) -> "ChatPermissions":
-        """
-        This method returns an :class:`ChatPermissions` instance with all attributes
-        set to :obj:`True`. This is e.g. useful when unrestricting a chat member with
-        :meth:`telegram.Bot.restrict_chat_member`.
-
-        .. versionadded:: 20.0
-
-        """
-        return cls(*(14 * (True,)))
-
-    @classmethod
-    def no_permissions(cls) -> "ChatPermissions":
-        """
-        This method returns an :class:`ChatPermissions` instance
-        with all attributes set to :obj:`False`.
-
-        .. versionadded:: 20.0
-        """
-        return cls(*(14 * (False,)))
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["ChatPermissions"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        api_kwargs = {}
-        # This is a deprecated field that TG still returns for backwards compatibility
-        # Let's filter it out to speed up the de-json process
-        if data.get("can_send_media_messages") is not None:
-            api_kwargs["can_send_media_messages"] = data.pop("can_send_media_messages")
-
-        return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs)
diff --git a/venv/lib/python3.11/site-packages/telegram/_choseninlineresult.py b/venv/lib/python3.11/site-packages/telegram/_choseninlineresult.py
deleted file mode 100755
index ee17d93..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_choseninlineresult.py
+++ /dev/null
@@ -1,109 +0,0 @@
-#!/usr/bin/env python
-# pylint: disable=too-many-arguments
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram ChosenInlineResult."""
-
-from typing import TYPE_CHECKING, Optional
-
-from telegram._files.location import Location
-from telegram._telegramobject import TelegramObject
-from telegram._user import User
-from telegram._utils.types import JSONDict
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class ChosenInlineResult(TelegramObject):
-    """
-    Represents a result of an inline query that was chosen by the user and sent to their chat
-    partner.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`result_id` is equal.
-
-    Note:
-        * In Python :keyword:`from` is a reserved word. Use :paramref:`from_user` instead.
-        * It is necessary to enable inline feedback via `@Botfather `_ in
-          order to receive these objects in updates.
-
-    Args:
-        result_id (:obj:`str`): The unique identifier for the result that was chosen.
-        from_user (:class:`telegram.User`): The user that chose the result.
-        location (:class:`telegram.Location`, optional): Sender location, only for bots that
-            require user location.
-        inline_message_id (:obj:`str`, optional): Identifier of the sent inline message. Available
-            only if there is an inline keyboard attached to the message. Will be also received in
-            callback queries and can be used to edit the message.
-        query (:obj:`str`): The query that was used to obtain the result.
-
-    Attributes:
-        result_id (:obj:`str`): The unique identifier for the result that was chosen.
-        from_user (:class:`telegram.User`): The user that chose the result.
-        location (:class:`telegram.Location`): Optional. Sender location, only for bots that
-            require user location.
-        inline_message_id (:obj:`str`): Optional. Identifier of the sent inline message. Available
-            only if there is an inline keyboard attached to the message. Will be also received in
-            callback queries and can be used to edit the message.
-        query (:obj:`str`): The query that was used to obtain the result.
-
-    """
-
-    __slots__ = ("from_user", "inline_message_id", "location", "query", "result_id")
-
-    def __init__(
-        self,
-        result_id: str,
-        from_user: User,
-        query: str,
-        location: Optional[Location] = None,
-        inline_message_id: Optional[str] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-
-        # Required
-        self.result_id: str = result_id
-        self.from_user: User = from_user
-        self.query: str = query
-        # Optionals
-        self.location: Optional[Location] = location
-        self.inline_message_id: Optional[str] = inline_message_id
-
-        self._id_attrs = (self.result_id,)
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["ChosenInlineResult"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        # Required
-        data["from_user"] = User.de_json(data.pop("from", None), bot)
-        # Optionals
-        data["location"] = Location.de_json(data.get("location"), bot)
-
-        return super().de_json(data=data, bot=bot)
diff --git a/venv/lib/python3.11/site-packages/telegram/_copytextbutton.py b/venv/lib/python3.11/site-packages/telegram/_copytextbutton.py
deleted file mode 100755
index 4a3cdb9..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_copytextbutton.py
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram CopyTextButton."""
-from typing import Optional
-
-from telegram._telegramobject import TelegramObject
-from telegram._utils.types import JSONDict
-
-
-class CopyTextButton(TelegramObject):
-    """
-    This object represents an inline keyboard button that copies specified text to the clipboard.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`text` is equal.
-
-    .. versionadded:: 21.7
-
-    Args:
-        text (:obj:`str`): The text to be copied to the clipboard;
-            :tg-const:`telegram.constants.InlineKeyboardButtonLimit.MIN_COPY_TEXT`-
-            :tg-const:`telegram.constants.InlineKeyboardButtonLimit.MAX_COPY_TEXT` characters
-
-    Attributes:
-        text (:obj:`str`): The text to be copied to the clipboard;
-            :tg-const:`telegram.constants.InlineKeyboardButtonLimit.MIN_COPY_TEXT`-
-            :tg-const:`telegram.constants.InlineKeyboardButtonLimit.MAX_COPY_TEXT` characters
-
-    """
-
-    __slots__ = ("text",)
-
-    def __init__(self, text: str, *, api_kwargs: Optional[JSONDict] = None):
-        super().__init__(api_kwargs=api_kwargs)
-        self.text: str = text
-
-        self._id_attrs = (self.text,)
-
-        self._freeze()
diff --git a/venv/lib/python3.11/site-packages/telegram/_dice.py b/venv/lib/python3.11/site-packages/telegram/_dice.py
deleted file mode 100755
index a549aef..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_dice.py
+++ /dev/null
@@ -1,160 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram Dice."""
-from typing import Final, Optional
-
-from telegram import constants
-from telegram._telegramobject import TelegramObject
-from telegram._utils.types import JSONDict
-
-
-class Dice(TelegramObject):
-    """
-    This object represents an animated emoji with a random value for currently supported base
-    emoji. (The singular form of "dice" is "die". However, PTB mimics the Telegram API, which uses
-    the term "dice".)
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`value` and :attr:`emoji` are equal.
-
-    Note:
-        If :attr:`emoji` is :tg-const:`telegram.Dice.DARTS`, a value of 6 currently
-        represents a bullseye, while a value of 1 indicates that the dartboard was missed.
-        However, this behaviour is undocumented and might be changed by Telegram.
-
-        If :attr:`emoji` is :tg-const:`telegram.Dice.BASKETBALL`, a value of 4 or 5
-        currently score a basket, while a value of 1 to 3 indicates that the basket was missed.
-        However, this behaviour is undocumented and might be changed by Telegram.
-
-        If :attr:`emoji` is :tg-const:`telegram.Dice.FOOTBALL`, a value of 4 to 5
-        currently scores a goal, while a value of 1 to 3 indicates that the goal was missed.
-        However, this behaviour is undocumented and might be changed by Telegram.
-
-        If :attr:`emoji` is :tg-const:`telegram.Dice.BOWLING`, a value of 6 knocks
-        all the pins, while a value of 1 means all the pins were missed.
-        However, this behaviour is undocumented and might be changed by Telegram.
-
-        If :attr:`emoji` is :tg-const:`telegram.Dice.SLOT_MACHINE`, each value
-        corresponds to a unique combination of symbols, which
-        can be found in our
-        :wiki:`wiki `.
-        However, this behaviour is undocumented and might be changed by Telegram.
-
-    ..
-        In args, some links for limits of `value` intentionally point to constants for only
-        one emoji of a group to avoid duplication. For example, maximum value for Dice, Darts and
-        Bowling is linked to a constant for Bowling.
-
-    Args:
-        value (:obj:`int`): Value of the dice.
-            :tg-const:`telegram.Dice.MIN_VALUE`-:tg-const:`telegram.Dice.MAX_VALUE_BOWLING`
-            for :tg-const:`telegram.Dice.DICE`, :tg-const:`telegram.Dice.DARTS` and
-            :tg-const:`telegram.Dice.BOWLING` base emoji,
-            :tg-const:`telegram.Dice.MIN_VALUE`-:tg-const:`telegram.Dice.MAX_VALUE_BASKETBALL`
-            for :tg-const:`telegram.Dice.BASKETBALL` and :tg-const:`telegram.Dice.FOOTBALL`
-            base emoji,
-            :tg-const:`telegram.Dice.MIN_VALUE`-:tg-const:`telegram.Dice.MAX_VALUE_SLOT_MACHINE`
-            for :tg-const:`telegram.Dice.SLOT_MACHINE` base emoji.
-        emoji (:obj:`str`): Emoji on which the dice throw animation is based.
-
-    Attributes:
-        value (:obj:`int`): Value of the dice.
-            :tg-const:`telegram.Dice.MIN_VALUE`-:tg-const:`telegram.Dice.MAX_VALUE_BOWLING`
-            for :tg-const:`telegram.Dice.DICE`, :tg-const:`telegram.Dice.DARTS` and
-            :tg-const:`telegram.Dice.BOWLING` base emoji,
-            :tg-const:`telegram.Dice.MIN_VALUE`-:tg-const:`telegram.Dice.MAX_VALUE_BASKETBALL`
-            for :tg-const:`telegram.Dice.BASKETBALL` and :tg-const:`telegram.Dice.FOOTBALL`
-            base emoji,
-            :tg-const:`telegram.Dice.MIN_VALUE`-:tg-const:`telegram.Dice.MAX_VALUE_SLOT_MACHINE`
-            for :tg-const:`telegram.Dice.SLOT_MACHINE` base emoji.
-        emoji (:obj:`str`): Emoji on which the dice throw animation is based.
-
-    """
-
-    __slots__ = ("emoji", "value")
-
-    def __init__(self, value: int, emoji: str, *, api_kwargs: Optional[JSONDict] = None):
-        super().__init__(api_kwargs=api_kwargs)
-        self.value: int = value
-        self.emoji: str = emoji
-
-        self._id_attrs = (self.value, self.emoji)
-
-        self._freeze()
-
-    DICE: Final[str] = constants.DiceEmoji.DICE
-    """:const:`telegram.constants.DiceEmoji.DICE`"""
-    DARTS: Final[str] = constants.DiceEmoji.DARTS
-    """:const:`telegram.constants.DiceEmoji.DARTS`"""
-    BASKETBALL: Final[str] = constants.DiceEmoji.BASKETBALL
-    """:const:`telegram.constants.DiceEmoji.BASKETBALL`"""
-    FOOTBALL: Final[str] = constants.DiceEmoji.FOOTBALL
-    """:const:`telegram.constants.DiceEmoji.FOOTBALL`"""
-    SLOT_MACHINE: Final[str] = constants.DiceEmoji.SLOT_MACHINE
-    """:const:`telegram.constants.DiceEmoji.SLOT_MACHINE`"""
-    BOWLING: Final[str] = constants.DiceEmoji.BOWLING
-    """
-    :const:`telegram.constants.DiceEmoji.BOWLING`
-
-    .. versionadded:: 13.4
-    """
-    ALL_EMOJI: Final[list[str]] = list(constants.DiceEmoji)
-    """list[:obj:`str`]: A list of all available dice emoji."""
-
-    MIN_VALUE: Final[int] = constants.DiceLimit.MIN_VALUE
-    """:const:`telegram.constants.DiceLimit.MIN_VALUE`
-
-    .. versionadded:: 20.0
-    """
-
-    MAX_VALUE_BOWLING: Final[int] = constants.DiceLimit.MAX_VALUE_BOWLING
-    """:const:`telegram.constants.DiceLimit.MAX_VALUE_BOWLING`
-
-    .. versionadded:: 20.0
-    """
-
-    MAX_VALUE_DARTS: Final[int] = constants.DiceLimit.MAX_VALUE_DARTS
-    """:const:`telegram.constants.DiceLimit.MAX_VALUE_DARTS`
-
-    .. versionadded:: 20.0
-    """
-
-    MAX_VALUE_DICE: Final[int] = constants.DiceLimit.MAX_VALUE_DICE
-    """:const:`telegram.constants.DiceLimit.MAX_VALUE_DICE`
-
-    .. versionadded:: 20.0
-    """
-
-    MAX_VALUE_BASKETBALL: Final[int] = constants.DiceLimit.MAX_VALUE_BASKETBALL
-    """:const:`telegram.constants.DiceLimit.MAX_VALUE_BASKETBALL`
-
-    .. versionadded:: 20.0
-    """
-
-    MAX_VALUE_FOOTBALL: Final[int] = constants.DiceLimit.MAX_VALUE_FOOTBALL
-    """:const:`telegram.constants.DiceLimit.MAX_VALUE_FOOTBALL`
-
-    .. versionadded:: 20.0
-    """
-
-    MAX_VALUE_SLOT_MACHINE: Final[int] = constants.DiceLimit.MAX_VALUE_SLOT_MACHINE
-    """:const:`telegram.constants.DiceLimit.MAX_VALUE_SLOT_MACHINE`
-
-    .. versionadded:: 20.0
-    """
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__init__.py b/venv/lib/python3.11/site-packages/telegram/_files/__init__.py
deleted file mode 100755
index e69de29..0000000
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/__init__.cpython-311.pyc
deleted file mode 100755
index 4f93629..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/__init__.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/_basemedium.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/_basemedium.cpython-311.pyc
deleted file mode 100755
index 3fda205..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/_basemedium.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/_basethumbedmedium.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/_basethumbedmedium.cpython-311.pyc
deleted file mode 100755
index 491b0d3..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/_basethumbedmedium.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/animation.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/animation.cpython-311.pyc
deleted file mode 100755
index bdb8bdd..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/animation.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/audio.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/audio.cpython-311.pyc
deleted file mode 100755
index 93f7072..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/audio.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/chatphoto.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/chatphoto.cpython-311.pyc
deleted file mode 100755
index 0b34e00..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/chatphoto.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/contact.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/contact.cpython-311.pyc
deleted file mode 100755
index 437b668..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/contact.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/document.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/document.cpython-311.pyc
deleted file mode 100755
index e9f567d..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/document.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/file.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/file.cpython-311.pyc
deleted file mode 100755
index 6f32327..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/file.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/inputfile.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/inputfile.cpython-311.pyc
deleted file mode 100755
index 9f99ef5..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/inputfile.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/inputmedia.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/inputmedia.cpython-311.pyc
deleted file mode 100755
index 1dc12ce..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/inputmedia.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/inputsticker.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/inputsticker.cpython-311.pyc
deleted file mode 100755
index aa9395e..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/inputsticker.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/location.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/location.cpython-311.pyc
deleted file mode 100755
index 33e97ac..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/location.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/photosize.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/photosize.cpython-311.pyc
deleted file mode 100755
index 65c5a87..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/photosize.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/sticker.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/sticker.cpython-311.pyc
deleted file mode 100755
index ec8ec1e..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/sticker.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/venue.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/venue.cpython-311.pyc
deleted file mode 100755
index cb1b1f3..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/venue.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/video.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/video.cpython-311.pyc
deleted file mode 100755
index 995a356..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/video.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/videonote.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/videonote.cpython-311.pyc
deleted file mode 100755
index f8c6fae..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/videonote.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/voice.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/voice.cpython-311.pyc
deleted file mode 100755
index cfc219a..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_files/__pycache__/voice.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/_basemedium.py b/venv/lib/python3.11/site-packages/telegram/_files/_basemedium.py
deleted file mode 100755
index 4dd76b1..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_files/_basemedium.py
+++ /dev/null
@@ -1,100 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""Common base class for media objects"""
-from typing import TYPE_CHECKING, Optional
-
-from telegram._telegramobject import TelegramObject
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.types import JSONDict, ODVInput
-
-if TYPE_CHECKING:
-    from telegram import File
-
-
-class _BaseMedium(TelegramObject):
-    """Base class for objects representing the various media file types.
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`file_unique_id` is equal.
-
-    Args:
-        file_id (:obj:`str`): Identifier for this file, which can be used to download
-            or reuse the file.
-        file_unique_id (:obj:`str`): Unique identifier for this file, which
-            is supposed to be the same over time and for different bots.
-            Can't be used to download or reuse the file.
-        file_size (:obj:`int`, optional): File size.
-
-    Attributes:
-        file_id (:obj:`str`): File identifier.
-        file_unique_id (:obj:`str`): Unique identifier for this file, which
-            is supposed to be the same over time and for different bots.
-            Can't be used to download or reuse the file.
-        file_size (:obj:`int`): Optional. File size.
-
-
-    """
-
-    __slots__ = ("file_id", "file_size", "file_unique_id")
-
-    def __init__(
-        self,
-        file_id: str,
-        file_unique_id: str,
-        file_size: Optional[int] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-
-        # Required
-        self.file_id: str = str(file_id)
-        self.file_unique_id: str = str(file_unique_id)
-        # Optionals
-        self.file_size: Optional[int] = file_size
-
-        self._id_attrs = (self.file_unique_id,)
-
-    async def get_file(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "File":
-        """Convenience wrapper over :meth:`telegram.Bot.get_file`
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
-
-        Returns:
-            :class:`telegram.File`
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        return await self.get_bot().get_file(
-            file_id=self.file_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/_basethumbedmedium.py b/venv/lib/python3.11/site-packages/telegram/_files/_basethumbedmedium.py
deleted file mode 100755
index a3dff3a..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_files/_basethumbedmedium.py
+++ /dev/null
@@ -1,103 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""Common base class for media objects with thumbnails"""
-from typing import TYPE_CHECKING, Optional, TypeVar
-
-from telegram._files._basemedium import _BaseMedium
-from telegram._files.photosize import PhotoSize
-from telegram._utils.types import JSONDict
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-# pylint: disable=invalid-name
-ThumbedMT_co = TypeVar("ThumbedMT_co", bound="_BaseThumbedMedium", covariant=True)
-
-
-class _BaseThumbedMedium(_BaseMedium):
-    """
-    Base class for objects representing the various media file types that may include a thumbnail.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`file_unique_id` is equal.
-
-    Args:
-        file_id (:obj:`str`): Identifier for this file, which can be used to download
-            or reuse the file.
-        file_unique_id (:obj:`str`): Unique identifier for this file, which
-            is supposed to be the same over time and for different bots.
-            Can't be used to download or reuse the file.
-        file_size (:obj:`int`, optional): File size.
-        thumbnail (:class:`telegram.PhotoSize`, optional): Thumbnail as defined by the sender.
-
-            .. versionadded:: 20.2
-
-    Attributes:
-        file_id (:obj:`str`): File identifier.
-        file_unique_id (:obj:`str`): Unique identifier for this file, which
-            is supposed to be the same over time and for different bots.
-            Can't be used to download or reuse the file.
-        file_size (:obj:`int`): Optional. File size.
-        thumbnail (:class:`telegram.PhotoSize`): Optional. Thumbnail as defined by the sender.
-
-            .. versionadded:: 20.2
-
-    """
-
-    __slots__ = ("thumbnail",)
-
-    def __init__(
-        self,
-        file_id: str,
-        file_unique_id: str,
-        file_size: Optional[int] = None,
-        thumbnail: Optional[PhotoSize] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(
-            file_id=file_id,
-            file_unique_id=file_unique_id,
-            file_size=file_size,
-            api_kwargs=api_kwargs,
-        )
-
-        self.thumbnail: Optional[PhotoSize] = thumbnail
-
-    @classmethod
-    def de_json(
-        cls: type[ThumbedMT_co], data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional[ThumbedMT_co]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        # In case this wasn't already done by the subclass
-        if not isinstance(data.get("thumbnail"), PhotoSize):
-            data["thumbnail"] = PhotoSize.de_json(data.get("thumbnail"), bot)
-
-        api_kwargs = {}
-        # This is a deprecated field that TG still returns for backwards compatibility
-        # Let's filter it out to speed up the de-json process
-        if data.get("thumb") is not None:
-            api_kwargs["thumb"] = data.pop("thumb")
-
-        return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs)
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/animation.py b/venv/lib/python3.11/site-packages/telegram/_files/animation.py
deleted file mode 100755
index 537ffc0..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_files/animation.py
+++ /dev/null
@@ -1,102 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram Animation."""
-from typing import Optional
-
-from telegram._files._basethumbedmedium import _BaseThumbedMedium
-from telegram._files.photosize import PhotoSize
-from telegram._utils.types import JSONDict
-
-
-class Animation(_BaseThumbedMedium):
-    """This object represents an animation file (GIF or H.264/MPEG-4 AVC video without sound).
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`file_unique_id` is equal.
-
-    .. versionchanged:: 20.5
-      |removed_thumb_note|
-
-    Args:
-        file_id (:obj:`str`): Identifier for this file, which can be used to download
-            or reuse the file.
-        file_unique_id (:obj:`str`): Unique identifier for this file, which
-            is supposed to be the same over time and for different bots.
-            Can't be used to download or reuse the file.
-        width (:obj:`int`): Video width as defined by the sender.
-        height (:obj:`int`): Video height as defined by the sender.
-        duration (:obj:`int`): Duration of the video in seconds as defined by the sender.
-        file_name (:obj:`str`, optional): Original animation filename as defined by the sender.
-        mime_type (:obj:`str`, optional): MIME type of the file as defined by the sender.
-        file_size (:obj:`int`, optional): File size in bytes.
-        thumbnail (:class:`telegram.PhotoSize`, optional): Animation thumbnail as defined by
-            sender.
-
-            .. versionadded:: 20.2
-
-    Attributes:
-        file_id (:obj:`str`): Identifier for this file, which can be used to download
-            or reuse the file.
-        file_unique_id (:obj:`str`): Unique identifier for this file, which
-            is supposed to be the same over time and for different bots.
-            Can't be used to download or reuse the file.
-        width (:obj:`int`): Video width as defined by the sender.
-        height (:obj:`int`): Video height as defined by the sender.
-        duration (:obj:`int`): Duration of the video in seconds as defined by the sender.
-        file_name (:obj:`str`): Optional. Original animation filename as defined by the sender.
-        mime_type (:obj:`str`): Optional. MIME type of the file as defined by the sender.
-        file_size (:obj:`int`): Optional. File size in bytes.
-        thumbnail (:class:`telegram.PhotoSize`): Optional. Animation thumbnail as defined by
-            sender.
-
-            .. versionadded:: 20.2
-
-    """
-
-    __slots__ = ("duration", "file_name", "height", "mime_type", "width")
-
-    def __init__(
-        self,
-        file_id: str,
-        file_unique_id: str,
-        width: int,
-        height: int,
-        duration: int,
-        file_name: Optional[str] = None,
-        mime_type: Optional[str] = None,
-        file_size: Optional[int] = None,
-        thumbnail: Optional[PhotoSize] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(
-            file_id=file_id,
-            file_unique_id=file_unique_id,
-            file_size=file_size,
-            api_kwargs=api_kwargs,
-            thumbnail=thumbnail,
-        )
-        with self._unfrozen():
-            # Required
-            self.width: int = width
-            self.height: int = height
-            self.duration: int = duration
-            # Optional
-            self.mime_type: Optional[str] = mime_type
-            self.file_name: Optional[str] = file_name
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/audio.py b/venv/lib/python3.11/site-packages/telegram/_files/audio.py
deleted file mode 100755
index af5e420..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_files/audio.py
+++ /dev/null
@@ -1,104 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram Audio."""
-from typing import Optional
-
-from telegram._files._basethumbedmedium import _BaseThumbedMedium
-from telegram._files.photosize import PhotoSize
-from telegram._utils.types import JSONDict
-
-
-class Audio(_BaseThumbedMedium):
-    """This object represents an audio file to be treated as music by the Telegram clients.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`file_unique_id` is equal.
-
-    .. versionchanged:: 20.5
-      |removed_thumb_note|
-
-
-    Args:
-        file_id (:obj:`str`): Identifier for this file, which can be used to download
-            or reuse the file.
-        file_unique_id (:obj:`str`): Unique identifier for this file, which is supposed to be
-            the same over time and for different bots. Can't be used to download or reuse the file.
-        duration (:obj:`int`): Duration of the audio in seconds as defined by the sender.
-        performer (:obj:`str`, optional): Performer of the audio as defined by the sender or by
-            audio tags.
-        title (:obj:`str`, optional): Title of the audio as defined by the sender or by audio tags.
-        file_name (:obj:`str`, optional): Original filename as defined by the sender.
-        mime_type (:obj:`str`, optional): MIME type of the file as defined by the sender.
-        file_size (:obj:`int`, optional): File size in bytes.
-        thumbnail (:class:`telegram.PhotoSize`, optional): Thumbnail of the album cover to
-            which the music file belongs.
-
-            .. versionadded:: 20.2
-
-    Attributes:
-        file_id (:obj:`str`): Identifier for this file, which can be used to download
-            or reuse the file.
-        file_unique_id (:obj:`str`): Unique identifier for this file, which is supposed to be
-            the same over time and for different bots. Can't be used to download or reuse the file.
-        duration (:obj:`int`): Duration of the audio in seconds as defined by the sender.
-        performer (:obj:`str`): Optional. Performer of the audio as defined by the sender or by
-            audio tags.
-        title (:obj:`str`): Optional. Title of the audio as defined by the sender or by audio tags.
-        file_name (:obj:`str`): Optional. Original filename as defined by the sender.
-        mime_type (:obj:`str`): Optional. MIME type of the file as defined by the sender.
-        file_size (:obj:`int`): Optional. File size in bytes.
-        thumbnail (:class:`telegram.PhotoSize`): Optional. Thumbnail of the album cover to
-            which the music file belongs.
-
-            .. versionadded:: 20.2
-
-
-    """
-
-    __slots__ = ("duration", "file_name", "mime_type", "performer", "title")
-
-    def __init__(
-        self,
-        file_id: str,
-        file_unique_id: str,
-        duration: int,
-        performer: Optional[str] = None,
-        title: Optional[str] = None,
-        mime_type: Optional[str] = None,
-        file_size: Optional[int] = None,
-        file_name: Optional[str] = None,
-        thumbnail: Optional[PhotoSize] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(
-            file_id=file_id,
-            file_unique_id=file_unique_id,
-            file_size=file_size,
-            thumbnail=thumbnail,
-            api_kwargs=api_kwargs,
-        )
-        with self._unfrozen():
-            # Required
-            self.duration: int = duration
-            # Optional
-            self.performer: Optional[str] = performer
-            self.title: Optional[str] = title
-            self.mime_type: Optional[str] = mime_type
-            self.file_name: Optional[str] = file_name
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/chatphoto.py b/venv/lib/python3.11/site-packages/telegram/_files/chatphoto.py
deleted file mode 100755
index 5d6e914..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_files/chatphoto.py
+++ /dev/null
@@ -1,176 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram ChatPhoto."""
-from typing import TYPE_CHECKING, Final, Optional
-
-from telegram import constants
-from telegram._telegramobject import TelegramObject
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.types import JSONDict, ODVInput
-
-if TYPE_CHECKING:
-    from telegram import File
-
-
-class ChatPhoto(TelegramObject):
-    """This object represents a chat photo.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`small_file_unique_id` and :attr:`big_file_unique_id` are
-    equal.
-
-    Args:
-        small_file_id (:obj:`str`): File identifier of small
-            (:tg-const:`telegram.ChatPhoto.SIZE_SMALL` x :tg-const:`telegram.ChatPhoto.SIZE_SMALL`)
-            chat photo. This file_id can be used only for photo download and only for as long
-            as the photo is not changed.
-        small_file_unique_id (:obj:`str`): Unique file identifier of small
-            (:tg-const:`telegram.ChatPhoto.SIZE_SMALL` x :tg-const:`telegram.ChatPhoto.SIZE_SMALL`)
-            chat photo, which is supposed to be the same over time and for different bots.
-            Can't be used to download or reuse the file.
-        big_file_id (:obj:`str`): File identifier of big
-            (:tg-const:`telegram.ChatPhoto.SIZE_BIG` x :tg-const:`telegram.ChatPhoto.SIZE_BIG`)
-            chat photo. This file_id can be used only for photo download and only for as long as
-            the photo is not changed.
-        big_file_unique_id (:obj:`str`): Unique file identifier of big
-            (:tg-const:`telegram.ChatPhoto.SIZE_BIG` x :tg-const:`telegram.ChatPhoto.SIZE_BIG`)
-            chat photo, which is supposed to be the same over time and for different bots.
-            Can't be used to download or reuse the file.
-
-    Attributes:
-        small_file_id (:obj:`str`): File identifier of small
-            (:tg-const:`telegram.ChatPhoto.SIZE_SMALL` x :tg-const:`telegram.ChatPhoto.SIZE_SMALL`)
-            chat photo. This file_id can be used only for photo download and only for as long
-            as the photo is not changed.
-        small_file_unique_id (:obj:`str`): Unique file identifier of small
-            (:tg-const:`telegram.ChatPhoto.SIZE_SMALL` x :tg-const:`telegram.ChatPhoto.SIZE_SMALL`)
-            chat photo, which is supposed to be the same over time and for different bots.
-            Can't be used to download or reuse the file.
-        big_file_id (:obj:`str`): File identifier of big
-            (:tg-const:`telegram.ChatPhoto.SIZE_BIG` x :tg-const:`telegram.ChatPhoto.SIZE_BIG`)
-            chat photo. This file_id can be used only for photo download and only for as long as
-            the photo is not changed.
-        big_file_unique_id (:obj:`str`): Unique file identifier of big
-            (:tg-const:`telegram.ChatPhoto.SIZE_BIG` x :tg-const:`telegram.ChatPhoto.SIZE_BIG`)
-            chat photo, which is supposed to be the same over time and for different bots.
-            Can't be used to download or reuse the file.
-
-    """
-
-    __slots__ = (
-        "big_file_id",
-        "big_file_unique_id",
-        "small_file_id",
-        "small_file_unique_id",
-    )
-
-    def __init__(
-        self,
-        small_file_id: str,
-        small_file_unique_id: str,
-        big_file_id: str,
-        big_file_unique_id: str,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.small_file_id: str = small_file_id
-        self.small_file_unique_id: str = small_file_unique_id
-        self.big_file_id: str = big_file_id
-        self.big_file_unique_id: str = big_file_unique_id
-
-        self._id_attrs = (
-            self.small_file_unique_id,
-            self.big_file_unique_id,
-        )
-
-        self._freeze()
-
-    async def get_small_file(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "File":
-        """Convenience wrapper over :meth:`telegram.Bot.get_file` for getting the small
-        (:tg-const:`telegram.ChatPhoto.SIZE_SMALL` x :tg-const:`telegram.ChatPhoto.SIZE_SMALL`)
-        chat photo
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
-
-        Returns:
-            :class:`telegram.File`
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        return await self.get_bot().get_file(
-            file_id=self.small_file_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def get_big_file(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "File":
-        """Convenience wrapper over :meth:`telegram.Bot.get_file` for getting the
-        big (:tg-const:`telegram.ChatPhoto.SIZE_BIG` x :tg-const:`telegram.ChatPhoto.SIZE_BIG`)
-        chat photo
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
-
-        Returns:
-            :class:`telegram.File`
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-
-        """
-        return await self.get_bot().get_file(
-            file_id=self.big_file_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    SIZE_SMALL: Final[int] = constants.ChatPhotoSize.SMALL
-    """:const:`telegram.constants.ChatPhotoSize.SMALL`
-
-    .. versionadded:: 20.0
-    """
-    SIZE_BIG: Final[int] = constants.ChatPhotoSize.BIG
-    """:const:`telegram.constants.ChatPhotoSize.BIG`
-
-    .. versionadded:: 20.0
-    """
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/contact.py b/venv/lib/python3.11/site-packages/telegram/_files/contact.py
deleted file mode 100755
index 1ff05b3..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_files/contact.py
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram Contact."""
-from typing import Optional
-
-from telegram._telegramobject import TelegramObject
-from telegram._utils.types import JSONDict
-
-
-class Contact(TelegramObject):
-    """This object represents a phone contact.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`phone_number` is equal.
-
-    Args:
-        phone_number (:obj:`str`): Contact's phone number.
-        first_name (:obj:`str`): Contact's first name.
-        last_name (:obj:`str`, optional): Contact's last name.
-        user_id (:obj:`int`, optional): Contact's user identifier in Telegram.
-        vcard (:obj:`str`, optional): Additional data about the contact in the form of a vCard.
-
-    Attributes:
-        phone_number (:obj:`str`): Contact's phone number.
-        first_name (:obj:`str`): Contact's first name.
-        last_name (:obj:`str`): Optional. Contact's last name.
-        user_id (:obj:`int`): Optional. Contact's user identifier in Telegram.
-        vcard (:obj:`str`): Optional. Additional data about the contact in the form of a vCard.
-
-    """
-
-    __slots__ = ("first_name", "last_name", "phone_number", "user_id", "vcard")
-
-    def __init__(
-        self,
-        phone_number: str,
-        first_name: str,
-        last_name: Optional[str] = None,
-        user_id: Optional[int] = None,
-        vcard: Optional[str] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        # Required
-        self.phone_number: str = str(phone_number)
-        self.first_name: str = first_name
-        # Optionals
-        self.last_name: Optional[str] = last_name
-        self.user_id: Optional[int] = user_id
-        self.vcard: Optional[str] = vcard
-
-        self._id_attrs = (self.phone_number,)
-
-        self._freeze()
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/document.py b/venv/lib/python3.11/site-packages/telegram/_files/document.py
deleted file mode 100755
index 7ddaeaf..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_files/document.py
+++ /dev/null
@@ -1,88 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram Document."""
-from typing import Optional
-
-from telegram._files._basethumbedmedium import _BaseThumbedMedium
-from telegram._files.photosize import PhotoSize
-from telegram._utils.types import JSONDict
-
-
-class Document(_BaseThumbedMedium):
-    """This object represents a general file
-    (as opposed to photos, voice messages and audio files).
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`file_unique_id` is equal.
-
-    .. versionchanged:: 20.5
-      |removed_thumb_note|
-
-    Args:
-        file_id (:obj:`str`): Identifier for this file, which can be used to download
-            or reuse the file.
-        file_unique_id (:obj:`str`): Unique identifier for this file, which is supposed to be
-            the same over time and for different bots. Can't be used to download or reuse the file.
-        file_name (:obj:`str`, optional): Original filename as defined by the sender.
-        mime_type (:obj:`str`, optional): MIME type of the file as defined by the sender.
-        file_size (:obj:`int`, optional): File size in bytes.
-        thumbnail (:class:`telegram.PhotoSize`, optional): Document thumbnail as defined by the
-            sender.
-
-            .. versionadded:: 20.2
-
-    Attributes:
-        file_id (:obj:`str`): Identifier for this file, which can be used to download
-            or reuse the file.
-        file_unique_id (:obj:`str`): Unique identifier for this file, which is supposed to be
-            the same over time and for different bots. Can't be used to download or reuse the file.
-        file_name (:obj:`str`): Optional. Original filename as defined by the sender.
-        mime_type (:obj:`str`): Optional. MIME type of the file as defined by the sender.
-        file_size (:obj:`int`): Optional. File size in bytes.
-        thumbnail (:class:`telegram.PhotoSize`): Optional. Document thumbnail as defined by the
-            sender.
-
-            .. versionadded:: 20.2
-
-    """
-
-    __slots__ = ("file_name", "mime_type")
-
-    def __init__(
-        self,
-        file_id: str,
-        file_unique_id: str,
-        file_name: Optional[str] = None,
-        mime_type: Optional[str] = None,
-        file_size: Optional[int] = None,
-        thumbnail: Optional[PhotoSize] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(
-            file_id=file_id,
-            file_unique_id=file_unique_id,
-            file_size=file_size,
-            thumbnail=thumbnail,
-            api_kwargs=api_kwargs,
-        )
-        with self._unfrozen():
-            # Optional
-            self.mime_type: Optional[str] = mime_type
-            self.file_name: Optional[str] = file_name
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/file.py b/venv/lib/python3.11/site-packages/telegram/_files/file.py
deleted file mode 100755
index 38fdac7..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_files/file.py
+++ /dev/null
@@ -1,371 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram File."""
-import shutil
-import urllib.parse as urllib_parse
-from base64 import b64decode
-from pathlib import Path
-from typing import TYPE_CHECKING, BinaryIO, Optional
-
-from telegram._passport.credentials import decrypt
-from telegram._telegramobject import TelegramObject
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.files import is_local_file
-from telegram._utils.types import FilePathInput, JSONDict, ODVInput
-
-if TYPE_CHECKING:
-    from telegram import FileCredentials
-
-
-class File(TelegramObject):
-    """
-    This object represents a file ready to be downloaded. The file can be e.g. downloaded with
-    :attr:`download_to_drive`. It is guaranteed that the link will be valid for at least 1 hour.
-    When the link expires, a new one can be requested by calling :meth:`telegram.Bot.get_file`.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`file_unique_id` is equal.
-
-    .. versionchanged:: 20.0
-        ``download`` was split into :meth:`download_to_drive` and :meth:`download_to_memory`.
-
-    Note:
-        * Maximum file size to download is
-          :tg-const:`telegram.constants.FileSizeLimit.FILESIZE_DOWNLOAD`.
-        * If you obtain an instance of this class from :attr:`telegram.PassportFile.get_file`,
-          then it will automatically be decrypted as it downloads when you call e.g.
-          :meth:`download_to_drive`.
-
-    Args:
-        file_id (:obj:`str`): Identifier for this file, which can be used to download
-            or reuse the file.
-        file_unique_id (:obj:`str`): Unique identifier for this file, which
-            is supposed to be the same over time and for different bots.
-            Can't be used to download or reuse the file.
-        file_size (:obj:`int`, optional): File size in bytes, if known.
-        file_path (:obj:`str`, optional): File path. Use e.g. :meth:`download_to_drive` to get the
-            file.
-
-    Attributes:
-        file_id (:obj:`str`): Identifier for this file, which can be used to download
-            or reuse the file.
-        file_unique_id (:obj:`str`): Unique identifier for this file, which
-            is supposed to be the same over time and for different bots.
-            Can't be used to download or reuse the file.
-        file_size (:obj:`int`): Optional. File size in bytes, if known.
-        file_path (:obj:`str`): Optional. File path. Use e.g. :meth:`download_to_drive` to get the
-            file.
-    """
-
-    __slots__ = (
-        "_credentials",
-        "file_id",
-        "file_path",
-        "file_size",
-        "file_unique_id",
-    )
-
-    def __init__(
-        self,
-        file_id: str,
-        file_unique_id: str,
-        file_size: Optional[int] = None,
-        file_path: Optional[str] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-
-        # Required
-        self.file_id: str = str(file_id)
-        self.file_unique_id: str = str(file_unique_id)
-        # Optionals
-        self.file_size: Optional[int] = file_size
-        self.file_path: Optional[str] = file_path
-
-        self._credentials: Optional[FileCredentials] = None
-
-        self._id_attrs = (self.file_unique_id,)
-
-        self._freeze()
-
-    def _get_encoded_url(self) -> str:
-        """Convert any UTF-8 char in :obj:`File.file_path` into a url encoded ASCII string."""
-        sres = urllib_parse.urlsplit(str(self.file_path))
-        return urllib_parse.urlunsplit(
-            urllib_parse.SplitResult(
-                sres.scheme, sres.netloc, urllib_parse.quote(sres.path), sres.query, sres.fragment
-            )
-        )
-
-    def _prepare_decrypt(self, buf: bytes) -> bytes:
-        return decrypt(b64decode(self._credentials.secret), b64decode(self._credentials.hash), buf)
-
-    async def download_to_drive(
-        self,
-        custom_path: Optional[FilePathInput] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-    ) -> Path:
-        """
-        Download this file. By default, the file is saved in the current working directory with
-        :attr:`file_path` as file name. If :paramref:`custom_path` is supplied as a :obj:`str` or
-        :obj:`pathlib.Path`, it will be saved to that path.
-
-        Note:
-            If :paramref:`custom_path` isn't provided and :attr:`file_path` is the path of a
-            local file (which is the case when a Bot API Server is running in local mode), this
-            method will just return the path.
-
-            The only exception to this are encrypted files (e.g. a passport file). For these, a
-            file with the prefix `decrypted_` will be created in the same directory as the
-            original file in order to decrypt the file without changing the existing one
-            in-place.
-
-        .. seealso:: :wiki:`Working with Files and Media `
-
-        .. versionchanged:: 20.0
-
-            * :paramref:`custom_path` parameter now also accepts :class:`pathlib.Path` as argument.
-            * Returns :class:`pathlib.Path` object in cases where previously a :obj:`str` was
-              returned.
-            * This method was previously called ``download``. It was split into
-              :meth:`download_to_drive` and :meth:`download_to_memory`.
-
-        .. versionchanged:: 21.7
-            Raises :exc:`RuntimeError` if :attr:`file_path` is not set. Note that files without
-            a :attr:`file_path` could never be downloaded, as this attribute is mandatory for that
-            operation.
-
-        Args:
-            custom_path (:class:`pathlib.Path` | :obj:`str` , optional): The path where the file
-                will be saved to. If not specified, will be saved in the current working directory
-                with :attr:`file_path` as file name or the :attr:`file_id` if :attr:`file_path`
-                is not set.
-
-        Keyword Args:
-            read_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
-                :paramref:`telegram.request.BaseRequest.post.read_timeout`. Defaults to
-                :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
-            write_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
-                :paramref:`telegram.request.BaseRequest.post.write_timeout`. Defaults to
-                :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
-            connect_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
-                :paramref:`telegram.request.BaseRequest.post.connect_timeout`. Defaults to
-                :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
-            pool_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
-                :paramref:`telegram.request.BaseRequest.post.pool_timeout`. Defaults to
-                :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
-
-        Returns:
-            :class:`pathlib.Path`: Returns the Path object the file was downloaded to.
-
-        Raises:
-            RuntimeError: If :attr:`file_path` is not set.
-
-        """
-        if not self.file_path:
-            raise RuntimeError("No `file_path` available for this file. Can not download.")
-
-        local_file = is_local_file(self.file_path)
-        url = None if local_file else self._get_encoded_url()
-
-        # if _credentials exists we want to decrypt the file
-        if local_file and self._credentials:
-            file_to_decrypt = Path(self.file_path)
-            buf = self._prepare_decrypt(file_to_decrypt.read_bytes())
-            if custom_path is not None:
-                path = Path(custom_path)
-            else:
-                path = Path(str(file_to_decrypt.parent) + "/decrypted_" + file_to_decrypt.name)
-            path.write_bytes(buf)
-            return path
-
-        if custom_path is not None and local_file:
-            shutil.copyfile(self.file_path, str(custom_path))
-            return Path(custom_path)
-
-        if custom_path:
-            filename = Path(custom_path)
-        elif local_file:
-            return Path(self.file_path)
-        else:
-            filename = Path(Path(self.file_path).name)
-
-        buf = await self.get_bot().request.retrieve(
-            url,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-        )
-        if self._credentials:
-            buf = self._prepare_decrypt(buf)
-        filename.write_bytes(buf)
-        return filename
-
-    async def download_to_memory(
-        self,
-        out: BinaryIO,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-    ) -> None:
-        """
-        Download this file into memory. :paramref:`out` needs to be supplied with a
-        :obj:`io.BufferedIOBase`, the file contents will be saved to that object using the
-        :obj:`out.write` method.
-
-        .. seealso:: :wiki:`Working with Files and Media `
-
-        Hint:
-            If you want to immediately read the data from ``out`` after calling this method, you
-            should call ``out.seek(0)`` first. See also :meth:`io.IOBase.seek`.
-
-        .. versionadded:: 20.0
-
-        .. versionchanged:: 21.7
-            Raises :exc:`RuntimeError` if :attr:`file_path` is not set. Note that files without
-            a :attr:`file_path` could never be downloaded, as this attribute is mandatory for that
-            operation.
-
-        Args:
-            out (:obj:`io.BufferedIOBase`): A file-like object. Must be opened for writing in
-                binary mode.
-
-        Keyword Args:
-            read_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
-                :paramref:`telegram.request.BaseRequest.post.read_timeout`. Defaults to
-                :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
-            write_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
-                :paramref:`telegram.request.BaseRequest.post.write_timeout`. Defaults to
-                :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
-            connect_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
-                :paramref:`telegram.request.BaseRequest.post.connect_timeout`. Defaults to
-                :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
-            pool_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
-                :paramref:`telegram.request.BaseRequest.post.pool_timeout`. Defaults to
-                :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
-
-        Raises:
-            RuntimeError: If :attr:`file_path` is not set.
-        """
-        if not self.file_path:
-            raise RuntimeError("No `file_path` available for this file. Can not download.")
-
-        local_file = is_local_file(self.file_path)
-        url = None if local_file else self._get_encoded_url()
-        path = Path(self.file_path) if local_file else None
-        if local_file:
-            buf = path.read_bytes()
-        else:
-            buf = await self.get_bot().request.retrieve(
-                url,
-                read_timeout=read_timeout,
-                write_timeout=write_timeout,
-                connect_timeout=connect_timeout,
-                pool_timeout=pool_timeout,
-            )
-        if self._credentials:
-            buf = self._prepare_decrypt(buf)
-        out.write(buf)
-
-    async def download_as_bytearray(
-        self,
-        buf: Optional[bytearray] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-    ) -> bytearray:
-        """Download this file and return it as a bytearray.
-
-        .. versionchanged:: 21.7
-            Raises :exc:`RuntimeError` if :attr:`file_path` is not set. Note that files without
-            a :attr:`file_path` could never be downloaded, as this attribute is mandatory for that
-            operation.
-
-        Args:
-            buf (:obj:`bytearray`, optional): Extend the given bytearray with the downloaded data.
-
-        Keyword Args:
-            read_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
-                :paramref:`telegram.request.BaseRequest.post.read_timeout`. Defaults to
-                :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
-
-                .. versionadded:: 20.0
-            write_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
-                :paramref:`telegram.request.BaseRequest.post.write_timeout`. Defaults to
-                :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
-
-                .. versionadded:: 20.0
-            connect_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
-                :paramref:`telegram.request.BaseRequest.post.connect_timeout`. Defaults to
-                :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
-
-                .. versionadded:: 20.0
-            pool_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to
-                :paramref:`telegram.request.BaseRequest.post.pool_timeout`. Defaults to
-                :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`.
-
-                .. versionadded:: 20.0
-
-        Returns:
-            :obj:`bytearray`: The same object as :paramref:`buf` if it was specified. Otherwise a
-            newly allocated :obj:`bytearray`.
-
-        Raises:
-            RuntimeError: If :attr:`file_path` is not set.
-
-        """
-        if not self.file_path:
-            raise RuntimeError("No `file_path` available for this file. Can not download.")
-
-        if buf is None:
-            buf = bytearray()
-
-        if is_local_file(self.file_path):
-            bytes_data = Path(self.file_path).read_bytes()
-        else:
-            bytes_data = await self.get_bot().request.retrieve(
-                self._get_encoded_url(),
-                read_timeout=read_timeout,
-                write_timeout=write_timeout,
-                connect_timeout=connect_timeout,
-                pool_timeout=pool_timeout,
-            )
-        if self._credentials:
-            buf.extend(self._prepare_decrypt(bytes_data))
-        else:
-            buf.extend(bytes_data)
-        return buf
-
-    def set_credentials(self, credentials: "FileCredentials") -> None:
-        """Sets the passport credentials for the file.
-
-        Args:
-            credentials (:class:`telegram.FileCredentials`): The credentials.
-        """
-        self._credentials = credentials
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/inputfile.py b/venv/lib/python3.11/site-packages/telegram/_files/inputfile.py
deleted file mode 100755
index 8c88a9d..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_files/inputfile.py
+++ /dev/null
@@ -1,142 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram InputFile."""
-
-import mimetypes
-from typing import IO, Optional, Union
-from uuid import uuid4
-
-from telegram._utils.files import guess_file_name, load_file
-from telegram._utils.strings import TextEncoding
-from telegram._utils.types import FieldTuple
-
-_DEFAULT_MIME_TYPE = "application/octet-stream"
-
-
-class InputFile:
-    """This object represents a Telegram InputFile.
-
-    .. versionchanged:: 20.0
-
-        * The former attribute ``attach`` was renamed to :attr:`attach_name`.
-        * Method ``is_image`` was removed. If you pass :obj:`bytes` to :paramref:`obj` and would
-          like to have the mime type automatically guessed, please pass :paramref:`filename`
-          in addition.
-
-    Args:
-        obj (:term:`file object` | :obj:`bytes` | :obj:`str`): An open file descriptor or the files
-            content as bytes or string.
-
-            Note:
-                If :paramref:`obj` is a string, it will be encoded as bytes via
-                :external:obj:`obj.encode('utf-8') `.
-
-            .. versionchanged:: 20.0
-                Accept string input.
-        filename (:obj:`str`, optional): Filename for this InputFile.
-        attach (:obj:`bool`, optional): Pass :obj:`True` if the parameter this file belongs to in
-            the request to Telegram should point to the multipart data via an ``attach://`` URI.
-            Defaults to `False`.
-        read_file_handle (:obj:`bool`, optional): If :obj:`True` and :paramref:`obj` is a file
-            handle, the data will be read from the file handle on initialization of this object.
-            If :obj:`False`, the file handle will be passed on to the
-            :attr:`networking backend ` which will have
-            to handle the reading. Defaults to :obj:`True`.
-
-            Tip:
-                If you upload extremely large files, you may want to set this to :obj:`False` to
-                avoid reading the complete file into memory. Additionally, this may be supported
-                better by the networking backend (in particular it is handled better by
-                the default :class:`~telegram.request.HTTPXRequest`).
-
-            Important:
-                If you set this to :obj:`False`, you have to ensure that the file handle is still
-                open when the request is made. In particular, the following snippet can *not* work
-                as expected.
-
-                .. code-block:: python
-
-                    with open('file.txt', 'rb') as file:
-                        input_file = InputFile(file, read_file_handle=False)
-
-                    # here the file handle is already closed and the upload will fail
-                    await bot.send_document(chat_id, input_file)
-
-            .. versionadded:: 21.5
-
-
-    Attributes:
-        input_file_content (:obj:`bytes` | :class:`IO`): The binary content of the file to send.
-        attach_name (:obj:`str`): Optional. If present, the parameter this file belongs to in
-            the request to Telegram should point to the multipart data via a an URI of the form
-            ``attach://`` URI.
-        filename (:obj:`str`): Filename for the file to be sent.
-        mimetype (:obj:`str`): The mimetype inferred from the file to be sent.
-
-    """
-
-    __slots__ = ("attach_name", "filename", "input_file_content", "mimetype")
-
-    def __init__(
-        self,
-        obj: Union[IO[bytes], bytes, str],
-        filename: Optional[str] = None,
-        attach: bool = False,
-        read_file_handle: bool = True,
-    ):
-        if isinstance(obj, bytes):
-            self.input_file_content: Union[bytes, IO[bytes]] = obj
-        elif isinstance(obj, str):
-            self.input_file_content = obj.encode(TextEncoding.UTF_8)
-        elif read_file_handle:
-            reported_filename, self.input_file_content = load_file(obj)
-            filename = filename or reported_filename
-        else:
-            self.input_file_content = obj
-            filename = filename or guess_file_name(obj)
-
-        self.attach_name: Optional[str] = "attached" + uuid4().hex if attach else None
-
-        if filename:
-            self.mimetype: str = (
-                mimetypes.guess_type(filename, strict=False)[0] or _DEFAULT_MIME_TYPE
-            )
-        else:
-            self.mimetype = _DEFAULT_MIME_TYPE
-
-        self.filename: str = filename or self.mimetype.replace("/", ".")
-
-    @property
-    def field_tuple(self) -> FieldTuple:
-        """Field tuple representing the contents of the file for upload to the Telegram servers.
-
-        .. versionchanged:: 21.5
-            Content may now be a file handle.
-
-        Returns:
-            tuple[:obj:`str`, :obj:`bytes` | :class:`IO`, :obj:`str`]:
-        """
-        return self.filename, self.input_file_content, self.mimetype
-
-    @property
-    def attach_uri(self) -> Optional[str]:
-        """URI to insert into the JSON data for uploading the file. Returns :obj:`None`, if
-        :attr:`attach_name` is :obj:`None`.
-        """
-        return f"attach://{self.attach_name}" if self.attach_name else None
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/inputmedia.py b/venv/lib/python3.11/site-packages/telegram/_files/inputmedia.py
deleted file mode 100755
index 0ac17c2..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_files/inputmedia.py
+++ /dev/null
@@ -1,827 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""Base class for Telegram InputMedia Objects."""
-from collections.abc import Sequence
-from typing import Final, Optional, Union
-
-from telegram import constants
-from telegram._files.animation import Animation
-from telegram._files.audio import Audio
-from telegram._files.document import Document
-from telegram._files.inputfile import InputFile
-from telegram._files.photosize import PhotoSize
-from telegram._files.video import Video
-from telegram._messageentity import MessageEntity
-from telegram._telegramobject import TelegramObject
-from telegram._utils import enum
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.files import parse_file_input
-from telegram._utils.types import FileInput, JSONDict, ODVInput
-from telegram.constants import InputMediaType
-
-MediaType = Union[Animation, Audio, Document, PhotoSize, Video]
-
-
-class InputMedia(TelegramObject):
-    """
-    Base class for Telegram InputMedia Objects.
-
-    .. versionchanged:: 20.0
-        Added arguments and attributes :attr:`type`, :attr:`media`, :attr:`caption`,
-            :attr:`caption_entities`, :paramref:`parse_mode`.
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    Args:
-        media_type (:obj:`str`): Type of media that the instance represents.
-        media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \
-            :class:`pathlib.Path` | :class:`telegram.Animation` |  :class:`telegram.Audio` | \
-            :class:`telegram.Document` | :class:`telegram.PhotoSize` | \
-            :class:`telegram.Video`): File to send.
-            |fileinputnopath|
-            Lastly you can pass an existing telegram media object of the corresponding type
-            to send.
-        caption (:obj:`str`, optional): Caption of the media to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities
-            parsing.
-        caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        parse_mode (:obj:`str`, optional): |parse_mode|
-
-    Attributes:
-        type (:obj:`str`): Type of the input media.
-        media (:obj:`str` | :class:`telegram.InputFile`): Media to send.
-        caption (:obj:`str`): Optional. Caption of the media to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities
-            parsing.
-        parse_mode (:obj:`str`): Optional. |parse_mode|
-        caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
-
-            .. versionchanged:: 20.0
-
-                * |tupleclassattrs|
-                * |alwaystuple|
-
-    """
-
-    __slots__ = ("caption", "caption_entities", "media", "parse_mode", "type")
-
-    def __init__(
-        self,
-        media_type: str,
-        media: Union[str, InputFile, MediaType],
-        caption: Optional[str] = None,
-        caption_entities: Optional[Sequence[MessageEntity]] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.type: str = enum.get_member(constants.InputMediaType, media_type, media_type)
-        self.media: Union[str, InputFile, Animation, Audio, Document, PhotoSize, Video] = media
-        self.caption: Optional[str] = caption
-        self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
-        self.parse_mode: ODVInput[str] = parse_mode
-
-        self._freeze()
-
-    @staticmethod
-    def _parse_thumbnail_input(thumbnail: Optional[FileInput]) -> Optional[Union[str, InputFile]]:
-        # We use local_mode=True because we don't have access to the actual setting and want
-        # things to work in local mode.
-        return (
-            parse_file_input(thumbnail, attach=True, local_mode=True)
-            if thumbnail is not None
-            else thumbnail
-        )
-
-
-class InputPaidMedia(TelegramObject):
-    """
-    Base class for Telegram InputPaidMedia Objects. Currently, it can be one of:
-
-    * :class:`telegram.InputMediaPhoto`
-    * :class:`telegram.InputMediaVideo`
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    .. versionadded:: 21.4
-
-    Args:
-        type (:obj:`str`): Type of media that the instance represents.
-        media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \
-            :class:`pathlib.Path` | :class:`telegram.PhotoSize` | :class:`telegram.Video`): File
-            to send. |fileinputnopath|
-            Lastly you can pass an existing telegram media object of the corresponding type
-            to send.
-
-    Attributes:
-        type (:obj:`str`): Type of the input media.
-        media (:obj:`str` | :class:`telegram.InputFile`): Media to send.
-    """
-
-    PHOTO: Final[str] = constants.InputPaidMediaType.PHOTO
-    """:const:`telegram.constants.InputPaidMediaType.PHOTO`"""
-    VIDEO: Final[str] = constants.InputPaidMediaType.VIDEO
-    """:const:`telegram.constants.InputPaidMediaType.VIDEO`"""
-
-    __slots__ = ("media", "type")
-
-    def __init__(
-        self,
-        type: str,  # pylint: disable=redefined-builtin
-        media: Union[str, InputFile, PhotoSize, Video],
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.type: str = enum.get_member(constants.InputPaidMediaType, type, type)
-        self.media: Union[str, InputFile, PhotoSize, Video] = media
-
-        self._freeze()
-
-
-class InputPaidMediaPhoto(InputPaidMedia):
-    """The paid media to send is a photo.
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    .. versionadded:: 21.4
-
-    Args:
-        media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \
-            :class:`pathlib.Path` | :class:`telegram.PhotoSize`): File to send. |fileinputnopath|
-            Lastly you can pass an existing :class:`telegram.PhotoSize` object to send.
-
-    Attributes:
-        type (:obj:`str`): Type of the media, always
-            :tg-const:`telegram.constants.InputPaidMediaType.PHOTO`.
-        media (:obj:`str` | :class:`telegram.InputFile`): Photo to send.
-    """
-
-    __slots__ = ()
-
-    def __init__(
-        self,
-        media: Union[FileInput, PhotoSize],
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        media = parse_file_input(media, PhotoSize, attach=True, local_mode=True)
-        super().__init__(type=InputPaidMedia.PHOTO, media=media, api_kwargs=api_kwargs)
-        self._freeze()
-
-
-class InputPaidMediaVideo(InputPaidMedia):
-    """
-    The paid media to send is a video.
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    .. versionadded:: 21.4
-
-    Note:
-        *  When using a :class:`telegram.Video` for the :attr:`media` attribute, it will take the
-           width, height and duration from that video, unless otherwise specified with the optional
-           arguments.
-        *  :paramref:`thumbnail` will be ignored for small video files, for which Telegram can
-           easily generate thumbnails. However, this behaviour is undocumented and might be
-           changed by Telegram.
-
-    Args:
-        media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \
-            :class:`pathlib.Path` | :class:`telegram.Video`): File to send. |fileinputnopath|
-            Lastly you can pass an existing :class:`telegram.Video` object to send.
-        thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
-                optional): |thumbdocstringnopath|
-        width (:obj:`int`, optional): Video width.
-        height (:obj:`int`, optional): Video height.
-        duration (:obj:`int`, optional): Video duration in seconds.
-        supports_streaming (:obj:`bool`, optional): Pass :obj:`True`, if the uploaded video is
-            suitable for streaming.
-
-    Attributes:
-        type (:obj:`str`): Type of the media, always
-            :tg-const:`telegram.constants.InputPaidMediaType.VIDEO`.
-        media (:obj:`str` | :class:`telegram.InputFile`): Video to send.
-        thumbnail (:class:`telegram.InputFile`): Optional. |thumbdocstringbase|
-        width (:obj:`int`): Optional. Video width.
-        height (:obj:`int`): Optional. Video height.
-        duration (:obj:`int`): Optional. Video duration in seconds.
-        supports_streaming (:obj:`bool`): Optional. :obj:`True`, if the uploaded video is
-            suitable for streaming.
-    """
-
-    __slots__ = ("duration", "height", "supports_streaming", "thumbnail", "width")
-
-    def __init__(
-        self,
-        media: Union[FileInput, Video],
-        thumbnail: Optional[FileInput] = None,
-        width: Optional[int] = None,
-        height: Optional[int] = None,
-        duration: Optional[int] = None,
-        supports_streaming: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        if isinstance(media, Video):
-            width = width if width is not None else media.width
-            height = height if height is not None else media.height
-            duration = duration if duration is not None else media.duration
-            media = media.file_id
-        else:
-            # We use local_mode=True because we don't have access to the actual setting and want
-            # things to work in local mode.
-            media = parse_file_input(media, attach=True, local_mode=True)
-
-        super().__init__(type=InputPaidMedia.VIDEO, media=media, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.thumbnail: Optional[Union[str, InputFile]] = InputMedia._parse_thumbnail_input(
-                thumbnail
-            )
-            self.width: Optional[int] = width
-            self.height: Optional[int] = height
-            self.duration: Optional[int] = duration
-            self.supports_streaming: Optional[bool] = supports_streaming
-
-
-class InputMediaAnimation(InputMedia):
-    """Represents an animation file (GIF or H.264/MPEG-4 AVC video without sound) to be sent.
-
-    Note:
-        When using a :class:`telegram.Animation` for the :attr:`media` attribute, it will take the
-        width, height and duration from that animation, unless otherwise specified with the
-        optional arguments.
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    .. versionchanged:: 20.5
-      |removed_thumb_note|
-
-    Args:
-        media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \
-            :class:`pathlib.Path` | :class:`telegram.Animation`): File to send. |fileinputnopath|
-            Lastly you can pass an existing :class:`telegram.Animation` object to send.
-
-            .. versionchanged:: 13.2
-               Accept :obj:`bytes` as input.
-        filename (:obj:`str`, optional): Custom file name for the animation, when uploading a
-            new file. Convenience parameter, useful e.g. when sending files generated by the
-            :obj:`tempfile` module.
-
-            .. versionadded:: 13.1
-        caption (:obj:`str`, optional): Caption of the animation to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
-            after entities parsing.
-        parse_mode (:obj:`str`, optional): |parse_mode|
-        caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        width (:obj:`int`, optional): Animation width.
-        height (:obj:`int`, optional): Animation height.
-        duration (:obj:`int`, optional): Animation duration in seconds.
-        has_spoiler (:obj:`bool`, optional): Pass :obj:`True`, if the animation needs to be covered
-            with a spoiler animation.
-
-            .. versionadded:: 20.0
-        thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
-                optional): |thumbdocstringnopath|
-
-            .. versionadded:: 20.2
-        show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
-
-            .. versionadded:: 21.3
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.ANIMATION`.
-        media (:obj:`str` | :class:`telegram.InputFile`): Animation to send.
-        caption (:obj:`str`): Optional. Caption of the animation to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
-            after entities parsing.
-        parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting.
-        caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
-
-            .. versionchanged:: 20.0
-
-                * |tupleclassattrs|
-                * |alwaystuple|
-        width (:obj:`int`): Optional. Animation width.
-        height (:obj:`int`): Optional. Animation height.
-        duration (:obj:`int`): Optional. Animation duration in seconds.
-        has_spoiler (:obj:`bool`): Optional. :obj:`True`, if the animation is covered with a
-            spoiler animation.
-
-            .. versionadded:: 20.0
-        thumbnail (:class:`telegram.InputFile`): Optional. |thumbdocstringbase|
-
-            .. versionadded:: 20.2
-        show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
-
-            .. versionadded:: 21.3
-    """
-
-    __slots__ = (
-        "duration",
-        "has_spoiler",
-        "height",
-        "show_caption_above_media",
-        "thumbnail",
-        "width",
-    )
-
-    def __init__(
-        self,
-        media: Union[FileInput, Animation],
-        caption: Optional[str] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        width: Optional[int] = None,
-        height: Optional[int] = None,
-        duration: Optional[int] = None,
-        caption_entities: Optional[Sequence[MessageEntity]] = None,
-        filename: Optional[str] = None,
-        has_spoiler: Optional[bool] = None,
-        thumbnail: Optional[FileInput] = None,
-        show_caption_above_media: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        if isinstance(media, Animation):
-            width = media.width if width is None else width
-            height = media.height if height is None else height
-            duration = media.duration if duration is None else duration
-            media = media.file_id
-        else:
-            # We use local_mode=True because we don't have access to the actual setting and want
-            # things to work in local mode.
-            media = parse_file_input(media, filename=filename, attach=True, local_mode=True)
-
-        super().__init__(
-            InputMediaType.ANIMATION,
-            media,
-            caption,
-            caption_entities,
-            parse_mode,
-            api_kwargs=api_kwargs,
-        )
-        with self._unfrozen():
-            self.thumbnail: Optional[Union[str, InputFile]] = self._parse_thumbnail_input(
-                thumbnail
-            )
-            self.width: Optional[int] = width
-            self.height: Optional[int] = height
-            self.duration: Optional[int] = duration
-            self.has_spoiler: Optional[bool] = has_spoiler
-            self.show_caption_above_media: Optional[bool] = show_caption_above_media
-
-
-class InputMediaPhoto(InputMedia):
-    """Represents a photo to be sent.
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    Args:
-        media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \
-            :class:`pathlib.Path` | :class:`telegram.PhotoSize`): File to send. |fileinputnopath|
-            Lastly you can pass an existing :class:`telegram.PhotoSize` object to send.
-
-            .. versionchanged:: 13.2
-               Accept :obj:`bytes` as input.
-        filename (:obj:`str`, optional): Custom file name for the photo, when uploading a
-            new file. Convenience parameter, useful e.g. when sending files generated by the
-            :obj:`tempfile` module.
-
-            .. versionadded:: 13.1
-        caption (:obj:`str`, optional ): Caption of the photo to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
-            entities parsing.
-        parse_mode (:obj:`str`, optional): |parse_mode|
-        caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-        has_spoiler (:obj:`bool`, optional): Pass :obj:`True`, if the photo needs to be covered
-            with a spoiler animation.
-
-            .. versionadded:: 20.0
-        show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
-
-            .. versionadded:: 21.3
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.PHOTO`.
-        media (:obj:`str` | :class:`telegram.InputFile`): Photo to send.
-        caption (:obj:`str`): Optional. Caption of the photo to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
-            after entities parsing.
-        parse_mode (:obj:`str`): Optional. |parse_mode|
-        caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
-
-            .. versionchanged:: 20.0
-
-                * |tupleclassattrs|
-                * |alwaystuple|
-        has_spoiler (:obj:`bool`): Optional. :obj:`True`, if the photo is covered with a
-            spoiler animation.
-
-            .. versionadded:: 20.0
-        show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
-
-            .. versionadded:: 21.3
-    """
-
-    __slots__ = (
-        "has_spoiler",
-        "show_caption_above_media",
-    )
-
-    def __init__(
-        self,
-        media: Union[FileInput, PhotoSize],
-        caption: Optional[str] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence[MessageEntity]] = None,
-        filename: Optional[str] = None,
-        has_spoiler: Optional[bool] = None,
-        show_caption_above_media: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        # We use local_mode=True because we don't have access to the actual setting and want
-        # things to work in local mode.
-        media = parse_file_input(media, PhotoSize, filename=filename, attach=True, local_mode=True)
-        super().__init__(
-            InputMediaType.PHOTO,
-            media,
-            caption,
-            caption_entities,
-            parse_mode,
-            api_kwargs=api_kwargs,
-        )
-
-        with self._unfrozen():
-            self.has_spoiler: Optional[bool] = has_spoiler
-            self.show_caption_above_media: Optional[bool] = show_caption_above_media
-
-
-class InputMediaVideo(InputMedia):
-    """Represents a video to be sent.
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    Note:
-        *  When using a :class:`telegram.Video` for the :attr:`media` attribute, it will take the
-           width, height and duration from that video, unless otherwise specified with the optional
-           arguments.
-        *  :paramref:`thumbnail` will be ignored for small video files, for which Telegram can
-            easily generate thumbnails. However, this behaviour is undocumented and might be
-            changed by Telegram.
-
-    .. versionchanged:: 20.5
-      |removed_thumb_note|
-
-    Args:
-        media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \
-            :class:`pathlib.Path` | :class:`telegram.Video`): File to send. |fileinputnopath|
-            Lastly you can pass an existing :class:`telegram.Video` object to send.
-
-            .. versionchanged:: 13.2
-               Accept :obj:`bytes` as input.
-        filename (:obj:`str`, optional): Custom file name for the video, when uploading a
-            new file. Convenience parameter, useful e.g. when sending files generated by the
-            :obj:`tempfile` module.
-
-            .. versionadded:: 13.1
-        caption (:obj:`str`, optional): Caption of the video to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
-            entities parsing.
-        parse_mode (:obj:`str`, optional): |parse_mode|
-        caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        width (:obj:`int`, optional): Video width.
-        height (:obj:`int`, optional): Video height.
-        duration (:obj:`int`, optional): Video duration in seconds.
-        supports_streaming (:obj:`bool`, optional): Pass :obj:`True`, if the uploaded video is
-            suitable for streaming.
-        has_spoiler (:obj:`bool`, optional): Pass :obj:`True`, if the video needs to be covered
-            with a spoiler animation.
-
-            .. versionadded:: 20.0
-        thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
-                optional): |thumbdocstringnopath|
-
-            .. versionadded:: 20.2
-        show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
-
-            .. versionadded:: 21.3
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.VIDEO`.
-        media (:obj:`str` | :class:`telegram.InputFile`): Video file to send.
-        caption (:obj:`str`): Optional. Caption of the video to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
-            after entities parsing.
-        parse_mode (:obj:`str`): Optional. |parse_mode|
-        caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
-
-            .. versionchanged:: 20.0
-
-                * |tupleclassattrs|
-                * |alwaystuple|
-        width (:obj:`int`): Optional. Video width.
-        height (:obj:`int`): Optional. Video height.
-        duration (:obj:`int`): Optional. Video duration in seconds.
-        supports_streaming (:obj:`bool`): Optional. :obj:`True`, if the uploaded video is
-            suitable for streaming.
-        has_spoiler (:obj:`bool`): Optional. :obj:`True`, if the video is covered with a
-            spoiler animation.
-
-            .. versionadded:: 20.0
-        thumbnail (:class:`telegram.InputFile`): Optional. |thumbdocstringbase|
-
-            .. versionadded:: 20.2
-        show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
-
-            .. versionadded:: 21.3
-    """
-
-    __slots__ = (
-        "duration",
-        "has_spoiler",
-        "height",
-        "show_caption_above_media",
-        "supports_streaming",
-        "thumbnail",
-        "width",
-    )
-
-    def __init__(
-        self,
-        media: Union[FileInput, Video],
-        caption: Optional[str] = None,
-        width: Optional[int] = None,
-        height: Optional[int] = None,
-        duration: Optional[int] = None,
-        supports_streaming: Optional[bool] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence[MessageEntity]] = None,
-        filename: Optional[str] = None,
-        has_spoiler: Optional[bool] = None,
-        thumbnail: Optional[FileInput] = None,
-        show_caption_above_media: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        if isinstance(media, Video):
-            width = width if width is not None else media.width
-            height = height if height is not None else media.height
-            duration = duration if duration is not None else media.duration
-            media = media.file_id
-        else:
-            # We use local_mode=True because we don't have access to the actual setting and want
-            # things to work in local mode.
-            media = parse_file_input(media, filename=filename, attach=True, local_mode=True)
-
-        super().__init__(
-            InputMediaType.VIDEO,
-            media,
-            caption,
-            caption_entities,
-            parse_mode,
-            api_kwargs=api_kwargs,
-        )
-        with self._unfrozen():
-            self.width: Optional[int] = width
-            self.height: Optional[int] = height
-            self.duration: Optional[int] = duration
-            self.thumbnail: Optional[Union[str, InputFile]] = self._parse_thumbnail_input(
-                thumbnail
-            )
-            self.supports_streaming: Optional[bool] = supports_streaming
-            self.has_spoiler: Optional[bool] = has_spoiler
-            self.show_caption_above_media: Optional[bool] = show_caption_above_media
-
-
-class InputMediaAudio(InputMedia):
-    """Represents an audio file to be treated as music to be sent.
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    Note:
-        When using a :class:`telegram.Audio` for the :attr:`media` attribute, it will take the
-        duration, performer and title from that video, unless otherwise specified with the
-        optional arguments.
-
-    .. versionchanged:: 20.5
-      |removed_thumb_note|
-
-    Args:
-        media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` | \
-            :class:`pathlib.Path` | :class:`telegram.Audio`): File to send. |fileinputnopath|
-            Lastly you can pass an existing :class:`telegram.Audio` object to send.
-
-            .. versionchanged:: 13.2
-               Accept :obj:`bytes` as input.
-        filename (:obj:`str`, optional): Custom file name for the audio, when uploading a
-            new file. Convenience parameter, useful e.g. when sending files generated by the
-            :obj:`tempfile` module.
-
-            .. versionadded:: 13.1
-        caption (:obj:`str`, optional): Caption of the audio to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
-            entities parsing.
-        parse_mode (:obj:`str`, optional): |parse_mode|
-        caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        duration (:obj:`int`, optional): Duration of the audio in seconds as defined by the sender.
-        performer (:obj:`str`, optional): Performer of the audio as defined by the sender or by
-            audio tags.
-        title (:obj:`str`, optional): Title of the audio as defined by the sender or by audio tags.
-        thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
-                optional): |thumbdocstringnopath|
-
-            .. versionadded:: 20.2
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.AUDIO`.
-        media (:obj:`str` | :class:`telegram.InputFile`): Audio file to send.
-        caption (:obj:`str`): Optional. Caption of the audio to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
-            after entities parsing.
-        parse_mode (:obj:`str`): Optional. |parse_mode|
-        caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
-
-            .. versionchanged:: 20.0
-
-                * |tupleclassattrs|
-                * |alwaystuple|
-        duration (:obj:`int`): Optional. Duration of the audio in seconds.
-        performer (:obj:`str`): Optional. Performer of the audio as defined by the sender or by
-            audio tags.
-        title (:obj:`str`): Optional. Title of the audio as defined by the sender or by audio tags.
-        thumbnail (:class:`telegram.InputFile`): Optional. |thumbdocstringbase|
-
-            .. versionadded:: 20.2
-
-    """
-
-    __slots__ = ("duration", "performer", "thumbnail", "title")
-
-    def __init__(
-        self,
-        media: Union[FileInput, Audio],
-        caption: Optional[str] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        duration: Optional[int] = None,
-        performer: Optional[str] = None,
-        title: Optional[str] = None,
-        caption_entities: Optional[Sequence[MessageEntity]] = None,
-        filename: Optional[str] = None,
-        thumbnail: Optional[FileInput] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        if isinstance(media, Audio):
-            duration = media.duration if duration is None else duration
-            performer = media.performer if performer is None else performer
-            title = media.title if title is None else title
-            media = media.file_id
-        else:
-            # We use local_mode=True because we don't have access to the actual setting and want
-            # things to work in local mode.
-            media = parse_file_input(media, filename=filename, attach=True, local_mode=True)
-
-        super().__init__(
-            InputMediaType.AUDIO,
-            media,
-            caption,
-            caption_entities,
-            parse_mode,
-            api_kwargs=api_kwargs,
-        )
-        with self._unfrozen():
-            self.thumbnail: Optional[Union[str, InputFile]] = self._parse_thumbnail_input(
-                thumbnail
-            )
-            self.duration: Optional[int] = duration
-            self.title: Optional[str] = title
-            self.performer: Optional[str] = performer
-
-
-class InputMediaDocument(InputMedia):
-    """Represents a general file to be sent.
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    .. versionchanged:: 20.5
-      |removed_thumb_note|
-
-    Args:
-        media (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` \
-            | :class:`pathlib.Path` | :class:`telegram.Document`): File to send. |fileinputnopath|
-            Lastly you can pass an existing :class:`telegram.Document` object to send.
-
-            .. versionchanged:: 13.2
-               Accept :obj:`bytes` as input.
-        filename (:obj:`str`, optional): Custom file name for the document, when uploading a
-            new file. Convenience parameter, useful e.g. when sending files generated by the
-            :obj:`tempfile` module.
-
-            .. versionadded:: 13.1
-        caption (:obj:`str`, optional): Caption of the document to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
-            entities parsing.
-        parse_mode (:obj:`str`, optional): |parse_mode|
-        caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        disable_content_type_detection (:obj:`bool`, optional): Disables automatic server-side
-            content type detection for files uploaded using multipart/form-data. Always
-            :obj:`True`, if the document is sent as part of an album.
-        thumbnail (:term:`file object` | :obj:`bytes` | :class:`pathlib.Path` | :obj:`str`, \
-                optional): |thumbdocstringnopath|
-
-            .. versionadded:: 20.2
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InputMediaType.DOCUMENT`.
-        media (:obj:`str` | :class:`telegram.InputFile`): File to send.
-        caption (:obj:`str`): Optional. Caption of the document to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
-            after entities parsing.
-        parse_mode (:obj:`str`): Optional. |parse_mode|
-        caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
-
-            .. versionchanged:: 20.0
-
-                * |tupleclassattrs|
-                * |alwaystuple|
-        disable_content_type_detection (:obj:`bool`): Optional. Disables automatic server-side
-            content type detection for files uploaded using multipart/form-data. Always
-            :obj:`True`, if the document is sent as part of an album.
-        thumbnail (:class:`telegram.InputFile`): Optional. |thumbdocstringbase|
-
-            .. versionadded:: 20.2
-    """
-
-    __slots__ = ("disable_content_type_detection", "thumbnail")
-
-    def __init__(
-        self,
-        media: Union[FileInput, Document],
-        caption: Optional[str] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        disable_content_type_detection: Optional[bool] = None,
-        caption_entities: Optional[Sequence[MessageEntity]] = None,
-        filename: Optional[str] = None,
-        thumbnail: Optional[FileInput] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        # We use local_mode=True because we don't have access to the actual setting and want
-        # things to work in local mode.
-        media = parse_file_input(media, Document, filename=filename, attach=True, local_mode=True)
-
-        super().__init__(
-            InputMediaType.DOCUMENT,
-            media,
-            caption,
-            caption_entities,
-            parse_mode,
-            api_kwargs=api_kwargs,
-        )
-        with self._unfrozen():
-            self.thumbnail: Optional[Union[str, InputFile]] = self._parse_thumbnail_input(
-                thumbnail
-            )
-            self.disable_content_type_detection: Optional[bool] = disable_content_type_detection
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/inputsticker.py b/venv/lib/python3.11/site-packages/telegram/_files/inputsticker.py
deleted file mode 100755
index 1edc51a..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_files/inputsticker.py
+++ /dev/null
@@ -1,119 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram InputSticker."""
-
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Optional, Union
-
-from telegram._files.sticker import MaskPosition
-from telegram._telegramobject import TelegramObject
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.files import parse_file_input
-from telegram._utils.types import FileInput, JSONDict
-
-if TYPE_CHECKING:
-    from telegram._files.inputfile import InputFile
-
-
-class InputSticker(TelegramObject):
-    """
-    This object describes a sticker to be added to a sticker set.
-
-    .. versionadded:: 20.2
-
-    .. versionchanged:: 21.1
-        As of Bot API 7.2, the new argument :paramref:`format` is a required argument, and thus the
-        order of the arguments has changed.
-
-    Args:
-        sticker (:obj:`str` | :term:`file object` | :class:`~telegram.InputFile` | :obj:`bytes` \
-            | :class:`pathlib.Path`): The
-            added sticker. |uploadinputnopath| Animated and video stickers can't be uploaded via
-            HTTP URL.
-        emoji_list (Sequence[:obj:`str`]): Sequence of
-            :tg-const:`telegram.constants.StickerLimit.MIN_STICKER_EMOJI` -
-            :tg-const:`telegram.constants.StickerLimit.MAX_STICKER_EMOJI` emoji associated with the
-            sticker.
-        mask_position (:class:`telegram.MaskPosition`, optional): Position where the mask should be
-            placed on faces. For ":tg-const:`telegram.constants.StickerType.MASK`" stickers only.
-        keywords (Sequence[:obj:`str`], optional): Sequence of
-            0-:tg-const:`telegram.constants.StickerLimit.MAX_SEARCH_KEYWORDS` search keywords
-            for the sticker with the total length of up to
-            :tg-const:`telegram.constants.StickerLimit.MAX_KEYWORD_LENGTH` characters. For
-            ":tg-const:`telegram.constants.StickerType.REGULAR`" and
-            ":tg-const:`telegram.constants.StickerType.CUSTOM_EMOJI`" stickers only.
-        format (:obj:`str`): Format of the added sticker, must be one of
-            :tg-const:`telegram.constants.StickerFormat.STATIC` for a
-            ``.WEBP`` or ``.PNG`` image, :tg-const:`telegram.constants.StickerFormat.ANIMATED`
-            for a ``.TGS`` animation, :tg-const:`telegram.constants.StickerFormat.VIDEO` for a WEBM
-            video.
-
-            .. versionadded:: 21.1
-
-    Attributes:
-        sticker (:obj:`str` | :class:`telegram.InputFile`): The added sticker.
-        emoji_list (tuple[:obj:`str`]): Tuple of
-            :tg-const:`telegram.constants.StickerLimit.MIN_STICKER_EMOJI` -
-            :tg-const:`telegram.constants.StickerLimit.MAX_STICKER_EMOJI` emoji associated with the
-            sticker.
-        mask_position (:class:`telegram.MaskPosition`): Optional. Position where the mask should be
-            placed on faces. For ":tg-const:`telegram.constants.StickerType.MASK`" stickers only.
-        keywords (tuple[:obj:`str`]): Optional. Tuple of
-            0-:tg-const:`telegram.constants.StickerLimit.MAX_SEARCH_KEYWORDS` search keywords
-            for the sticker with the total length of up to
-            :tg-const:`telegram.constants.StickerLimit.MAX_KEYWORD_LENGTH` characters. For
-            ":tg-const:`telegram.constants.StickerType.REGULAR`" and
-            ":tg-const:`telegram.constants.StickerType.CUSTOM_EMOJI`" stickers only.
-            ":tg-const:`telegram.constants.StickerType.CUSTOM_EMOJI`" stickers only.
-        format (:obj:`str`): Format of the added sticker, must be one of
-            :tg-const:`telegram.constants.StickerFormat.STATIC` for a
-            ``.WEBP`` or ``.PNG`` image, :tg-const:`telegram.constants.StickerFormat.ANIMATED`
-            for a ``.TGS`` animation, :tg-const:`telegram.constants.StickerFormat.VIDEO` for a WEBM
-            video.
-
-            .. versionadded:: 21.1
-    """
-
-    __slots__ = ("emoji_list", "format", "keywords", "mask_position", "sticker")
-
-    def __init__(
-        self,
-        sticker: FileInput,
-        emoji_list: Sequence[str],
-        format: str,  # pylint: disable=redefined-builtin
-        mask_position: Optional[MaskPosition] = None,
-        keywords: Optional[Sequence[str]] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-
-        # We use local_mode=True because we don't have access to the actual setting and want
-        # things to work in local mode.
-        self.sticker: Union[str, InputFile] = parse_file_input(
-            sticker,
-            local_mode=True,
-            attach=True,
-        )
-        self.emoji_list: tuple[str, ...] = parse_sequence_arg(emoji_list)
-        self.format: str = format
-        self.mask_position: Optional[MaskPosition] = mask_position
-        self.keywords: tuple[str, ...] = parse_sequence_arg(keywords)
-
-        self._freeze()
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/location.py b/venv/lib/python3.11/site-packages/telegram/_files/location.py
deleted file mode 100755
index 87c895b..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_files/location.py
+++ /dev/null
@@ -1,113 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram Location."""
-
-from typing import Final, Optional
-
-from telegram import constants
-from telegram._telegramobject import TelegramObject
-from telegram._utils.types import JSONDict
-
-
-class Location(TelegramObject):
-    """This object represents a point on the map.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`longitude` and :attr:`latitude` are equal.
-
-    Args:
-        longitude (:obj:`float`): Longitude as defined by the sender.
-        latitude (:obj:`float`): Latitude as defined by the sender.
-        horizontal_accuracy (:obj:`float`, optional): The radius of uncertainty for the location,
-            measured in meters; 0-:tg-const:`telegram.Location.HORIZONTAL_ACCURACY`.
-        live_period (:obj:`int`, optional): Time relative to the message sending date, during which
-            the location can be updated, in seconds. For active live locations only.
-        heading (:obj:`int`, optional): The direction in which user is moving, in degrees;
-            :tg-const:`telegram.Location.MIN_HEADING`-:tg-const:`telegram.Location.MAX_HEADING`.
-            For active live locations only.
-        proximity_alert_radius (:obj:`int`, optional): Maximum distance for proximity alerts about
-            approaching another chat member, in meters. For sent live locations only.
-
-    Attributes:
-        longitude (:obj:`float`): Longitude as defined by the sender.
-        latitude (:obj:`float`): Latitude as defined by the sender.
-        horizontal_accuracy (:obj:`float`): Optional. The radius of uncertainty for the location,
-            measured in meters; 0-:tg-const:`telegram.Location.HORIZONTAL_ACCURACY`.
-        live_period (:obj:`int`): Optional. Time relative to the message sending date, during which
-            the location can be updated, in seconds. For active live locations only.
-        heading (:obj:`int`): Optional. The direction in which user is moving, in degrees;
-            :tg-const:`telegram.Location.MIN_HEADING`-:tg-const:`telegram.Location.MAX_HEADING`.
-            For active live locations only.
-        proximity_alert_radius (:obj:`int`): Optional. Maximum distance for proximity alerts about
-            approaching another chat member, in meters. For sent live locations only.
-
-    """
-
-    __slots__ = (
-        "heading",
-        "horizontal_accuracy",
-        "latitude",
-        "live_period",
-        "longitude",
-        "proximity_alert_radius",
-    )
-
-    def __init__(
-        self,
-        longitude: float,
-        latitude: float,
-        horizontal_accuracy: Optional[float] = None,
-        live_period: Optional[int] = None,
-        heading: Optional[int] = None,
-        proximity_alert_radius: Optional[int] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        # Required
-        self.longitude: float = longitude
-        self.latitude: float = latitude
-
-        # Optionals
-        self.horizontal_accuracy: Optional[float] = horizontal_accuracy
-        self.live_period: Optional[int] = live_period
-        self.heading: Optional[int] = heading
-        self.proximity_alert_radius: Optional[int] = (
-            int(proximity_alert_radius) if proximity_alert_radius else None
-        )
-
-        self._id_attrs = (self.longitude, self.latitude)
-
-        self._freeze()
-
-    HORIZONTAL_ACCURACY: Final[int] = constants.LocationLimit.HORIZONTAL_ACCURACY
-    """:const:`telegram.constants.LocationLimit.HORIZONTAL_ACCURACY`
-
-    .. versionadded:: 20.0
-    """
-    MIN_HEADING: Final[int] = constants.LocationLimit.MIN_HEADING
-    """:const:`telegram.constants.LocationLimit.MIN_HEADING`
-
-    .. versionadded:: 20.0
-    """
-    MAX_HEADING: Final[int] = constants.LocationLimit.MAX_HEADING
-    """:const:`telegram.constants.LocationLimit.MAX_HEADING`
-
-    .. versionadded:: 20.0
-    """
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/photosize.py b/venv/lib/python3.11/site-packages/telegram/_files/photosize.py
deleted file mode 100755
index e06dc3b..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_files/photosize.py
+++ /dev/null
@@ -1,77 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram PhotoSize."""
-
-from typing import Optional
-
-from telegram._files._basemedium import _BaseMedium
-from telegram._utils.types import JSONDict
-
-
-class PhotoSize(_BaseMedium):
-    """This object represents one size of a photo or a file/sticker thumbnail.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`file_unique_id` is equal.
-
-    Args:
-        file_id (:obj:`str`): Identifier for this file, which can be used to download
-            or reuse the file.
-        file_unique_id (:obj:`str`): Unique identifier for this file, which
-            is supposed to be the same over time and for different bots.
-            Can't be used to download or reuse the file.
-        width (:obj:`int`): Photo width.
-        height (:obj:`int`): Photo height.
-        file_size (:obj:`int`, optional): File size in bytes.
-
-    Attributes:
-        file_id (:obj:`str`): Identifier for this file, which can be used to download
-            or reuse the file.
-        file_unique_id (:obj:`str`): Unique identifier for this file, which
-            is supposed to be the same over time and for different bots.
-            Can't be used to download or reuse the file.
-        width (:obj:`int`): Photo width.
-        height (:obj:`int`): Photo height.
-        file_size (:obj:`int`): Optional. File size in bytes.
-
-
-    """
-
-    __slots__ = ("height", "width")
-
-    def __init__(
-        self,
-        file_id: str,
-        file_unique_id: str,
-        width: int,
-        height: int,
-        file_size: Optional[int] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(
-            file_id=file_id,
-            file_unique_id=file_unique_id,
-            file_size=file_size,
-            api_kwargs=api_kwargs,
-        )
-        with self._unfrozen():
-            # Required
-            self.width: int = width
-            self.height: int = height
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/sticker.py b/venv/lib/python3.11/site-packages/telegram/_files/sticker.py
deleted file mode 100755
index d5e6d8b..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_files/sticker.py
+++ /dev/null
@@ -1,388 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains objects that represent stickers."""
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Final, Optional
-
-from telegram import constants
-from telegram._files._basethumbedmedium import _BaseThumbedMedium
-from telegram._files.file import File
-from telegram._files.photosize import PhotoSize
-from telegram._telegramobject import TelegramObject
-from telegram._utils import enum
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.types import JSONDict
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class Sticker(_BaseThumbedMedium):
-    """This object represents a sticker.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`file_unique_id` is equal.
-
-    Note:
-        As of v13.11 :paramref:`is_video` is a required argument and therefore the order of the
-        arguments had to be changed. Use keyword arguments to make sure that the arguments are
-        passed correctly.
-
-    .. versionchanged:: 20.5
-      |removed_thumb_note|
-
-    Args:
-        file_id (:obj:`str`): Identifier for this file, which can be used to download
-            or reuse the file.
-        file_unique_id (:obj:`str`): Unique identifier for this file, which
-            is supposed to be the same over time and for different bots.
-            Can't be used to download or reuse the file.
-        width (:obj:`int`): Sticker width.
-        height (:obj:`int`): Sticker height.
-        is_animated (:obj:`bool`): :obj:`True`, if the sticker is animated.
-        is_video (:obj:`bool`): :obj:`True`, if the sticker is a video sticker.
-
-            .. versionadded:: 13.11
-        type (:obj:`str`): Type of the sticker. Currently one of :attr:`REGULAR`,
-            :attr:`MASK`, :attr:`CUSTOM_EMOJI`. The type of the sticker is independent from its
-            format, which is determined by the fields :attr:`is_animated` and :attr:`is_video`.
-
-            .. versionadded:: 20.0
-        emoji (:obj:`str`, optional): Emoji associated with the sticker
-        set_name (:obj:`str`, optional): Name of the sticker set to which the sticker belongs.
-        mask_position (:class:`telegram.MaskPosition`, optional): For mask stickers, the position
-            where the mask should be placed.
-        file_size (:obj:`int`, optional): File size in bytes.
-
-        premium_animation (:class:`telegram.File`, optional): For premium regular stickers,
-            premium animation for the sticker.
-
-            .. versionadded:: 20.0
-        custom_emoji_id (:obj:`str`, optional): For custom emoji stickers, unique identifier of the
-            custom emoji.
-
-            .. versionadded:: 20.0
-        thumbnail (:class:`telegram.PhotoSize`, optional): Sticker thumbnail in the ``.WEBP`` or
-            ``.JPG`` format.
-
-            .. versionadded:: 20.2
-        needs_repainting (:obj:`bool`, optional): :obj:`True`, if the sticker must be repainted to
-            a text color in messages, the color of the Telegram Premium badge in emoji status,
-            white color on chat photos, or another appropriate color in other places.
-
-            .. versionadded:: 20.2
-
-    Attributes:
-        file_id (:obj:`str`): Identifier for this file, which can be used to download
-            or reuse the file.
-        file_unique_id (:obj:`str`): Unique identifier for this file, which
-            is supposed to be the same over time and for different bots.
-            Can't be used to download or reuse the file.
-        width (:obj:`int`): Sticker width.
-        height (:obj:`int`): Sticker height.
-        is_animated (:obj:`bool`): :obj:`True`, if the sticker is animated.
-        is_video (:obj:`bool`): :obj:`True`, if the sticker is a video sticker.
-
-            .. versionadded:: 13.11
-        type (:obj:`str`): Type of the sticker. Currently one of :attr:`REGULAR`,
-            :attr:`MASK`, :attr:`CUSTOM_EMOJI`. The type of the sticker is independent from its
-            format, which is determined by the fields :attr:`is_animated` and :attr:`is_video`.
-
-            .. versionadded:: 20.0
-        emoji (:obj:`str`): Optional. Emoji associated with the sticker.
-        set_name (:obj:`str`): Optional. Name of the sticker set to which the sticker belongs.
-        mask_position (:class:`telegram.MaskPosition`): Optional. For mask stickers, the position
-            where the mask should be placed.
-        file_size (:obj:`int`): Optional. File size in bytes.
-
-        premium_animation (:class:`telegram.File`): Optional. For premium regular stickers,
-            premium animation for the sticker.
-
-            .. versionadded:: 20.0
-        custom_emoji_id (:obj:`str`): Optional. For custom emoji stickers, unique identifier of the
-            custom emoji.
-
-            .. versionadded:: 20.0
-        thumbnail (:class:`telegram.PhotoSize`): Optional. Sticker thumbnail in the ``.WEBP`` or
-            ``.JPG`` format.
-
-            .. versionadded:: 20.2
-        needs_repainting (:obj:`bool`): Optional. :obj:`True`, if the sticker must be repainted to
-            a text color in messages, the color of the Telegram Premium badge in emoji status,
-            white color on chat photos, or another appropriate color in other places.
-
-            .. versionadded:: 20.2
-    """
-
-    __slots__ = (
-        "custom_emoji_id",
-        "emoji",
-        "height",
-        "is_animated",
-        "is_video",
-        "mask_position",
-        "needs_repainting",
-        "premium_animation",
-        "set_name",
-        "type",
-        "width",
-    )
-
-    def __init__(
-        self,
-        file_id: str,
-        file_unique_id: str,
-        width: int,
-        height: int,
-        is_animated: bool,
-        is_video: bool,
-        type: str,  # pylint: disable=redefined-builtin
-        emoji: Optional[str] = None,
-        file_size: Optional[int] = None,
-        set_name: Optional[str] = None,
-        mask_position: Optional["MaskPosition"] = None,
-        premium_animation: Optional["File"] = None,
-        custom_emoji_id: Optional[str] = None,
-        thumbnail: Optional[PhotoSize] = None,
-        needs_repainting: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(
-            file_id=file_id,
-            file_unique_id=file_unique_id,
-            file_size=file_size,
-            thumbnail=thumbnail,
-            api_kwargs=api_kwargs,
-        )
-        with self._unfrozen():
-            # Required
-            self.width: int = width
-            self.height: int = height
-            self.is_animated: bool = is_animated
-            self.is_video: bool = is_video
-            self.type: str = enum.get_member(constants.StickerType, type, type)
-            # Optional
-            self.emoji: Optional[str] = emoji
-            self.set_name: Optional[str] = set_name
-            self.mask_position: Optional[MaskPosition] = mask_position
-            self.premium_animation: Optional[File] = premium_animation
-            self.custom_emoji_id: Optional[str] = custom_emoji_id
-            self.needs_repainting: Optional[bool] = needs_repainting
-
-    REGULAR: Final[str] = constants.StickerType.REGULAR
-    """:const:`telegram.constants.StickerType.REGULAR`"""
-    MASK: Final[str] = constants.StickerType.MASK
-    """:const:`telegram.constants.StickerType.MASK`"""
-    CUSTOM_EMOJI: Final[str] = constants.StickerType.CUSTOM_EMOJI
-    """:const:`telegram.constants.StickerType.CUSTOM_EMOJI`"""
-
-    @classmethod
-    def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Sticker"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        data["thumbnail"] = PhotoSize.de_json(data.get("thumbnail"), bot)
-        data["mask_position"] = MaskPosition.de_json(data.get("mask_position"), bot)
-        data["premium_animation"] = File.de_json(data.get("premium_animation"), bot)
-
-        api_kwargs = {}
-        # This is a deprecated field that TG still returns for backwards compatibility
-        # Let's filter it out to speed up the de-json process
-        if data.get("thumb") is not None:
-            api_kwargs["thumb"] = data.pop("thumb")
-
-        return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs)
-
-
-class StickerSet(TelegramObject):
-    """This object represents a sticker set.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`name` is equal.
-
-    Note:
-        As of v13.11 :paramref:`is_video` is a required argument and therefore the order of the
-        arguments had to be changed. Use keyword arguments to make sure that the arguments are
-        passed correctly.
-
-    .. versionchanged:: 20.0
-        The parameter ``contains_masks`` has been removed. Use :paramref:`sticker_type` instead.
-
-
-    .. versionchanged:: 21.1
-        The parameters ``is_video`` and ``is_animated`` are deprecated and now made optional. Thus,
-        the order of the arguments had to be changed.
-
-    .. versionchanged:: 20.5
-       |removed_thumb_note|
-
-    .. versionremoved:: 21.2
-       Removed the deprecated arguments and attributes ``is_animated`` and ``is_video``.
-
-    Args:
-        name (:obj:`str`): Sticker set name.
-        title (:obj:`str`): Sticker set title.
-        stickers (Sequence[:class:`telegram.Sticker`]): List of all set stickers.
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        sticker_type (:obj:`str`): Type of stickers in the set, currently one of
-            :attr:`telegram.Sticker.REGULAR`, :attr:`telegram.Sticker.MASK`,
-            :attr:`telegram.Sticker.CUSTOM_EMOJI`.
-
-            .. versionadded:: 20.0
-        thumbnail (:class:`telegram.PhotoSize`, optional): Sticker set thumbnail in the ``.WEBP``,
-            ``.TGS``, or ``.WEBM`` format.
-
-            .. versionadded:: 20.2
-
-    Attributes:
-        name (:obj:`str`): Sticker set name.
-        title (:obj:`str`): Sticker set title.
-        stickers (tuple[:class:`telegram.Sticker`]): List of all set stickers.
-
-            .. versionchanged:: 20.0
-                |tupleclassattrs|
-
-        sticker_type (:obj:`str`): Type of stickers in the set, currently one of
-            :attr:`telegram.Sticker.REGULAR`, :attr:`telegram.Sticker.MASK`,
-            :attr:`telegram.Sticker.CUSTOM_EMOJI`.
-
-            .. versionadded:: 20.0
-        thumbnail (:class:`telegram.PhotoSize`): Optional. Sticker set thumbnail in the ``.WEBP``,
-            ``.TGS``, or ``.WEBM`` format.
-
-            .. versionadded:: 20.2
-    """
-
-    __slots__ = (
-        "name",
-        "sticker_type",
-        "stickers",
-        "thumbnail",
-        "title",
-    )
-
-    def __init__(
-        self,
-        name: str,
-        title: str,
-        stickers: Sequence[Sticker],
-        sticker_type: str,
-        thumbnail: Optional[PhotoSize] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.name: str = name
-        self.title: str = title
-        self.stickers: tuple[Sticker, ...] = parse_sequence_arg(stickers)
-        self.sticker_type: str = sticker_type
-        # Optional
-        self.thumbnail: Optional[PhotoSize] = thumbnail
-        self._id_attrs = (self.name,)
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["StickerSet"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        if not data:
-            return None
-
-        data["thumbnail"] = PhotoSize.de_json(data.get("thumbnail"), bot)
-        data["stickers"] = Sticker.de_list(data.get("stickers"), bot)
-
-        api_kwargs = {}
-        # These are deprecated fields that TG still returns for backwards compatibility
-        # Let's filter them out to speed up the de-json process
-        for deprecated_field in ("contains_masks", "thumb", "is_animated", "is_video"):
-            if deprecated_field in data:
-                api_kwargs[deprecated_field] = data.pop(deprecated_field)
-
-        return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs)
-
-
-class MaskPosition(TelegramObject):
-    """This object describes the position on faces where a mask should be placed by default.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`point`, :attr:`x_shift`, :attr:`y_shift` and, :attr:`scale`
-    are equal.
-
-    Args:
-        point (:obj:`str`): The part of the face relative to which the mask should be placed.
-            One of :attr:`FOREHEAD`, :attr:`EYES`, :attr:`MOUTH`, or :attr:`CHIN`.
-        x_shift (:obj:`float`): Shift by X-axis measured in widths of the mask scaled to the face
-            size, from left to right. For example, choosing ``-1.0`` will place mask just to the
-            left of the default mask position.
-        y_shift (:obj:`float`): Shift by Y-axis measured in heights of the mask scaled to the face
-            size, from top to bottom. For example, ``1.0`` will place the mask just below the
-            default mask position.
-        scale (:obj:`float`): Mask scaling coefficient. For example, ``2.0`` means double size.
-
-    Attributes:
-        point (:obj:`str`): The part of the face relative to which the mask should be placed.
-            One of :attr:`FOREHEAD`, :attr:`EYES`, :attr:`MOUTH`, or :attr:`CHIN`.
-        x_shift (:obj:`float`): Shift by X-axis measured in widths of the mask scaled to the face
-            size, from left to right. For example, choosing ``-1.0`` will place mask just to the
-            left of the default mask position.
-        y_shift (:obj:`float`): Shift by Y-axis measured in heights of the mask scaled to the face
-            size, from top to bottom. For example, ``1.0`` will place the mask just below the
-            default mask position.
-        scale (:obj:`float`): Mask scaling coefficient. For example, ``2.0`` means double size.
-
-    """
-
-    __slots__ = ("point", "scale", "x_shift", "y_shift")
-
-    FOREHEAD: Final[str] = constants.MaskPosition.FOREHEAD
-    """:const:`telegram.constants.MaskPosition.FOREHEAD`"""
-    EYES: Final[str] = constants.MaskPosition.EYES
-    """:const:`telegram.constants.MaskPosition.EYES`"""
-    MOUTH: Final[str] = constants.MaskPosition.MOUTH
-    """:const:`telegram.constants.MaskPosition.MOUTH`"""
-    CHIN: Final[str] = constants.MaskPosition.CHIN
-    """:const:`telegram.constants.MaskPosition.CHIN`"""
-
-    def __init__(
-        self,
-        point: str,
-        x_shift: float,
-        y_shift: float,
-        scale: float,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.point: str = point
-        self.x_shift: float = x_shift
-        self.y_shift: float = y_shift
-        self.scale: float = scale
-
-        self._id_attrs = (self.point, self.x_shift, self.y_shift, self.scale)
-
-        self._freeze()
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/venue.py b/venv/lib/python3.11/site-packages/telegram/_files/venue.py
deleted file mode 100755
index c169a52..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_files/venue.py
+++ /dev/null
@@ -1,115 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram Venue."""
-
-from typing import TYPE_CHECKING, Optional
-
-from telegram._files.location import Location
-from telegram._telegramobject import TelegramObject
-from telegram._utils.types import JSONDict
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class Venue(TelegramObject):
-    """This object represents a venue.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`location` and :attr:`title` are equal.
-
-    Note:
-      Foursquare details and Google Place details are mutually exclusive. However, this
-      behaviour is undocumented and might be changed by Telegram.
-
-    Args:
-        location (:class:`telegram.Location`): Venue location.
-        title (:obj:`str`): Name of the venue.
-        address (:obj:`str`): Address of the venue.
-        foursquare_id (:obj:`str`, optional): Foursquare identifier of the venue.
-        foursquare_type (:obj:`str`, optional): Foursquare type of the venue. (For example,
-            "arts_entertainment/default", "arts_entertainment/aquarium" or "food/icecream".)
-        google_place_id (:obj:`str`, optional): Google Places identifier of the venue.
-        google_place_type (:obj:`str`, optional): Google Places type of the venue. (See
-            `supported types `_.)
-
-    Attributes:
-        location (:class:`telegram.Location`): Venue location.
-        title (:obj:`str`): Name of the venue.
-        address (:obj:`str`): Address of the venue.
-        foursquare_id (:obj:`str`): Optional. Foursquare identifier of the venue.
-        foursquare_type (:obj:`str`): Optional. Foursquare type of the venue. (For example,
-            "arts_entertainment/default", "arts_entertainment/aquarium" or "food/icecream".)
-        google_place_id (:obj:`str`): Optional. Google Places identifier of the venue.
-        google_place_type (:obj:`str`): Optional. Google Places type of the venue. (See
-            `supported types `_.)
-
-    """
-
-    __slots__ = (
-        "address",
-        "foursquare_id",
-        "foursquare_type",
-        "google_place_id",
-        "google_place_type",
-        "location",
-        "title",
-    )
-
-    def __init__(
-        self,
-        location: Location,
-        title: str,
-        address: str,
-        foursquare_id: Optional[str] = None,
-        foursquare_type: Optional[str] = None,
-        google_place_id: Optional[str] = None,
-        google_place_type: Optional[str] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-
-        # Required
-        self.location: Location = location
-        self.title: str = title
-        self.address: str = address
-        # Optionals
-        self.foursquare_id: Optional[str] = foursquare_id
-        self.foursquare_type: Optional[str] = foursquare_type
-        self.google_place_id: Optional[str] = google_place_id
-        self.google_place_type: Optional[str] = google_place_type
-
-        self._id_attrs = (self.location, self.title)
-
-        self._freeze()
-
-    @classmethod
-    def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Venue"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        data["location"] = Location.de_json(data.get("location"), bot)
-
-        return super().de_json(data=data, bot=bot)
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/video.py b/venv/lib/python3.11/site-packages/telegram/_files/video.py
deleted file mode 100755
index c5ca6f3..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_files/video.py
+++ /dev/null
@@ -1,99 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram Video."""
-from typing import Optional
-
-from telegram._files._basethumbedmedium import _BaseThumbedMedium
-from telegram._files.photosize import PhotoSize
-from telegram._utils.types import JSONDict
-
-
-class Video(_BaseThumbedMedium):
-    """This object represents a video file.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`file_unique_id` is equal.
-
-    .. versionchanged:: 20.5
-      |removed_thumb_note|
-
-    Args:
-        file_id (:obj:`str`): Identifier for this file, which can be used to download
-            or reuse the file.
-        file_unique_id (:obj:`str`): Unique identifier for this file, which
-            is supposed to be the same over time and for different bots.
-            Can't be used to download or reuse the file.
-        width (:obj:`int`): Video width as defined by the sender.
-        height (:obj:`int`): Video height as defined by the sender.
-        duration (:obj:`int`): Duration of the video in seconds as defined by the sender.
-        file_name (:obj:`str`, optional): Original filename as defined by the sender.
-        mime_type (:obj:`str`, optional): MIME type of a file as defined by the sender.
-        file_size (:obj:`int`, optional): File size in bytes.
-        thumbnail (:class:`telegram.PhotoSize`, optional): Video thumbnail.
-
-            .. versionadded:: 20.2
-
-    Attributes:
-        file_id (:obj:`str`): Identifier for this file, which can be used to download
-            or reuse the file.
-        file_unique_id (:obj:`str`): Unique identifier for this file, which
-            is supposed to be the same over time and for different bots.
-            Can't be used to download or reuse the file.
-        width (:obj:`int`): Video width as defined by the sender.
-        height (:obj:`int`): Video height as defined by the sender.
-        duration (:obj:`int`): Duration of the video in seconds as defined by the sender.
-        file_name (:obj:`str`): Optional. Original filename as defined by the sender.
-        mime_type (:obj:`str`): Optional. MIME type of a file as defined by the sender.
-        file_size (:obj:`int`): Optional. File size in bytes.
-        thumbnail (:class:`telegram.PhotoSize`): Optional. Video thumbnail.
-
-            .. versionadded:: 20.2
-    """
-
-    __slots__ = ("duration", "file_name", "height", "mime_type", "width")
-
-    def __init__(
-        self,
-        file_id: str,
-        file_unique_id: str,
-        width: int,
-        height: int,
-        duration: int,
-        mime_type: Optional[str] = None,
-        file_size: Optional[int] = None,
-        file_name: Optional[str] = None,
-        thumbnail: Optional[PhotoSize] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(
-            file_id=file_id,
-            file_unique_id=file_unique_id,
-            file_size=file_size,
-            thumbnail=thumbnail,
-            api_kwargs=api_kwargs,
-        )
-        with self._unfrozen():
-            # Required
-            self.width: int = width
-            self.height: int = height
-            self.duration: int = duration
-            # Optional
-            self.mime_type: Optional[str] = mime_type
-            self.file_name: Optional[str] = file_name
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/videonote.py b/venv/lib/python3.11/site-packages/telegram/_files/videonote.py
deleted file mode 100755
index edb9e55..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_files/videonote.py
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram VideoNote."""
-
-from typing import Optional
-
-from telegram._files._basethumbedmedium import _BaseThumbedMedium
-from telegram._files.photosize import PhotoSize
-from telegram._utils.types import JSONDict
-
-
-class VideoNote(_BaseThumbedMedium):
-    """This object represents a video message (available in Telegram apps as of v.4.0).
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`file_unique_id` is equal.
-
-    .. versionchanged:: 20.5
-      |removed_thumb_note|
-
-    Args:
-        file_id (:obj:`str`): Identifier for this file, which can be used to download
-            or reuse the file.
-        file_unique_id (:obj:`str`): Unique identifier for this file, which
-            is supposed to be the same over time and for different bots.
-            Can't be used to download or reuse the file.
-        length (:obj:`int`): Video width and height (diameter of the video message) as defined
-            by sender.
-        duration (:obj:`int`): Duration of the video in seconds as defined by the sender.
-        file_size (:obj:`int`, optional): File size in bytes.
-        thumbnail (:class:`telegram.PhotoSize`, optional): Video thumbnail.
-
-            .. versionadded:: 20.2
-
-    Attributes:
-        file_id (:obj:`str`): Identifier for this file, which can be used to download
-            or reuse the file.
-        file_unique_id (:obj:`str`): Unique identifier for this file, which
-            is supposed to be the same over time and for different bots.
-            Can't be used to download or reuse the file.
-        length (:obj:`int`): Video width and height (diameter of the video message) as defined
-            by sender.
-        duration (:obj:`int`): Duration of the video in seconds as defined by the sender.
-        file_size (:obj:`int`): Optional. File size in bytes.
-        thumbnail (:class:`telegram.PhotoSize`): Optional. Video thumbnail.
-
-            .. versionadded:: 20.2
-
-    """
-
-    __slots__ = ("duration", "length")
-
-    def __init__(
-        self,
-        file_id: str,
-        file_unique_id: str,
-        length: int,
-        duration: int,
-        file_size: Optional[int] = None,
-        thumbnail: Optional[PhotoSize] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(
-            file_id=file_id,
-            file_unique_id=file_unique_id,
-            file_size=file_size,
-            thumbnail=thumbnail,
-            api_kwargs=api_kwargs,
-        )
-        with self._unfrozen():
-            # Required
-            self.length: int = length
-            self.duration: int = duration
diff --git a/venv/lib/python3.11/site-packages/telegram/_files/voice.py b/venv/lib/python3.11/site-packages/telegram/_files/voice.py
deleted file mode 100755
index 19c0e85..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_files/voice.py
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram Voice."""
-from typing import Optional
-
-from telegram._files._basemedium import _BaseMedium
-from telegram._utils.types import JSONDict
-
-
-class Voice(_BaseMedium):
-    """This object represents a voice note.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`file_unique_id` is equal.
-
-    Args:
-        file_id (:obj:`str`): Identifier for this file, which can be used to download
-            or reuse the file.
-        file_unique_id (:obj:`str`): Unique identifier for this file, which
-            is supposed to be the same over time and for different bots.
-            Can't be used to download or reuse the file.
-        duration (:obj:`int`): Duration of the audio in seconds as defined by the sender.
-        mime_type (:obj:`str`, optional): MIME type of the file as defined by the sender.
-        file_size (:obj:`int`, optional): File size in bytes.
-
-    Attributes:
-        file_id (:obj:`str`): Identifier for this file, which can be used to download
-            or reuse the file.
-        file_unique_id (:obj:`str`): Unique identifier for this file, which
-            is supposed to be the same over time and for different bots.
-            Can't be used to download or reuse the file.
-        duration (:obj:`int`): Duration of the audio in seconds as defined by the sender.
-        mime_type (:obj:`str`): Optional. MIME type of the file as defined by the sender.
-        file_size (:obj:`int`): Optional. File size in bytes.
-
-    """
-
-    __slots__ = ("duration", "mime_type")
-
-    def __init__(
-        self,
-        file_id: str,
-        file_unique_id: str,
-        duration: int,
-        mime_type: Optional[str] = None,
-        file_size: Optional[int] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(
-            file_id=file_id,
-            file_unique_id=file_unique_id,
-            file_size=file_size,
-            api_kwargs=api_kwargs,
-        )
-        with self._unfrozen():
-            # Required
-            self.duration: int = duration
-            # Optional
-            self.mime_type: Optional[str] = mime_type
diff --git a/venv/lib/python3.11/site-packages/telegram/_forcereply.py b/venv/lib/python3.11/site-packages/telegram/_forcereply.py
deleted file mode 100755
index b24b271..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_forcereply.py
+++ /dev/null
@@ -1,106 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram ForceReply."""
-
-from typing import Final, Optional
-
-from telegram import constants
-from telegram._telegramobject import TelegramObject
-from telegram._utils.types import JSONDict
-
-
-class ForceReply(TelegramObject):
-    """
-    Upon receiving a message with this object, Telegram clients will display a reply interface to
-    the user (act as if the user has selected the bot's message and tapped 'Reply'). This can be
-    extremely useful if you want to create user-friendly step-by-step interfaces without having
-    to sacrifice `privacy mode `_. Not
-    supported in channels and for messages sent on behalf of a Telegram Business account.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`selective` is equal.
-
-    .. versionchanged:: 20.0
-        The (undocumented) argument ``force_reply`` was removed and instead :attr:`force_reply`
-        is now always set to :obj:`True` as expected by the Bot API.
-
-    Args:
-        selective (:obj:`bool`, optional): Use this parameter if you want to force reply from
-            specific users only. Targets:
-
-            1) Users that are @mentioned in the :attr:`~telegram.Message.text` of the
-               :class:`telegram.Message` object.
-            2) If the bot's message is a reply to a message in the same chat and forum topic,
-               sender of the original message.
-
-        input_field_placeholder (:obj:`str`, optional): The placeholder to be shown in the input
-            field when the reply is active;
-            :tg-const:`telegram.ForceReply.MIN_INPUT_FIELD_PLACEHOLDER`-
-            :tg-const:`telegram.ForceReply.MAX_INPUT_FIELD_PLACEHOLDER`
-            characters.
-
-            .. versionadded:: 13.7
-
-    Attributes:
-        force_reply (:obj:`True`): Shows reply interface to the user, as if they manually selected
-            the bots message and tapped 'Reply'.
-        selective (:obj:`bool`): Optional. Force reply from specific users only. Targets:
-
-            1) Users that are @mentioned in the :attr:`~telegram.Message.text` of the
-               :class:`telegram.Message` object.
-            2) If the bot's message is a reply to a message in the same chat and forum topic,
-                sender of the original message.
-        input_field_placeholder (:obj:`str`): Optional. The placeholder to be shown in the input
-            field when the reply is active;
-            :tg-const:`telegram.ForceReply.MIN_INPUT_FIELD_PLACEHOLDER`-
-            :tg-const:`telegram.ForceReply.MAX_INPUT_FIELD_PLACEHOLDER`
-            characters.
-
-            .. versionadded:: 13.7
-
-    """
-
-    __slots__ = ("force_reply", "input_field_placeholder", "selective")
-
-    def __init__(
-        self,
-        selective: Optional[bool] = None,
-        input_field_placeholder: Optional[str] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.force_reply: bool = True
-        self.selective: Optional[bool] = selective
-        self.input_field_placeholder: Optional[str] = input_field_placeholder
-
-        self._id_attrs = (self.selective,)
-
-        self._freeze()
-
-    MIN_INPUT_FIELD_PLACEHOLDER: Final[int] = constants.ReplyLimit.MIN_INPUT_FIELD_PLACEHOLDER
-    """:const:`telegram.constants.ReplyLimit.MIN_INPUT_FIELD_PLACEHOLDER`
-
-    .. versionadded:: 20.0
-    """
-    MAX_INPUT_FIELD_PLACEHOLDER: Final[int] = constants.ReplyLimit.MAX_INPUT_FIELD_PLACEHOLDER
-    """:const:`telegram.constants.ReplyLimit.MAX_INPUT_FIELD_PLACEHOLDER`
-
-    .. versionadded:: 20.0
-    """
diff --git a/venv/lib/python3.11/site-packages/telegram/_forumtopic.py b/venv/lib/python3.11/site-packages/telegram/_forumtopic.py
deleted file mode 100755
index 81b64e2..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_forumtopic.py
+++ /dev/null
@@ -1,215 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains objects related to Telegram forum topics."""
-from typing import Optional
-
-from telegram._telegramobject import TelegramObject
-from telegram._utils.types import JSONDict
-
-
-class ForumTopic(TelegramObject):
-    """
-    This object represents a forum topic.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`message_thread_id`, :attr:`name` and :attr:`icon_color`
-    are equal.
-
-    .. versionadded:: 20.0
-
-    Args:
-        message_thread_id (:obj:`int`): Unique identifier of the forum topic
-        name (:obj:`str`): Name of the topic
-        icon_color (:obj:`int`): Color of the topic icon in RGB format
-        icon_custom_emoji_id (:obj:`str`, optional): Unique identifier of the custom emoji shown
-            as the topic icon.
-
-    Attributes:
-        message_thread_id (:obj:`int`): Unique identifier of the forum topic
-        name (:obj:`str`): Name of the topic
-        icon_color (:obj:`int`): Color of the topic icon in RGB format
-        icon_custom_emoji_id (:obj:`str`): Optional. Unique identifier of the custom emoji shown
-            as the topic icon.
-    """
-
-    __slots__ = ("icon_color", "icon_custom_emoji_id", "message_thread_id", "name")
-
-    def __init__(
-        self,
-        message_thread_id: int,
-        name: str,
-        icon_color: int,
-        icon_custom_emoji_id: Optional[str] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.message_thread_id: int = message_thread_id
-        self.name: str = name
-        self.icon_color: int = icon_color
-        self.icon_custom_emoji_id: Optional[str] = icon_custom_emoji_id
-
-        self._id_attrs = (self.message_thread_id, self.name, self.icon_color)
-
-        self._freeze()
-
-
-class ForumTopicCreated(TelegramObject):
-    """
-    This object represents the content of a service message about a new forum topic created in
-    the chat.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`name` and :attr:`icon_color` are equal.
-
-    .. versionadded:: 20.0
-
-    Args:
-        name (:obj:`str`): Name of the topic
-        icon_color (:obj:`int`): Color of the topic icon in RGB format
-        icon_custom_emoji_id (:obj:`str`, optional): Unique identifier of the custom emoji shown
-            as the topic icon.
-
-    Attributes:
-        name (:obj:`str`): Name of the topic
-        icon_color (:obj:`int`): Color of the topic icon in RGB format
-        icon_custom_emoji_id (:obj:`str`): Optional. Unique identifier of the custom emoji shown
-            as the topic icon.
-    """
-
-    __slots__ = ("icon_color", "icon_custom_emoji_id", "name")
-
-    def __init__(
-        self,
-        name: str,
-        icon_color: int,
-        icon_custom_emoji_id: Optional[str] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.name: str = name
-        self.icon_color: int = icon_color
-        self.icon_custom_emoji_id: Optional[str] = icon_custom_emoji_id
-
-        self._id_attrs = (self.name, self.icon_color)
-
-        self._freeze()
-
-
-class ForumTopicClosed(TelegramObject):
-    """
-    This object represents a service message about a forum topic closed in the chat.
-    Currently holds no information.
-
-    .. versionadded:: 20.0
-    """
-
-    __slots__ = ()
-
-    def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None:
-        super().__init__(api_kwargs=api_kwargs)
-
-        self._freeze()
-
-
-class ForumTopicReopened(TelegramObject):
-    """
-    This object represents a service message about a forum topic reopened in the chat.
-    Currently holds no information.
-
-    .. versionadded:: 20.0
-    """
-
-    __slots__ = ()
-
-    def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None:
-        super().__init__(api_kwargs=api_kwargs)
-
-        self._freeze()
-
-
-class ForumTopicEdited(TelegramObject):
-    """
-    This object represents a service message about an edited forum topic.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`name` and :attr:`icon_custom_emoji_id` are equal.
-
-    .. versionadded:: 20.0
-
-    Args:
-        name (:obj:`str`, optional): New name of the topic, if it was edited.
-        icon_custom_emoji_id (:obj:`str`, optional): New identifier of the custom emoji shown as
-            the topic icon, if it was edited; an empty string if the icon was removed.
-
-    Attributes:
-        name (:obj:`str`): Optional. New name of the topic, if it was edited.
-        icon_custom_emoji_id (:obj:`str`): Optional. New identifier of the custom emoji shown as
-            the topic icon, if it was edited; an empty string if the icon was removed.
-    """
-
-    __slots__ = ("icon_custom_emoji_id", "name")
-
-    def __init__(
-        self,
-        name: Optional[str] = None,
-        icon_custom_emoji_id: Optional[str] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.name: Optional[str] = name
-        self.icon_custom_emoji_id: Optional[str] = icon_custom_emoji_id
-
-        self._id_attrs = (self.name, self.icon_custom_emoji_id)
-
-        self._freeze()
-
-
-class GeneralForumTopicHidden(TelegramObject):
-    """
-    This object represents a service message about General forum topic hidden in the chat.
-    Currently holds no information.
-
-    .. versionadded:: 20.0
-    """
-
-    __slots__ = ()
-
-    def __init__(self, *, api_kwargs: Optional[JSONDict] = None):
-        super().__init__(api_kwargs=api_kwargs)
-
-        self._freeze()
-
-
-class GeneralForumTopicUnhidden(TelegramObject):
-    """
-    This object represents a service message about General forum topic unhidden in the chat.
-    Currently holds no information.
-
-    .. versionadded:: 20.0
-    """
-
-    __slots__ = ()
-
-    def __init__(self, *, api_kwargs: Optional[JSONDict] = None):
-        super().__init__(api_kwargs=api_kwargs)
-
-        self._freeze()
diff --git a/venv/lib/python3.11/site-packages/telegram/_games/__init__.py b/venv/lib/python3.11/site-packages/telegram/_games/__init__.py
deleted file mode 100755
index e69de29..0000000
diff --git a/venv/lib/python3.11/site-packages/telegram/_games/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_games/__pycache__/__init__.cpython-311.pyc
deleted file mode 100755
index a2d2c34..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_games/__pycache__/__init__.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_games/__pycache__/callbackgame.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_games/__pycache__/callbackgame.cpython-311.pyc
deleted file mode 100755
index e6cbcb3..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_games/__pycache__/callbackgame.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_games/__pycache__/game.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_games/__pycache__/game.cpython-311.pyc
deleted file mode 100755
index f2cb20c..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_games/__pycache__/game.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_games/__pycache__/gamehighscore.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_games/__pycache__/gamehighscore.cpython-311.pyc
deleted file mode 100755
index 234749a..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_games/__pycache__/gamehighscore.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_games/callbackgame.py b/venv/lib/python3.11/site-packages/telegram/_games/callbackgame.py
deleted file mode 100755
index 0917a11..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_games/callbackgame.py
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram CallbackGame."""
-
-from typing import Optional
-
-from telegram._telegramobject import TelegramObject
-from telegram._utils.types import JSONDict
-
-
-class CallbackGame(TelegramObject):
-    """A placeholder, currently holds no information. Use BotFather to set up your game."""
-
-    __slots__ = ()
-
-    def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None:
-        super().__init__(api_kwargs=api_kwargs)
-
-        self._freeze()
diff --git a/venv/lib/python3.11/site-packages/telegram/_games/game.py b/venv/lib/python3.11/site-packages/telegram/_games/game.py
deleted file mode 100755
index ab74276..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_games/game.py
+++ /dev/null
@@ -1,197 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram Game."""
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Optional
-
-from telegram._files.animation import Animation
-from telegram._files.photosize import PhotoSize
-from telegram._messageentity import MessageEntity
-from telegram._telegramobject import TelegramObject
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.strings import TextEncoding
-from telegram._utils.types import JSONDict
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class Game(TelegramObject):
-    """
-    This object represents a game. Use `BotFather `_ to create and edit
-    games, their short names will act as unique identifiers.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`title`, :attr:`description` and :attr:`photo` are equal.
-
-    Args:
-        title (:obj:`str`): Title of the game.
-        description (:obj:`str`): Description of the game.
-        photo (Sequence[:class:`telegram.PhotoSize`]): Photo that will be displayed in the game
-            message in chats.
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        text (:obj:`str`, optional): Brief description of the game or high scores included in the
-            game message. Can be automatically edited to include current high scores for the game
-            when the bot calls :meth:`telegram.Bot.set_game_score`, or manually edited
-            using :meth:`telegram.Bot.edit_message_text`.
-            0-:tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters.
-        text_entities (Sequence[:class:`telegram.MessageEntity`], optional): Special entities that
-            appear in text, such as usernames, URLs, bot commands, etc.
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        animation (:class:`telegram.Animation`, optional): Animation that will be displayed in the
-            game message in chats. Upload via `BotFather `_.
-
-    Attributes:
-        title (:obj:`str`): Title of the game.
-        description (:obj:`str`): Description of the game.
-        photo (tuple[:class:`telegram.PhotoSize`]): Photo that will be displayed in the game
-            message in chats.
-
-            .. versionchanged:: 20.0
-                |tupleclassattrs|
-
-        text (:obj:`str`): Optional. Brief description of the game or high scores included in the
-            game message. Can be automatically edited to include current high scores for the game
-            when the bot calls :meth:`telegram.Bot.set_game_score`, or manually edited
-            using :meth:`telegram.Bot.edit_message_text`.
-            0-:tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters.
-        text_entities (tuple[:class:`telegram.MessageEntity`]): Optional. Special entities that
-            appear in text, such as usernames, URLs, bot commands, etc.
-            This tuple is empty if the message does not contain text entities.
-
-            .. versionchanged:: 20.0
-                |tupleclassattrs|
-
-        animation (:class:`telegram.Animation`): Optional. Animation that will be displayed in the
-            game message in chats. Upload via `BotFather `_.
-
-    """
-
-    __slots__ = (
-        "animation",
-        "description",
-        "photo",
-        "text",
-        "text_entities",
-        "title",
-    )
-
-    def __init__(
-        self,
-        title: str,
-        description: str,
-        photo: Sequence[PhotoSize],
-        text: Optional[str] = None,
-        text_entities: Optional[Sequence[MessageEntity]] = None,
-        animation: Optional[Animation] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        # Required
-        self.title: str = title
-        self.description: str = description
-        self.photo: tuple[PhotoSize, ...] = parse_sequence_arg(photo)
-        # Optionals
-        self.text: Optional[str] = text
-        self.text_entities: tuple[MessageEntity, ...] = parse_sequence_arg(text_entities)
-        self.animation: Optional[Animation] = animation
-
-        self._id_attrs = (self.title, self.description, self.photo)
-
-        self._freeze()
-
-    @classmethod
-    def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Game"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        data["photo"] = PhotoSize.de_list(data.get("photo"), bot)
-        data["text_entities"] = MessageEntity.de_list(data.get("text_entities"), bot)
-        data["animation"] = Animation.de_json(data.get("animation"), bot)
-
-        return super().de_json(data=data, bot=bot)
-
-    def parse_text_entity(self, entity: MessageEntity) -> str:
-        """Returns the text from a given :class:`telegram.MessageEntity`.
-
-        Note:
-            This method is present because Telegram calculates the offset and length in
-            UTF-16 codepoint pairs, which some versions of Python don't handle automatically.
-            (That is, you can't just slice ``Message.text`` with the offset and length.)
-
-        Args:
-            entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must
-                be an entity that belongs to this message.
-
-        Returns:
-            :obj:`str`: The text of the given entity.
-
-        Raises:
-            RuntimeError: If this game has no text.
-
-        """
-        if not self.text:
-            raise RuntimeError("This Game has no 'text'.")
-
-        entity_text = self.text.encode(TextEncoding.UTF_16_LE)
-        entity_text = entity_text[entity.offset * 2 : (entity.offset + entity.length) * 2]
-
-        return entity_text.decode(TextEncoding.UTF_16_LE)
-
-    def parse_text_entities(self, types: Optional[list[str]] = None) -> dict[MessageEntity, str]:
-        """
-        Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`.
-        It contains entities from this message filtered by their
-        :attr:`~telegram.MessageEntity.type` attribute as the key, and the text that each entity
-        belongs to as the value of the :obj:`dict`.
-
-        Note:
-            This method should always be used instead of the :attr:`text_entities` attribute, since
-            it calculates the correct substring from the message text based on UTF-16 codepoints.
-            See :attr:`parse_text_entity` for more info.
-
-        Args:
-            types (list[:obj:`str`], optional): List of :class:`telegram.MessageEntity` types as
-                strings. If the :attr:`~telegram.MessageEntity.type` attribute of an entity is
-                contained in this list, it will be returned. Defaults to
-                :attr:`telegram.MessageEntity.ALL_TYPES`.
-
-        Returns:
-            dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to
-            the text that belongs to them, calculated based on UTF-16 codepoints.
-
-        """
-        if types is None:
-            types = MessageEntity.ALL_TYPES
-
-        return {
-            entity: self.parse_text_entity(entity)
-            for entity in self.text_entities
-            if entity.type in types
-        }
diff --git a/venv/lib/python3.11/site-packages/telegram/_games/gamehighscore.py b/venv/lib/python3.11/site-packages/telegram/_games/gamehighscore.py
deleted file mode 100755
index ad3dbd7..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_games/gamehighscore.py
+++ /dev/null
@@ -1,75 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram GameHighScore."""
-
-from typing import TYPE_CHECKING, Optional
-
-from telegram._telegramobject import TelegramObject
-from telegram._user import User
-from telegram._utils.types import JSONDict
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class GameHighScore(TelegramObject):
-    """This object represents one row of the high scores table for a game.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`position`, :attr:`user` and :attr:`score` are equal.
-
-    Args:
-        position (:obj:`int`): Position in high score table for the game.
-        user (:class:`telegram.User`): User.
-        score (:obj:`int`): Score.
-
-    Attributes:
-        position (:obj:`int`): Position in high score table for the game.
-        user (:class:`telegram.User`): User.
-        score (:obj:`int`): Score.
-
-    """
-
-    __slots__ = ("position", "score", "user")
-
-    def __init__(
-        self, position: int, user: User, score: int, *, api_kwargs: Optional[JSONDict] = None
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.position: int = position
-        self.user: User = user
-        self.score: int = score
-
-        self._id_attrs = (self.position, self.user, self.score)
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["GameHighScore"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        data["user"] = User.de_json(data.get("user"), bot)
-
-        return super().de_json(data=data, bot=bot)
diff --git a/venv/lib/python3.11/site-packages/telegram/_gifts.py b/venv/lib/python3.11/site-packages/telegram/_gifts.py
deleted file mode 100755
index d711320..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_gifts.py
+++ /dev/null
@@ -1,153 +0,0 @@
-#!/usr/bin/env python
-# pylint: disable=redefined-builtin
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/]
-"""This module contains classes related to gifs sent by bots."""
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Optional
-
-from telegram._files.sticker import Sticker
-from telegram._telegramobject import TelegramObject
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.types import JSONDict
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class Gift(TelegramObject):
-    """This object represents a gift that can be sent by the bot.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal if their :attr:`id` is equal.
-
-    .. versionadded:: 21.8
-
-    Args:
-        id (:obj:`str`): Unique identifier of the gift
-        sticker (:class:`~telegram.Sticker`): The sticker that represents the gift
-        star_count (:obj:`int`): The number of Telegram Stars that must be paid to send the sticker
-        total_count (:obj:`int`, optional): The total number of the gifts of this type that can be
-            sent; for limited gifts only
-        remaining_count (:obj:`int`, optional): The number of remaining gifts of this type that can
-            be sent; for limited gifts only
-        upgrade_star_count (:obj:`int`, optional): The number of Telegram Stars that must be paid
-            to upgrade the gift to a unique one
-
-            .. versionadded:: 21.10
-
-    Attributes:
-        id (:obj:`str`): Unique identifier of the gift
-        sticker (:class:`~telegram.Sticker`): The sticker that represents the gift
-        star_count (:obj:`int`): The number of Telegram Stars that must be paid to send the sticker
-        total_count (:obj:`int`): Optional. The total number of the gifts of this type that can be
-            sent; for limited gifts only
-        remaining_count (:obj:`int`): Optional. The number of remaining gifts of this type that can
-            be sent; for limited gifts only
-        upgrade_star_count (:obj:`int`): Optional. The number of Telegram Stars that must be paid
-            to upgrade the gift to a unique one
-
-            .. versionadded:: 21.10
-
-    """
-
-    __slots__ = (
-        "id",
-        "remaining_count",
-        "star_count",
-        "sticker",
-        "total_count",
-        "upgrade_star_count",
-    )
-
-    def __init__(
-        self,
-        id: str,
-        sticker: Sticker,
-        star_count: int,
-        total_count: Optional[int] = None,
-        remaining_count: Optional[int] = None,
-        upgrade_star_count: Optional[int] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.id: str = id
-        self.sticker: Sticker = sticker
-        self.star_count: int = star_count
-        self.total_count: Optional[int] = total_count
-        self.remaining_count: Optional[int] = remaining_count
-        self.upgrade_star_count: Optional[int] = upgrade_star_count
-
-        self._id_attrs = (self.id,)
-
-        self._freeze()
-
-    @classmethod
-    def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Gift"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        data["sticker"] = Sticker.de_json(data.get("sticker"), bot)
-        return super().de_json(data=data, bot=bot)
-
-
-class Gifts(TelegramObject):
-    """This object represent a list of gifts.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal if their :attr:`gifts` are equal.
-
-    .. versionadded:: 21.8
-
-    Args:
-        gifts (Sequence[:class:`Gift`]): The sequence of gifts
-
-    Attributes:
-        gifts (tuple[:class:`Gift`]): The sequence of gifts
-
-    """
-
-    __slots__ = ("gifts",)
-
-    def __init__(
-        self,
-        gifts: Sequence[Gift],
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.gifts: tuple[Gift, ...] = parse_sequence_arg(gifts)
-
-        self._id_attrs = (self.gifts,)
-
-        self._freeze()
-
-    @classmethod
-    def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Gifts"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        data["gifts"] = Gift.de_list(data.get("gifts"), bot)
-        return super().de_json(data=data, bot=bot)
diff --git a/venv/lib/python3.11/site-packages/telegram/_giveaway.py b/venv/lib/python3.11/site-packages/telegram/_giveaway.py
deleted file mode 100755
index 67c6b23..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_giveaway.py
+++ /dev/null
@@ -1,393 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an objects that are related to Telegram giveaways."""
-import datetime as dtm
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Optional
-
-from telegram._chat import Chat
-from telegram._telegramobject import TelegramObject
-from telegram._user import User
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
-from telegram._utils.types import JSONDict
-
-if TYPE_CHECKING:
-    from telegram import Bot, Message
-
-
-class Giveaway(TelegramObject):
-    """This object represents a message about a scheduled giveaway.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`chats`, :attr:`winners_selection_date` and
-    :attr:`winner_count` are equal.
-
-    .. versionadded:: 20.8
-
-    Args:
-        chats (tuple[:class:`telegram.Chat`]): The list of chats which the user must join to
-            participate in the giveaway.
-        winners_selection_date (:class:`datetime.datetime`): The date when the giveaway winner will
-            be selected. |datetime_localization|
-        winner_count (:obj:`int`): The number of users which are supposed to be selected as winners
-            of the giveaway.
-        only_new_members (:obj:`True`, optional): If :obj:`True`, only users who join the chats
-            after the giveaway started should be eligible to win.
-        has_public_winners (:obj:`True`, optional): :obj:`True`, if the list of giveaway winners
-            will be visible to everyone
-        prize_description (:obj:`str`, optional): Description of additional giveaway prize
-        country_codes (Sequence[:obj:`str`]): A list of two-letter ISO 3166-1 alpha-2
-            country codes indicating the countries from which eligible users for the giveaway must
-            come. If empty, then all users can participate in the giveaway. Users with a phone
-            number that was bought on Fragment can always participate in giveaways.
-        prize_star_count (:obj:`int`, optional): The number of Telegram Stars to be split between
-            giveaway winners; for Telegram Star giveaways only.
-
-            .. versionadded:: 21.6
-        premium_subscription_month_count (:obj:`int`, optional): The number of months the Telegram
-            Premium subscription won from the giveaway will be active for; for Telegram Premium
-            giveaways only.
-
-    Attributes:
-        chats (Sequence[:class:`telegram.Chat`]): The list of chats which the user must join to
-            participate in the giveaway.
-        winners_selection_date (:class:`datetime.datetime`): The date when the giveaway winner will
-            be selected. |datetime_localization|
-        winner_count (:obj:`int`): The number of users which are supposed to be selected as winners
-            of the giveaway.
-        only_new_members (:obj:`True`): Optional. If :obj:`True`, only users who join the chats
-            after the giveaway started should be eligible to win.
-        has_public_winners (:obj:`True`): Optional. :obj:`True`, if the list of giveaway winners
-            will be visible to everyone
-        prize_description (:obj:`str`): Optional. Description of additional giveaway prize
-        country_codes (tuple[:obj:`str`]): Optional. A tuple of two-letter ISO 3166-1 alpha-2
-            country codes indicating the countries from which eligible users for the giveaway must
-            come. If empty, then all users can participate in the giveaway. Users with a phone
-            number that was bought on Fragment can always participate in giveaways.
-        prize_star_count (:obj:`int`): Optional. The number of Telegram Stars to be split between
-            giveaway winners; for Telegram Star giveaways only.
-
-            .. versionadded:: 21.6
-        premium_subscription_month_count (:obj:`int`): Optional. The number of months the Telegram
-            Premium subscription won from the giveaway will be active for; for Telegram Premium
-            giveaways only.
-    """
-
-    __slots__ = (
-        "chats",
-        "country_codes",
-        "has_public_winners",
-        "only_new_members",
-        "premium_subscription_month_count",
-        "prize_description",
-        "prize_star_count",
-        "winner_count",
-        "winners_selection_date",
-    )
-
-    def __init__(
-        self,
-        chats: Sequence[Chat],
-        winners_selection_date: dtm.datetime,
-        winner_count: int,
-        only_new_members: Optional[bool] = None,
-        has_public_winners: Optional[bool] = None,
-        prize_description: Optional[str] = None,
-        country_codes: Optional[Sequence[str]] = None,
-        premium_subscription_month_count: Optional[int] = None,
-        prize_star_count: Optional[int] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-
-        self.chats: tuple[Chat, ...] = tuple(chats)
-        self.winners_selection_date: dtm.datetime = winners_selection_date
-        self.winner_count: int = winner_count
-        self.only_new_members: Optional[bool] = only_new_members
-        self.has_public_winners: Optional[bool] = has_public_winners
-        self.prize_description: Optional[str] = prize_description
-        self.country_codes: tuple[str, ...] = parse_sequence_arg(country_codes)
-        self.premium_subscription_month_count: Optional[int] = premium_subscription_month_count
-        self.prize_star_count: Optional[int] = prize_star_count
-
-        self._id_attrs = (
-            self.chats,
-            self.winners_selection_date,
-            self.winner_count,
-        )
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["Giveaway"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if data is None:
-            return None
-
-        # Get the local timezone from the bot if it has defaults
-        loc_tzinfo = extract_tzinfo_from_defaults(bot)
-
-        data["chats"] = tuple(Chat.de_list(data.get("chats"), bot))
-        data["winners_selection_date"] = from_timestamp(
-            data.get("winners_selection_date"), tzinfo=loc_tzinfo
-        )
-
-        return super().de_json(data=data, bot=bot)
-
-
-class GiveawayCreated(TelegramObject):
-    """This object represents a service message about the creation of a scheduled giveaway.
-
-    Args:
-        prize_star_count (:obj:`int`, optional): The number of Telegram Stars to be
-            split between giveaway winners; for Telegram Star giveaways only.
-
-            .. versionadded:: 21.6
-
-    Attributes:
-        prize_star_count (:obj:`int`): Optional. The number of Telegram Stars to be
-            split between giveaway winners; for Telegram Star giveaways only.
-
-            .. versionadded:: 21.6
-
-    """
-
-    __slots__ = ("prize_star_count",)
-
-    def __init__(
-        self, prize_star_count: Optional[int] = None, *, api_kwargs: Optional[JSONDict] = None
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.prize_star_count: Optional[int] = prize_star_count
-
-        self._freeze()
-
-
-class GiveawayWinners(TelegramObject):
-    """This object represents a message about the completion of a giveaway with public winners.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`chat`, :attr:`giveaway_message_id`,
-    :attr:`winners_selection_date`, :attr:`winner_count` and :attr:`winners` are equal.
-
-    .. versionadded:: 20.8
-
-    Args:
-        chat (:class:`telegram.Chat`): The chat that created the giveaway
-        giveaway_message_id (:obj:`int`): Identifier of the message with the giveaway in the chat
-        winners_selection_date (:class:`datetime.datetime`): Point in time when winners of the
-            giveaway were selected. |datetime_localization|
-        winner_count (:obj:`int`): Total number of winners in the giveaway
-        winners	(Sequence[:class:`telegram.User`]): List of up to
-            :tg-const:`telegram.constants.GiveawayLimit.MAX_WINNERS` winners of the giveaway
-        prize_star_count (:obj:`int`, optional): The number of Telegram Stars to be split between
-            giveaway winners; for Telegram Star giveaways only.
-
-            .. versionadded:: 21.6
-        additional_chat_count (:obj:`int`, optional): The number of other chats the user had to
-            join in order to be eligible for the giveaway
-        premium_subscription_month_count (:obj:`int`, optional): The number of months the Telegram
-            Premium subscription won from the giveaway will be active for
-        unclaimed_prize_count (:obj:`int`, optional): Number of undistributed prizes
-        only_new_members (:obj:`True`, optional): :obj:`True`, if only users who had joined the
-            chats after the giveaway started were eligible to win
-        was_refunded (:obj:`True`, optional): :obj:`True`, if the giveaway was canceled because the
-            payment for it was refunded
-        prize_description (:obj:`str`, optional): Description of additional giveaway prize
-
-    Attributes:
-        chat (:class:`telegram.Chat`): The chat that created the giveaway
-        giveaway_message_id (:obj:`int`): Identifier of the message with the giveaway in the chat
-        winners_selection_date (:class:`datetime.datetime`): Point in time when winners of the
-            giveaway were selected. |datetime_localization|
-        winner_count (:obj:`int`): Total number of winners in the giveaway
-        winners	(tuple[:class:`telegram.User`]): tuple of up to
-            :tg-const:`telegram.constants.GiveawayLimit.MAX_WINNERS` winners of the giveaway
-        additional_chat_count (:obj:`int`): Optional. The number of other chats the user had to
-            join in order to be eligible for the giveaway
-        prize_star_count (:obj:`int`): Optional. The number of Telegram Stars to be split between
-            giveaway winners; for Telegram Star giveaways only.
-
-            .. versionadded:: 21.6
-        premium_subscription_month_count (:obj:`int`): Optional. The number of months the Telegram
-            Premium subscription won from the giveaway will be active for
-        unclaimed_prize_count (:obj:`int`): Optional. Number of undistributed prizes
-        only_new_members (:obj:`True`): Optional. :obj:`True`, if only users who had joined the
-            chats after the giveaway started were eligible to win
-        was_refunded (:obj:`True`): Optional. :obj:`True`, if the giveaway was canceled because the
-            payment for it was refunded
-        prize_description (:obj:`str`): Optional. Description of additional giveaway prize
-    """
-
-    __slots__ = (
-        "additional_chat_count",
-        "chat",
-        "giveaway_message_id",
-        "only_new_members",
-        "premium_subscription_month_count",
-        "prize_description",
-        "prize_star_count",
-        "unclaimed_prize_count",
-        "was_refunded",
-        "winner_count",
-        "winners",
-        "winners_selection_date",
-    )
-
-    def __init__(
-        self,
-        chat: Chat,
-        giveaway_message_id: int,
-        winners_selection_date: dtm.datetime,
-        winner_count: int,
-        winners: Sequence[User],
-        additional_chat_count: Optional[int] = None,
-        premium_subscription_month_count: Optional[int] = None,
-        unclaimed_prize_count: Optional[int] = None,
-        only_new_members: Optional[bool] = None,
-        was_refunded: Optional[bool] = None,
-        prize_description: Optional[str] = None,
-        prize_star_count: Optional[int] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-
-        self.chat: Chat = chat
-        self.giveaway_message_id: int = giveaway_message_id
-        self.winners_selection_date: dtm.datetime = winners_selection_date
-        self.winner_count: int = winner_count
-        self.winners: tuple[User, ...] = tuple(winners)
-        self.additional_chat_count: Optional[int] = additional_chat_count
-        self.premium_subscription_month_count: Optional[int] = premium_subscription_month_count
-        self.unclaimed_prize_count: Optional[int] = unclaimed_prize_count
-        self.only_new_members: Optional[bool] = only_new_members
-        self.was_refunded: Optional[bool] = was_refunded
-        self.prize_description: Optional[str] = prize_description
-        self.prize_star_count: Optional[int] = prize_star_count
-
-        self._id_attrs = (
-            self.chat,
-            self.giveaway_message_id,
-            self.winners_selection_date,
-            self.winner_count,
-            self.winners,
-        )
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["GiveawayWinners"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if data is None:
-            return None
-
-        # Get the local timezone from the bot if it has defaults
-        loc_tzinfo = extract_tzinfo_from_defaults(bot)
-
-        data["chat"] = Chat.de_json(data.get("chat"), bot)
-        data["winners"] = tuple(User.de_list(data.get("winners"), bot))
-        data["winners_selection_date"] = from_timestamp(
-            data.get("winners_selection_date"), tzinfo=loc_tzinfo
-        )
-
-        return super().de_json(data=data, bot=bot)
-
-
-class GiveawayCompleted(TelegramObject):
-    """This object represents a service message about the completion of a giveaway without public
-    winners.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`winner_count` and :attr:`unclaimed_prize_count` are equal.
-
-    .. versionadded:: 20.8
-
-
-    Args:
-        winner_count (:obj:`int`): Number of winners in the giveaway
-        unclaimed_prize_count (:obj:`int`, optional): Number of undistributed prizes
-        giveaway_message (:class:`telegram.Message`, optional): Message with the giveaway that was
-            completed, if it wasn't deleted
-        is_star_giveaway (:obj:`bool`, optional): :obj:`True`, if the giveaway is a Telegram Star
-            giveaway. Otherwise, currently, the giveaway is a Telegram Premium giveaway.
-
-            .. versionadded:: 21.6
-    Attributes:
-        winner_count (:obj:`int`): Number of winners in the giveaway
-        unclaimed_prize_count (:obj:`int`): Optional. Number of undistributed prizes
-        giveaway_message (:class:`telegram.Message`): Optional. Message with the giveaway that was
-            completed, if it wasn't deleted
-        is_star_giveaway (:obj:`bool`): Optional. :obj:`True`, if the giveaway is a Telegram Star
-            giveaway. Otherwise, currently, the giveaway is a Telegram Premium giveaway.
-
-            .. versionadded:: 21.6
-    """
-
-    __slots__ = ("giveaway_message", "is_star_giveaway", "unclaimed_prize_count", "winner_count")
-
-    def __init__(
-        self,
-        winner_count: int,
-        unclaimed_prize_count: Optional[int] = None,
-        giveaway_message: Optional["Message"] = None,
-        is_star_giveaway: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-
-        self.winner_count: int = winner_count
-        self.unclaimed_prize_count: Optional[int] = unclaimed_prize_count
-        self.giveaway_message: Optional[Message] = giveaway_message
-        self.is_star_giveaway: Optional[bool] = is_star_giveaway
-
-        self._id_attrs = (
-            self.winner_count,
-            self.unclaimed_prize_count,
-        )
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["GiveawayCompleted"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if data is None:
-            return None
-
-        # Unfortunately, this needs to be here due to cyclic imports
-        from telegram._message import Message  # pylint: disable=import-outside-toplevel
-
-        data["giveaway_message"] = Message.de_json(data.get("giveaway_message"), bot)
-
-        return super().de_json(data=data, bot=bot)
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__init__.py b/venv/lib/python3.11/site-packages/telegram/_inline/__init__.py
deleted file mode 100755
index e69de29..0000000
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/__init__.cpython-311.pyc
deleted file mode 100755
index bc12d0c..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/__init__.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinekeyboardbutton.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinekeyboardbutton.cpython-311.pyc
deleted file mode 100755
index ff2a8da..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinekeyboardbutton.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinekeyboardmarkup.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinekeyboardmarkup.cpython-311.pyc
deleted file mode 100755
index ff43581..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinekeyboardmarkup.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequery.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequery.cpython-311.pyc
deleted file mode 100755
index 3a8e209..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequery.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresult.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresult.cpython-311.pyc
deleted file mode 100755
index ab2d388..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresult.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultarticle.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultarticle.cpython-311.pyc
deleted file mode 100755
index e6a7e7f..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultarticle.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultaudio.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultaudio.cpython-311.pyc
deleted file mode 100755
index 6e39d53..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultaudio.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedaudio.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedaudio.cpython-311.pyc
deleted file mode 100755
index 764cef1..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedaudio.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcacheddocument.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcacheddocument.cpython-311.pyc
deleted file mode 100755
index 40ac907..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcacheddocument.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedgif.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedgif.cpython-311.pyc
deleted file mode 100755
index 7a6e7e3..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedgif.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedmpeg4gif.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedmpeg4gif.cpython-311.pyc
deleted file mode 100755
index 63cacc7..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedmpeg4gif.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedphoto.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedphoto.cpython-311.pyc
deleted file mode 100755
index 79bf91b..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedphoto.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedsticker.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedsticker.cpython-311.pyc
deleted file mode 100755
index 1ed9a3c..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedsticker.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedvideo.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedvideo.cpython-311.pyc
deleted file mode 100755
index 7519e31..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedvideo.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedvoice.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedvoice.cpython-311.pyc
deleted file mode 100755
index e459242..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcachedvoice.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcontact.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcontact.cpython-311.pyc
deleted file mode 100755
index 3cc469a..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultcontact.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultdocument.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultdocument.cpython-311.pyc
deleted file mode 100755
index e2fe813..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultdocument.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultgame.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultgame.cpython-311.pyc
deleted file mode 100755
index 1c07d0e..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultgame.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultgif.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultgif.cpython-311.pyc
deleted file mode 100755
index 8a3be79..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultgif.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultlocation.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultlocation.cpython-311.pyc
deleted file mode 100755
index e594dca..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultlocation.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultmpeg4gif.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultmpeg4gif.cpython-311.pyc
deleted file mode 100755
index 9f712dc..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultmpeg4gif.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultphoto.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultphoto.cpython-311.pyc
deleted file mode 100755
index d8712fe..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultphoto.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultsbutton.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultsbutton.cpython-311.pyc
deleted file mode 100755
index 31bc533..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultsbutton.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultvenue.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultvenue.cpython-311.pyc
deleted file mode 100755
index 52a68bf..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultvenue.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultvideo.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultvideo.cpython-311.pyc
deleted file mode 100755
index b6be891..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultvideo.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultvoice.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultvoice.cpython-311.pyc
deleted file mode 100755
index 1835a19..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inlinequeryresultvoice.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputcontactmessagecontent.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputcontactmessagecontent.cpython-311.pyc
deleted file mode 100755
index 6e9d38e..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputcontactmessagecontent.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputinvoicemessagecontent.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputinvoicemessagecontent.cpython-311.pyc
deleted file mode 100755
index a8e4007..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputinvoicemessagecontent.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputlocationmessagecontent.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputlocationmessagecontent.cpython-311.pyc
deleted file mode 100755
index e78983b..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputlocationmessagecontent.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputmessagecontent.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputmessagecontent.cpython-311.pyc
deleted file mode 100755
index da96d22..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputmessagecontent.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputtextmessagecontent.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputtextmessagecontent.cpython-311.pyc
deleted file mode 100755
index 78464b1..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputtextmessagecontent.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputvenuemessagecontent.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputvenuemessagecontent.cpython-311.pyc
deleted file mode 100755
index ef5be75..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/inputvenuemessagecontent.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/preparedinlinemessage.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/preparedinlinemessage.cpython-311.pyc
deleted file mode 100755
index f1d9a85..0000000
Binary files a/venv/lib/python3.11/site-packages/telegram/_inline/__pycache__/preparedinlinemessage.cpython-311.pyc and /dev/null differ
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinekeyboardbutton.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinekeyboardbutton.py
deleted file mode 100755
index 61169ca..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinekeyboardbutton.py
+++ /dev/null
@@ -1,341 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram InlineKeyboardButton."""
-
-from typing import TYPE_CHECKING, Final, Optional, Union
-
-from telegram import constants
-from telegram._copytextbutton import CopyTextButton
-from telegram._games.callbackgame import CallbackGame
-from telegram._loginurl import LoginUrl
-from telegram._switchinlinequerychosenchat import SwitchInlineQueryChosenChat
-from telegram._telegramobject import TelegramObject
-from telegram._utils.types import JSONDict
-from telegram._webappinfo import WebAppInfo
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class InlineKeyboardButton(TelegramObject):
-    """This object represents one button of an inline keyboard.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`text`, :attr:`url`, :attr:`login_url`, :attr:`callback_data`,
-    :attr:`switch_inline_query`, :attr:`switch_inline_query_current_chat`, :attr:`callback_game`,
-    :attr:`web_app` and :attr:`pay` are equal.
-
-    Note:
-        * Exactly one of the optional fields must be used to specify type of the button.
-        * Mind that :attr:`callback_game` is not
-          working as expected. Putting a game short name in it might, but is not guaranteed to
-          work.
-        * If your bot allows for arbitrary callback data, in keyboards returned in a response
-          from telegram, :attr:`callback_data` may be an instance of
-          :class:`telegram.ext.InvalidCallbackData`. This will be the case, if the data
-          associated with the button was already deleted.
-
-          .. versionadded:: 13.6
-
-        * Since Bot API 5.5, it's now allowed to mention users by their ID in inline keyboards.
-          This will only work in Telegram versions released after December 7, 2021.
-          Older clients will display *unsupported message*.
-
-    Warning:
-        * If your bot allows your arbitrary callback data, buttons whose callback data is a
-          non-hashable object will become unhashable. Trying to evaluate ``hash(button)`` will
-          result in a :class:`TypeError`.
-
-          .. versionchanged:: 13.6
-
-        * After Bot API 6.1, only ``HTTPS`` links will be allowed in :paramref:`login_url`.
-
-    Examples:
-        * :any:`Inline Keyboard 1 `
-        * :any:`Inline Keyboard 2 `
-
-    .. seealso:: :class:`telegram.InlineKeyboardMarkup`
-
-    .. versionchanged:: 20.0
-       :attr:`web_app` is considered as well when comparing objects of this type in terms of
-       equality.
-
-    Args:
-        text (:obj:`str`): Label text on the button.
-        url (:obj:`str`, optional): HTTP or tg:// url to be opened when the button is pressed.
-            Links ``tg://user?id=`` can be used to mention a user by
-            their ID without using a username, if this is allowed by their privacy settings.
-
-            .. versionchanged:: 13.9
-               You can now mention a user using ``tg://user?id=``.
-        login_url (:class:`telegram.LoginUrl`, optional): An ``HTTPS`` URL used to automatically
-            authorize the user. Can be used as a replacement for the Telegram Login Widget.
-
-            Caution:
-                Only ``HTTPS`` links are allowed after Bot API 6.1.
-        callback_data (:obj:`str` | :obj:`object`, optional): Data to be sent in a callback query
-            to the bot when the button is pressed, UTF-8
-            :tg-const:`telegram.InlineKeyboardButton.MIN_CALLBACK_DATA`-
-            :tg-const:`telegram.InlineKeyboardButton.MAX_CALLBACK_DATA` bytes.
-            If the bot instance allows arbitrary callback data, anything can be passed.
-
-            Tip:
-                The value entered here will be available in :attr:`telegram.CallbackQuery.data`.
-
-            .. seealso:: :wiki:`Arbitrary callback_data `
-
-        web_app (:class:`telegram.WebAppInfo`, optional): Description of the `Web App
-            `_  that will be launched when the user presses
-            the button. The Web App will be able to send an arbitrary message on behalf of the user
-            using the method :meth:`~telegram.Bot.answer_web_app_query`. Available only in
-            private chats between a user and the bot. Not supported for messages sent on behalf of
-            a Telegram Business account.
-
-            .. versionadded:: 20.0
-        switch_inline_query (:obj:`str`, optional): If set, pressing the button will prompt the
-            user to select one of their chats, open that chat and insert the bot's username and the
-            specified inline query in the input field. May be empty, in which case just the bot's
-            username will be inserted. Not supported for messages sent on behalf of a Telegram
-            Business account.
-
-            Tip:
-                This is similar to the parameter :paramref:`switch_inline_query_chosen_chat`,
-                but gives no control over which chats can be selected.
-        switch_inline_query_current_chat (:obj:`str`, optional): If set, pressing the button will
-            insert the bot's username and the specified inline query in the current chat's input
-            field. May be empty, in which case only the bot's username will be inserted.
-
-            This offers a quick way for the user to open your bot in inline mode in the same chat
-            - good for selecting something from multiple options. Not supported in channels and for
-            messages sent on behalf of a Telegram Business account.
-        copy_text (:class:`telegram.CopyTextButton`, optional): Description of the button that
-            copies the specified text to the clipboard.
-
-            .. versionadded:: 21.7
-        callback_game (:class:`telegram.CallbackGame`, optional): Description of the game that will
-            be launched when the user presses the button
-
-            Note:
-                This type of button **must** always be the first button in the first row.
-        pay (:obj:`bool`, optional): Specify :obj:`True`, to send a Pay button.
-            Substrings ``“⭐️”`` and ``“XTR”`` in the buttons's text will be replaced with a
-            Telegram Star icon.
-
-            Note:
-                This type of button **must** always be the first button in the first row and can
-                only be used in invoice messages.
-        switch_inline_query_chosen_chat (:class:`telegram.SwitchInlineQueryChosenChat`, optional):
-            If set, pressing the button will prompt the user to select one of their chats of the
-            specified type, open that chat and insert the bot's username and the specified inline
-            query in the input field. Not supported for messages sent on behalf of a Telegram
-            Business account.
-
-            .. versionadded:: 20.3
-
-            Tip:
-                This is similar to :paramref:`switch_inline_query`, but gives more control on
-                which chats can be selected.
-
-            Caution:
-                The PTB team has discovered that this field works correctly only if your Telegram
-                client is released after April 20th 2023.
-
-    Attributes:
-        text (:obj:`str`): Label text on the button.
-        url (:obj:`str`): Optional. HTTP or tg:// url to be opened when the button is pressed.
-            Links ``tg://user?id=`` can be used to mention a user by
-            their ID without using a username, if this is allowed by their privacy settings.
-
-            .. versionchanged:: 13.9
-               You can now mention a user using ``tg://user?id=``.
-        login_url (:class:`telegram.LoginUrl`): Optional. An ``HTTPS`` URL used to automatically
-            authorize the user. Can be used as a replacement for the Telegram Login Widget.
-
-            Caution:
-                Only ``HTTPS`` links are allowed after Bot API 6.1.
-        callback_data (:obj:`str` | :obj:`object`): Optional. Data to be sent in a callback query
-            to the bot when the button is pressed, UTF-8
-            :tg-const:`telegram.InlineKeyboardButton.MIN_CALLBACK_DATA`-
-            :tg-const:`telegram.InlineKeyboardButton.MAX_CALLBACK_DATA` bytes.
-        web_app (:class:`telegram.WebAppInfo`): Optional. Description of the `Web App
-            `_  that will be launched when the user presses
-            the button. The Web App will be able to send an arbitrary message on behalf of the user
-            using the method :meth:`~telegram.Bot.answer_web_app_query`. Available only in
-            private chats between a user and the bot. Not supported for messages sent on behalf of
-            a Telegram Business account.
-
-            .. versionadded:: 20.0
-        switch_inline_query (:obj:`str`): Optional. If set, pressing the button will prompt the
-            user to select one of their chats, open that chat and insert the bot's username and the
-            specified inline query in the input field. May be empty, in which case just the bot's
-            username will be inserted. Not supported for messages sent on behalf of a Telegram
-            Business account.
-
-            Tip:
-                This is similar to the parameter :paramref:`switch_inline_query_chosen_chat`,
-                but gives no control over which chats can be selected.
-        switch_inline_query_current_chat (:obj:`str`): Optional. If set, pressing the button will
-            insert the bot's username and the specified inline query in the current chat's input
-            field. May be empty, in which case only the bot's username will be inserted.
-
-            This offers a quick way for the user to open your bot in inline mode in the same chat
-            - good for selecting something from multiple options. Not supported in channels and for
-            messages sent on behalf of a Telegram Business account.
-        copy_text (:class:`telegram.CopyTextButton`): Optional. Description of the button that
-            copies the specified text to the clipboard.
-
-            .. versionadded:: 21.7
-        callback_game (:class:`telegram.CallbackGame`): Optional. Description of the game that will
-            be launched when the user presses the button.
-
-            Note:
-                This type of button **must** always be the first button in the first row.
-        pay (:obj:`bool`): Optional. Specify :obj:`True`, to send a Pay button.
-            Substrings ``“⭐️”`` and ``“XTR”`` in the buttons's text will be replaced with a
-            Telegram Star icon.
-
-            Note:
-                This type of button **must** always be the first button in the first row and can
-                only be used in invoice messages.
-        switch_inline_query_chosen_chat (:class:`telegram.SwitchInlineQueryChosenChat`): Optional.
-            If set, pressing the button will prompt the user to select one of their chats of the
-            specified type, open that chat and insert the bot's username and the specified inline
-            query in the input field. Not supported for messages sent on behalf of a Telegram
-            Business account.
-
-            .. versionadded:: 20.3
-
-            Tip:
-                This is similar to :attr:`switch_inline_query`, but gives more control on
-                which chats can be selected.
-
-            Caution:
-                The PTB team has discovered that this field works correctly only if your Telegram
-                client is released after April 20th 2023.
-    """
-
-    __slots__ = (
-        "callback_data",
-        "callback_game",
-        "copy_text",
-        "login_url",
-        "pay",
-        "switch_inline_query",
-        "switch_inline_query_chosen_chat",
-        "switch_inline_query_current_chat",
-        "text",
-        "url",
-        "web_app",
-    )
-
-    def __init__(
-        self,
-        text: str,
-        url: Optional[str] = None,
-        callback_data: Optional[Union[str, object]] = None,
-        switch_inline_query: Optional[str] = None,
-        switch_inline_query_current_chat: Optional[str] = None,
-        callback_game: Optional[CallbackGame] = None,
-        pay: Optional[bool] = None,
-        login_url: Optional[LoginUrl] = None,
-        web_app: Optional[WebAppInfo] = None,
-        switch_inline_query_chosen_chat: Optional[SwitchInlineQueryChosenChat] = None,
-        copy_text: Optional[CopyTextButton] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        # Required
-        self.text: str = text
-
-        # Optionals
-        self.url: Optional[str] = url
-        self.login_url: Optional[LoginUrl] = login_url
-        self.callback_data: Optional[Union[str, object]] = callback_data
-        self.switch_inline_query: Optional[str] = switch_inline_query
-        self.switch_inline_query_current_chat: Optional[str] = switch_inline_query_current_chat
-        self.callback_game: Optional[CallbackGame] = callback_game
-        self.pay: Optional[bool] = pay
-        self.web_app: Optional[WebAppInfo] = web_app
-        self.switch_inline_query_chosen_chat: Optional[SwitchInlineQueryChosenChat] = (
-            switch_inline_query_chosen_chat
-        )
-        self.copy_text: Optional[CopyTextButton] = copy_text
-        self._id_attrs = ()
-        self._set_id_attrs()
-
-        self._freeze()
-
-    def _set_id_attrs(self) -> None:
-        self._id_attrs = (
-            self.text,
-            self.url,
-            self.login_url,
-            self.callback_data,
-            self.web_app,
-            self.switch_inline_query,
-            self.switch_inline_query_current_chat,
-            self.callback_game,
-            self.pay,
-        )
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["InlineKeyboardButton"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        data["login_url"] = LoginUrl.de_json(data.get("login_url"), bot)
-        data["web_app"] = WebAppInfo.de_json(data.get("web_app"), bot)
-        data["callback_game"] = CallbackGame.de_json(data.get("callback_game"), bot)
-        data["switch_inline_query_chosen_chat"] = SwitchInlineQueryChosenChat.de_json(
-            data.get("switch_inline_query_chosen_chat"), bot
-        )
-        data["copy_text"] = CopyTextButton.de_json(data.get("copy_text"), bot)
-
-        return super().de_json(data=data, bot=bot)
-
-    def update_callback_data(self, callback_data: Union[str, object]) -> None:
-        """
-        Sets :attr:`callback_data` to the passed object. Intended to be used by
-        :class:`telegram.ext.CallbackDataCache`.
-
-        .. versionadded:: 13.6
-
-        Args:
-            callback_data (:class:`object`): The new callback data.
-        """
-        with self._unfrozen():
-            self.callback_data = callback_data
-            self._set_id_attrs()
-
-    MIN_CALLBACK_DATA: Final[int] = constants.InlineKeyboardButtonLimit.MIN_CALLBACK_DATA
-    """:const:`telegram.constants.InlineKeyboardButtonLimit.MIN_CALLBACK_DATA`
-
-    .. versionadded:: 20.0
-    """
-    MAX_CALLBACK_DATA: Final[int] = constants.InlineKeyboardButtonLimit.MAX_CALLBACK_DATA
-    """:const:`telegram.constants.InlineKeyboardButtonLimit.MAX_CALLBACK_DATA`
-
-    .. versionadded:: 20.0
-    """
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinekeyboardmarkup.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinekeyboardmarkup.py
deleted file mode 100755
index 834225e..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinekeyboardmarkup.py
+++ /dev/null
@@ -1,165 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram InlineKeyboardMarkup."""
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Optional
-
-from telegram._inline.inlinekeyboardbutton import InlineKeyboardButton
-from telegram._telegramobject import TelegramObject
-from telegram._utils.markup import check_keyboard_type
-from telegram._utils.types import JSONDict
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class InlineKeyboardMarkup(TelegramObject):
-    """
-    This object represents an inline keyboard that appears right next to the message it belongs to.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their size of :attr:`inline_keyboard` and all the buttons are equal.
-
-    .. figure:: https://core.telegram.org/file/464001863/110f3/I47qTXAD9Z4.120010/e0\
-        ea04f66357b640ec
-        :align: center
-
-        An inline keyboard on a message
-
-    .. seealso::
-        Another kind of keyboard would be the :class:`telegram.ReplyKeyboardMarkup`.
-
-    Examples:
-        * :any:`Inline Keyboard 1 `
-        * :any:`Inline Keyboard 2 `
-
-    Args:
-        inline_keyboard (Sequence[Sequence[:class:`telegram.InlineKeyboardButton`]]): Sequence of
-            button rows, each represented by a sequence of :class:`~telegram.InlineKeyboardButton`
-            objects.
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-    Attributes:
-        inline_keyboard (tuple[tuple[:class:`telegram.InlineKeyboardButton`]]): Tuple of
-            button rows, each represented by a tuple of :class:`~telegram.InlineKeyboardButton`
-            objects.
-
-            .. versionchanged:: 20.0
-                |tupleclassattrs|
-
-    """
-
-    __slots__ = ("inline_keyboard",)
-
-    def __init__(
-        self,
-        inline_keyboard: Sequence[Sequence[InlineKeyboardButton]],
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        if not check_keyboard_type(inline_keyboard):
-            raise ValueError(
-                "The parameter `inline_keyboard` should be a sequence of sequences of "
-                "InlineKeyboardButtons"
-            )
-        # Required
-        self.inline_keyboard: tuple[tuple[InlineKeyboardButton, ...], ...] = tuple(
-            tuple(row) for row in inline_keyboard
-        )
-
-        self._id_attrs = (self.inline_keyboard,)
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["InlineKeyboardMarkup"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        if not data:
-            return None
-
-        keyboard = []
-        for row in data["inline_keyboard"]:
-            tmp = []
-            for col in row:
-                btn = InlineKeyboardButton.de_json(col, bot)
-                if btn:
-                    tmp.append(btn)
-            keyboard.append(tmp)
-
-        return cls(keyboard)
-
-    @classmethod
-    def from_button(cls, button: InlineKeyboardButton, **kwargs: object) -> "InlineKeyboardMarkup":
-        """Shortcut for::
-
-            InlineKeyboardMarkup([[button]], **kwargs)
-
-        Return an InlineKeyboardMarkup from a single InlineKeyboardButton
-
-        Args:
-            button (:class:`telegram.InlineKeyboardButton`): The button to use in the markup
-
-        """
-        return cls([[button]], **kwargs)  # type: ignore[arg-type]
-
-    @classmethod
-    def from_row(
-        cls, button_row: Sequence[InlineKeyboardButton], **kwargs: object
-    ) -> "InlineKeyboardMarkup":
-        """Shortcut for::
-
-            InlineKeyboardMarkup([button_row], **kwargs)
-
-        Return an InlineKeyboardMarkup from a single row of InlineKeyboardButtons
-
-        Args:
-            button_row (Sequence[:class:`telegram.InlineKeyboardButton`]): The button to use
-                in the markup
-
-                .. versionchanged:: 20.0
-                    |sequenceargs|
-
-        """
-        return cls([button_row], **kwargs)  # type: ignore[arg-type]
-
-    @classmethod
-    def from_column(
-        cls, button_column: Sequence[InlineKeyboardButton], **kwargs: object
-    ) -> "InlineKeyboardMarkup":
-        """Shortcut for::
-
-            InlineKeyboardMarkup([[button] for button in button_column], **kwargs)
-
-        Return an InlineKeyboardMarkup from a single column of InlineKeyboardButtons
-
-        Args:
-            button_column (Sequence[:class:`telegram.InlineKeyboardButton`]): The button to use
-                in the markup
-
-                 .. versionchanged:: 20.0
-                    |sequenceargs|
-
-        """
-        button_grid = [[button] for button in button_column]
-        return cls(button_grid, **kwargs)  # type: ignore[arg-type]
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequery.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequery.py
deleted file mode 100755
index dd6b957..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequery.py
+++ /dev/null
@@ -1,228 +0,0 @@
-#!/usr/bin/env python
-# pylint: disable=too-many-arguments
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram InlineQuery."""
-
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Callable, Final, Optional, Union
-
-from telegram import constants
-from telegram._files.location import Location
-from telegram._inline.inlinequeryresultsbutton import InlineQueryResultsButton
-from telegram._telegramobject import TelegramObject
-from telegram._user import User
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.types import JSONDict, ODVInput
-
-if TYPE_CHECKING:
-    from telegram import Bot, InlineQueryResult
-
-
-class InlineQuery(TelegramObject):
-    """
-    This object represents an incoming inline query. When the user sends an empty query, your bot
-    could return some default or trending results.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`id` is equal.
-
-    .. figure:: https://core.telegram.org/file/464001466/10e4a/r4FKyQ7gw5g.134366/f2\
-        606a53d683374703
-        :align: center
-
-        Inline queries on Telegram
-
-    .. seealso::
-        The :class:`telegram.InlineQueryResult` classes represent the media the user can choose
-        from (see above figure).
-
-    Note:
-        In Python :keyword:`from` is a reserved word. Use :paramref:`from_user` instead.
-
-    .. versionchanged:: 20.0
-        The following are now keyword-only arguments in Bot methods:
-        ``{read, write, connect, pool}_timeout``, :paramref:`answer.api_kwargs`,
-        ``auto_pagination``. Use a named argument for those,
-        and notice that some positional arguments changed position as a result.
-
-    Args:
-        id (:obj:`str`): Unique identifier for this query.
-        from_user (:class:`telegram.User`): Sender.
-        query (:obj:`str`): Text of the query (up to
-            :tg-const:`telegram.InlineQuery.MAX_QUERY_LENGTH` characters).
-        offset (:obj:`str`): Offset of the results to be returned, can be controlled by the bot.
-        chat_type (:obj:`str`, optional): Type of the chat, from which the inline query was sent.
-            Can be either :tg-const:`telegram.Chat.SENDER` for a private chat with the inline query
-            sender, :tg-const:`telegram.Chat.PRIVATE`, :tg-const:`telegram.Chat.GROUP`,
-            :tg-const:`telegram.Chat.SUPERGROUP` or :tg-const:`telegram.Chat.CHANNEL`. The chat
-            type should be always known for requests sent from official clients and most
-            third-party clients, unless the request was sent from a secret chat.
-
-            .. versionadded:: 13.5
-        location (:class:`telegram.Location`, optional): Sender location, only for bots that
-            request user location.
-
-    Attributes:
-        id (:obj:`str`): Unique identifier for this query.
-        from_user (:class:`telegram.User`): Sender.
-        query (:obj:`str`): Text of the query (up to
-            :tg-const:`telegram.InlineQuery.MAX_QUERY_LENGTH` characters).
-        offset (:obj:`str`): Offset of the results to be returned, can be controlled by the bot.
-        chat_type (:obj:`str`): Optional. Type of the chat, from which the inline query was sent.
-            Can be either :tg-const:`telegram.Chat.SENDER` for a private chat with the inline query
-            sender, :tg-const:`telegram.Chat.PRIVATE`, :tg-const:`telegram.Chat.GROUP`,
-            :tg-const:`telegram.Chat.SUPERGROUP` or :tg-const:`telegram.Chat.CHANNEL`. The chat
-            type should be always known for requests sent from official clients and most
-            third-party clients, unless the request was sent from a secret chat.
-
-            .. versionadded:: 13.5
-        location (:class:`telegram.Location`): Optional. Sender location, only for bots that
-            request user location.
-
-    """
-
-    __slots__ = ("chat_type", "from_user", "id", "location", "offset", "query")
-
-    def __init__(
-        self,
-        id: str,  # pylint: disable=redefined-builtin
-        from_user: User,
-        query: str,
-        offset: str,
-        location: Optional[Location] = None,
-        chat_type: Optional[str] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        # Required
-        self.id: str = id
-        self.from_user: User = from_user
-        self.query: str = query
-        self.offset: str = offset
-
-        # Optional
-        self.location: Optional[Location] = location
-        self.chat_type: Optional[str] = chat_type
-
-        self._id_attrs = (self.id,)
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["InlineQuery"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        data["from_user"] = User.de_json(data.pop("from", None), bot)
-        data["location"] = Location.de_json(data.get("location"), bot)
-
-        return super().de_json(data=data, bot=bot)
-
-    async def answer(
-        self,
-        results: Union[
-            Sequence["InlineQueryResult"], Callable[[int], Optional[Sequence["InlineQueryResult"]]]
-        ],
-        cache_time: Optional[int] = None,
-        is_personal: Optional[bool] = None,
-        next_offset: Optional[str] = None,
-        button: Optional[InlineQueryResultsButton] = None,
-        *,
-        current_offset: Optional[str] = None,
-        auto_pagination: bool = False,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-            await bot.answer_inline_query(
-                update.inline_query.id,
-                *args,
-                current_offset=self.offset if auto_pagination else None,
-                **kwargs
-            )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.answer_inline_query`.
-
-        .. versionchanged:: 20.0
-            Raises :class:`ValueError` instead of :class:`TypeError`.
-
-        Keyword Args:
-            auto_pagination (:obj:`bool`, optional): If set to :obj:`True`, :attr:`offset` will be
-                passed as
-                :paramref:`current_offset ` to
-                :meth:`telegram.Bot.answer_inline_query`.
-                Defaults to :obj:`False`.
-
-        Raises:
-            ValueError: If both :paramref:`~telegram.Bot.answer_inline_query.current_offset` and
-                :paramref:`auto_pagination` are supplied.
-        """
-        if current_offset and auto_pagination:
-            raise ValueError("current_offset and auto_pagination are mutually exclusive!")
-        return await self.get_bot().answer_inline_query(
-            inline_query_id=self.id,
-            current_offset=self.offset if auto_pagination else current_offset,
-            results=results,
-            cache_time=cache_time,
-            is_personal=is_personal,
-            next_offset=next_offset,
-            button=button,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    MAX_RESULTS: Final[int] = constants.InlineQueryLimit.RESULTS
-    """:const:`telegram.constants.InlineQueryLimit.RESULTS`
-
-    .. versionadded:: 13.2
-    """
-    MIN_SWITCH_PM_TEXT_LENGTH: Final[int] = constants.InlineQueryLimit.MIN_SWITCH_PM_TEXT_LENGTH
-    """:const:`telegram.constants.InlineQueryLimit.MIN_SWITCH_PM_TEXT_LENGTH`
-
-    .. versionadded:: 20.0
-    """
-    MAX_SWITCH_PM_TEXT_LENGTH: Final[int] = constants.InlineQueryLimit.MAX_SWITCH_PM_TEXT_LENGTH
-    """:const:`telegram.constants.InlineQueryLimit.MAX_SWITCH_PM_TEXT_LENGTH`
-
-    .. versionadded:: 20.0
-    """
-    MAX_OFFSET_LENGTH: Final[int] = constants.InlineQueryLimit.MAX_OFFSET_LENGTH
-    """:const:`telegram.constants.InlineQueryLimit.MAX_OFFSET_LENGTH`
-
-    .. versionadded:: 20.0
-    """
-    MAX_QUERY_LENGTH: Final[int] = constants.InlineQueryLimit.MAX_QUERY_LENGTH
-    """:const:`telegram.constants.InlineQueryLimit.MAX_QUERY_LENGTH`
-
-    .. versionadded:: 20.0
-    """
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresult.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresult.py
deleted file mode 100755
index 67ce6e4..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresult.py
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-# pylint: disable=redefined-builtin
-"""This module contains the classes that represent Telegram InlineQueryResult."""
-
-from typing import Final, Optional
-
-from telegram import constants
-from telegram._telegramobject import TelegramObject
-from telegram._utils import enum
-from telegram._utils.types import JSONDict
-
-
-class InlineQueryResult(TelegramObject):
-    """Baseclass for the InlineQueryResult* classes.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`id` is equal.
-
-    Note:
-        All URLs passed in inline query results will be available to end users and therefore must
-        be assumed to be *public*.
-
-    Examples:
-        :any:`Inline Bot `
-
-    Args:
-        type (:obj:`str`): Type of the result.
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-
-    Attributes:
-        type (:obj:`str`): Type of the result.
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-
-    """
-
-    __slots__ = ("id", "type")
-
-    def __init__(self, type: str, id: str, *, api_kwargs: Optional[JSONDict] = None):
-        super().__init__(api_kwargs=api_kwargs)
-
-        # Required
-        self.type: str = enum.get_member(constants.InlineQueryResultType, type, type)
-        self.id: str = str(id)
-
-        self._id_attrs = (self.id,)
-
-        self._freeze()
-
-    MIN_ID_LENGTH: Final[int] = constants.InlineQueryResultLimit.MIN_ID_LENGTH
-    """:const:`telegram.constants.InlineQueryResultLimit.MIN_ID_LENGTH`
-
-    .. versionadded:: 20.0
-    """
-    MAX_ID_LENGTH: Final[int] = constants.InlineQueryResultLimit.MAX_ID_LENGTH
-    """:const:`telegram.constants.InlineQueryResultLimit.MAX_ID_LENGTH`
-
-    .. versionadded:: 20.0
-    """
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultarticle.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultarticle.py
deleted file mode 100755
index 5fcee85..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultarticle.py
+++ /dev/null
@@ -1,149 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InlineQueryResultArticle."""
-
-from typing import TYPE_CHECKING, Optional
-
-from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
-from telegram._inline.inlinequeryresult import InlineQueryResult
-from telegram._utils.types import JSONDict
-from telegram._utils.warnings import warn
-from telegram.constants import InlineQueryResultType
-from telegram.warnings import PTBDeprecationWarning
-
-if TYPE_CHECKING:
-    from telegram import InputMessageContent
-
-
-class InlineQueryResultArticle(InlineQueryResult):
-    """This object represents a Telegram InlineQueryResultArticle.
-
-    Examples:
-        :any:`Inline Bot `
-
-    .. versionchanged:: 20.5
-      Removed the deprecated arguments and attributes ``thumb_*``.
-
-    Args:
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        title (:obj:`str`): Title of the result.
-        input_message_content (:class:`telegram.InputMessageContent`): Content of the message to
-            be sent.
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
-            to the message.
-        url (:obj:`str`, optional): URL of the result.
-        hide_url (:obj:`bool`, optional): Pass :obj:`True`, if you don't want the URL to be shown
-            in the message.
-
-            .. deprecated:: 21.10
-                This attribute will be removed in future PTB versions. Pass an empty string as URL
-                instead.
-        description (:obj:`str`, optional): Short description of the result.
-        thumbnail_url (:obj:`str`, optional): Url of the thumbnail for the result.
-
-            .. versionadded:: 20.2
-        thumbnail_width (:obj:`int`, optional): Thumbnail width.
-
-            .. versionadded:: 20.2
-        thumbnail_height (:obj:`int`, optional): Thumbnail height.
-
-            .. versionadded:: 20.2
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.ARTICLE`.
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        title (:obj:`str`): Title of the result.
-        input_message_content (:class:`telegram.InputMessageContent`): Content of the message to
-            be sent.
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
-            to the message.
-        url (:obj:`str`): Optional. URL of the result.
-        hide_url (:obj:`bool`): Optional. Pass :obj:`True`, if you don't want the URL to be shown
-            in the message.
-
-            .. deprecated:: 21.10
-                This attribute will be removed in future PTB versions. Pass an empty string as URL
-                instead.
-        description (:obj:`str`): Optional. Short description of the result.
-        thumbnail_url (:obj:`str`): Optional. Url of the thumbnail for the result.
-
-            .. versionadded:: 20.2
-        thumbnail_width (:obj:`int`): Optional. Thumbnail width.
-
-            .. versionadded:: 20.2
-        thumbnail_height (:obj:`int`): Optional. Thumbnail height.
-
-            .. versionadded:: 20.2
-
-    """
-
-    __slots__ = (
-        "description",
-        "hide_url",
-        "input_message_content",
-        "reply_markup",
-        "thumbnail_height",
-        "thumbnail_url",
-        "thumbnail_width",
-        "title",
-        "url",
-    )
-
-    def __init__(
-        self,
-        id: str,  # pylint: disable=redefined-builtin
-        title: str,
-        input_message_content: "InputMessageContent",
-        reply_markup: Optional[InlineKeyboardMarkup] = None,
-        url: Optional[str] = None,
-        hide_url: Optional[bool] = None,
-        description: Optional[str] = None,
-        thumbnail_url: Optional[str] = None,
-        thumbnail_width: Optional[int] = None,
-        thumbnail_height: Optional[int] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        # Required
-        super().__init__(InlineQueryResultType.ARTICLE, id, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.title: str = title
-            self.input_message_content: InputMessageContent = input_message_content
-
-            # Optional
-            self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
-            self.url: Optional[str] = url
-            if hide_url is not None:
-                warn(
-                    PTBDeprecationWarning(
-                        "21.10",
-                        "The argument `hide_url` will be removed in future PTB"
-                        "versions. Pass an empty string as URL instead.",
-                    ),
-                    stacklevel=2,
-                )
-            self.hide_url: Optional[bool] = hide_url
-            self.description: Optional[str] = description
-            self.thumbnail_url: Optional[str] = thumbnail_url
-            self.thumbnail_width: Optional[int] = thumbnail_width
-            self.thumbnail_height: Optional[int] = thumbnail_height
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultaudio.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultaudio.py
deleted file mode 100755
index 8e3376a..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultaudio.py
+++ /dev/null
@@ -1,130 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InlineQueryResultAudio."""
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Optional
-
-from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
-from telegram._inline.inlinequeryresult import InlineQueryResult
-from telegram._messageentity import MessageEntity
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.types import JSONDict, ODVInput
-from telegram.constants import InlineQueryResultType
-
-if TYPE_CHECKING:
-    from telegram import InputMessageContent
-
-
-class InlineQueryResultAudio(InlineQueryResult):
-    """
-    Represents a link to an mp3 audio file. By default, this audio file will be sent by the user.
-    Alternatively, you can use :attr:`input_message_content` to send a message with the specified
-    content instead of the audio.
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    Args:
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        audio_url (:obj:`str`): A valid URL for the audio file.
-        title (:obj:`str`): Title.
-        performer (:obj:`str`, optional): Performer.
-        audio_duration (:obj:`str`, optional): Audio duration in seconds.
-        caption (:obj:`str`, optional): Caption,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities
-            parsing.
-        parse_mode (:obj:`str`, optional): |parse_mode|
-        caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
-            message to be sent instead of the audio.
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.AUDIO`.
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        audio_url (:obj:`str`): A valid URL for the audio file.
-        title (:obj:`str`): Title.
-        performer (:obj:`str`): Optional. Performer.
-        audio_duration (:obj:`str`): Optional. Audio duration in seconds.
-        caption (:obj:`str`): Optional. Caption,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities
-            parsing.
-        parse_mode (:obj:`str`): Optional. |parse_mode|
-        caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
-
-            .. versionchanged:: 20.0
-
-                * |tupleclassattrs|
-                * |alwaystuple|
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
-            message to be sent instead of the audio.
-
-    """
-
-    __slots__ = (
-        "audio_duration",
-        "audio_url",
-        "caption",
-        "caption_entities",
-        "input_message_content",
-        "parse_mode",
-        "performer",
-        "reply_markup",
-        "title",
-    )
-
-    def __init__(
-        self,
-        id: str,  # pylint: disable=redefined-builtin
-        audio_url: str,
-        title: str,
-        performer: Optional[str] = None,
-        audio_duration: Optional[int] = None,
-        caption: Optional[str] = None,
-        reply_markup: Optional[InlineKeyboardMarkup] = None,
-        input_message_content: Optional["InputMessageContent"] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence[MessageEntity]] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        # Required
-        super().__init__(InlineQueryResultType.AUDIO, id, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.audio_url: str = audio_url
-            self.title: str = title
-
-            # Optionals
-            self.performer: Optional[str] = performer
-            self.audio_duration: Optional[int] = audio_duration
-            self.caption: Optional[str] = caption
-            self.parse_mode: ODVInput[str] = parse_mode
-            self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
-            self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
-            self.input_message_content: Optional[InputMessageContent] = input_message_content
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedaudio.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedaudio.py
deleted file mode 100755
index f1f75a1..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedaudio.py
+++ /dev/null
@@ -1,116 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InlineQueryResultCachedAudio."""
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Optional
-
-from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
-from telegram._inline.inlinequeryresult import InlineQueryResult
-from telegram._messageentity import MessageEntity
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.types import JSONDict, ODVInput
-from telegram.constants import InlineQueryResultType
-
-if TYPE_CHECKING:
-    from telegram import InputMessageContent
-
-
-class InlineQueryResultCachedAudio(InlineQueryResult):
-    """
-    Represents a link to an mp3 audio file stored on the Telegram servers. By default, this audio
-    file will be sent by the user. Alternatively, you can use :attr:`input_message_content` to
-    send a message with the specified content instead of the audio.
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    Args:
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        audio_file_id (:obj:`str`): A valid file identifier for the audio file.
-        caption (:obj:`str`, optional): Caption,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities
-            parsing.
-        parse_mode (:obj:`str`, optional): |parse_mode|
-        caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
-            message to be sent instead of the audio.
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.AUDIO`.
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        audio_file_id (:obj:`str`): A valid file identifier for the audio file.
-        caption (:obj:`str`): Optional. Caption,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities
-            parsing.
-        parse_mode (:obj:`str`): Optional. |parse_mode|
-        caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
-
-            .. versionchanged:: 20.0
-
-                * |tupleclassattrs|
-                * |alwaystuple|
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
-            message to be sent instead of the audio.
-
-    """
-
-    __slots__ = (
-        "audio_file_id",
-        "caption",
-        "caption_entities",
-        "input_message_content",
-        "parse_mode",
-        "reply_markup",
-    )
-
-    def __init__(
-        self,
-        id: str,  # pylint: disable=redefined-builtin
-        audio_file_id: str,
-        caption: Optional[str] = None,
-        reply_markup: Optional[InlineKeyboardMarkup] = None,
-        input_message_content: Optional["InputMessageContent"] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence[MessageEntity]] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        # Required
-        super().__init__(InlineQueryResultType.AUDIO, id, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.audio_file_id: str = audio_file_id
-
-            # Optionals
-            self.caption: Optional[str] = caption
-            self.parse_mode: ODVInput[str] = parse_mode
-            self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
-            self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
-            self.input_message_content: Optional[InputMessageContent] = input_message_content
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcacheddocument.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcacheddocument.py
deleted file mode 100755
index af2e6ef..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcacheddocument.py
+++ /dev/null
@@ -1,126 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InlineQueryResultCachedDocument."""
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Optional
-
-from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
-from telegram._inline.inlinequeryresult import InlineQueryResult
-from telegram._messageentity import MessageEntity
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.types import JSONDict, ODVInput
-from telegram.constants import InlineQueryResultType
-
-if TYPE_CHECKING:
-    from telegram import InputMessageContent
-
-
-class InlineQueryResultCachedDocument(InlineQueryResult):
-    """
-    Represents a link to a file stored on the Telegram servers. By default, this file will be sent
-    by the user with an optional caption. Alternatively, you can use :attr:`input_message_content`
-    to send a message with the specified content instead of the file.
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    Args:
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        title (:obj:`str`): Title for the result.
-        document_file_id (:obj:`str`): A valid file identifier for the file.
-        description (:obj:`str`, optional): Short description of the result.
-        caption (:obj:`str`, optional): Caption of the document to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
-            after entities parsing.
-        parse_mode (:obj:`str`, optional): |parse_mode|
-        caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
-            message to be sent instead of the file.
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.DOCUMENT`.
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        title (:obj:`str`): Title for the result.
-        document_file_id (:obj:`str`): A valid file identifier for the file.
-        description (:obj:`str`): Optional. Short description of the result.
-        caption (:obj:`str`): Optional. Caption of the document to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
-            after entities parsing.
-        parse_mode (:obj:`str`): Optional. |parse_mode|
-        caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
-
-            .. versionchanged:: 20.0
-
-                * |tupleclassattrs|
-                * |alwaystuple|
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
-            message to be sent instead of the file.
-
-    """
-
-    __slots__ = (
-        "caption",
-        "caption_entities",
-        "description",
-        "document_file_id",
-        "input_message_content",
-        "parse_mode",
-        "reply_markup",
-        "title",
-    )
-
-    def __init__(
-        self,
-        id: str,  # pylint: disable=redefined-builtin
-        title: str,
-        document_file_id: str,
-        description: Optional[str] = None,
-        caption: Optional[str] = None,
-        reply_markup: Optional[InlineKeyboardMarkup] = None,
-        input_message_content: Optional["InputMessageContent"] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence[MessageEntity]] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        # Required
-        super().__init__(InlineQueryResultType.DOCUMENT, id, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.title: str = title
-            self.document_file_id: str = document_file_id
-
-            # Optionals
-            self.description: Optional[str] = description
-            self.caption: Optional[str] = caption
-            self.parse_mode: ODVInput[str] = parse_mode
-            self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
-            self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
-            self.input_message_content: Optional[InputMessageContent] = input_message_content
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedgif.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedgif.py
deleted file mode 100755
index f682ec0..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedgif.py
+++ /dev/null
@@ -1,131 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InlineQueryResultCachedGif."""
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Optional
-
-from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
-from telegram._inline.inlinequeryresult import InlineQueryResult
-from telegram._messageentity import MessageEntity
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.types import JSONDict, ODVInput
-from telegram.constants import InlineQueryResultType
-
-if TYPE_CHECKING:
-    from telegram import InputMessageContent
-
-
-class InlineQueryResultCachedGif(InlineQueryResult):
-    """
-    Represents a link to an animated GIF file stored on the Telegram servers. By default, this
-    animated GIF file will be sent by the user with an optional caption. Alternatively, you can
-    use :attr:`input_message_content` to send a message with specified content instead of
-    the animation.
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    Args:
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        gif_file_id (:obj:`str`): A valid file identifier for the GIF file.
-        title (:obj:`str`, optional): Title for the result.
-        caption (:obj:`str`, optional): Caption of the GIF file to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
-            after entities parsing.
-        parse_mode (:obj:`str`, optional): |parse_mode|
-        caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
-            message to be sent instead of the gif.
-        show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
-
-            .. versionadded:: 21.3
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.GIF`.
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        gif_file_id (:obj:`str`): A valid file identifier for the GIF file.
-        title (:obj:`str`): Optional. Title for the result.
-        caption (:obj:`str`): Optional. Caption of the GIF file to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
-            after entities parsing.
-        parse_mode (:obj:`str`): Optional. |parse_mode|
-        caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
-
-            .. versionchanged:: 20.0
-
-                * |tupleclassattrs|
-                * |alwaystuple|
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
-            message to be sent instead of the gif.
-        show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
-
-            .. versionadded:: 21.3
-
-    """
-
-    __slots__ = (
-        "caption",
-        "caption_entities",
-        "gif_file_id",
-        "input_message_content",
-        "parse_mode",
-        "reply_markup",
-        "show_caption_above_media",
-        "title",
-    )
-
-    def __init__(
-        self,
-        id: str,  # pylint: disable=redefined-builtin
-        gif_file_id: str,
-        title: Optional[str] = None,
-        caption: Optional[str] = None,
-        reply_markup: Optional[InlineKeyboardMarkup] = None,
-        input_message_content: Optional["InputMessageContent"] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence[MessageEntity]] = None,
-        show_caption_above_media: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        # Required
-        super().__init__(InlineQueryResultType.GIF, id, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.gif_file_id: str = gif_file_id
-
-            # Optionals
-            self.title: Optional[str] = title
-            self.caption: Optional[str] = caption
-            self.parse_mode: ODVInput[str] = parse_mode
-            self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
-            self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
-            self.input_message_content: Optional[InputMessageContent] = input_message_content
-            self.show_caption_above_media: Optional[bool] = show_caption_above_media
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedmpeg4gif.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedmpeg4gif.py
deleted file mode 100755
index 6dc7e55..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedmpeg4gif.py
+++ /dev/null
@@ -1,131 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InlineQueryResultMpeg4Gif."""
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Optional
-
-from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
-from telegram._inline.inlinequeryresult import InlineQueryResult
-from telegram._messageentity import MessageEntity
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.types import JSONDict, ODVInput
-from telegram.constants import InlineQueryResultType
-
-if TYPE_CHECKING:
-    from telegram import InputMessageContent
-
-
-class InlineQueryResultCachedMpeg4Gif(InlineQueryResult):
-    """
-    Represents a link to a video animation (H.264/MPEG-4 AVC video without sound) stored on the
-    Telegram servers. By default, this animated MPEG-4 file will be sent by the user with an
-    optional caption. Alternatively, you can use :attr:`input_message_content` to send a message
-    with the specified content instead of the animation.
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    Args:
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        mpeg4_file_id (:obj:`str`): A valid file identifier for the MP4 file.
-        title (:obj:`str`, optional): Title for the result.
-        caption (:obj:`str`, optional): Caption of the MPEG-4 file to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
-            after entities parsing.
-        parse_mode (:obj:`str`, optional): |parse_mode|
-        caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
-            message to be sent instead of the MPEG-4 file.
-        show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
-
-            .. versionadded:: 21.3
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.MPEG4GIF`.
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        mpeg4_file_id (:obj:`str`): A valid file identifier for the MP4 file.
-        title (:obj:`str`): Optional. Title for the result.
-        caption (:obj:`str`): Optional. Caption of the MPEG-4 file to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
-            after entities parsing.
-        parse_mode (:obj:`str`): Optional. |parse_mode|
-        caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
-
-            .. versionchanged:: 20.0
-
-                * |tupleclassattrs|
-                * |alwaystuple|
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
-            message to be sent instead of the MPEG-4 file.
-        show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
-
-            .. versionadded:: 21.3
-
-    """
-
-    __slots__ = (
-        "caption",
-        "caption_entities",
-        "input_message_content",
-        "mpeg4_file_id",
-        "parse_mode",
-        "reply_markup",
-        "show_caption_above_media",
-        "title",
-    )
-
-    def __init__(
-        self,
-        id: str,  # pylint: disable=redefined-builtin
-        mpeg4_file_id: str,
-        title: Optional[str] = None,
-        caption: Optional[str] = None,
-        reply_markup: Optional[InlineKeyboardMarkup] = None,
-        input_message_content: Optional["InputMessageContent"] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence[MessageEntity]] = None,
-        show_caption_above_media: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        # Required
-        super().__init__(InlineQueryResultType.MPEG4GIF, id, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.mpeg4_file_id: str = mpeg4_file_id
-
-            # Optionals
-            self.title: Optional[str] = title
-            self.caption: Optional[str] = caption
-            self.parse_mode: ODVInput[str] = parse_mode
-            self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
-            self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
-            self.input_message_content: Optional[InputMessageContent] = input_message_content
-            self.show_caption_above_media: Optional[bool] = show_caption_above_media
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedphoto.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedphoto.py
deleted file mode 100755
index adf8ea6..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedphoto.py
+++ /dev/null
@@ -1,136 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InlineQueryResultPhoto"""
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Optional
-
-from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
-from telegram._inline.inlinequeryresult import InlineQueryResult
-from telegram._messageentity import MessageEntity
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.types import JSONDict, ODVInput
-from telegram.constants import InlineQueryResultType
-
-if TYPE_CHECKING:
-    from telegram import InputMessageContent
-
-
-class InlineQueryResultCachedPhoto(InlineQueryResult):
-    """
-    Represents a link to a photo stored on the Telegram servers. By default, this photo will be
-    sent by the user with an optional caption. Alternatively, you can use
-    :attr:`input_message_content` to send a message with the specified content instead
-    of the photo.
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    Args:
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        photo_file_id (:obj:`str`): A valid file identifier of the photo.
-        title (:obj:`str`, optional): Title for the result.
-        description (:obj:`str`, optional): Short description of the result.
-        caption (:obj:`str`, optional): Caption of the photo to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
-            entities parsing.
-        parse_mode (:obj:`str`, optional): |parse_mode|
-        caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
-            message to be sent instead of the photo.
-        show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
-
-            .. versionadded:: 21.3
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.PHOTO`.
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        photo_file_id (:obj:`str`): A valid file identifier of the photo.
-        title (:obj:`str`): Optional. Title for the result.
-        description (:obj:`str`): Optional. Short description of the result.
-        caption (:obj:`str`): Optional. Caption of the photo to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
-            entities parsing.
-        parse_mode (:obj:`str`): Optional. |parse_mode|
-        caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
-
-            .. versionchanged:: 20.0
-
-                * |tupleclassattrs|
-                * |alwaystuple|
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
-            message to be sent instead of the photo.
-        show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
-
-            .. versionadded:: 21.3
-
-    """
-
-    __slots__ = (
-        "caption",
-        "caption_entities",
-        "description",
-        "input_message_content",
-        "parse_mode",
-        "photo_file_id",
-        "reply_markup",
-        "show_caption_above_media",
-        "title",
-    )
-
-    def __init__(
-        self,
-        id: str,  # pylint: disable=redefined-builtin
-        photo_file_id: str,
-        title: Optional[str] = None,
-        description: Optional[str] = None,
-        caption: Optional[str] = None,
-        reply_markup: Optional[InlineKeyboardMarkup] = None,
-        input_message_content: Optional["InputMessageContent"] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence[MessageEntity]] = None,
-        show_caption_above_media: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        # Required
-        super().__init__(InlineQueryResultType.PHOTO, id, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.photo_file_id: str = photo_file_id
-
-            # Optionals
-            self.title: Optional[str] = title
-            self.description: Optional[str] = description
-            self.caption: Optional[str] = caption
-            self.parse_mode: ODVInput[str] = parse_mode
-            self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
-            self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
-            self.input_message_content: Optional[InputMessageContent] = input_message_content
-            self.show_caption_above_media: Optional[bool] = show_caption_above_media
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedsticker.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedsticker.py
deleted file mode 100755
index 0dd8c55..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedsticker.py
+++ /dev/null
@@ -1,81 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InlineQueryResultCachedSticker."""
-
-from typing import TYPE_CHECKING, Optional
-
-from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
-from telegram._inline.inlinequeryresult import InlineQueryResult
-from telegram._utils.types import JSONDict
-from telegram.constants import InlineQueryResultType
-
-if TYPE_CHECKING:
-    from telegram import InputMessageContent
-
-
-class InlineQueryResultCachedSticker(InlineQueryResult):
-    """
-    Represents a link to a sticker stored on the Telegram servers. By default, this sticker will
-    be sent by the user. Alternatively, you can use :attr:`input_message_content` to send a
-    message with the specified content instead of the sticker.
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    Args:
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        sticker_file_id (:obj:`str`): A valid file identifier of the sticker.
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
-            message to be sent instead of the sticker.
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.STICKER`.
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        sticker_file_id (:obj:`str`): A valid file identifier of the sticker.
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
-            message to be sent instead of the sticker.
-
-    """
-
-    __slots__ = ("input_message_content", "reply_markup", "sticker_file_id")
-
-    def __init__(
-        self,
-        id: str,  # pylint: disable=redefined-builtin
-        sticker_file_id: str,
-        reply_markup: Optional[InlineKeyboardMarkup] = None,
-        input_message_content: Optional["InputMessageContent"] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        # Required
-        super().__init__(InlineQueryResultType.STICKER, id, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.sticker_file_id: str = sticker_file_id
-
-            # Optionals
-            self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
-            self.input_message_content: Optional[InputMessageContent] = input_message_content
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedvideo.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedvideo.py
deleted file mode 100755
index 3595330..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedvideo.py
+++ /dev/null
@@ -1,132 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InlineQueryResultCachedVideo."""
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Optional
-
-from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
-from telegram._inline.inlinequeryresult import InlineQueryResult
-from telegram._messageentity import MessageEntity
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.types import JSONDict, ODVInput
-from telegram.constants import InlineQueryResultType
-
-if TYPE_CHECKING:
-    from telegram import InputMessageContent
-
-
-class InlineQueryResultCachedVideo(InlineQueryResult):
-    """
-    Represents a link to a video file stored on the Telegram servers. By default, this video file
-    will be sent by the user with an optional caption. Alternatively, you can use
-    :attr:`input_message_content` to send a message with the specified content instead
-    of the video.
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    Args:
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        video_file_id (:obj:`str`): A valid file identifier for the video file.
-        title (:obj:`str`): Title for the result.
-        description (:obj:`str`, optional): Short description of the result.
-        caption (:obj:`str`, optional): Caption of the video to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
-            entities parsing.
-        parse_mode (:obj:`str`, optional): |parse_mode|
-        caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
-            message to be sent instead of the video.
-        show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
-
-            .. versionadded:: 21.3
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.VIDEO`.
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        video_file_id (:obj:`str`): A valid file identifier for the video file.
-        title (:obj:`str`): Title for the result.
-        description (:obj:`str`): Optional. Short description of the result.
-        caption (:obj:`str`): Optional. Caption of the video to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
-            entities parsing.
-        parse_mode (:obj:`str`): Optional. |parse_mode|
-        caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
-
-            .. versionchanged:: 20.0
-
-                * |tupleclassattrs|
-                * |alwaystuple|
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
-            message to be sent instead of the video.
-        show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
-
-            .. versionadded:: 21.3
-
-    """
-
-    __slots__ = (
-        "caption",
-        "caption_entities",
-        "description",
-        "input_message_content",
-        "parse_mode",
-        "reply_markup",
-        "show_caption_above_media",
-        "title",
-        "video_file_id",
-    )
-
-    def __init__(
-        self,
-        id: str,  # pylint: disable=redefined-builtin
-        video_file_id: str,
-        title: str,
-        description: Optional[str] = None,
-        caption: Optional[str] = None,
-        reply_markup: Optional[InlineKeyboardMarkup] = None,
-        input_message_content: Optional["InputMessageContent"] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence[MessageEntity]] = None,
-        show_caption_above_media: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        # Required
-        super().__init__(InlineQueryResultType.VIDEO, id, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.video_file_id: str = video_file_id
-            self.title: str = title
-
-            # Optionals
-            self.description: Optional[str] = description
-            self.caption: Optional[str] = caption
-            self.parse_mode: ODVInput[str] = parse_mode
-            self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
-            self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
-            self.input_message_content: Optional[InputMessageContent] = input_message_content
-            self.show_caption_above_media: Optional[bool] = show_caption_above_media
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedvoice.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedvoice.py
deleted file mode 100755
index 139fdab..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcachedvoice.py
+++ /dev/null
@@ -1,121 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InlineQueryResultCachedVoice."""
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Optional
-
-from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
-from telegram._inline.inlinequeryresult import InlineQueryResult
-from telegram._messageentity import MessageEntity
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.types import JSONDict, ODVInput
-from telegram.constants import InlineQueryResultType
-
-if TYPE_CHECKING:
-    from telegram import InputMessageContent
-
-
-class InlineQueryResultCachedVoice(InlineQueryResult):
-    """
-    Represents a link to a voice message stored on the Telegram servers. By default, this voice
-    message will be sent by the user. Alternatively, you can use :attr:`input_message_content` to
-    send a message with the specified content instead of the voice message.
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    Args:
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        voice_file_id (:obj:`str`): A valid file identifier for the voice message.
-        title (:obj:`str`): Voice message title.
-        caption (:obj:`str`, optional): Caption,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities
-            parsing.
-        parse_mode (:obj:`str`, optional): |parse_mode|
-        caption_entities (Sequence[:class:`telegram.MessageEntity`], optional):
-            |captionentitiesattr|
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
-            message to be sent instead of the voice message.
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.VOICE`.
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        voice_file_id (:obj:`str`): A valid file identifier for the voice message.
-        title (:obj:`str`): Voice message title.
-        caption (:obj:`str`): Optional. Caption,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities
-            parsing.
-        parse_mode (:obj:`str`): Optional. |parse_mode|
-        caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
-
-            .. versionchanged:: 20.0
-
-                * |tupleclassattrs|
-                * |alwaystuple|
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
-            message to be sent instead of the voice message.
-
-    """
-
-    __slots__ = (
-        "caption",
-        "caption_entities",
-        "input_message_content",
-        "parse_mode",
-        "reply_markup",
-        "title",
-        "voice_file_id",
-    )
-
-    def __init__(
-        self,
-        id: str,  # pylint: disable=redefined-builtin
-        voice_file_id: str,
-        title: str,
-        caption: Optional[str] = None,
-        reply_markup: Optional[InlineKeyboardMarkup] = None,
-        input_message_content: Optional["InputMessageContent"] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence[MessageEntity]] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        # Required
-        super().__init__(InlineQueryResultType.VOICE, id, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.voice_file_id: str = voice_file_id
-            self.title: str = title
-
-            # Optionals
-            self.caption: Optional[str] = caption
-            self.parse_mode: ODVInput[str] = parse_mode
-            self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
-            self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
-            self.input_message_content: Optional[InputMessageContent] = input_message_content
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcontact.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcontact.py
deleted file mode 100755
index 7ededbb..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultcontact.py
+++ /dev/null
@@ -1,130 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InlineQueryResultContact."""
-
-from typing import TYPE_CHECKING, Optional
-
-from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
-from telegram._inline.inlinequeryresult import InlineQueryResult
-from telegram._utils.types import JSONDict
-from telegram.constants import InlineQueryResultType
-
-if TYPE_CHECKING:
-    from telegram import InputMessageContent
-
-
-class InlineQueryResultContact(InlineQueryResult):
-    """
-    Represents a contact with a phone number. By default, this contact will be sent by the user.
-    Alternatively, you can use :attr:`input_message_content` to send a message with the specified
-    content instead of the contact.
-
-    .. versionchanged:: 20.5
-        |removed_thumb_wildcard_note|
-
-    Args:
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        phone_number (:obj:`str`): Contact's phone number.
-        first_name (:obj:`str`): Contact's first name.
-        last_name (:obj:`str`, optional): Contact's last name.
-        vcard (:obj:`str`, optional): Additional data about the contact in the form of a vCard,
-            0-:tg-const:`telegram.constants.ContactLimit.VCARD` bytes.
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
-            message to be sent instead of the contact.
-        thumbnail_url (:obj:`str`, optional): Url of the thumbnail for the result.
-
-            .. versionadded:: 20.2
-        thumbnail_width (:obj:`int`, optional): Thumbnail width.
-
-            .. versionadded:: 20.2
-        thumbnail_height (:obj:`int`, optional): Thumbnail height.
-
-            .. versionadded:: 20.2
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.CONTACT`.
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        phone_number (:obj:`str`): Contact's phone number.
-        first_name (:obj:`str`): Contact's first name.
-        last_name (:obj:`str`): Optional. Contact's last name.
-        vcard (:obj:`str`): Optional. Additional data about the contact in the form of a vCard,
-            0-:tg-const:`telegram.constants.ContactLimit.VCARD` bytes.
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
-            message to be sent instead of the contact.
-        thumbnail_url (:obj:`str`): Optional. Url of the thumbnail for the result.
-
-            .. versionadded:: 20.2
-        thumbnail_width (:obj:`int`): Optional. Thumbnail width.
-
-            .. versionadded:: 20.2
-        thumbnail_height (:obj:`int`): Optional. Thumbnail height.
-
-            .. versionadded:: 20.2
-
-    """
-
-    __slots__ = (
-        "first_name",
-        "input_message_content",
-        "last_name",
-        "phone_number",
-        "reply_markup",
-        "thumbnail_height",
-        "thumbnail_url",
-        "thumbnail_width",
-        "vcard",
-    )
-
-    def __init__(
-        self,
-        id: str,  # pylint: disable=redefined-builtin
-        phone_number: str,
-        first_name: str,
-        last_name: Optional[str] = None,
-        reply_markup: Optional[InlineKeyboardMarkup] = None,
-        input_message_content: Optional["InputMessageContent"] = None,
-        vcard: Optional[str] = None,
-        thumbnail_url: Optional[str] = None,
-        thumbnail_width: Optional[int] = None,
-        thumbnail_height: Optional[int] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        # Required
-        super().__init__(InlineQueryResultType.CONTACT, id, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.phone_number: str = phone_number
-            self.first_name: str = first_name
-
-            # Optionals
-            self.last_name: Optional[str] = last_name
-            self.vcard: Optional[str] = vcard
-            self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
-            self.input_message_content: Optional[InputMessageContent] = input_message_content
-            self.thumbnail_url: Optional[str] = thumbnail_url
-            self.thumbnail_width: Optional[int] = thumbnail_width
-            self.thumbnail_height: Optional[int] = thumbnail_height
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultdocument.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultdocument.py
deleted file mode 100755
index e7114ef..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultdocument.py
+++ /dev/null
@@ -1,165 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InlineQueryResultDocument"""
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Optional
-
-from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
-from telegram._inline.inlinequeryresult import InlineQueryResult
-from telegram._messageentity import MessageEntity
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.types import JSONDict, ODVInput
-from telegram.constants import InlineQueryResultType
-
-if TYPE_CHECKING:
-    from telegram import InputMessageContent
-
-
-class InlineQueryResultDocument(InlineQueryResult):
-    """
-    Represents a link to a file. By default, this file will be sent by the user with an optional
-    caption. Alternatively, you can use :attr:`input_message_content` to send a message with the
-    specified content instead of the file. Currently, only .PDF and .ZIP files can be sent
-    using this method.
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    .. versionchanged:: 20.5
-        |removed_thumb_wildcard_note|
-
-    Args:
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        title (:obj:`str`): Title for the result.
-        caption (:obj:`str`, optional): Caption of the document to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
-            after entities parsing.
-        parse_mode (:obj:`str`, optional): |parse_mode|
-        caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        document_url (:obj:`str`): A valid URL for the file.
-        mime_type (:obj:`str`): Mime type of the content of the file, either "application/pdf"
-            or "application/zip".
-        description (:obj:`str`, optional): Short description of the result.
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
-            message to be sent instead of the file.
-        thumbnail_url (:obj:`str`, optional): URL of the thumbnail (JPEG only) for the file.
-
-            .. versionadded:: 20.2
-        thumbnail_width (:obj:`int`, optional): Thumbnail width.
-
-            .. versionadded:: 20.2
-        thumbnail_height (:obj:`int`, optional): Thumbnail height.
-
-            .. versionadded:: 20.2
-
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.DOCUMENT`.
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        title (:obj:`str`): Title for the result.
-        caption (:obj:`str`): Optional. Caption of the document to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
-            after entities parsing.
-        parse_mode (:obj:`str`): Optional. |parse_mode|
-        caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
-
-            .. versionchanged:: 20.0
-
-                * |tupleclassattrs|
-                * |alwaystuple|
-        document_url (:obj:`str`): A valid URL for the file.
-        mime_type (:obj:`str`): Mime type of the content of the file, either "application/pdf"
-            or "application/zip".
-        description (:obj:`str`): Optional. Short description of the result.
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
-            message to be sent instead of the file.
-        thumbnail_url (:obj:`str`): Optional. URL of the thumbnail (JPEG only) for the file.
-
-            .. versionadded:: 20.2
-        thumbnail_width (:obj:`int`): Optional. Thumbnail width.
-
-            .. versionadded:: 20.2
-        thumbnail_height (:obj:`int`): Optional. Thumbnail height.
-
-            .. versionadded:: 20.2
-
-    """
-
-    __slots__ = (
-        "caption",
-        "caption_entities",
-        "description",
-        "document_url",
-        "input_message_content",
-        "mime_type",
-        "parse_mode",
-        "reply_markup",
-        "thumbnail_height",
-        "thumbnail_url",
-        "thumbnail_width",
-        "title",
-    )
-
-    def __init__(
-        self,
-        id: str,  # pylint: disable=redefined-builtin
-        document_url: str,
-        title: str,
-        mime_type: str,
-        caption: Optional[str] = None,
-        description: Optional[str] = None,
-        reply_markup: Optional[InlineKeyboardMarkup] = None,
-        input_message_content: Optional["InputMessageContent"] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence[MessageEntity]] = None,
-        thumbnail_url: Optional[str] = None,
-        thumbnail_width: Optional[int] = None,
-        thumbnail_height: Optional[int] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        # Required
-        super().__init__(InlineQueryResultType.DOCUMENT, id, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.document_url: str = document_url
-            self.title: str = title
-            self.mime_type: str = mime_type
-
-            # Optionals
-            self.caption: Optional[str] = caption
-            self.parse_mode: ODVInput[str] = parse_mode
-            self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
-            self.description: Optional[str] = description
-            self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
-            self.input_message_content: Optional[InputMessageContent] = input_message_content
-            self.thumbnail_url: Optional[str] = thumbnail_url
-            self.thumbnail_width: Optional[int] = thumbnail_width
-            self.thumbnail_height: Optional[int] = thumbnail_height
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultgame.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultgame.py
deleted file mode 100755
index 27b12c8..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultgame.py
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InlineQueryResultGame."""
-from typing import Optional
-
-from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
-from telegram._inline.inlinequeryresult import InlineQueryResult
-from telegram._utils.types import JSONDict
-from telegram.constants import InlineQueryResultType
-
-
-class InlineQueryResultGame(InlineQueryResult):
-    """Represents a :class:`telegram.Game`.
-
-    Args:
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        game_short_name (:obj:`str`): Short name of the game.
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
-            to the message.
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.GAME`.
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        game_short_name (:obj:`str`): Short name of the game.
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
-            to the message.
-
-    """
-
-    __slots__ = ("game_short_name", "reply_markup")
-
-    def __init__(
-        self,
-        id: str,  # pylint: disable=redefined-builtin
-        game_short_name: str,
-        reply_markup: Optional[InlineKeyboardMarkup] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        # Required
-        super().__init__(InlineQueryResultType.GAME, id, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.id: str = id
-            self.game_short_name: str = game_short_name
-
-            self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultgif.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultgif.py
deleted file mode 100755
index f454f44..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultgif.py
+++ /dev/null
@@ -1,174 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InlineQueryResultGif."""
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Optional
-
-from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
-from telegram._inline.inlinequeryresult import InlineQueryResult
-from telegram._messageentity import MessageEntity
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.types import JSONDict, ODVInput
-from telegram.constants import InlineQueryResultType
-
-if TYPE_CHECKING:
-    from telegram import InputMessageContent
-
-
-class InlineQueryResultGif(InlineQueryResult):
-    """
-    Represents a link to an animated GIF file. By default, this animated GIF file will be sent by
-    the user with optional caption. Alternatively, you can use :attr:`input_message_content` to
-    send a message with the specified content instead of the animation.
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    .. versionchanged:: 20.5
-      |removed_thumb_wildcard_note|
-
-    Args:
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        gif_url (:obj:`str`): A valid URL for the GIF file. File size must not exceed 1MB.
-        gif_width (:obj:`int`, optional): Width of the GIF.
-        gif_height (:obj:`int`, optional): Height of the GIF.
-        gif_duration (:obj:`int`, optional): Duration of the GIF in seconds.
-        thumbnail_url (:obj:`str`): URL of the static (JPEG or GIF) or animated (MPEG4)
-            thumbnail for the result.
-
-            .. versionadded:: 20.2
-
-            ..versionchanged:: 20.5
-              |thumbnail_url_mandatory|
-
-        thumbnail_mime_type (:obj:`str`, optional): MIME type of the thumbnail, must be one of
-            ``'image/jpeg'``, ``'image/gif'``, or ``'video/mp4'``. Defaults to ``'image/jpeg'``.
-
-            .. versionadded:: 20.2
-        title (:obj:`str`, optional): Title for the result.
-        caption (:obj:`str`, optional): Caption of the GIF file to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
-            after entities parsing.
-        parse_mode (:obj:`str`, optional): |parse_mode|
-        caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
-            message to be sent instead of the GIF animation.
-        show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
-
-            .. versionadded:: 21.3
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.GIF`.
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        gif_url (:obj:`str`): A valid URL for the GIF file. File size must not exceed 1MB.
-        gif_width (:obj:`int`): Optional. Width of the GIF.
-        gif_height (:obj:`int`): Optional. Height of the GIF.
-        gif_duration (:obj:`int`): Optional. Duration of the GIF in seconds.
-        thumbnail_url (:obj:`str`): URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail
-            for the result.
-
-            .. versionadded:: 20.2
-        thumbnail_mime_type (:obj:`str`): Optional. MIME type of the thumbnail, must be one of
-            ``'image/jpeg'``, ``'image/gif'``, or ``'video/mp4'``. Defaults to ``'image/jpeg'``.
-
-            .. versionadded:: 20.2
-        title (:obj:`str`): Optional. Title for the result.
-        caption (:obj:`str`): Optional. Caption of the GIF file to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
-            after entities parsing.
-        parse_mode (:obj:`str`): Optional. |parse_mode|
-        caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
-
-            .. versionchanged:: 20.0
-
-                * |tupleclassattrs|
-                * |alwaystuple|
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
-            message to be sent instead of the GIF animation.
-        show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
-
-            .. versionadded:: 21.3
-
-    """
-
-    __slots__ = (
-        "caption",
-        "caption_entities",
-        "gif_duration",
-        "gif_height",
-        "gif_url",
-        "gif_width",
-        "input_message_content",
-        "parse_mode",
-        "reply_markup",
-        "show_caption_above_media",
-        "thumbnail_mime_type",
-        "thumbnail_url",
-        "title",
-    )
-
-    def __init__(
-        self,
-        id: str,  # pylint: disable=redefined-builtin
-        gif_url: str,
-        thumbnail_url: str,
-        gif_width: Optional[int] = None,
-        gif_height: Optional[int] = None,
-        title: Optional[str] = None,
-        caption: Optional[str] = None,
-        reply_markup: Optional[InlineKeyboardMarkup] = None,
-        input_message_content: Optional["InputMessageContent"] = None,
-        gif_duration: Optional[int] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence[MessageEntity]] = None,
-        thumbnail_mime_type: Optional[str] = None,
-        show_caption_above_media: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        # Required
-        super().__init__(InlineQueryResultType.GIF, id, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.gif_url: str = gif_url
-            self.thumbnail_url: str = thumbnail_url
-
-            # Optionals
-            self.gif_width: Optional[int] = gif_width
-            self.gif_height: Optional[int] = gif_height
-            self.gif_duration: Optional[int] = gif_duration
-            self.title: Optional[str] = title
-            self.caption: Optional[str] = caption
-            self.parse_mode: ODVInput[str] = parse_mode
-            self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
-            self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
-            self.input_message_content: Optional[InputMessageContent] = input_message_content
-            self.thumbnail_mime_type: Optional[str] = thumbnail_mime_type
-            self.show_caption_above_media: Optional[bool] = show_caption_above_media
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultlocation.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultlocation.py
deleted file mode 100755
index 0103553..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultlocation.py
+++ /dev/null
@@ -1,207 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InlineQueryResultLocation."""
-
-from typing import TYPE_CHECKING, Final, Optional
-
-from telegram import constants
-from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
-from telegram._inline.inlinequeryresult import InlineQueryResult
-from telegram._utils.types import JSONDict
-
-if TYPE_CHECKING:
-    from telegram import InputMessageContent
-
-
-class InlineQueryResultLocation(InlineQueryResult):
-    """
-    Represents a location on a map. By default, the location will be sent by the user.
-    Alternatively, you can use :attr:`input_message_content` to send a message with the specified
-    content instead of the location.
-
-    .. versionchanged:: 20.5
-        |removed_thumb_wildcard_note|
-
-    Args:
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        latitude (:obj:`float`): Location latitude in degrees.
-        longitude (:obj:`float`): Location longitude in degrees.
-        title (:obj:`str`): Location title.
-        horizontal_accuracy (:obj:`float`, optional): The radius of uncertainty for the location,
-            measured in meters; 0-
-            :tg-const:`telegram.InlineQueryResultLocation.HORIZONTAL_ACCURACY`.
-        live_period (:obj:`int`, optional): Period in seconds for which the location will be
-            updated, should be between
-            :tg-const:`telegram.InlineQueryResultLocation.MIN_LIVE_PERIOD` and
-            :tg-const:`telegram.InlineQueryResultLocation.MAX_LIVE_PERIOD`.
-        heading (:obj:`int`, optional): For live locations, a direction in which the user is
-            moving, in degrees. Must be between
-            :tg-const:`telegram.InlineQueryResultLocation.MIN_HEADING` and
-            :tg-const:`telegram.InlineQueryResultLocation.MAX_HEADING` if specified.
-        proximity_alert_radius (:obj:`int`, optional): For live locations, a maximum distance
-            for proximity alerts about approaching another chat member, in meters. Must be
-            between :tg-const:`telegram.InlineQueryResultLocation.MIN_PROXIMITY_ALERT_RADIUS`
-            and :tg-const:`telegram.InlineQueryResultLocation.MAX_PROXIMITY_ALERT_RADIUS`
-            if specified.
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
-            message to be sent instead of the location.
-        thumbnail_url (:obj:`str`, optional): Url of the thumbnail for the result.
-
-            .. versionadded:: 20.2
-        thumbnail_width (:obj:`int`, optional): Thumbnail width.
-
-            .. versionadded:: 20.2
-        thumbnail_height (:obj:`int`, optional): Thumbnail height.
-
-            .. versionadded:: 20.2
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.LOCATION`.
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        latitude (:obj:`float`): Location latitude in degrees.
-        longitude (:obj:`float`): Location longitude in degrees.
-        title (:obj:`str`): Location title.
-        horizontal_accuracy (:obj:`float`): Optional. The radius of uncertainty for the location,
-            measured in meters; 0-
-            :tg-const:`telegram.InlineQueryResultLocation.HORIZONTAL_ACCURACY`.
-        live_period (:obj:`int`): Optional. Period in seconds for which the location will be
-            updated, should be between
-            :tg-const:`telegram.InlineQueryResultLocation.MIN_LIVE_PERIOD` and
-            :tg-const:`telegram.InlineQueryResultLocation.MAX_LIVE_PERIOD` or
-            :tg-const:`telegram.constants.LocationLimit.LIVE_PERIOD_FOREVER` for live
-            locations that can be edited indefinitely.
-        heading (:obj:`int`): Optional. For live locations, a direction in which the user is
-            moving, in degrees. Must be between
-            :tg-const:`telegram.InlineQueryResultLocation.MIN_HEADING` and
-            :tg-const:`telegram.InlineQueryResultLocation.MAX_HEADING` if specified.
-        proximity_alert_radius (:obj:`int`): Optional. For live locations, a maximum distance
-            for proximity alerts about approaching another chat member, in meters. Must be
-            between :tg-const:`telegram.InlineQueryResultLocation.MIN_PROXIMITY_ALERT_RADIUS`
-            and :tg-const:`telegram.InlineQueryResultLocation.MAX_PROXIMITY_ALERT_RADIUS`
-            if specified.
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
-            message to be sent instead of the location.
-        thumbnail_url (:obj:`str`): Optional. Url of the thumbnail for the result.
-
-            .. versionadded:: 20.2
-        thumbnail_width (:obj:`int`): Optional. Thumbnail width.
-
-            .. versionadded:: 20.2
-        thumbnail_height (:obj:`int`): Optional. Thumbnail height.
-
-            .. versionadded:: 20.2
-
-    """
-
-    __slots__ = (
-        "heading",
-        "horizontal_accuracy",
-        "input_message_content",
-        "latitude",
-        "live_period",
-        "longitude",
-        "proximity_alert_radius",
-        "reply_markup",
-        "thumbnail_height",
-        "thumbnail_url",
-        "thumbnail_width",
-        "title",
-    )
-
-    def __init__(
-        self,
-        id: str,  # pylint: disable=redefined-builtin
-        latitude: float,
-        longitude: float,
-        title: str,
-        live_period: Optional[int] = None,
-        reply_markup: Optional[InlineKeyboardMarkup] = None,
-        input_message_content: Optional["InputMessageContent"] = None,
-        horizontal_accuracy: Optional[float] = None,
-        heading: Optional[int] = None,
-        proximity_alert_radius: Optional[int] = None,
-        thumbnail_url: Optional[str] = None,
-        thumbnail_width: Optional[int] = None,
-        thumbnail_height: Optional[int] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        # Required
-        super().__init__(constants.InlineQueryResultType.LOCATION, id, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.latitude: float = latitude
-            self.longitude: float = longitude
-            self.title: str = title
-
-            # Optionals
-            self.live_period: Optional[int] = live_period
-            self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
-            self.input_message_content: Optional[InputMessageContent] = input_message_content
-            self.thumbnail_url: Optional[str] = thumbnail_url
-            self.thumbnail_width: Optional[int] = thumbnail_width
-            self.thumbnail_height: Optional[int] = thumbnail_height
-            self.horizontal_accuracy: Optional[float] = horizontal_accuracy
-            self.heading: Optional[int] = heading
-            self.proximity_alert_radius: Optional[int] = (
-                int(proximity_alert_radius) if proximity_alert_radius else None
-            )
-
-    HORIZONTAL_ACCURACY: Final[int] = constants.LocationLimit.HORIZONTAL_ACCURACY
-    """:const:`telegram.constants.LocationLimit.HORIZONTAL_ACCURACY`
-
-    .. versionadded:: 20.0
-    """
-    MIN_HEADING: Final[int] = constants.LocationLimit.MIN_HEADING
-    """:const:`telegram.constants.LocationLimit.MIN_HEADING`
-
-    .. versionadded:: 20.0
-    """
-    MAX_HEADING: Final[int] = constants.LocationLimit.MAX_HEADING
-    """:const:`telegram.constants.LocationLimit.MAX_HEADING`
-
-    .. versionadded:: 20.0
-    """
-    MIN_LIVE_PERIOD: Final[int] = constants.LocationLimit.MIN_LIVE_PERIOD
-    """:const:`telegram.constants.LocationLimit.MIN_LIVE_PERIOD`
-
-    .. versionadded:: 20.0
-    """
-    MAX_LIVE_PERIOD: Final[int] = constants.LocationLimit.MAX_LIVE_PERIOD
-    """:const:`telegram.constants.LocationLimit.MAX_LIVE_PERIOD`
-
-    .. versionadded:: 20.0
-    """
-    MIN_PROXIMITY_ALERT_RADIUS: Final[int] = constants.LocationLimit.MIN_PROXIMITY_ALERT_RADIUS
-    """:const:`telegram.constants.LocationLimit.MIN_PROXIMITY_ALERT_RADIUS`
-
-    .. versionadded:: 20.0
-    """
-    MAX_PROXIMITY_ALERT_RADIUS: Final[int] = constants.LocationLimit.MAX_PROXIMITY_ALERT_RADIUS
-    """:const:`telegram.constants.LocationLimit.MAX_PROXIMITY_ALERT_RADIUS`
-
-    .. versionadded:: 20.0
-    """
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultmpeg4gif.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultmpeg4gif.py
deleted file mode 100755
index ee2ed79..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultmpeg4gif.py
+++ /dev/null
@@ -1,176 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InlineQueryResultMpeg4Gif."""
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Optional
-
-from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
-from telegram._inline.inlinequeryresult import InlineQueryResult
-from telegram._messageentity import MessageEntity
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.types import JSONDict, ODVInput
-from telegram.constants import InlineQueryResultType
-
-if TYPE_CHECKING:
-    from telegram import InputMessageContent
-
-
-class InlineQueryResultMpeg4Gif(InlineQueryResult):
-    """
-    Represents a link to a video animation (H.264/MPEG-4 AVC video without sound). By default, this
-    animated MPEG-4 file will be sent by the user with optional caption. Alternatively, you can
-    use :attr:`input_message_content` to send a message with the specified content instead of the
-    animation.
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    .. versionchanged:: 20.5
-        |removed_thumb_wildcard_note|
-
-    Args:
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        mpeg4_url (:obj:`str`): A valid URL for the MP4 file. File size must not exceed 1MB.
-        mpeg4_width (:obj:`int`, optional): Video width.
-        mpeg4_height (:obj:`int`, optional): Video height.
-        mpeg4_duration (:obj:`int`, optional): Video duration in seconds.
-        thumbnail_url (:obj:`str`): URL of the static (JPEG or GIF) or animated (MPEG4)
-            thumbnail for the result.
-
-            .. versionadded:: 20.2
-
-            ..versionchanged:: 20.5
-              |thumbnail_url_mandatory|
-
-        thumbnail_mime_type (:obj:`str`, optional): MIME type of the thumbnail, must be one of
-            ``'image/jpeg'``, ``'image/gif'``, or ``'video/mp4'``. Defaults to ``'image/jpeg'``.
-
-            .. versionadded:: 20.2
-        title (:obj:`str`, optional): Title for the result.
-        caption (:obj:`str`, optional): Caption of the MPEG-4 file to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
-            after entities parsing.
-        parse_mode (:obj:`str`, optional): |parse_mode|
-        caption_entities (Sequence[:class:`telegram.MessageEntity`], optional):
-            |captionentitiesattr|
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
-            message to be sent instead of the video animation.
-        show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
-
-            .. versionadded:: 21.3
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.MPEG4GIF`.
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        mpeg4_url (:obj:`str`): A valid URL for the MP4 file. File size must not exceed 1MB.
-        mpeg4_width (:obj:`int`): Optional. Video width.
-        mpeg4_height (:obj:`int`): Optional. Video height.
-        mpeg4_duration (:obj:`int`): Optional. Video duration in seconds.
-        thumbnail_url (:obj:`str`): URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail
-            for the result.
-
-            .. versionadded:: 20.2
-        thumbnail_mime_type (:obj:`str`): Optional. MIME type of the thumbnail, must be one of
-            ``'image/jpeg'``, ``'image/gif'``, or ``'video/mp4'``. Defaults to ``'image/jpeg'``.
-
-            .. versionadded:: 20.2
-        title (:obj:`str`): Optional. Title for the result.
-        caption (:obj:`str`): Optional. Caption of the MPEG-4 file to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters
-            after entities parsing.
-        parse_mode (:obj:`str`): Optional. |parse_mode|
-        caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |caption_entities|
-
-            .. versionchanged:: 20.0
-
-                * |tupleclassattrs|
-                * |alwaystuple|
-
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
-            message to be sent instead of the video animation.
-        show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
-
-            .. versionadded:: 21.3
-    """
-
-    __slots__ = (
-        "caption",
-        "caption_entities",
-        "input_message_content",
-        "mpeg4_duration",
-        "mpeg4_height",
-        "mpeg4_url",
-        "mpeg4_width",
-        "parse_mode",
-        "reply_markup",
-        "show_caption_above_media",
-        "thumbnail_mime_type",
-        "thumbnail_url",
-        "title",
-    )
-
-    def __init__(
-        self,
-        id: str,  # pylint: disable=redefined-builtin
-        mpeg4_url: str,
-        thumbnail_url: str,
-        mpeg4_width: Optional[int] = None,
-        mpeg4_height: Optional[int] = None,
-        title: Optional[str] = None,
-        caption: Optional[str] = None,
-        reply_markup: Optional[InlineKeyboardMarkup] = None,
-        input_message_content: Optional["InputMessageContent"] = None,
-        mpeg4_duration: Optional[int] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence[MessageEntity]] = None,
-        thumbnail_mime_type: Optional[str] = None,
-        show_caption_above_media: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        # Required
-        super().__init__(InlineQueryResultType.MPEG4GIF, id, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.mpeg4_url: str = mpeg4_url
-            self.thumbnail_url: str = thumbnail_url
-
-            # Optional
-            self.mpeg4_width: Optional[int] = mpeg4_width
-            self.mpeg4_height: Optional[int] = mpeg4_height
-            self.mpeg4_duration: Optional[int] = mpeg4_duration
-            self.title: Optional[str] = title
-            self.caption: Optional[str] = caption
-            self.parse_mode: ODVInput[str] = parse_mode
-            self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
-            self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
-            self.input_message_content: Optional[InputMessageContent] = input_message_content
-            self.thumbnail_mime_type: Optional[str] = thumbnail_mime_type
-            self.show_caption_above_media: Optional[bool] = show_caption_above_media
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultphoto.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultphoto.py
deleted file mode 100755
index e4556d6..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultphoto.py
+++ /dev/null
@@ -1,161 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InlineQueryResultPhoto."""
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Optional
-
-from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
-from telegram._inline.inlinequeryresult import InlineQueryResult
-from telegram._messageentity import MessageEntity
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.types import JSONDict, ODVInput
-from telegram.constants import InlineQueryResultType
-
-if TYPE_CHECKING:
-    from telegram import InputMessageContent
-
-
-class InlineQueryResultPhoto(InlineQueryResult):
-    """
-    Represents a link to a photo. By default, this photo will be sent by the user with optional
-    caption. Alternatively, you can use :attr:`input_message_content` to send a message with the
-    specified content instead of the photo.
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    .. versionchanged:: 20.5
-      |removed_thumb_url_note|
-
-    Args:
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        photo_url (:obj:`str`): A valid URL of the photo. Photo must be in JPEG format. Photo size
-            must not exceed 5MB.
-        thumbnail_url (:obj:`str`): URL of the thumbnail for the photo.
-
-            .. versionadded:: 20.2
-
-            ..versionchanged:: 20.5
-              |thumbnail_url_mandatory|
-
-        photo_width (:obj:`int`, optional): Width of the photo.
-        photo_height (:obj:`int`, optional): Height of the photo.
-        title (:obj:`str`, optional): Title for the result.
-        description (:obj:`str`, optional): Short description of the result.
-        caption (:obj:`str`, optional): Caption of the photo to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
-            entities parsing.
-        parse_mode (:obj:`str`, optional): |parse_mode|
-        caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
-            message to be sent instead of the photo.
-        show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
-
-            .. versionadded:: 21.3
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.PHOTO`.
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        photo_url (:obj:`str`): A valid URL of the photo. Photo must be in JPEG format. Photo size
-            must not exceed 5MB.
-        thumbnail_url (:obj:`str`): URL of the thumbnail for the photo.
-        photo_width (:obj:`int`): Optional. Width of the photo.
-        photo_height (:obj:`int`): Optional. Height of the photo.
-        title (:obj:`str`): Optional. Title for the result.
-        description (:obj:`str`): Optional. Short description of the result.
-        caption (:obj:`str`): Optional. Caption of the photo to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after
-            entities parsing.
-        parse_mode (:obj:`str`): Optional. |parse_mode|
-        caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
-
-            .. versionchanged:: 20.0
-
-                * |tupleclassattrs|
-                * |alwaystuple|
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
-            message to be sent instead of the photo.
-        show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
-
-            .. versionadded:: 21.3
-
-    """
-
-    __slots__ = (
-        "caption",
-        "caption_entities",
-        "description",
-        "input_message_content",
-        "parse_mode",
-        "photo_height",
-        "photo_url",
-        "photo_width",
-        "reply_markup",
-        "show_caption_above_media",
-        "thumbnail_url",
-        "title",
-    )
-
-    def __init__(
-        self,
-        id: str,  # pylint: disable=redefined-builtin
-        photo_url: str,
-        thumbnail_url: str,
-        photo_width: Optional[int] = None,
-        photo_height: Optional[int] = None,
-        title: Optional[str] = None,
-        description: Optional[str] = None,
-        caption: Optional[str] = None,
-        reply_markup: Optional[InlineKeyboardMarkup] = None,
-        input_message_content: Optional["InputMessageContent"] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence[MessageEntity]] = None,
-        show_caption_above_media: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        # Required
-        super().__init__(InlineQueryResultType.PHOTO, id, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.photo_url: str = photo_url
-            self.thumbnail_url: str = thumbnail_url
-
-            # Optionals
-            self.photo_width: Optional[int] = photo_width
-            self.photo_height: Optional[int] = photo_height
-            self.title: Optional[str] = title
-            self.description: Optional[str] = description
-            self.caption: Optional[str] = caption
-            self.parse_mode: ODVInput[str] = parse_mode
-            self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
-            self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
-            self.input_message_content: Optional[InputMessageContent] = input_message_content
-            self.show_caption_above_media: Optional[bool] = show_caption_above_media
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultsbutton.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultsbutton.py
deleted file mode 100755
index 11ba092..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultsbutton.py
+++ /dev/null
@@ -1,118 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the class that represent a Telegram InlineQueryResultsButton."""
-
-from typing import TYPE_CHECKING, Final, Optional
-
-from telegram import constants
-from telegram._telegramobject import TelegramObject
-from telegram._utils.types import JSONDict
-from telegram._webappinfo import WebAppInfo
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class InlineQueryResultsButton(TelegramObject):
-    """This object represents a button to be shown above inline query results. You **must** use
-    exactly one of the optional fields.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`text`, :attr:`web_app` and :attr:`start_parameter` are equal.
-
-    Args:
-        text (:obj:`str`): Label text on the button.
-        web_app (:class:`telegram.WebAppInfo`, optional): Description of the
-            `Web App `_ that will be launched when the
-            user presses the button. The Web App will be able to switch back to the inline mode
-            using the method
-            `switchInlineQuery `_
-            inside the Web App.
-        start_parameter (:obj:`str`, optional):  Deep-linking parameter for the
-            :guilabel:`/start` message sent to the bot when user presses the switch button.
-            :tg-const:`telegram.InlineQuery.MIN_SWITCH_PM_TEXT_LENGTH`-
-            :tg-const:`telegram.InlineQuery.MAX_SWITCH_PM_TEXT_LENGTH` characters,
-            only ``A-Z``, ``a-z``, ``0-9``, ``_`` and ``-`` are allowed.
-
-            Example:
-                An inline bot that sends YouTube videos can ask the user to connect the bot to
-                their YouTube account to adapt search results accordingly. To do this, it displays
-                a 'Connect your YouTube account' button above the results, or even before showing
-                any. The user presses the button, switches to a private chat with the bot and, in
-                doing so, passes a start parameter that instructs the bot to return an OAuth link.
-                Once done, the bot can offer a switch_inline button so that the user can easily
-                return to the chat where they wanted to use the bot's inline capabilities.
-
-    Attributes:
-        text (:obj:`str`): Label text on the button.
-        web_app (:class:`telegram.WebAppInfo`): Optional. Description of the
-            `Web App `_ that will be launched when the
-            user presses the button. The Web App will be able to switch back to the inline mode
-            using the method ``web_app_switch_inline_query`` inside the Web App.
-        start_parameter (:obj:`str`): Optional. Deep-linking parameter for the
-            :guilabel:`/start` message sent to the bot when user presses the switch button.
-            :tg-const:`telegram.InlineQuery.MIN_SWITCH_PM_TEXT_LENGTH`-
-            :tg-const:`telegram.InlineQuery.MAX_SWITCH_PM_TEXT_LENGTH` characters,
-            only ``A-Z``, ``a-z``, ``0-9``, ``_`` and ``-`` are allowed.
-
-    """
-
-    __slots__ = ("start_parameter", "text", "web_app")
-
-    def __init__(
-        self,
-        text: str,
-        web_app: Optional[WebAppInfo] = None,
-        start_parameter: Optional[str] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-
-        # Required
-        self.text: str = text
-
-        # Optional
-        self.web_app: Optional[WebAppInfo] = web_app
-        self.start_parameter: Optional[str] = start_parameter
-
-        self._id_attrs = (self.text, self.web_app, self.start_parameter)
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["InlineQueryResultsButton"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        if not data:
-            return None
-
-        data["web_app"] = WebAppInfo.de_json(data.get("web_app"), bot)
-
-        return super().de_json(data=data, bot=bot)
-
-    MIN_START_PARAMETER_LENGTH: Final[int] = (
-        constants.InlineQueryResultsButtonLimit.MIN_START_PARAMETER_LENGTH
-    )
-    """:const:`telegram.constants.InlineQueryResultsButtonLimit.MIN_START_PARAMETER_LENGTH`"""
-    MAX_START_PARAMETER_LENGTH: Final[int] = (
-        constants.InlineQueryResultsButtonLimit.MAX_START_PARAMETER_LENGTH
-    )
-    """:const:`telegram.constants.InlineQueryResultsButtonLimit.MAX_START_PARAMETER_LENGTH`"""
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultvenue.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultvenue.py
deleted file mode 100755
index 639b0da..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultvenue.py
+++ /dev/null
@@ -1,160 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InlineQueryResultVenue."""
-
-from typing import TYPE_CHECKING, Optional
-
-from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
-from telegram._inline.inlinequeryresult import InlineQueryResult
-from telegram._utils.types import JSONDict
-from telegram.constants import InlineQueryResultType
-
-if TYPE_CHECKING:
-    from telegram import InputMessageContent
-
-
-class InlineQueryResultVenue(InlineQueryResult):
-    """
-    Represents a venue. By default, the venue will be sent by the user. Alternatively, you can
-    use :attr:`input_message_content` to send a message with the specified content instead of the
-    venue.
-
-    Note:
-      Foursquare details and Google Pace details are mutually exclusive. However, this
-      behaviour is undocumented and might be changed by Telegram.
-
-    .. versionchanged:: 20.5
-        |removed_thumb_wildcard_note|
-
-    Args:
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        latitude (:obj:`float`): Latitude of the venue location in degrees.
-        longitude (:obj:`float`): Longitude of the venue location in degrees.
-        title (:obj:`str`): Title of the venue.
-        address (:obj:`str`): Address of the venue.
-        foursquare_id (:obj:`str`, optional): Foursquare identifier of the venue if known.
-        foursquare_type (:obj:`str`, optional): Foursquare type of the venue, if known.
-            (For example, "arts_entertainment/default", "arts_entertainment/aquarium" or
-            "food/icecream".)
-        google_place_id (:obj:`str`, optional): Google Places identifier of the venue.
-        google_place_type (:obj:`str`, optional): Google Places type of the venue. (See
-            `supported types `_.)
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
-            message to be sent instead of the venue.
-        thumbnail_url (:obj:`str`, optional): Url of the thumbnail for the result.
-
-            .. versionadded:: 20.2
-        thumbnail_width (:obj:`int`, optional): Thumbnail width.
-
-            .. versionadded:: 20.2
-        thumbnail_height (:obj:`int`, optional): Thumbnail height.
-
-            .. versionadded:: 20.2
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.VENUE`.
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        latitude (:obj:`float`): Latitude of the venue location in degrees.
-        longitude (:obj:`float`): Longitude of the venue location in degrees.
-        title (:obj:`str`): Title of the venue.
-        address (:obj:`str`): Address of the venue.
-        foursquare_id (:obj:`str`): Optional. Foursquare identifier of the venue if known.
-        foursquare_type (:obj:`str`): Optional. Foursquare type of the venue, if known.
-            (For example, "arts_entertainment/default", "arts_entertainment/aquarium" or
-            "food/icecream".)
-        google_place_id (:obj:`str`): Optional. Google Places identifier of the venue.
-        google_place_type (:obj:`str`): Optional. Google Places type of the venue. (See
-            `supported types `_.)
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
-            message to be sent instead of the venue.
-        thumbnail_url (:obj:`str`): Optional. Url of the thumbnail for the result.
-
-            .. versionadded:: 20.2
-        thumbnail_width (:obj:`int`): Optional. Thumbnail width.
-
-            .. versionadded:: 20.2
-        thumbnail_height (:obj:`int`): Optional. Thumbnail height.
-
-            .. versionadded:: 20.2
-
-    """
-
-    __slots__ = (
-        "address",
-        "foursquare_id",
-        "foursquare_type",
-        "google_place_id",
-        "google_place_type",
-        "input_message_content",
-        "latitude",
-        "longitude",
-        "reply_markup",
-        "thumbnail_height",
-        "thumbnail_url",
-        "thumbnail_width",
-        "title",
-    )
-
-    def __init__(
-        self,
-        id: str,  # pylint: disable=redefined-builtin
-        latitude: float,
-        longitude: float,
-        title: str,
-        address: str,
-        foursquare_id: Optional[str] = None,
-        foursquare_type: Optional[str] = None,
-        reply_markup: Optional[InlineKeyboardMarkup] = None,
-        input_message_content: Optional["InputMessageContent"] = None,
-        google_place_id: Optional[str] = None,
-        google_place_type: Optional[str] = None,
-        thumbnail_url: Optional[str] = None,
-        thumbnail_width: Optional[int] = None,
-        thumbnail_height: Optional[int] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        # Required
-        super().__init__(InlineQueryResultType.VENUE, id, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.latitude: float = latitude
-            self.longitude: float = longitude
-            self.title: str = title
-            self.address: str = address
-
-            # Optional
-            self.foursquare_id: Optional[str] = foursquare_id
-            self.foursquare_type: Optional[str] = foursquare_type
-            self.google_place_id: Optional[str] = google_place_id
-            self.google_place_type: Optional[str] = google_place_type
-            self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
-            self.input_message_content: Optional[InputMessageContent] = input_message_content
-            self.thumbnail_url: Optional[str] = thumbnail_url
-            self.thumbnail_width: Optional[int] = thumbnail_width
-            self.thumbnail_height: Optional[int] = thumbnail_height
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultvideo.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultvideo.py
deleted file mode 100755
index edc6ce3..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultvideo.py
+++ /dev/null
@@ -1,182 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InlineQueryResultVideo."""
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Optional
-
-from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
-from telegram._inline.inlinequeryresult import InlineQueryResult
-from telegram._messageentity import MessageEntity
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.types import JSONDict, ODVInput
-from telegram.constants import InlineQueryResultType
-
-if TYPE_CHECKING:
-    from telegram import InputMessageContent
-
-
-class InlineQueryResultVideo(InlineQueryResult):
-    """
-    Represents a link to a page containing an embedded video player or a video file. By default,
-    this video file will be sent by the user with an optional caption. Alternatively, you can use
-    :attr:`input_message_content` to send a message with the specified content instead of
-    the video.
-
-    Note:
-        If an InlineQueryResultVideo message contains an embedded video (e.g., YouTube), you must
-        replace its content using :attr:`input_message_content`.
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    .. versionchanged:: 20.5
-        |removed_thumb_url_note|
-
-    Args:
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        video_url (:obj:`str`): A valid URL for the embedded video player or video file.
-        mime_type (:obj:`str`): Mime type of the content of video url, "text/html" or "video/mp4".
-        thumbnail_url (:obj:`str`, optional): URL of the thumbnail (JPEG only) for the video.
-
-            .. versionadded:: 20.2
-
-            ..versionchanged:: 20.5
-              |thumbnail_url_mandatory|
-
-        title (:obj:`str`): Title for the result.
-        caption (:obj:`str`, optional): Caption of the video to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities
-            parsing.
-        parse_mode (:obj:`str`, optional): |parse_mode|
-        caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        video_width (:obj:`int`, optional): Video width.
-        video_height (:obj:`int`, optional): Video height.
-        video_duration (:obj:`int`, optional): Video duration in seconds.
-        description (:obj:`str`, optional): Short description of the result.
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
-            message to be sent instead of the video. This field is required if
-            ``InlineQueryResultVideo`` is used to send an HTML-page as a result
-            (e.g., a YouTube video).
-        show_caption_above_media (:obj:`bool`, optional): Pass |show_cap_above_med|
-
-            .. versionadded:: 21.3
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.VIDEO`.
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        video_url (:obj:`str`): A valid URL for the embedded video player or video file.
-        mime_type (:obj:`str`): Mime type of the content of video url, "text/html" or "video/mp4".
-        thumbnail_url (:obj:`str`): URL of the thumbnail (JPEG only) for the video.
-
-            .. versionadded:: 20.2
-        title (:obj:`str`): Title for the result.
-        caption (:obj:`str`): Optional. Caption of the video to be sent,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities
-            parsing.
-        parse_mode (:obj:`str`): Optional. |parse_mode|
-        caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional.
-            |captionentitiesattr|
-
-            .. versionchanged:: 20.0
-
-                * |tupleclassattrs|
-                * |alwaystuple|
-
-        video_width (:obj:`int`): Optional. Video width.
-        video_height (:obj:`int`): Optional. Video height.
-        video_duration (:obj:`int`): Optional. Video duration in seconds.
-        description (:obj:`str`): Optional. Short description of the result.
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
-            message to be sent instead of the video. This field is required if
-            ``InlineQueryResultVideo`` is used to send an HTML-page as a result
-            (e.g., a YouTube video).
-        show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
-
-            .. versionadded:: 21.3
-
-    """
-
-    __slots__ = (
-        "caption",
-        "caption_entities",
-        "description",
-        "input_message_content",
-        "mime_type",
-        "parse_mode",
-        "reply_markup",
-        "show_caption_above_media",
-        "thumbnail_url",
-        "title",
-        "video_duration",
-        "video_height",
-        "video_url",
-        "video_width",
-    )
-
-    def __init__(
-        self,
-        id: str,  # pylint: disable=redefined-builtin
-        video_url: str,
-        mime_type: str,
-        thumbnail_url: str,
-        title: str,
-        caption: Optional[str] = None,
-        video_width: Optional[int] = None,
-        video_height: Optional[int] = None,
-        video_duration: Optional[int] = None,
-        description: Optional[str] = None,
-        reply_markup: Optional[InlineKeyboardMarkup] = None,
-        input_message_content: Optional["InputMessageContent"] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence[MessageEntity]] = None,
-        show_caption_above_media: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        # Required
-        super().__init__(InlineQueryResultType.VIDEO, id, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.video_url: str = video_url
-            self.mime_type: str = mime_type
-            self.thumbnail_url: str = thumbnail_url
-            self.title: str = title
-
-            # Optional
-            self.caption: Optional[str] = caption
-            self.parse_mode: ODVInput[str] = parse_mode
-            self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
-            self.video_width: Optional[int] = video_width
-            self.video_height: Optional[int] = video_height
-            self.video_duration: Optional[int] = video_duration
-            self.description: Optional[str] = description
-            self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
-            self.input_message_content: Optional[InputMessageContent] = input_message_content
-            self.show_caption_above_media: Optional[bool] = show_caption_above_media
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultvoice.py b/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultvoice.py
deleted file mode 100755
index b798040..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inlinequeryresultvoice.py
+++ /dev/null
@@ -1,127 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InlineQueryResultVoice."""
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Optional
-
-from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
-from telegram._inline.inlinequeryresult import InlineQueryResult
-from telegram._messageentity import MessageEntity
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.types import JSONDict, ODVInput
-from telegram.constants import InlineQueryResultType
-
-if TYPE_CHECKING:
-    from telegram import InputMessageContent
-
-
-class InlineQueryResultVoice(InlineQueryResult):
-    """
-    Represents a link to a voice recording in an .ogg container encoded with OPUS. By default,
-    this voice recording will be sent by the user. Alternatively, you can use
-    :attr:`input_message_content` to send a message with the specified content instead of
-    the voice message.
-
-    .. seealso:: :wiki:`Working with Files and Media `
-
-    Args:
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        voice_url (:obj:`str`): A valid URL for the voice recording.
-        title (:obj:`str`): Recording title.
-        caption (:obj:`str`, optional): Caption,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities
-            parsing.
-        parse_mode (:obj:`str`, optional): |parse_mode|
-        caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        voice_duration (:obj:`int`, optional): Recording duration in seconds.
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
-            message to be sent instead of the voice recording.
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.InlineQueryResultType.VOICE`.
-        id (:obj:`str`): Unique identifier for this result,
-            :tg-const:`telegram.InlineQueryResult.MIN_ID_LENGTH`-
-            :tg-const:`telegram.InlineQueryResult.MAX_ID_LENGTH` Bytes.
-        voice_url (:obj:`str`): A valid URL for the voice recording.
-        title (:obj:`str`): Recording title.
-        caption (:obj:`str`): Optional. Caption,
-            0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters after entities
-            parsing.
-        parse_mode (:obj:`str`): Optional. |parse_mode|
-        caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
-
-            .. versionchanged:: 20.0
-
-                * |tupleclassattrs|
-                * |alwaystuple|
-        voice_duration (:obj:`int`): Optional. Recording duration in seconds.
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
-            to the message.
-        input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
-            message to be sent instead of the voice recording.
-
-    """
-
-    __slots__ = (
-        "caption",
-        "caption_entities",
-        "input_message_content",
-        "parse_mode",
-        "reply_markup",
-        "title",
-        "voice_duration",
-        "voice_url",
-    )
-
-    def __init__(
-        self,
-        id: str,  # pylint: disable=redefined-builtin
-        voice_url: str,
-        title: str,
-        voice_duration: Optional[int] = None,
-        caption: Optional[str] = None,
-        reply_markup: Optional[InlineKeyboardMarkup] = None,
-        input_message_content: Optional["InputMessageContent"] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence[MessageEntity]] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        # Required
-        super().__init__(InlineQueryResultType.VOICE, id, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.voice_url: str = voice_url
-            self.title: str = title
-
-            # Optional
-            self.voice_duration: Optional[int] = voice_duration
-            self.caption: Optional[str] = caption
-            self.parse_mode: ODVInput[str] = parse_mode
-            self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
-            self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
-            self.input_message_content: Optional[InputMessageContent] = input_message_content
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inputcontactmessagecontent.py b/venv/lib/python3.11/site-packages/telegram/_inline/inputcontactmessagecontent.py
deleted file mode 100755
index f7a76df..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inputcontactmessagecontent.py
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InputContactMessageContent."""
-from typing import Optional
-
-from telegram._inline.inputmessagecontent import InputMessageContent
-from telegram._utils.types import JSONDict
-
-
-class InputContactMessageContent(InputMessageContent):
-    """Represents the content of a contact message to be sent as the result of an inline query.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`phone_number` is equal.
-
-    Args:
-        phone_number (:obj:`str`): Contact's phone number.
-        first_name (:obj:`str`): Contact's first name.
-        last_name (:obj:`str`, optional): Contact's last name.
-        vcard (:obj:`str`, optional): Additional data about the contact in the form of a vCard,
-            0-:tg-const:`telegram.constants.ContactLimit.VCARD` bytes.
-
-    Attributes:
-        phone_number (:obj:`str`): Contact's phone number.
-        first_name (:obj:`str`): Contact's first name.
-        last_name (:obj:`str`): Optional. Contact's last name.
-        vcard (:obj:`str`): Optional. Additional data about the contact in the form of a vCard,
-            0-:tg-const:`telegram.constants.ContactLimit.VCARD` bytes.
-
-    """
-
-    __slots__ = ("first_name", "last_name", "phone_number", "vcard")
-
-    def __init__(
-        self,
-        phone_number: str,
-        first_name: str,
-        last_name: Optional[str] = None,
-        vcard: Optional[str] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        with self._unfrozen():
-            # Required
-            self.phone_number: str = phone_number
-            self.first_name: str = first_name
-            # Optionals
-            self.last_name: Optional[str] = last_name
-            self.vcard: Optional[str] = vcard
-
-            self._id_attrs = (self.phone_number,)
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inputinvoicemessagecontent.py b/venv/lib/python3.11/site-packages/telegram/_inline/inputinvoicemessagecontent.py
deleted file mode 100755
index ecef394..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inputinvoicemessagecontent.py
+++ /dev/null
@@ -1,268 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains a class that represents a Telegram InputInvoiceMessageContent."""
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Optional
-
-from telegram._inline.inputmessagecontent import InputMessageContent
-from telegram._payment.labeledprice import LabeledPrice
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.types import JSONDict
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class InputInvoiceMessageContent(InputMessageContent):
-    """
-    Represents the content of a invoice message to be sent as the result of an inline query.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`title`, :attr:`description`, :attr:`payload`,
-    :attr:`provider_token`, :attr:`currency` and :attr:`prices` are equal.
-
-    .. versionadded:: 13.5
-
-    Args:
-        title (:obj:`str`): Product name. :tg-const:`telegram.Invoice.MIN_TITLE_LENGTH`-
-            :tg-const:`telegram.Invoice.MAX_TITLE_LENGTH` characters.
-        description (:obj:`str`): Product description.
-            :tg-const:`telegram.Invoice.MIN_DESCRIPTION_LENGTH`-
-            :tg-const:`telegram.Invoice.MAX_DESCRIPTION_LENGTH` characters.
-        payload (:obj:`str`): Bot-defined invoice payload.
-            :tg-const:`telegram.Invoice.MIN_PAYLOAD_LENGTH`-
-            :tg-const:`telegram.Invoice.MAX_PAYLOAD_LENGTH` bytes. This will not be displayed
-            to the user, use it for your internal processes.
-        provider_token (:obj:`str`): Payment provider token, obtained via
-            `@Botfather `_. Pass an empty string for payments in
-            |tg_stars|.
-
-            .. deprecated:: 21.3
-                As of Bot API 7.4, this parameter is now optional and future versions of the
-                library will make it optional as well.
-        currency (:obj:`str`): Three-letter ISO 4217 currency code, see more on
-            `currencies `_.
-            Pass ``XTR`` for payments in |tg_stars|.
-        prices (Sequence[:class:`telegram.LabeledPrice`]): Price breakdown, a list of
-            components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus,
-            etc.). Must contain exactly one item for payments in |tg_stars|.
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        max_tip_amount (:obj:`int`, optional): The maximum accepted amount for tips in the
-            *smallest units* of the currency (integer, **not** float/double). For example, for a
-            maximum tip of ``US$ 1.45`` pass ``max_tip_amount = 145``. See the ``exp`` parameter in
-            `currencies.json `_, it
-            shows the number of digits past the decimal point for each currency (2 for the majority
-            of currencies). Defaults to ``0``. Not supported for payments in |tg_stars|.
-        suggested_tip_amounts (Sequence[:obj:`int`], optional): An array of suggested
-            amounts of tip in the *smallest units* of the currency (integer, **not** float/double).
-            At most 4 suggested tip amounts can be specified. The suggested tip amounts must be
-            positive, passed in a strictly increased order and must not exceed
-            :attr:`max_tip_amount`.
-
-            .. versionchanged:: 20.0
-
-                * |tupleclassattrs|
-                * |alwaystuple|
-
-        provider_data (:obj:`str`, optional): An object for data about the invoice,
-            which will be shared with the payment provider. A detailed description of the required
-            fields should be provided by the payment provider.
-        photo_url (:obj:`str`, optional): URL of the product photo for the invoice. Can be a photo
-            of the goods or a marketing image for a service. People like it better when they see
-            what they are paying for.
-        photo_size (:obj:`int`, optional): Photo size.
-        photo_width (:obj:`int`, optional): Photo width.
-        photo_height (:obj:`int`, optional): Photo height.
-        need_name (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's full
-            name to complete the order. Ignored for payments in |tg_stars|.
-        need_phone_number (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's
-            phone number to complete the order. Ignored for payments in |tg_stars|.
-        need_email (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's email
-            address to complete the order. Ignored for payments in |tg_stars|.
-        need_shipping_address (:obj:`bool`, optional): Pass :obj:`True`, if you require the
-            user's shipping address to complete the order. Ignored for payments in |tg_stars|
-        send_phone_number_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's
-            phone number should be sent to provider. Ignored for payments in |tg_stars|.
-        send_email_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's email
-            address should be sent to provider. Ignored for payments in |tg_stars|.
-        is_flexible (:obj:`bool`, optional): Pass :obj:`True`, if the final price depends on
-            the shipping method. Ignored for payments in |tg_stars|.
-
-    Attributes:
-        title (:obj:`str`): Product name. :tg-const:`telegram.Invoice.MIN_TITLE_LENGTH`-
-            :tg-const:`telegram.Invoice.MAX_TITLE_LENGTH` characters.
-        description (:obj:`str`): Product description.
-            :tg-const:`telegram.Invoice.MIN_DESCRIPTION_LENGTH`-
-            :tg-const:`telegram.Invoice.MAX_DESCRIPTION_LENGTH` characters.
-        payload (:obj:`str`): Bot-defined invoice payload.
-            :tg-const:`telegram.Invoice.MIN_PAYLOAD_LENGTH`-
-            :tg-const:`telegram.Invoice.MAX_PAYLOAD_LENGTH` bytes. This will not be displayed
-            to the user, use it for your internal processes.
-        provider_token (:obj:`str`): Payment provider token, obtained via
-            `@Botfather `_. Pass an empty string for payments in `Telegram
-            Stars `_.
-        currency (:obj:`str`): Three-letter ISO 4217 currency code, see more on
-            `currencies `_.
-            Pass ``XTR`` for payments in |tg_stars|.
-        prices (tuple[:class:`telegram.LabeledPrice`]): Price breakdown, a list of
-            components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus,
-            etc.). Must contain exactly one item for payments in |tg_stars|.
-
-            .. versionchanged:: 20.0
-                |tupleclassattrs|
-
-        max_tip_amount (:obj:`int`): Optional. The maximum accepted amount for tips in the
-            *smallest units* of the currency (integer, **not** float/double). For example, for a
-            maximum tip of ``US$ 1.45`` ``max_tip_amount`` is ``145``. See the ``exp`` parameter in
-            `currencies.json `_, it
-            shows the number of digits past the decimal point for each currency (2 for the majority
-            of currencies). Defaults to ``0``. Not supported for payments in |tg_stars|.
-        suggested_tip_amounts (tuple[:obj:`int`]): Optional. An array of suggested
-            amounts of tip in the *smallest units* of the currency (integer, **not** float/double).
-            At most 4 suggested tip amounts can be specified. The suggested tip amounts must be
-            positive, passed in a strictly increased order and must not exceed
-            :attr:`max_tip_amount`.
-
-            .. versionchanged:: 20.0
-                |tupleclassattrs|
-
-        provider_data (:obj:`str`): Optional. An object for data about the invoice,
-            which will be shared with the payment provider. A detailed description of the required
-            fields should be provided by the payment provider.
-        photo_url (:obj:`str`): Optional. URL of the product photo for the invoice. Can be a photo
-            of the goods or a marketing image for a service. People like it better when they see
-            what they are paying for.
-        photo_size (:obj:`int`): Optional. Photo size.
-        photo_width (:obj:`int`): Optional. Photo width.
-        photo_height (:obj:`int`): Optional. Photo height.
-        need_name (:obj:`bool`): Optional. Pass :obj:`True`, if you require the user's full name to
-            complete the order. Ignored for payments in |tg_stars|.
-        need_phone_number (:obj:`bool`): Optional. Pass :obj:`True`, if you require the user's
-            phone number to complete the order. Ignored for payments in |tg_stars|.
-        need_email (:obj:`bool`): Optional. Pass :obj:`True`, if you require the user's email
-            address to complete the order. Ignored for payments in |tg_stars|.
-        need_shipping_address (:obj:`bool`): Optional. Pass :obj:`True`, if you require the user's
-            shipping address to complete the order. Ignored for payments in |tg_stars|.
-        send_phone_number_to_provider (:obj:`bool`): Optional. Pass :obj:`True`, if user's phone
-            number should be sent to provider. Ignored for payments in |tg_stars|.
-        send_email_to_provider (:obj:`bool`): Optional. Pass :obj:`True`, if user's email address
-            should be sent to provider. Ignored for payments in |tg_stars|.
-        is_flexible (:obj:`bool`): Optional. Pass :obj:`True`, if the final price depends on the
-            shipping method. Ignored for payments in |tg_stars|.
-
-    """
-
-    __slots__ = (
-        "currency",
-        "description",
-        "is_flexible",
-        "max_tip_amount",
-        "need_email",
-        "need_name",
-        "need_phone_number",
-        "need_shipping_address",
-        "payload",
-        "photo_height",
-        "photo_size",
-        "photo_url",
-        "photo_width",
-        "prices",
-        "provider_data",
-        "provider_token",
-        "send_email_to_provider",
-        "send_phone_number_to_provider",
-        "suggested_tip_amounts",
-        "title",
-    )
-
-    def __init__(
-        self,
-        title: str,
-        description: str,
-        payload: str,
-        provider_token: Optional[str],  # This arg is now optional since Bot API 7.4
-        currency: str,
-        prices: Sequence[LabeledPrice],
-        max_tip_amount: Optional[int] = None,
-        suggested_tip_amounts: Optional[Sequence[int]] = None,
-        provider_data: Optional[str] = None,
-        photo_url: Optional[str] = None,
-        photo_size: Optional[int] = None,
-        photo_width: Optional[int] = None,
-        photo_height: Optional[int] = None,
-        need_name: Optional[bool] = None,
-        need_phone_number: Optional[bool] = None,
-        need_email: Optional[bool] = None,
-        need_shipping_address: Optional[bool] = None,
-        send_phone_number_to_provider: Optional[bool] = None,
-        send_email_to_provider: Optional[bool] = None,
-        is_flexible: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        with self._unfrozen():
-            # Required
-            self.title: str = title
-            self.description: str = description
-            self.payload: str = payload
-            self.provider_token: Optional[str] = provider_token
-            self.currency: str = currency
-            self.prices: tuple[LabeledPrice, ...] = parse_sequence_arg(prices)
-            # Optionals
-            self.max_tip_amount: Optional[int] = max_tip_amount
-            self.suggested_tip_amounts: tuple[int, ...] = parse_sequence_arg(suggested_tip_amounts)
-            self.provider_data: Optional[str] = provider_data
-            self.photo_url: Optional[str] = photo_url
-            self.photo_size: Optional[int] = photo_size
-            self.photo_width: Optional[int] = photo_width
-            self.photo_height: Optional[int] = photo_height
-            self.need_name: Optional[bool] = need_name
-            self.need_phone_number: Optional[bool] = need_phone_number
-            self.need_email: Optional[bool] = need_email
-            self.need_shipping_address: Optional[bool] = need_shipping_address
-            self.send_phone_number_to_provider: Optional[bool] = send_phone_number_to_provider
-            self.send_email_to_provider: Optional[bool] = send_email_to_provider
-            self.is_flexible: Optional[bool] = is_flexible
-
-            self._id_attrs = (
-                self.title,
-                self.description,
-                self.payload,
-                self.provider_token,
-                self.currency,
-                self.prices,
-            )
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["InputInvoiceMessageContent"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        data["prices"] = LabeledPrice.de_list(data.get("prices"), bot)
-
-        return super().de_json(data=data, bot=bot)
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inputlocationmessagecontent.py b/venv/lib/python3.11/site-packages/telegram/_inline/inputlocationmessagecontent.py
deleted file mode 100755
index f71a716..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inputlocationmessagecontent.py
+++ /dev/null
@@ -1,150 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InputLocationMessageContent."""
-
-from typing import Final, Optional
-
-from telegram import constants
-from telegram._inline.inputmessagecontent import InputMessageContent
-from telegram._utils.types import JSONDict
-
-
-class InputLocationMessageContent(InputMessageContent):
-    # fmt: off
-    """
-    Represents the content of a location message to be sent as the result of an inline query.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`latitude` and :attr:`longitude` are equal.
-
-    Args:
-        latitude (:obj:`float`): Latitude of the location in degrees.
-        longitude (:obj:`float`): Longitude of the location in degrees.
-        horizontal_accuracy (:obj:`float`, optional): The radius of uncertainty for the location,
-            measured in meters; 0-
-            :tg-const:`telegram.InputLocationMessageContent.HORIZONTAL_ACCURACY`.
-        live_period (:obj:`int`, optional): Period in seconds for which the location will be
-            updated, should be between
-            :tg-const:`telegram.InputLocationMessageContent.MIN_LIVE_PERIOD` and
-            :tg-const:`telegram.InputLocationMessageContent.MAX_LIVE_PERIOD` or
-            :tg-const:`telegram.constants.LocationLimit.LIVE_PERIOD_FOREVER` for live
-            locations that can be edited indefinitely.
-        heading (:obj:`int`, optional): For live locations, a direction in which the user is
-            moving, in degrees. Must be between
-            :tg-const:`telegram.InputLocationMessageContent.MIN_HEADING` and
-            :tg-const:`telegram.InputLocationMessageContent.MAX_HEADING` if specified.
-        proximity_alert_radius (:obj:`int`, optional): For live locations, a maximum distance
-            for proximity alerts about approaching another chat member, in meters. Must be
-            between :tg-const:`telegram.InputLocationMessageContent.MIN_PROXIMITY_ALERT_RADIUS`
-            and :tg-const:`telegram.InputLocationMessageContent.MAX_PROXIMITY_ALERT_RADIUS`
-            if specified.
-
-    Attributes:
-        latitude (:obj:`float`): Latitude of the location in degrees.
-        longitude (:obj:`float`): Longitude of the location in degrees.
-        horizontal_accuracy (:obj:`float`): Optional. The radius of uncertainty for the location,
-            measured in meters; 0-
-            :tg-const:`telegram.InputLocationMessageContent.HORIZONTAL_ACCURACY`.
-        live_period (:obj:`int`): Optional. Period in seconds for which the location can be
-            updated, should be between
-            :tg-const:`telegram.InputLocationMessageContent.MIN_LIVE_PERIOD` and
-            :tg-const:`telegram.InputLocationMessageContent.MAX_LIVE_PERIOD`.
-        heading (:obj:`int`): Optional. For live locations, a direction in which the user is
-            moving, in degrees. Must be between
-            :tg-const:`telegram.InputLocationMessageContent.MIN_HEADING` and
-            :tg-const:`telegram.InputLocationMessageContent.MAX_HEADING` if specified.
-        proximity_alert_radius (:obj:`int`): Optional. For live locations, a maximum distance
-            for proximity alerts about approaching another chat member, in meters. Must be
-            between :tg-const:`telegram.InputLocationMessageContent.MIN_PROXIMITY_ALERT_RADIUS`
-            and :tg-const:`telegram.InputLocationMessageContent.MAX_PROXIMITY_ALERT_RADIUS`
-            if specified.
-
-    """
-
-    __slots__ = (
-        "heading",
-        "horizontal_accuracy",
-        "latitude",
-        "live_period",
-        "longitude",
-        "proximity_alert_radius")
-    # fmt: on
-
-    def __init__(
-        self,
-        latitude: float,
-        longitude: float,
-        live_period: Optional[int] = None,
-        horizontal_accuracy: Optional[float] = None,
-        heading: Optional[int] = None,
-        proximity_alert_radius: Optional[int] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        with self._unfrozen():
-            # Required
-            self.latitude: float = latitude
-            self.longitude: float = longitude
-
-            # Optionals
-            self.live_period: Optional[int] = live_period
-            self.horizontal_accuracy: Optional[float] = horizontal_accuracy
-            self.heading: Optional[int] = heading
-            self.proximity_alert_radius: Optional[int] = (
-                int(proximity_alert_radius) if proximity_alert_radius else None
-            )
-
-            self._id_attrs = (self.latitude, self.longitude)
-
-    HORIZONTAL_ACCURACY: Final[int] = constants.LocationLimit.HORIZONTAL_ACCURACY
-    """:const:`telegram.constants.LocationLimit.HORIZONTAL_ACCURACY`
-
-    .. versionadded:: 20.0
-    """
-    MIN_HEADING: Final[int] = constants.LocationLimit.MIN_HEADING
-    """:const:`telegram.constants.LocationLimit.MIN_HEADING`
-
-    .. versionadded:: 20.0
-    """
-    MAX_HEADING: Final[int] = constants.LocationLimit.MAX_HEADING
-    """:const:`telegram.constants.LocationLimit.MAX_HEADING`
-
-    .. versionadded:: 20.0
-    """
-    MIN_LIVE_PERIOD: Final[int] = constants.LocationLimit.MIN_LIVE_PERIOD
-    """:const:`telegram.constants.LocationLimit.MIN_LIVE_PERIOD`
-
-    .. versionadded:: 20.0
-    """
-    MAX_LIVE_PERIOD: Final[int] = constants.LocationLimit.MAX_LIVE_PERIOD
-    """:const:`telegram.constants.LocationLimit.MAX_LIVE_PERIOD`
-
-    .. versionadded:: 20.0
-    """
-    MIN_PROXIMITY_ALERT_RADIUS: Final[int] = constants.LocationLimit.MIN_PROXIMITY_ALERT_RADIUS
-    """:const:`telegram.constants.LocationLimit.MIN_PROXIMITY_ALERT_RADIUS`
-
-    .. versionadded:: 20.0
-    """
-    MAX_PROXIMITY_ALERT_RADIUS: Final[int] = constants.LocationLimit.MAX_PROXIMITY_ALERT_RADIUS
-    """:const:`telegram.constants.LocationLimit.MAX_PROXIMITY_ALERT_RADIUS`
-
-    .. versionadded:: 20.0
-    """
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inputmessagecontent.py b/venv/lib/python3.11/site-packages/telegram/_inline/inputmessagecontent.py
deleted file mode 100755
index e37fa12..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inputmessagecontent.py
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InputMessageContent."""
-
-from typing import Optional
-
-from telegram._telegramobject import TelegramObject
-from telegram._utils.types import JSONDict
-
-
-class InputMessageContent(TelegramObject):
-    """Base class for Telegram InputMessageContent Objects.
-
-    See: :class:`telegram.InputContactMessageContent`,
-    :class:`telegram.InputInvoiceMessageContent`,
-    :class:`telegram.InputLocationMessageContent`, :class:`telegram.InputTextMessageContent` and
-    :class:`telegram.InputVenueMessageContent` for more details.
-
-    """
-
-    __slots__ = ()
-
-    def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None:
-        super().__init__(api_kwargs=api_kwargs)
-
-        self._freeze()
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inputtextmessagecontent.py b/venv/lib/python3.11/site-packages/telegram/_inline/inputtextmessagecontent.py
deleted file mode 100755
index 11a2373..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inputtextmessagecontent.py
+++ /dev/null
@@ -1,116 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InputTextMessageContent."""
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Optional
-
-from telegram._inline.inputmessagecontent import InputMessageContent
-from telegram._messageentity import MessageEntity
-from telegram._utils.argumentparsing import parse_lpo_and_dwpp, parse_sequence_arg
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.types import JSONDict, ODVInput
-
-if TYPE_CHECKING:
-    from telegram._linkpreviewoptions import LinkPreviewOptions
-
-
-class InputTextMessageContent(InputMessageContent):
-    """
-    Represents the content of a text message to be sent as the result of an inline query.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`message_text` is equal.
-
-    Examples:
-        :any:`Inline Bot `
-
-    Args:
-        message_text (:obj:`str`): Text of the message to be sent,
-            :tg-const:`telegram.constants.MessageLimit.MIN_TEXT_LENGTH`-
-            :tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters after entities
-            parsing.
-        parse_mode (:obj:`str`, optional): |parse_mode|
-        entities (Sequence[:class:`telegram.MessageEntity`], optional): |caption_entities|
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        link_preview_options (:obj:`LinkPreviewOptions`, optional): Link preview generation
-            options for the message. Mutually exclusive with
-            :paramref:`disable_web_page_preview`.
-
-            .. versionadded:: 20.8
-
-    Keyword Args:
-        disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in the
-            sent message. Convenience parameter for setting :paramref:`link_preview_options`.
-            Mutually exclusive with :paramref:`link_preview_options`.
-
-            .. versionchanged:: 20.8
-                Bot API 7.0 introduced :paramref:`link_preview_options` replacing this
-                argument. PTB will automatically convert this argument to that one, but
-                for advanced options, please use :paramref:`link_preview_options` directly.
-
-            .. versionchanged:: 21.0
-                |keyword_only_arg|
-
-    Attributes:
-        message_text (:obj:`str`): Text of the message to be sent,
-            :tg-const:`telegram.constants.MessageLimit.MIN_TEXT_LENGTH`-
-            :tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters after entities
-            parsing.
-        parse_mode (:obj:`str`): Optional. |parse_mode|
-        entities (tuple[:class:`telegram.MessageEntity`]): Optional. |captionentitiesattr|
-
-            .. versionchanged:: 20.0
-
-                * |tupleclassattrs|
-                * |alwaystuple|
-        link_preview_options (:obj:`LinkPreviewOptions`): Optional. Link preview generation
-            options for the message.
-
-            .. versionadded:: 20.8
-
-    """
-
-    __slots__ = ("entities", "link_preview_options", "message_text", "parse_mode")
-
-    def __init__(
-        self,
-        message_text: str,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        entities: Optional[Sequence[MessageEntity]] = None,
-        link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE,
-        *,
-        disable_web_page_preview: Optional[bool] = None,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-
-        with self._unfrozen():
-            # Required
-            self.message_text: str = message_text
-            # Optionals
-            self.parse_mode: ODVInput[str] = parse_mode
-            self.entities: tuple[MessageEntity, ...] = parse_sequence_arg(entities)
-            self.link_preview_options: ODVInput[LinkPreviewOptions] = parse_lpo_and_dwpp(
-                disable_web_page_preview, link_preview_options
-            )
-
-            self._id_attrs = (self.message_text,)
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/inputvenuemessagecontent.py b/venv/lib/python3.11/site-packages/telegram/_inline/inputvenuemessagecontent.py
deleted file mode 100755
index c836ea1..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/inputvenuemessagecontent.py
+++ /dev/null
@@ -1,108 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the classes that represent Telegram InputVenueMessageContent."""
-from typing import Optional
-
-from telegram._inline.inputmessagecontent import InputMessageContent
-from telegram._utils.types import JSONDict
-
-
-class InputVenueMessageContent(InputMessageContent):
-    """Represents the content of a venue message to be sent as the result of an inline query.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`latitude`, :attr:`longitude` and :attr:`title`
-    are equal.
-
-    Note:
-      Foursquare details and Google Pace details are mutually exclusive. However, this
-      behaviour is undocumented and might be changed by Telegram.
-
-    Args:
-        latitude (:obj:`float`): Latitude of the location in degrees.
-        longitude (:obj:`float`): Longitude of the location in degrees.
-        title (:obj:`str`): Name of the venue.
-        address (:obj:`str`): Address of the venue.
-        foursquare_id (:obj:`str`, optional): Foursquare identifier of the venue, if known.
-        foursquare_type (:obj:`str`, optional): Foursquare type of the venue, if known.
-            (For example, "arts_entertainment/default", "arts_entertainment/aquarium" or
-            "food/icecream".)
-        google_place_id (:obj:`str`, optional): Google Places identifier of the venue.
-        google_place_type (:obj:`str`, optional): Google Places type of the venue. (See
-            `supported types `_.)
-
-    Attributes:
-        latitude (:obj:`float`): Latitude of the location in degrees.
-        longitude (:obj:`float`): Longitude of the location in degrees.
-        title (:obj:`str`): Name of the venue.
-        address (:obj:`str`): Address of the venue.
-        foursquare_id (:obj:`str`): Optional. Foursquare identifier of the venue, if known.
-        foursquare_type (:obj:`str`): Optional. Foursquare type of the venue, if known.
-            (For example, "arts_entertainment/default", "arts_entertainment/aquarium" or
-            "food/icecream".)
-        google_place_id (:obj:`str`): Optional. Google Places identifier of the venue.
-        google_place_type (:obj:`str`): Optional. Google Places type of the venue. (See
-            `supported types `_.)
-
-    """
-
-    __slots__ = (
-        "address",
-        "foursquare_id",
-        "foursquare_type",
-        "google_place_id",
-        "google_place_type",
-        "latitude",
-        "longitude",
-        "title",
-    )
-
-    def __init__(
-        self,
-        latitude: float,
-        longitude: float,
-        title: str,
-        address: str,
-        foursquare_id: Optional[str] = None,
-        foursquare_type: Optional[str] = None,
-        google_place_id: Optional[str] = None,
-        google_place_type: Optional[str] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        with self._unfrozen():
-            # Required
-            self.latitude: float = latitude
-            self.longitude: float = longitude
-            self.title: str = title
-            self.address: str = address
-            # Optionals
-            self.foursquare_id: Optional[str] = foursquare_id
-            self.foursquare_type: Optional[str] = foursquare_type
-            self.google_place_id: Optional[str] = google_place_id
-            self.google_place_type: Optional[str] = google_place_type
-
-            self._id_attrs = (
-                self.latitude,
-                self.longitude,
-                self.title,
-            )
diff --git a/venv/lib/python3.11/site-packages/telegram/_inline/preparedinlinemessage.py b/venv/lib/python3.11/site-packages/telegram/_inline/preparedinlinemessage.py
deleted file mode 100755
index 35f4628..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_inline/preparedinlinemessage.py
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram Prepared inline Message."""
-import datetime as dtm
-from typing import TYPE_CHECKING, Optional
-
-from telegram._telegramobject import TelegramObject
-from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
-from telegram._utils.types import JSONDict
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class PreparedInlineMessage(TelegramObject):
-    """Describes an inline message to be sent by a user of a Mini App.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`id` is equal.
-
-    .. versionadded:: 21.8
-
-    Args:
-        id (:obj:`str`): Unique identifier of the prepared message
-        expiration_date (:class:`datetime.datetime`): Expiration date of the prepared message.
-            Expired prepared messages can no longer be used.
-            |datetime_localization|
-
-    Attributes:
-        id (:obj:`str`): Unique identifier of the prepared message
-        expiration_date (:class:`datetime.datetime`): Expiration date of the prepared message.
-            Expired prepared messages can no longer be used.
-            |datetime_localization|
-    """
-
-    __slots__ = ("expiration_date", "id")
-
-    def __init__(
-        self,
-        id: str,  # pylint: disable=redefined-builtin
-        expiration_date: dtm.datetime,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.id: str = id
-        self.expiration_date: dtm.datetime = expiration_date
-
-        self._id_attrs = (self.id,)
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["PreparedInlineMessage"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if data is None:
-            return None
-
-        # Get the local timezone from the bot if it has defaults
-        loc_tzinfo = extract_tzinfo_from_defaults(bot)
-        data["expiration_date"] = from_timestamp(data.get("expiration_date"), tzinfo=loc_tzinfo)
-
-        return super().de_json(data=data, bot=bot)
diff --git a/venv/lib/python3.11/site-packages/telegram/_keyboardbutton.py b/venv/lib/python3.11/site-packages/telegram/_keyboardbutton.py
deleted file mode 100755
index 7bb8949..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_keyboardbutton.py
+++ /dev/null
@@ -1,191 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram KeyboardButton."""
-
-from typing import TYPE_CHECKING, Optional
-
-from telegram._keyboardbuttonpolltype import KeyboardButtonPollType
-from telegram._keyboardbuttonrequest import KeyboardButtonRequestChat, KeyboardButtonRequestUsers
-from telegram._telegramobject import TelegramObject
-from telegram._utils.types import JSONDict
-from telegram._webappinfo import WebAppInfo
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class KeyboardButton(TelegramObject):
-    """
-    This object represents one button of the reply keyboard. At most one of the optional fields
-    must be used to specify type of the button. For simple text buttons, :obj:`str`
-    can be used instead of this object to specify text of the button.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`text`, :attr:`request_contact`, :attr:`request_location`,
-    :attr:`request_poll`, :attr:`web_app`, :attr:`request_users` and :attr:`request_chat` are
-    equal.
-
-    Note:
-        * Optional fields are mutually exclusive.
-        * :attr:`request_contact` and :attr:`request_location` options will only work in Telegram
-          versions released after 9 April, 2016. Older clients will display unsupported message.
-        * :attr:`request_poll` option will only work in Telegram versions released after 23
-          January, 2020. Older clients will display unsupported message.
-        * :attr:`web_app` option will only work in Telegram versions released after 16 April, 2022.
-          Older clients will display unsupported message.
-        * :attr:`request_users` and :attr:`request_chat` options will only work in Telegram
-          versions released after 3 February, 2023. Older clients will display unsupported
-          message.
-
-    .. versionchanged:: 21.0
-       Removed deprecated argument and attribute ``request_user``.
-    .. versionchanged:: 20.0
-       :attr:`web_app` is considered as well when comparing objects of this type in terms of
-       equality.
-    .. versionchanged:: 20.5
-       :attr:`request_users` and :attr:`request_chat` are considered as well when
-       comparing objects of this type in terms of equality.
-
-    Args:
-        text (:obj:`str`): Text of the button. If none of the optional fields are used, it will be
-            sent to the bot as a message when the button is pressed.
-        request_contact (:obj:`bool`, optional): If :obj:`True`, the user's phone number will be
-            sent as a contact when the button is pressed. Available in private chats only.
-        request_location (:obj:`bool`, optional): If :obj:`True`, the user's current location will
-            be sent when the button is pressed. Available in private chats only.
-        request_poll (:class:`~telegram.KeyboardButtonPollType`, optional): If specified, the user
-            will be asked to create a poll and send it to the bot when the button is pressed.
-            Available in private chats only.
-        web_app (:class:`~telegram.WebAppInfo`, optional): If specified, the described `Web App
-            `_ will be launched when the button is pressed.
-            The Web App will be able to send a :attr:`Message.web_app_data` service message.
-            Available in private chats only.
-
-            .. versionadded:: 20.0
-
-        request_users (:class:`KeyboardButtonRequestUsers`, optional): If specified, pressing the
-            button will open a list of suitable users. Tapping on any user will send its
-            identifier to the bot in a :attr:`telegram.Message.users_shared` service message.
-            Available in private chats only.
-
-            .. versionadded:: 20.8
-        request_chat (:class:`KeyboardButtonRequestChat`, optional): If specified, pressing the
-            button will open a list of suitable chats. Tapping on a chat will send its
-            identifier to the bot in a :attr:`telegram.Message.chat_shared` service message.
-            Available in private chats only.
-
-            .. versionadded:: 20.1
-    Attributes:
-        text (:obj:`str`): Text of the button. If none of the optional fields are used, it will be
-            sent to the bot as a message when the button is pressed.
-        request_contact (:obj:`bool`): Optional. If :obj:`True`, the user's phone number will be
-            sent as a contact when the button is pressed. Available in private chats only.
-        request_location (:obj:`bool`): Optional. If :obj:`True`, the user's current location will
-            be sent when the button is pressed. Available in private chats only.
-        request_poll (:class:`~telegram.KeyboardButtonPollType`): Optional. If specified,
-            the user will be asked to create a poll and send it to the bot when the button is
-            pressed. Available in private chats only.
-        web_app (:class:`~telegram.WebAppInfo`): Optional. If specified, the described `Web App
-            `_ will be launched when the button is pressed.
-            The Web App will be able to send a :attr:`Message.web_app_data` service message.
-            Available in private chats only.
-
-            .. versionadded:: 20.0
-        request_users (:class:`KeyboardButtonRequestUsers`): Optional. If specified, pressing the
-            button will open a list of suitable users. Tapping on any user will send its
-            identifier to the bot in a :attr:`telegram.Message.users_shared` service message.
-            Available in private chats only.
-
-            .. versionadded:: 20.8
-        request_chat (:class:`KeyboardButtonRequestChat`): Optional. If specified, pressing the
-            button will open a list of suitable chats. Tapping on a chat will send its
-            identifier to the bot in a :attr:`telegram.Message.chat_shared` service message.
-            Available in private chats only.
-
-            .. versionadded:: 20.1
-    """
-
-    __slots__ = (
-        "request_chat",
-        "request_contact",
-        "request_location",
-        "request_poll",
-        "request_users",
-        "text",
-        "web_app",
-    )
-
-    def __init__(
-        self,
-        text: str,
-        request_contact: Optional[bool] = None,
-        request_location: Optional[bool] = None,
-        request_poll: Optional[KeyboardButtonPollType] = None,
-        web_app: Optional[WebAppInfo] = None,
-        request_chat: Optional[KeyboardButtonRequestChat] = None,
-        request_users: Optional[KeyboardButtonRequestUsers] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-
-        # Required
-        self.text: str = text
-        # Optionals
-        self.request_contact: Optional[bool] = request_contact
-        self.request_location: Optional[bool] = request_location
-        self.request_poll: Optional[KeyboardButtonPollType] = request_poll
-        self.web_app: Optional[WebAppInfo] = web_app
-        self.request_users: Optional[KeyboardButtonRequestUsers] = request_users
-        self.request_chat: Optional[KeyboardButtonRequestChat] = request_chat
-
-        self._id_attrs = (
-            self.text,
-            self.request_contact,
-            self.request_location,
-            self.request_poll,
-            self.web_app,
-            self.request_users,
-            self.request_chat,
-        )
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["KeyboardButton"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        data["request_poll"] = KeyboardButtonPollType.de_json(data.get("request_poll"), bot)
-        data["request_users"] = KeyboardButtonRequestUsers.de_json(data.get("request_users"), bot)
-        data["request_chat"] = KeyboardButtonRequestChat.de_json(data.get("request_chat"), bot)
-        data["web_app"] = WebAppInfo.de_json(data.get("web_app"), bot)
-
-        api_kwargs = {}
-        # This is a deprecated field that TG still returns for backwards compatibility
-        # Let's filter it out to speed up the de-json process
-        if request_user := data.get("request_user"):
-            api_kwargs = {"request_user": request_user}
-
-        return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs)
diff --git a/venv/lib/python3.11/site-packages/telegram/_keyboardbuttonpolltype.py b/venv/lib/python3.11/site-packages/telegram/_keyboardbuttonpolltype.py
deleted file mode 100755
index fb21cfe..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_keyboardbuttonpolltype.py
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a type of a Telegram Poll."""
-from typing import Optional
-
-from telegram._telegramobject import TelegramObject
-from telegram._utils import enum
-from telegram._utils.types import JSONDict
-from telegram.constants import PollType
-
-
-class KeyboardButtonPollType(TelegramObject):
-    """This object represents type of a poll, which is allowed to be created
-    and sent when the corresponding button is pressed.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`type` is equal.
-
-    Examples:
-        :any:`Poll Bot `
-
-    Args:
-        type (:obj:`str`, optional): If :tg-const:`telegram.Poll.QUIZ` is passed, the user will be
-            allowed to create only polls in the quiz mode. If :tg-const:`telegram.Poll.REGULAR` is
-            passed, only regular polls will be allowed. Otherwise, the user will be allowed to
-            create a poll of any type.
-    Attributes:
-        type (:obj:`str`): Optional. If equals :tg-const:`telegram.Poll.QUIZ`, the user will
-            be allowed to create only polls in the quiz mode. If equals
-            :tg-const:`telegram.Poll.REGULAR`, only regular polls will be allowed.
-            Otherwise, the user will be allowed to create a poll of any type.
-    """
-
-    __slots__ = ("type",)
-
-    def __init__(
-        self,
-        type: Optional[str] = None,  # pylint: disable=redefined-builtin
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.type: Optional[str] = enum.get_member(PollType, type, type)
-
-        self._id_attrs = (self.type,)
-
-        self._freeze()
diff --git a/venv/lib/python3.11/site-packages/telegram/_keyboardbuttonrequest.py b/venv/lib/python3.11/site-packages/telegram/_keyboardbuttonrequest.py
deleted file mode 100755
index b929f0b..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_keyboardbuttonrequest.py
+++ /dev/null
@@ -1,276 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains two objects to request chats/users."""
-
-from typing import TYPE_CHECKING, Optional
-
-from telegram._chatadministratorrights import ChatAdministratorRights
-from telegram._telegramobject import TelegramObject
-from telegram._utils.types import JSONDict
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class KeyboardButtonRequestUsers(TelegramObject):
-    """This object defines the criteria used to request a suitable user. The identifier of the
-    selected user will be shared with the bot when the corresponding button is pressed. `More
-    about requesting users » `_.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`request_id` is equal.
-
-    .. versionadded:: 20.8
-        This class was previously named ``KeyboardButtonRequestUser``.
-
-    Args:
-        request_id (:obj:`int`): Signed 32-bit identifier of the request, which will be received
-            back in the :class:`telegram.UsersShared` object. Must be unique within the message.
-        user_is_bot (:obj:`bool`, optional): Pass :obj:`True` to request a bot, pass :obj:`False`
-            to request a regular user. If not specified, no additional restrictions are applied.
-        user_is_premium (:obj:`bool`, optional): Pass :obj:`True` to request a premium user, pass
-            :obj:`False` to request a non-premium user. If not specified, no additional
-            restrictions are applied.
-        max_quantity (:obj:`int`, optional): The maximum number of users to be selected;
-            :tg-const:`telegram.constants.KeyboardButtonRequestUsersLimit.MIN_QUANTITY` -
-            :tg-const:`telegram.constants.KeyboardButtonRequestUsersLimit.MAX_QUANTITY`.
-            Defaults to :tg-const:`telegram.constants.KeyboardButtonRequestUsersLimit.MIN_QUANTITY`
-            .
-
-            .. versionadded:: 20.8
-        request_name (:obj:`bool`, optional): Pass :obj:`True` to request the users' first and last
-            name.
-
-            .. versionadded:: 21.1
-        request_username (:obj:`bool`, optional): Pass :obj:`True` to request the users' username.
-
-            .. versionadded:: 21.1
-        request_photo (:obj:`bool`, optional): Pass :obj:`True` to request the users' photo.
-
-            .. versionadded:: 21.1
-
-    Attributes:
-        request_id (:obj:`int`): Identifier of the request.
-        user_is_bot (:obj:`bool`): Optional. Pass :obj:`True` to request a bot, pass :obj:`False`
-            to request a regular user. If not specified, no additional restrictions are applied.
-        user_is_premium (:obj:`bool`): Optional. Pass :obj:`True` to request a premium user, pass
-            :obj:`False` to request a non-premium user. If not specified, no additional
-            restrictions are applied.
-        max_quantity (:obj:`int`): Optional. The maximum number of users to be selected;
-            :tg-const:`telegram.constants.KeyboardButtonRequestUsersLimit.MIN_QUANTITY` -
-            :tg-const:`telegram.constants.KeyboardButtonRequestUsersLimit.MAX_QUANTITY`.
-            Defaults to :tg-const:`telegram.constants.KeyboardButtonRequestUsersLimit.MIN_QUANTITY`
-            .
-
-            .. versionadded:: 20.8
-        request_name (:obj:`bool`): Optional. Pass :obj:`True` to request the users' first and last
-            name.
-
-            .. versionadded:: 21.1
-        request_username (:obj:`bool`): Optional. Pass :obj:`True` to request the users' username.
-
-            .. versionadded:: 21.1
-        request_photo (:obj:`bool`): Optional. Pass :obj:`True` to request the users' photo.
-
-            .. versionadded:: 21.1
-
-    """
-
-    __slots__ = (
-        "max_quantity",
-        "request_id",
-        "request_name",
-        "request_photo",
-        "request_username",
-        "user_is_bot",
-        "user_is_premium",
-    )
-
-    def __init__(
-        self,
-        request_id: int,
-        user_is_bot: Optional[bool] = None,
-        user_is_premium: Optional[bool] = None,
-        max_quantity: Optional[int] = None,
-        request_name: Optional[bool] = None,
-        request_username: Optional[bool] = None,
-        request_photo: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        # Required
-        self.request_id: int = request_id
-
-        # Optionals
-        self.user_is_bot: Optional[bool] = user_is_bot
-        self.user_is_premium: Optional[bool] = user_is_premium
-        self.max_quantity: Optional[int] = max_quantity
-        self.request_name: Optional[bool] = request_name
-        self.request_username: Optional[bool] = request_username
-        self.request_photo: Optional[bool] = request_photo
-
-        self._id_attrs = (self.request_id,)
-
-        self._freeze()
-
-
-class KeyboardButtonRequestChat(TelegramObject):
-    """This object defines the criteria used to request a suitable chat. The identifier of the
-    selected user will be shared with the bot when the corresponding button is pressed. `More
-    about requesting users » `_.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`request_id` is equal.
-
-    .. versionadded:: 20.1
-
-    Args:
-        request_id (:obj:`int`): Signed 32-bit identifier of the request, which will be received
-            back in the :class:`telegram.ChatShared` object. Must be unique within the message.
-        chat_is_channel (:obj:`bool`): Pass :obj:`True` to request a channel chat, pass
-            :obj:`False` to request a group or a supergroup chat.
-        chat_is_forum (:obj:`bool`, optional): Pass :obj:`True` to request a forum supergroup, pass
-            :obj:`False` to request a non-forum chat. If not specified, no additional
-            restrictions are applied.
-        chat_has_username (:obj:`bool`, optional): Pass :obj:`True` to request a supergroup or a
-            channel with a username, pass :obj:`False` to request a chat without a username. If
-            not specified, no additional restrictions are applied.
-        chat_is_created (:obj:`bool`, optional): Pass :obj:`True` to request a chat owned by the
-            user. Otherwise, no additional restrictions are applied.
-        user_administrator_rights (:class:`ChatAdministratorRights`, optional): Specifies the
-            required administrator rights of the user in the chat. If not specified, no additional
-            restrictions are applied.
-        bot_administrator_rights (:class:`ChatAdministratorRights`, optional): Specifies the
-            required administrator rights of the bot in the chat. The rights must be a subset of
-            :paramref:`user_administrator_rights`. If not specified, no additional restrictions are
-            applied.
-        bot_is_member (:obj:`bool`, optional): Pass :obj:`True` to request a chat with the bot
-            as a member. Otherwise, no additional restrictions are applied.
-        request_title (:obj:`bool`, optional): Pass :obj:`True` to request the chat's title.
-
-            .. versionadded:: 21.1
-        request_username (:obj:`bool`, optional): Pass :obj:`True` to request the chat's username.
-
-            .. versionadded:: 21.1
-        request_photo (:obj:`bool`, optional): Pass :obj:`True` to request the chat's photo.
-
-            .. versionadded:: 21.1
-    Attributes:
-        request_id (:obj:`int`): Identifier of the request.
-        chat_is_channel (:obj:`bool`): Pass :obj:`True` to request a channel chat, pass
-            :obj:`False` to request a group or a supergroup chat.
-        chat_is_forum (:obj:`bool`): Optional. Pass :obj:`True` to request a forum supergroup, pass
-            :obj:`False` to request a non-forum chat. If not specified, no additional
-            restrictions are applied.
-        chat_has_username (:obj:`bool`): Optional. Pass :obj:`True` to request a supergroup or a
-            channel with a username, pass :obj:`False` to request a chat without a username. If
-            not specified, no additional restrictions are applied.
-        chat_is_created (:obj:`bool`) Optional. Pass :obj:`True` to request a chat owned by the
-            user. Otherwise, no additional restrictions are applied.
-        user_administrator_rights (:class:`ChatAdministratorRights`) Optional. Specifies the
-            required administrator rights of the user in the chat. If not specified, no additional
-            restrictions are applied.
-        bot_administrator_rights (:class:`ChatAdministratorRights`) Optional. Specifies the
-            required administrator rights of the bot in the chat. The rights must be a subset of
-            :attr:`user_administrator_rights`. If not specified, no additional restrictions are
-            applied.
-        bot_is_member (:obj:`bool`) Optional. Pass :obj:`True` to request a chat with the bot
-            as a member. Otherwise, no additional restrictions are applied.
-        request_title (:obj:`bool`): Optional. Pass :obj:`True` to request the chat's title.
-
-            .. versionadded:: 21.1
-        request_username (:obj:`bool`): Optional. Pass :obj:`True` to request the chat's username.
-
-            .. versionadded:: 21.1
-        request_photo (:obj:`bool`): Optional. Pass :obj:`True` to request the chat's photo.
-
-            .. versionadded:: 21.1
-    """
-
-    __slots__ = (
-        "bot_administrator_rights",
-        "bot_is_member",
-        "chat_has_username",
-        "chat_is_channel",
-        "chat_is_created",
-        "chat_is_forum",
-        "request_id",
-        "request_photo",
-        "request_title",
-        "request_username",
-        "user_administrator_rights",
-    )
-
-    def __init__(
-        self,
-        request_id: int,
-        chat_is_channel: bool,
-        chat_is_forum: Optional[bool] = None,
-        chat_has_username: Optional[bool] = None,
-        chat_is_created: Optional[bool] = None,
-        user_administrator_rights: Optional[ChatAdministratorRights] = None,
-        bot_administrator_rights: Optional[ChatAdministratorRights] = None,
-        bot_is_member: Optional[bool] = None,
-        request_title: Optional[bool] = None,
-        request_username: Optional[bool] = None,
-        request_photo: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        # required
-        self.request_id: int = request_id
-        self.chat_is_channel: bool = chat_is_channel
-
-        # optional
-        self.chat_is_forum: Optional[bool] = chat_is_forum
-        self.chat_has_username: Optional[bool] = chat_has_username
-        self.chat_is_created: Optional[bool] = chat_is_created
-        self.user_administrator_rights: Optional[ChatAdministratorRights] = (
-            user_administrator_rights
-        )
-        self.bot_administrator_rights: Optional[ChatAdministratorRights] = bot_administrator_rights
-        self.bot_is_member: Optional[bool] = bot_is_member
-        self.request_title: Optional[bool] = request_title
-        self.request_username: Optional[bool] = request_username
-        self.request_photo: Optional[bool] = request_photo
-
-        self._id_attrs = (self.request_id,)
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["KeyboardButtonRequestChat"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        data["user_administrator_rights"] = ChatAdministratorRights.de_json(
-            data.get("user_administrator_rights"), bot
-        )
-        data["bot_administrator_rights"] = ChatAdministratorRights.de_json(
-            data.get("bot_administrator_rights"), bot
-        )
-
-        return super().de_json(data=data, bot=bot)
diff --git a/venv/lib/python3.11/site-packages/telegram/_linkpreviewoptions.py b/venv/lib/python3.11/site-packages/telegram/_linkpreviewoptions.py
deleted file mode 100755
index 6e28c92..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_linkpreviewoptions.py
+++ /dev/null
@@ -1,103 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains the LinkPreviewOptions class."""
-
-
-from typing import Optional
-
-from telegram._telegramobject import TelegramObject
-from telegram._utils.defaultvalue import DEFAULT_NONE
-from telegram._utils.types import JSONDict, ODVInput
-
-
-class LinkPreviewOptions(TelegramObject):
-    """
-    Describes the options used for link preview generation.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`is_disabled`, :attr:`url`, :attr:`prefer_small_media`,
-    :attr:`prefer_large_media`, and :attr:`show_above_text` are equal.
-
-    .. versionadded:: 20.8
-
-    Args:
-        is_disabled (:obj:`bool`, optional): :obj:`True`, if the link preview is disabled.
-        url (:obj:`str`, optional): The URL to use for the link preview. If empty, then the first
-            URL found in the message text will be used.
-        prefer_small_media (:obj:`bool`, optional): :obj:`True`, if the media in the link preview
-            is supposed to be shrunk; ignored if the URL isn't explicitly specified or media size
-            change isn't supported for the preview.
-        prefer_large_media (:obj:`bool`, optional): :obj:`True`, if the media in the link preview
-            is supposed to be enlarged; ignored if the URL isn't explicitly specified or media
-            size change isn't supported for the preview.
-        show_above_text (:obj:`bool`, optional): :obj:`True`, if the link preview must be shown
-            above the message text; otherwise, the link preview will be shown below the message
-            text.
-
-    Attributes:
-        is_disabled (:obj:`bool`): Optional. :obj:`True`, if the link preview is disabled.
-        url (:obj:`str`): Optional. The URL to use for the link preview. If empty, then the first
-            URL found in the message text will be used.
-        prefer_small_media (:obj:`bool`): Optional. :obj:`True`, if the media in the link preview
-            is supposed to be shrunk; ignored if the URL isn't explicitly specified or media size
-            change isn't supported for the preview.
-        prefer_large_media (:obj:`bool`): Optional. :obj:`True`, if the media in the link preview
-            is supposed to be enlarged; ignored if the URL isn't explicitly specified or media size
-            change isn't supported for the preview.
-        show_above_text (:obj:`bool`): Optional. :obj:`True`, if the link preview must be shown
-            above the message text; otherwise, the link preview will be shown below the message
-            text.
-    """
-
-    __slots__ = (
-        "is_disabled",
-        "prefer_large_media",
-        "prefer_small_media",
-        "show_above_text",
-        "url",
-    )
-
-    def __init__(
-        self,
-        is_disabled: ODVInput[bool] = DEFAULT_NONE,
-        url: ODVInput[str] = DEFAULT_NONE,
-        prefer_small_media: ODVInput[bool] = DEFAULT_NONE,
-        prefer_large_media: ODVInput[bool] = DEFAULT_NONE,
-        show_above_text: ODVInput[bool] = DEFAULT_NONE,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-
-        # Optionals
-
-        self.is_disabled: ODVInput[bool] = is_disabled
-        self.url: ODVInput[str] = url
-        self.prefer_small_media: ODVInput[bool] = prefer_small_media
-        self.prefer_large_media: ODVInput[bool] = prefer_large_media
-        self.show_above_text: ODVInput[bool] = show_above_text
-
-        self._id_attrs = (
-            self.is_disabled,
-            self.url,
-            self.prefer_small_media,
-            self.prefer_large_media,
-            self.show_above_text,
-        )
-        self._freeze()
diff --git a/venv/lib/python3.11/site-packages/telegram/_loginurl.py b/venv/lib/python3.11/site-packages/telegram/_loginurl.py
deleted file mode 100755
index 3400542..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_loginurl.py
+++ /dev/null
@@ -1,105 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram LoginUrl."""
-from typing import Optional
-
-from telegram._telegramobject import TelegramObject
-from telegram._utils.types import JSONDict
-
-
-class LoginUrl(TelegramObject):
-    """This object represents a parameter of the inline keyboard button used to automatically
-    authorize a user. Serves as a great replacement for the Telegram Login Widget when the user is
-    coming from Telegram. All the user needs to do is tap/click a button and confirm that they want
-    to log in. Telegram apps support these buttons as of version 5.7.
-
-    Sample bot: `@discussbot `_
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`url` is equal.
-
-    Note:
-        You must always check the hash of the received data to verify the authentication
-        and the integrity of the data as described in
-        `Checking authorization `_
-
-    Args:
-        url (:obj:`str`): An HTTPS URL to be opened with user authorization data added to the query
-            string when the button is pressed. If the user refuses to provide authorization data,
-            the original URL without information about the user will be opened. The data added is
-            the same as described in
-            `Receiving authorization data
-            `_.
-        forward_text (:obj:`str`, optional): New text of the button in forwarded messages.
-        bot_username (:obj:`str`, optional): Username of a bot, which will be used for user
-            authorization. See
-            `Setting up a bot `_
-            for more details. If not specified, the current
-            bot's username will be assumed. The url's domain must be the same as the domain linked
-            with the bot. See
-            `Linking your domain to the bot
-            `_
-            for more details.
-        request_write_access (:obj:`bool`, optional): Pass :obj:`True` to request the permission
-            for your bot to send messages to the user.
-
-    Attributes:
-        url (:obj:`str`): An HTTPS URL to be opened with user authorization data added to the query
-            string when the button is pressed. If the user refuses to provide authorization data,
-            the original URL without information about the user will be opened. The data added is
-            the same as described in
-            `Receiving authorization data
-            `_.
-        forward_text (:obj:`str`): Optional. New text of the button in forwarded messages.
-        bot_username (:obj:`str`): Optional. Username of a bot, which will be used for user
-            authorization. See
-            `Setting up a bot `_
-            for more details. If not specified, the current
-            bot's username will be assumed. The url's domain must be the same as the domain linked
-            with the bot. See
-            `Linking your domain to the bot
-            `_
-            for more details.
-        request_write_access (:obj:`bool`): Optional. Pass :obj:`True` to request the permission
-            for your bot to send messages to the user.
-
-    """
-
-    __slots__ = ("bot_username", "forward_text", "request_write_access", "url")
-
-    def __init__(
-        self,
-        url: str,
-        forward_text: Optional[str] = None,
-        bot_username: Optional[str] = None,
-        request_write_access: Optional[bool] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        # Required
-        self.url: str = url
-        # Optional
-        self.forward_text: Optional[str] = forward_text
-        self.bot_username: Optional[str] = bot_username
-        self.request_write_access: Optional[bool] = request_write_access
-
-        self._id_attrs = (self.url,)
-
-        self._freeze()
diff --git a/venv/lib/python3.11/site-packages/telegram/_menubutton.py b/venv/lib/python3.11/site-packages/telegram/_menubutton.py
deleted file mode 100755
index 76c0ee4..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_menubutton.py
+++ /dev/null
@@ -1,201 +0,0 @@
-#!/usr/bin/env python
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains objects related to Telegram menu buttons."""
-from typing import TYPE_CHECKING, Final, Optional
-
-from telegram import constants
-from telegram._telegramobject import TelegramObject
-from telegram._utils import enum
-from telegram._utils.types import JSONDict
-from telegram._webappinfo import WebAppInfo
-
-if TYPE_CHECKING:
-    from telegram import Bot
-
-
-class MenuButton(TelegramObject):
-    """This object describes the bot's menu button in a private chat. It should be one of
-
-    * :class:`telegram.MenuButtonCommands`
-    * :class:`telegram.MenuButtonWebApp`
-    * :class:`telegram.MenuButtonDefault`
-
-    If a menu button other than :class:`telegram.MenuButtonDefault` is set for a private chat,
-    then it is applied in the chat. Otherwise the default menu button is applied. By default, the
-    menu button opens the list of bot commands.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`type` is equal. For subclasses with additional attributes,
-    the notion of equality is overridden.
-
-    .. versionadded:: 20.0
-
-    Args:
-        type (:obj:`str`): Type of menu button that the instance represents.
-
-    Attributes:
-        type (:obj:`str`): Type of menu button that the instance represents.
-    """
-
-    __slots__ = ("type",)
-
-    def __init__(
-        self,
-        type: str,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):  # pylint: disable=redefined-builtin
-        super().__init__(api_kwargs=api_kwargs)
-        self.type: str = enum.get_member(constants.MenuButtonType, type, type)
-
-        self._id_attrs = (self.type,)
-
-        self._freeze()
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["MenuButton"]:
-        """Converts JSON data to the appropriate :class:`MenuButton` object, i.e. takes
-        care of selecting the correct subclass.
-
-        Args:
-            data (dict[:obj:`str`, ...]): The JSON data.
-            bot (:class:`telegram.Bot`, optional): The bot associated with this object. Defaults to
-                :obj:`None`, in which case shortcut methods will not be available.
-
-                .. versionchanged:: 21.4
-                   :paramref:`bot` is now optional and defaults to :obj:`None`
-
-        Returns:
-            The Telegram object.
-
-        """
-        data = cls._parse_data(data)
-
-        if data is None:
-            return None
-
-        if not data and cls is MenuButton:
-            return None
-
-        _class_mapping: dict[str, type[MenuButton]] = {
-            cls.COMMANDS: MenuButtonCommands,
-            cls.WEB_APP: MenuButtonWebApp,
-            cls.DEFAULT: MenuButtonDefault,
-        }
-
-        if cls is MenuButton and data.get("type") in _class_mapping:
-            return _class_mapping[data.pop("type")].de_json(data, bot=bot)
-        return super().de_json(data=data, bot=bot)
-
-    COMMANDS: Final[str] = constants.MenuButtonType.COMMANDS
-    """:const:`telegram.constants.MenuButtonType.COMMANDS`"""
-    WEB_APP: Final[str] = constants.MenuButtonType.WEB_APP
-    """:const:`telegram.constants.MenuButtonType.WEB_APP`"""
-    DEFAULT: Final[str] = constants.MenuButtonType.DEFAULT
-    """:const:`telegram.constants.MenuButtonType.DEFAULT`"""
-
-
-class MenuButtonCommands(MenuButton):
-    """Represents a menu button, which opens the bot's list of commands.
-
-    .. include:: inclusions/menu_button_command_video.rst
-
-    .. versionadded:: 20.0
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.MenuButtonType.COMMANDS`.
-    """
-
-    __slots__ = ()
-
-    def __init__(self, *, api_kwargs: Optional[JSONDict] = None):
-        super().__init__(type=constants.MenuButtonType.COMMANDS, api_kwargs=api_kwargs)
-        self._freeze()
-
-
-class MenuButtonWebApp(MenuButton):
-    """Represents a menu button, which launches a
-    `Web App `_.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`type`, :attr:`text` and :attr:`web_app`
-    are equal.
-
-    .. versionadded:: 20.0
-
-    Args:
-        text (:obj:`str`): Text of the button.
-        web_app (:class:`telegram.WebAppInfo`): Description of the Web App that will be launched
-            when the user presses the button. The Web App will be able to send an arbitrary
-            message on behalf of the user using the method :meth:`~telegram.Bot.answerWebAppQuery`
-            of :class:`~telegram.Bot`. Alternatively, a ``t.me`` link to a Web App of the bot can
-            be specified in the object instead of the Web App's URL, in which case the Web App
-            will be opened as if the user pressed the link.
-
-
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.MenuButtonType.WEB_APP`.
-        text (:obj:`str`): Text of the button.
-        web_app (:class:`telegram.WebAppInfo`): Description of the Web App that will be launched
-            when the user presses the button. The Web App will be able to send an arbitrary
-            message on behalf of the user using the method :meth:`~telegram.Bot.answerWebAppQuery`
-            of :class:`~telegram.Bot`. Alternatively, a ``t.me`` link to a Web App of the bot can
-            be specified in the object instead of the Web App's URL, in which case the Web App
-            will be opened as if the user pressed the link.
-    """
-
-    __slots__ = ("text", "web_app")
-
-    def __init__(self, text: str, web_app: WebAppInfo, *, api_kwargs: Optional[JSONDict] = None):
-        super().__init__(type=constants.MenuButtonType.WEB_APP, api_kwargs=api_kwargs)
-        with self._unfrozen():
-            self.text: str = text
-            self.web_app: WebAppInfo = web_app
-
-            self._id_attrs = (self.type, self.text, self.web_app)
-
-    @classmethod
-    def de_json(
-        cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
-    ) -> Optional["MenuButtonWebApp"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        data["web_app"] = WebAppInfo.de_json(data.get("web_app"), bot)
-
-        return super().de_json(data=data, bot=bot)  # type: ignore[return-value]
-
-
-class MenuButtonDefault(MenuButton):
-    """Describes that no specific value for the menu button was set.
-
-    .. versionadded:: 20.0
-    Attributes:
-        type (:obj:`str`): :tg-const:`telegram.constants.MenuButtonType.DEFAULT`.
-    """
-
-    __slots__ = ()
-
-    def __init__(self, *, api_kwargs: Optional[JSONDict] = None):
-        super().__init__(type=constants.MenuButtonType.DEFAULT, api_kwargs=api_kwargs)
-        self._freeze()
diff --git a/venv/lib/python3.11/site-packages/telegram/_message.py b/venv/lib/python3.11/site-packages/telegram/_message.py
deleted file mode 100755
index df8ea36..0000000
--- a/venv/lib/python3.11/site-packages/telegram/_message.py
+++ /dev/null
@@ -1,5160 +0,0 @@
-#!/usr/bin/env python
-# pylint: disable=too-many-instance-attributes, too-many-arguments
-#
-# A library that provides a Python interface to the Telegram Bot API
-# Copyright (C) 2015-2025
-# Leandro Toledo de Souza 
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser Public License for more details.
-#
-# You should have received a copy of the GNU Lesser Public License
-# along with this program.  If not, see [http://www.gnu.org/licenses/].
-"""This module contains an object that represents a Telegram Message."""
-
-import datetime as dtm
-import re
-from collections.abc import Sequence
-from html import escape
-from typing import TYPE_CHECKING, Optional, TypedDict, Union
-
-from telegram._chat import Chat
-from telegram._chatbackground import ChatBackground
-from telegram._chatboost import ChatBoostAdded
-from telegram._dice import Dice
-from telegram._files.animation import Animation
-from telegram._files.audio import Audio
-from telegram._files.contact import Contact
-from telegram._files.document import Document
-from telegram._files.location import Location
-from telegram._files.photosize import PhotoSize
-from telegram._files.sticker import Sticker
-from telegram._files.venue import Venue
-from telegram._files.video import Video
-from telegram._files.videonote import VideoNote
-from telegram._files.voice import Voice
-from telegram._forumtopic import (
-    ForumTopicClosed,
-    ForumTopicCreated,
-    ForumTopicEdited,
-    ForumTopicReopened,
-    GeneralForumTopicHidden,
-    GeneralForumTopicUnhidden,
-)
-from telegram._games.game import Game
-from telegram._inline.inlinekeyboardmarkup import InlineKeyboardMarkup
-from telegram._linkpreviewoptions import LinkPreviewOptions
-from telegram._messageautodeletetimerchanged import MessageAutoDeleteTimerChanged
-from telegram._messageentity import MessageEntity
-from telegram._paidmedia import PaidMediaInfo
-from telegram._passport.passportdata import PassportData
-from telegram._payment.invoice import Invoice
-from telegram._payment.refundedpayment import RefundedPayment
-from telegram._payment.successfulpayment import SuccessfulPayment
-from telegram._poll import Poll
-from telegram._proximityalerttriggered import ProximityAlertTriggered
-from telegram._reply import ReplyParameters
-from telegram._shared import ChatShared, UsersShared
-from telegram._story import Story
-from telegram._telegramobject import TelegramObject
-from telegram._user import User
-from telegram._utils.argumentparsing import parse_sequence_arg
-from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp
-from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue
-from telegram._utils.entities import parse_message_entities, parse_message_entity
-from telegram._utils.strings import TextEncoding
-from telegram._utils.types import (
-    CorrectOptionID,
-    FileInput,
-    JSONDict,
-    MarkdownVersion,
-    ODVInput,
-    ReplyMarkup,
-)
-from telegram._utils.warnings import warn
-from telegram._videochat import (
-    VideoChatEnded,
-    VideoChatParticipantsInvited,
-    VideoChatScheduled,
-    VideoChatStarted,
-)
-from telegram._webappdata import WebAppData
-from telegram._writeaccessallowed import WriteAccessAllowed
-from telegram.constants import ZERO_DATE, MessageAttachmentType, ParseMode
-from telegram.helpers import escape_markdown
-from telegram.warnings import PTBDeprecationWarning
-
-if TYPE_CHECKING:
-    from telegram import (
-        Bot,
-        ExternalReplyInfo,
-        GameHighScore,
-        Giveaway,
-        GiveawayCompleted,
-        GiveawayCreated,
-        GiveawayWinners,
-        InputMedia,
-        InputMediaAudio,
-        InputMediaDocument,
-        InputMediaPhoto,
-        InputMediaVideo,
-        InputPaidMedia,
-        InputPollOption,
-        LabeledPrice,
-        MessageId,
-        MessageOrigin,
-        ReactionType,
-        TextQuote,
-    )
-
-
-class _ReplyKwargs(TypedDict):
-    __slots__ = ("chat_id", "reply_parameters")  # type: ignore[misc]
-
-    chat_id: Union[str, int]
-    reply_parameters: ReplyParameters
-
-
-class MaybeInaccessibleMessage(TelegramObject):
-    """Base class for Telegram Message Objects.
-
-    Currently, that includes :class:`telegram.Message` and :class:`telegram.InaccessibleMessage`.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`message_id` and :attr:`chat` are equal
-
-    .. versionchanged:: 21.0
-       ``__bool__`` is no longer overriden and defaults to Pythons standard implementation.
-
-    .. versionadded:: 20.8
-
-    Args:
-        message_id (:obj:`int`): Unique message identifier.
-        date (:class:`datetime.datetime`): Date the message was sent in Unix time or 0 in Unix
-            time. Converted to :class:`datetime.datetime`
-
-            |datetime_localization|
-        chat (:class:`telegram.Chat`): Conversation the message belongs to.
-
-    Attributes:
-        message_id (:obj:`int`): Unique message identifier.
-        date (:class:`datetime.datetime`): Date the message was sent in Unix time or 0 in Unix
-            time. Converted to :class:`datetime.datetime`
-
-            |datetime_localization|
-        chat (:class:`telegram.Chat`): Conversation the message belongs to.
-    """
-
-    __slots__ = ("chat", "date", "message_id")
-
-    def __init__(
-        self,
-        chat: Chat,
-        message_id: int,
-        date: dtm.datetime,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(api_kwargs=api_kwargs)
-        self.chat: Chat = chat
-        self.message_id: int = message_id
-        self.date: dtm.datetime = date
-
-        self._id_attrs = (self.message_id, self.chat)
-
-        self._freeze()
-
-    @property
-    def is_accessible(self) -> bool:
-        """Convenience attribute. :obj:`True`, if the date is not 0 in Unix time.
-
-        .. versionadded:: 20.8
-        """
-        # Once we drop support for python 3.9, this can be made a TypeGuard function:
-        # def is_accessible(self) -> TypeGuard[Message]:
-        return self.date != ZERO_DATE
-
-    @classmethod
-    def _de_json(
-        cls,
-        data: Optional[JSONDict],
-        bot: Optional["Bot"] = None,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Optional["MaybeInaccessibleMessage"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        if cls is MaybeInaccessibleMessage:
-            if data["date"] == 0:
-                return InaccessibleMessage.de_json(data=data, bot=bot)
-            return Message.de_json(data=data, bot=bot)
-
-        # Get the local timezone from the bot if it has defaults
-        loc_tzinfo = extract_tzinfo_from_defaults(bot)
-
-        # this is to include the Literal from InaccessibleMessage
-        if data["date"] == 0:
-            data["date"] = ZERO_DATE
-        else:
-            data["date"] = from_timestamp(data["date"], tzinfo=loc_tzinfo)
-
-        data["chat"] = Chat.de_json(data.get("chat"), bot)
-        return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs)
-
-
-class InaccessibleMessage(MaybeInaccessibleMessage):
-    """This object represents an inaccessible message.
-
-    These are messages that are e.g. deleted.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`message_id` and :attr:`chat` are equal
-
-    .. versionadded:: 20.8
-
-    Args:
-        message_id (:obj:`int`): Unique message identifier.
-        chat (:class:`telegram.Chat`): Chat the message belongs to.
-
-    Attributes:
-        message_id (:obj:`int`): Unique message identifier.
-        date (:class:`constants.ZERO_DATE`): Always :tg-const:`telegram.constants.ZERO_DATE`.
-            The field can be used to differentiate regular and inaccessible messages.
-        chat (:class:`telegram.Chat`): Chat the message belongs to.
-    """
-
-    __slots__ = ()
-
-    def __init__(
-        self,
-        chat: Chat,
-        message_id: int,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(chat=chat, message_id=message_id, date=ZERO_DATE, api_kwargs=api_kwargs)
-        self._freeze()
-
-
-class Message(MaybeInaccessibleMessage):
-    # fmt: off
-    """This object represents a message.
-
-    Objects of this class are comparable in terms of equality. Two objects of this class are
-    considered equal, if their :attr:`message_id` and :attr:`chat` are equal.
-
-    Note:
-        In Python :keyword:`from` is a reserved word. Use :paramref:`from_user` instead.
-
-    .. versionchanged:: 21.0
-       Removed deprecated arguments and attributes ``user_shared``, ``forward_from``,
-       ``forward_from_chat``, ``forward_from_message_id``, ``forward_signature``,
-       ``forward_sender_name`` and ``forward_date``.
-
-    .. versionchanged:: 20.8
-        * This class is now a subclass of :class:`telegram.MaybeInaccessibleMessage`.
-        * The :paramref:`pinned_message` now can be either :class:`telegram.Message` or
-          :class:`telegram.InaccessibleMessage`.
-
-    .. versionchanged:: 20.0
-
-        * The arguments and attributes ``voice_chat_scheduled``, ``voice_chat_started`` and
-          ``voice_chat_ended``, ``voice_chat_participants_invited`` were renamed to
-          :paramref:`video_chat_scheduled`/:attr:`video_chat_scheduled`,
-          :paramref:`video_chat_started`/:attr:`video_chat_started`,
-          :paramref:`video_chat_ended`/:attr:`video_chat_ended` and
-          :paramref:`video_chat_participants_invited`/:attr:`video_chat_participants_invited`,
-          respectively, in accordance to Bot API 6.0.
-        * The following are now keyword-only arguments in Bot methods:
-          ``{read, write, connect, pool}_timeout``, ``api_kwargs``, ``contact``, ``quote``,
-          ``filename``, ``loaction``, ``venue``. Use a named argument for those,
-          and notice that some positional arguments changed position as a result.
-
-    Args:
-        message_id (:obj:`int`): Unique message identifier inside this chat. In specific instances
-            (e.g., message containing a video sent to a big chat), the server might automatically
-            schedule a message instead of sending it immediately. In such cases, this field will be
-            ``0`` and the relevant message will be unusable until it is actually sent.
-        from_user (:class:`telegram.User`, optional): Sender of the message; may be empty for
-            messages sent to channels. For backward compatibility, if the message was sent on
-            behalf of a chat, the field contains a fake sender user in non-channel chats.
-        sender_chat (:class:`telegram.Chat`, optional): Sender of the message when sent on behalf
-            of a chat. For example, the supergroup itself for messages sent by its anonymous
-            administrators or a linked channel for messages automatically forwarded to the
-            channel's discussion group. For backward compatibility, if the message was sent on
-            behalf of a chat, the field from contains a fake sender user in non-channel chats.
-        date (:class:`datetime.datetime`): Date the message was sent in Unix time. Converted to
-            :class:`datetime.datetime`.
-
-            .. versionchanged:: 20.3
-                |datetime_localization|
-        chat (:class:`telegram.Chat`): Conversation the message belongs to.
-        is_automatic_forward (:obj:`bool`, optional): :obj:`True`, if the message is a channel
-            post that was automatically forwarded to the connected discussion group.
-
-            .. versionadded:: 13.9
-        reply_to_message (:class:`telegram.Message`, optional): For replies, the original message.
-            Note that the Message object in this field will not contain further
-            ``reply_to_message`` fields even if it itself is a reply.
-        edit_date (:class:`datetime.datetime`, optional): Date the message was last edited in Unix
-            time. Converted to :class:`datetime.datetime`.
-
-            .. versionchanged:: 20.3
-                |datetime_localization|
-        has_protected_content (:obj:`bool`, optional): :obj:`True`, if the message can't be
-            forwarded.
-
-            .. versionadded:: 13.9
-        is_from_offline (:obj:`bool`, optional): :obj:`True`, if the message was sent
-            by an implicit action, for example, as an away or a greeting business message,
-            or as a scheduled message.
-
-            .. versionadded:: 21.1
-        media_group_id (:obj:`str`, optional): The unique identifier of a media message group this
-            message belongs to.
-        text (:obj:`str`, optional): For text messages, the actual UTF-8 text of the message,
-            0-:tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters.
-        entities (Sequence[:class:`telegram.MessageEntity`], optional): For text messages, special
-            entities like usernames, URLs, bot commands, etc. that appear in the text. See
-            :attr:`parse_entity` and :attr:`parse_entities` methods for how to use properly.
-            This list is empty if the message does not contain entities.
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        link_preview_options (:class:`telegram.LinkPreviewOptions`, optional): Options used for
-            link preview generation for the message, if it is a text message and link preview
-            options were changed.
-
-            .. versionadded:: 20.8
-
-        effect_id (:obj:`str`, optional): Unique identifier of the message effect added to the
-            message.
-
-            .. versionadded:: 21.3
-
-        caption_entities (Sequence[:class:`telegram.MessageEntity`], optional): For messages with a
-            Caption. Special entities like usernames, URLs, bot commands, etc. that appear in the
-            caption. See :attr:`Message.parse_caption_entity` and :attr:`parse_caption_entities`
-            methods for how to use properly. This list is empty if the message does not contain
-            caption entities.
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        show_caption_above_media (:obj:`bool`, optional): |show_cap_above_med|
-
-            .. versionadded:: 21.3
-        audio (:class:`telegram.Audio`, optional): Message is an audio file, information
-            about the file.
-        document (:class:`telegram.Document`, optional): Message is a general file, information
-            about the file.
-        animation (:class:`telegram.Animation`, optional): Message is an animation, information
-            about the animation. For backward compatibility, when this field is set, the document
-            field will also be set.
-        game (:class:`telegram.Game`, optional): Message is a game, information about the game.
-            :ref:`More about games >> `.
-        photo (Sequence[:class:`telegram.PhotoSize`], optional): Message is a photo, available
-            sizes of the photo. This list is empty if the message does not contain a photo.
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        sticker (:class:`telegram.Sticker`, optional): Message is a sticker, information
-            about the sticker.
-        story (:class:`telegram.Story`, optional): Message is a forwarded story.
-
-            .. versionadded:: 20.5
-        video (:class:`telegram.Video`, optional): Message is a video, information about the
-            video.
-        voice (:class:`telegram.Voice`, optional): Message is a voice message, information about
-            the file.
-        video_note (:class:`telegram.VideoNote`, optional): Message is a
-            `video note `_, information
-            about the video message.
-        new_chat_members (Sequence[:class:`telegram.User`], optional): New members that were added
-            to the group or supergroup and information about them (the bot itself may be one of
-            these members). This list is empty if the message does not contain new chat members.
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        caption (:obj:`str`, optional): Caption for the animation, audio, document, paid media,
-            photo, video
-            or voice, 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters.
-        contact (:class:`telegram.Contact`, optional): Message is a shared contact, information
-            about the contact.
-        location (:class:`telegram.Location`, optional): Message is a shared location, information
-            about the location.
-        venue (:class:`telegram.Venue`, optional): Message is a venue, information about the
-            venue. For backward compatibility, when this field is set, the location field will
-            also be set.
-        left_chat_member (:class:`telegram.User`, optional): A member was removed from the group,
-            information about them (this member may be the bot itself).
-        new_chat_title (:obj:`str`, optional): A chat title was changed to this value.
-        new_chat_photo (Sequence[:class:`telegram.PhotoSize`], optional): A chat photo was changed
-            to this value. This list is empty if the message does not contain a new chat photo.
-
-            .. versionchanged:: 20.0
-                |sequenceclassargs|
-
-        delete_chat_photo (:obj:`bool`, optional): Service message: The chat photo was deleted.
-        group_chat_created (:obj:`bool`, optional): Service message: The group has been created.
-        supergroup_chat_created (:obj:`bool`, optional): Service message: The supergroup has been
-            created. This field can't be received in a message coming through updates, because bot
-            can't be a member of a supergroup when it is created. It can only be found in
-            :attr:`reply_to_message` if someone replies to a very first message in a directly
-            created supergroup.
-        channel_chat_created (:obj:`bool`, optional): Service message: The channel has been
-            created. This field can't be received in a message coming through updates, because bot
-            can't be a member of a channel when it is created. It can only be found in
-            :attr:`reply_to_message` if someone replies to a very first message in a channel.
-        message_auto_delete_timer_changed (:class:`telegram.MessageAutoDeleteTimerChanged`, \
-            optional): Service message: auto-delete timer settings changed in the chat.
-
-            .. versionadded:: 13.4
-        migrate_to_chat_id (:obj:`int`, optional): The group has been migrated to a supergroup
-            with the specified identifier.
-        migrate_from_chat_id (:obj:`int`, optional): The supergroup has been migrated from a group
-            with the specified identifier.
-        pinned_message (:class:`telegram.MaybeInaccessibleMessage`, optional): Specified message
-            was pinned. Note that the Message object in this field will not contain further
-            :attr:`reply_to_message` fields even if it is itself a reply.
-
-            .. versionchanged:: 20.8
-                This attribute now is either :class:`telegram.Message` or
-                :class:`telegram.InaccessibleMessage`.
-        invoice (:class:`telegram.Invoice`, optional): Message is an invoice for a payment,
-            information about the invoice.
-            :ref:`More about payments >> `.
-        successful_payment (:class:`telegram.SuccessfulPayment`, optional): Message is a service
-            message about a successful payment, information about the payment.
-            :ref:`More about payments >> `.
-        connected_website (:obj:`str`, optional): The domain name of the website on which the user
-            has logged in.
-            `More about Telegram Login >> `_.
-        author_signature (:obj:`str`, optional): Signature of the post author for messages in
-            channels, or the custom title of an anonymous group administrator.
-        passport_data (:class:`telegram.PassportData`, optional): Telegram Passport data.
-        poll (:class:`telegram.Poll`, optional): Message is a native poll,
-            information about the poll.
-        dice (:class:`telegram.Dice`, optional): Message is a dice with random value.
-        via_bot (:class:`telegram.User`, optional): Bot through which message was sent.
-        proximity_alert_triggered (:class:`telegram.ProximityAlertTriggered`, optional): Service
-            message. A user in the chat triggered another user's proximity alert while sharing
-            Live Location.
-        video_chat_scheduled (:class:`telegram.VideoChatScheduled`, optional): Service message:
-            video chat scheduled.
-
-            .. versionadded:: 20.0
-        video_chat_started (:class:`telegram.VideoChatStarted`, optional): Service message: video
-            chat started.
-
-            .. versionadded:: 20.0
-        video_chat_ended (:class:`telegram.VideoChatEnded`, optional): Service message: video chat
-            ended.
-
-            .. versionadded:: 20.0
-        video_chat_participants_invited (:class:`telegram.VideoChatParticipantsInvited` optional):
-            Service message: new participants invited to a video chat.
-
-            .. versionadded:: 20.0
-        web_app_data (:class:`telegram.WebAppData`, optional): Service message: data sent by a Web
-            App.
-
-            .. versionadded:: 20.0
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
-            to the message. :paramref:`~telegram.InlineKeyboardButton.login_url` buttons are
-            represented as ordinary url buttons.
-        is_topic_message (:obj:`bool`, optional): :obj:`True`, if the message is sent to a forum
-            topic.
-
-            .. versionadded:: 20.0
-        message_thread_id (:obj:`int`, optional): Unique identifier of a message thread to which
-            the message belongs; for supergroups only.
-
-            .. versionadded:: 20.0
-        forum_topic_created (:class:`telegram.ForumTopicCreated`, optional): Service message:
-            forum topic created.
-
-            .. versionadded:: 20.0
-        forum_topic_closed (:class:`telegram.ForumTopicClosed`, optional): Service message:
-            forum topic closed.
-
-            .. versionadded:: 20.0
-        forum_topic_reopened (:class:`telegram.ForumTopicReopened`, optional): Service message:
-            forum topic reopened.
-
-            .. versionadded:: 20.0
-        forum_topic_edited (:class:`telegram.ForumTopicEdited`, optional): Service message:
-            forum topic edited.
-
-            .. versionadded:: 20.0
-        general_forum_topic_hidden (:class:`telegram.GeneralForumTopicHidden`, optional):
-            Service message: General forum topic hidden.
-
-            .. versionadded:: 20.0
-        general_forum_topic_unhidden (:class:`telegram.GeneralForumTopicUnhidden`, optional):
-            Service message: General forum topic unhidden.
-
-            .. versionadded:: 20.0
-        write_access_allowed (:class:`telegram.WriteAccessAllowed`, optional): Service message:
-            the user allowed the bot to write messages after adding it to the attachment or side
-            menu, launching a Web App from a link, or accepting an explicit request from a Web App
-            sent by the method
-            `requestWriteAccess `_.
-
-            .. versionadded:: 20.0
-        has_media_spoiler (:obj:`bool`, optional): :obj:`True`, if the message media is covered
-            by a spoiler animation.
-
-            .. versionadded:: 20.0
-        users_shared (:class:`telegram.UsersShared`, optional): Service message: users were shared
-            with the bot
-
-            .. versionadded:: 20.8
-        chat_shared (:class:`telegram.ChatShared`, optional):Service message: a chat was shared
-            with the bot.
-
-            .. versionadded:: 20.1
-        giveaway_created (:class:`telegram.GiveawayCreated`, optional): Service message: a
-            scheduled giveaway was created
-
-            .. versionadded:: 20.8
-        giveaway (:class:`telegram.Giveaway`, optional): The message is a scheduled giveaway
-            message
-
-            .. versionadded:: 20.8
-        giveaway_winners (:class:`telegram.GiveawayWinners`, optional): A giveaway with public
-            winners was completed
-
-            .. versionadded:: 20.8
-        giveaway_completed (:class:`telegram.GiveawayCompleted`, optional): Service message: a
-            giveaway without public winners was completed
-
-            .. versionadded:: 20.8
-        external_reply (:class:`telegram.ExternalReplyInfo`, optional): Information about the
-            message that is being replied to, which may come from another chat or forum topic.
-
-            .. versionadded:: 20.8
-        quote (:class:`telegram.TextQuote`, optional): For replies that quote part of the original
-            message, the quoted part of the message.
-
-            .. versionadded:: 20.8
-        forward_origin (:class:`telegram.MessageOrigin`, optional): Information about the original
-            message for forwarded messages
-
-            .. versionadded:: 20.8
-        reply_to_story (:class:`telegram.Story`, optional): For replies to a story, the original
-            story.
-
-            .. versionadded:: 21.0
-        boost_added (:class:`telegram.ChatBoostAdded`, optional): Service message: user boosted
-            the chat.
-
-            .. versionadded:: 21.0
-        sender_boost_count (:obj:`int`, optional): If the sender of the
-            message boosted the chat, the number of boosts added by the user.
-
-            .. versionadded:: 21.0
-        business_connection_id (:obj:`str`, optional): Unique identifier of the business connection
-            from which the message was received. If non-empty, the message belongs to a chat of the
-            corresponding business account that is independent from any potential bot chat which
-            might share the same identifier.
-
-            .. versionadded:: 21.1
-
-        sender_business_bot (:class:`telegram.User`, optional): The bot that actually sent the
-            message on behalf of the business account. Available only for outgoing messages sent
-            on behalf of the connected business account.
-
-            .. versionadded:: 21.1
-
-        chat_background_set  (:class:`telegram.ChatBackground`, optional): Service message: chat
-            background set.
-
-            .. versionadded:: 21.2
-        paid_media (:class:`telegram.PaidMediaInfo`, optional): Message contains paid media;
-            information about the paid media.
-
-            .. versionadded:: 21.4
-        refunded_payment (:class:`telegram.RefundedPayment`, optional): Message is a service
-            message about a refunded payment, information about the payment.
-
-            .. versionadded:: 21.4
-
-    Attributes:
-        message_id (:obj:`int`): Unique message identifier inside this chat. In specific instances
-            (e.g., message containing a video sent to a big chat), the server might automatically
-            schedule a message instead of sending it immediately. In such cases, this field will be
-            ``0`` and the relevant message will be unusable until it is actually sent.
-        from_user (:class:`telegram.User`): Optional. Sender of the message; may be empty for
-            messages sent to channels. For backward compatibility, if the message was sent on
-            behalf of a chat, the field contains a fake sender user in non-channel chats.
-        sender_chat (:class:`telegram.Chat`): Optional. Sender of the message when sent on behalf
-            of a chat. For example, the supergroup itself for messages sent by its anonymous
-            administrators or a linked channel for messages automatically forwarded to the
-            channel's discussion group. For backward compatibility, if the message was sent on
-            behalf of a chat, the field from contains a fake sender user in non-channel chats.
-        date (:class:`datetime.datetime`): Date the message was sent in Unix time. Converted to
-            :class:`datetime.datetime`.
-
-            .. versionchanged:: 20.3
-                |datetime_localization|
-        chat (:class:`telegram.Chat`): Conversation the message belongs to.
-        is_automatic_forward (:obj:`bool`): Optional. :obj:`True`, if the message is a channel
-            post that was automatically forwarded to the connected discussion group.
-
-            .. versionadded:: 13.9
-        reply_to_message (:class:`telegram.Message`): Optional. For replies, the original message.
-            Note that the Message object in this field will not contain further
-            ``reply_to_message`` fields even if it itself is a reply.
-        edit_date (:class:`datetime.datetime`): Optional. Date the message was last edited in Unix
-            time. Converted to :class:`datetime.datetime`.
-
-            .. versionchanged:: 20.3
-                |datetime_localization|
-        has_protected_content (:obj:`bool`): Optional. :obj:`True`, if the message can't be
-            forwarded.
-
-            .. versionadded:: 13.9
-        is_from_offline (:obj:`bool`): Optional. :obj:`True`, if the message was sent
-            by an implicit action, for example, as an away or a greeting business message,
-            or as a scheduled message.
-
-            .. versionadded:: 21.1
-        media_group_id (:obj:`str`): Optional. The unique identifier of a media message group this
-            message belongs to.
-        text (:obj:`str`): Optional. For text messages, the actual UTF-8 text of the message,
-            0-:tg-const:`telegram.constants.MessageLimit.MAX_TEXT_LENGTH` characters.
-        entities (tuple[:class:`telegram.MessageEntity`]): Optional. For text messages, special
-            entities like usernames, URLs, bot commands, etc. that appear in the text. See
-            :attr:`parse_entity` and :attr:`parse_entities` methods for how to use properly.
-            This list is empty if the message does not contain entities.
-
-            .. versionchanged:: 20.0
-                |tupleclassattrs|
-
-        link_preview_options (:class:`telegram.LinkPreviewOptions`): Optional. Options used for
-            link preview generation for the message, if it is a text message and link preview
-            options were changed.
-
-            .. versionadded:: 20.8
-
-        effect_id (:obj:`str`): Optional. Unique identifier of the message effect added to the
-            message.
-
-            ..versionadded:: 21.3
-
-        caption_entities (tuple[:class:`telegram.MessageEntity`]): Optional. For messages with a
-            Caption. Special entities like usernames, URLs, bot commands, etc. that appear in the
-            caption. See :attr:`Message.parse_caption_entity` and :attr:`parse_caption_entities`
-            methods for how to use properly. This list is empty if the message does not contain
-            caption entities.
-
-            .. versionchanged:: 20.0
-                |tupleclassattrs|
-
-        show_caption_above_media (:obj:`bool`): Optional. |show_cap_above_med|
-
-            .. versionadded:: 21.3
-        audio (:class:`telegram.Audio`): Optional. Message is an audio file, information
-            about the file.
-
-            .. seealso:: :wiki:`Working with Files and Media `
-        document (:class:`telegram.Document`): Optional. Message is a general file, information
-            about the file.
-
-            .. seealso:: :wiki:`Working with Files and Media `
-        animation (:class:`telegram.Animation`): Optional. Message is an animation, information
-            about the animation. For backward compatibility, when this field is set, the document
-            field will also be set.
-
-            .. seealso:: :wiki:`Working with Files and Media `
-        game (:class:`telegram.Game`): Optional. Message is a game, information about the game.
-            :ref:`More about games >> `.
-        photo (tuple[:class:`telegram.PhotoSize`]): Optional. Message is a photo, available
-            sizes of the photo. This list is empty if the message does not contain a photo.
-
-            .. seealso:: :wiki:`Working with Files and Media `
-
-            .. versionchanged:: 20.0
-                |tupleclassattrs|
-
-        sticker (:class:`telegram.Sticker`): Optional. Message is a sticker, information
-            about the sticker.
-
-            .. seealso:: :wiki:`Working with Files and Media `
-        story (:class:`telegram.Story`): Optional. Message is a forwarded story.
-
-            .. versionadded:: 20.5
-        video (:class:`telegram.Video`): Optional. Message is a video, information about the
-            video.
-
-            .. seealso:: :wiki:`Working with Files and Media `
-        voice (:class:`telegram.Voice`): Optional. Message is a voice message, information about
-            the file.
-
-            .. seealso:: :wiki:`Working with Files and Media `
-        video_note (:class:`telegram.VideoNote`): Optional. Message is a
-            `video note `_, information
-            about the video message.
-
-            .. seealso:: :wiki:`Working with Files and Media `
-        new_chat_members (tuple[:class:`telegram.User`]): Optional. New members that were added
-            to the group or supergroup and information about them (the bot itself may be one of
-            these members). This list is empty if the message does not contain new chat members.
-
-            .. versionchanged:: 20.0
-                |tupleclassattrs|
-        caption (:obj:`str`): Optional. Caption for the animation, audio, document, paid media,
-            photo, video
-            or voice, 0-:tg-const:`telegram.constants.MessageLimit.CAPTION_LENGTH` characters.
-        contact (:class:`telegram.Contact`): Optional. Message is a shared contact, information
-            about the contact.
-        location (:class:`telegram.Location`): Optional. Message is a shared location, information
-            about the location.
-        venue (:class:`telegram.Venue`): Optional. Message is a venue, information about the
-            venue. For backward compatibility, when this field is set, the location field will
-            also be set.
-        left_chat_member (:class:`telegram.User`): Optional. A member was removed from the group,
-            information about them (this member may be the bot itself).
-        new_chat_title (:obj:`str`): Optional. A chat title was changed to this value.
-        new_chat_photo (tuple[:class:`telegram.PhotoSize`]): A chat photo was changed to
-            this value. This list is empty if the message does not contain a new chat photo.
-
-            .. versionchanged:: 20.0
-                |tupleclassattrs|
-
-        delete_chat_photo (:obj:`bool`): Optional. Service message: The chat photo was deleted.
-        group_chat_created (:obj:`bool`): Optional. Service message: The group has been created.
-        supergroup_chat_created (:obj:`bool`): Optional. Service message: The supergroup has been
-            created. This field can't be received in a message coming through updates, because bot
-            can't be a member of a supergroup when it is created. It can only be found in
-            :attr:`reply_to_message` if someone replies to a very first message in a directly
-            created supergroup.
-        channel_chat_created (:obj:`bool`): Optional. Service message: The channel has been
-            created. This field can't be received in a message coming through updates, because bot
-            can't be a member of a channel when it is created. It can only be found in
-            :attr:`reply_to_message` if someone replies to a very first message in a channel.
-        message_auto_delete_timer_changed (:class:`telegram.MessageAutoDeleteTimerChanged`):
-            Optional. Service message: auto-delete timer settings changed in the chat.
-
-            .. versionadded:: 13.4
-        migrate_to_chat_id (:obj:`int`): Optional. The group has been migrated to a supergroup
-            with the specified identifier.
-        migrate_from_chat_id (:obj:`int`): Optional. The supergroup has been migrated from a group
-            with the specified identifier.
-        pinned_message (:class:`telegram.MaybeInaccessibleMessage`): Optional. Specified message
-            was pinned. Note that the Message object in this field will not contain further
-            :attr:`reply_to_message` fields even if it is itself a reply.
-
-            .. versionchanged:: 20.8
-                This attribute now is either :class:`telegram.Message` or
-                :class:`telegram.InaccessibleMessage`.
-        invoice (:class:`telegram.Invoice`): Optional. Message is an invoice for a payment,
-            information about the invoice.
-            :ref:`More about payments >> `.
-        successful_payment (:class:`telegram.SuccessfulPayment`): Optional. Message is a service
-            message about a successful payment, information about the payment.
-            :ref:`More about payments >> `.
-        connected_website (:obj:`str`): Optional. The domain name of the website on which the user
-            has logged in.
-            `More about Telegram Login >> `_.
-        author_signature (:obj:`str`): Optional. Signature of the post author for messages in
-            channels, or the custom title of an anonymous group administrator.
-        passport_data (:class:`telegram.PassportData`): Optional. Telegram Passport data.
-
-            Examples:
-                :any:`Passport Bot `
-        poll (:class:`telegram.Poll`): Optional. Message is a native poll,
-            information about the poll.
-        dice (:class:`telegram.Dice`): Optional. Message is a dice with random value.
-        via_bot (:class:`telegram.User`): Optional. Bot through which message was sent.
-        proximity_alert_triggered (:class:`telegram.ProximityAlertTriggered`): Optional. Service
-            message. A user in the chat triggered another user's proximity alert while sharing
-            Live Location.
-        video_chat_scheduled (:class:`telegram.VideoChatScheduled`): Optional. Service message:
-            video chat scheduled.
-
-            .. versionadded:: 20.0
-        video_chat_started (:class:`telegram.VideoChatStarted`): Optional. Service message: video
-            chat started.
-
-            .. versionadded:: 20.0
-        video_chat_ended (:class:`telegram.VideoChatEnded`): Optional. Service message: video chat
-            ended.
-
-            .. versionadded:: 20.0
-        video_chat_participants_invited (:class:`telegram.VideoChatParticipantsInvited`): Optional.
-            Service message: new participants invited to a video chat.
-
-            .. versionadded:: 20.0
-        web_app_data (:class:`telegram.WebAppData`): Optional. Service message: data sent by a Web
-            App.
-
-            .. versionadded:: 20.0
-        reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
-            to the message. :paramref:`~telegram.InlineKeyboardButton.login_url` buttons are
-            represented as ordinary url buttons.
-        is_topic_message (:obj:`bool`): Optional. :obj:`True`, if the message is sent to a forum
-            topic.
-
-            .. versionadded:: 20.0
-        message_thread_id (:obj:`int`): Optional. Unique identifier of a message thread to which
-            the message belongs; for supergroups only.
-
-            .. versionadded:: 20.0
-        forum_topic_created (:class:`telegram.ForumTopicCreated`): Optional. Service message:
-            forum topic created.
-
-            .. versionadded:: 20.0
-        forum_topic_closed (:class:`telegram.ForumTopicClosed`): Optional. Service message:
-            forum topic closed.
-
-            .. versionadded:: 20.0
-        forum_topic_reopened (:class:`telegram.ForumTopicReopened`): Optional. Service message:
-            forum topic reopened.
-
-            .. versionadded:: 20.0
-        forum_topic_edited (:class:`telegram.ForumTopicEdited`): Optional. Service message:
-            forum topic edited.
-
-            .. versionadded:: 20.0
-        general_forum_topic_hidden (:class:`telegram.GeneralForumTopicHidden`): Optional.
-            Service message: General forum topic hidden.
-
-            .. versionadded:: 20.0
-        general_forum_topic_unhidden (:class:`telegram.GeneralForumTopicUnhidden`): Optional.
-            Service message: General forum topic unhidden.
-
-            .. versionadded:: 20.0
-        write_access_allowed (:class:`telegram.WriteAccessAllowed`): Optional. Service message:
-            the user allowed the bot added to the attachment menu to write messages.
-
-            .. versionadded:: 20.0
-        has_media_spoiler (:obj:`bool`): Optional. :obj:`True`, if the message media is covered
-            by a spoiler animation.
-
-            .. versionadded:: 20.0
-        users_shared (:class:`telegram.UsersShared`): Optional. Service message: users were shared
-            with the bot
-
-            .. versionadded:: 20.8
-        chat_shared (:class:`telegram.ChatShared`): Optional. Service message: a chat was shared
-            with the bot.
-
-            .. versionadded:: 20.1
-        giveaway_created (:class:`telegram.GiveawayCreated`): Optional. Service message: a
-            scheduled giveaway was created
-
-            .. versionadded:: 20.8
-        giveaway (:class:`telegram.Giveaway`): Optional. The message is a scheduled giveaway
-            message
-
-            .. versionadded:: 20.8
-        giveaway_winners (:class:`telegram.GiveawayWinners`): Optional. A giveaway with public
-            winners was completed
-
-            .. versionadded:: 20.8
-        giveaway_completed (:class:`telegram.GiveawayCompleted`): Optional. Service message: a
-            giveaway without public winners was completed
-
-            .. versionadded:: 20.8
-        external_reply (:class:`telegram.ExternalReplyInfo`): Optional. Information about the
-            message that is being replied to, which may come from another chat or forum topic.
-
-            .. versionadded:: 20.8
-        quote (:class:`telegram.TextQuote`): Optional. For replies that quote part of the original
-            message, the quoted part of the message.
-
-            .. versionadded:: 20.8
-        forward_origin (:class:`telegram.MessageOrigin`): Optional. Information about the original
-            message for forwarded messages
-
-            .. versionadded:: 20.8
-        reply_to_story (:class:`telegram.Story`): Optional. For replies to a story, the original
-            story.
-
-            .. versionadded:: 21.0
-        boost_added (:class:`telegram.ChatBoostAdded`): Optional. Service message: user boosted
-            the chat.
-
-            .. versionadded:: 21.0
-        sender_boost_count (:obj:`int`): Optional. If the sender of the
-            message boosted the chat, the number of boosts added by the user.
-
-            .. versionadded:: 21.0
-
-        business_connection_id (:obj:`str`): Optional. Unique identifier of the business connection
-            from which the message was received. If non-empty, the message belongs to a chat of the
-            corresponding business account that is independent from any potential bot chat which
-            might share the same identifier.
-
-            .. versionadded:: 21.1
-
-        sender_business_bot (:class:`telegram.User`): Optional. The bot that actually sent the
-            message on behalf of the business account. Available only for outgoing messages sent
-            on behalf of the connected business account.
-
-            .. versionadded:: 21.1
-
-        chat_background_set (:class:`telegram.ChatBackground`): Optional. Service message: chat
-            background set
-
-            .. versionadded:: 21.2
-        paid_media (:class:`telegram.PaidMediaInfo`): Optional. Message contains paid media;
-            information about the paid media.
-
-            .. versionadded:: 21.4
-        refunded_payment (:class:`telegram.RefundedPayment`): Optional. Message is a service
-            message about a refunded payment, information about the payment.
-
-            .. versionadded:: 21.4
-
-    .. |custom_emoji_no_md1_support| replace:: Since custom emoji entities are not supported by
-       :attr:`~telegram.constants.ParseMode.MARKDOWN`, this method now raises a
-       :exc:`ValueError` when encountering a custom emoji.
-
-    .. |blockquote_no_md1_support| replace:: Since block quotation entities are not supported
-       by :attr:`~telegram.constants.ParseMode.MARKDOWN`, this method now raises a
-       :exc:`ValueError` when encountering a block quotation.
-
-    .. |reply_same_thread| replace:: If :paramref:`message_thread_id` is not provided,
-       this will reply to the same thread (topic) of the original message.
-    """
-
-    # fmt: on
-    __slots__ = (
-        "_effective_attachment",
-        "animation",
-        "audio",
-        "author_signature",
-        "boost_added",
-        "business_connection_id",
-        "caption",
-        "caption_entities",
-        "channel_chat_created",
-        "chat_background_set",
-        "chat_shared",
-        "connected_website",
-        "contact",
-        "delete_chat_photo",
-        "dice",
-        "document",
-        "edit_date",
-        "effect_id",
-        "entities",
-        "external_reply",
-        "forum_topic_closed",
-        "forum_topic_created",
-        "forum_topic_edited",
-        "forum_topic_reopened",
-        "forward_origin",
-        "from_user",
-        "game",
-        "general_forum_topic_hidden",
-        "general_forum_topic_unhidden",
-        "giveaway",
-        "giveaway_completed",
-        "giveaway_created",
-        "giveaway_winners",
-        "group_chat_created",
-        "has_media_spoiler",
-        "has_protected_content",
-        "invoice",
-        "is_automatic_forward",
-        "is_from_offline",
-        "is_topic_message",
-        "left_chat_member",
-        "link_preview_options",
-        "location",
-        "media_group_id",
-        "message_auto_delete_timer_changed",
-        "message_thread_id",
-        "migrate_from_chat_id",
-        "migrate_to_chat_id",
-        "new_chat_members",
-        "new_chat_photo",
-        "new_chat_title",
-        "paid_media",
-        "passport_data",
-        "photo",
-        "pinned_message",
-        "poll",
-        "proximity_alert_triggered",
-        "quote",
-        "refunded_payment",
-        "reply_markup",
-        "reply_to_message",
-        "reply_to_story",
-        "sender_boost_count",
-        "sender_business_bot",
-        "sender_chat",
-        "show_caption_above_media",
-        "sticker",
-        "story",
-        "successful_payment",
-        "supergroup_chat_created",
-        "text",
-        "users_shared",
-        "venue",
-        "via_bot",
-        "video",
-        "video_chat_ended",
-        "video_chat_participants_invited",
-        "video_chat_scheduled",
-        "video_chat_started",
-        "video_note",
-        "voice",
-        "web_app_data",
-        "write_access_allowed",
-    )
-
-    def __init__(
-        self,
-        message_id: int,
-        date: dtm.datetime,
-        chat: Chat,
-        from_user: Optional[User] = None,
-        reply_to_message: Optional["Message"] = None,
-        edit_date: Optional[dtm.datetime] = None,
-        text: Optional[str] = None,
-        entities: Optional[Sequence["MessageEntity"]] = None,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        audio: Optional[Audio] = None,
-        document: Optional[Document] = None,
-        game: Optional[Game] = None,
-        photo: Optional[Sequence[PhotoSize]] = None,
-        sticker: Optional[Sticker] = None,
-        video: Optional[Video] = None,
-        voice: Optional[Voice] = None,
-        video_note: Optional[VideoNote] = None,
-        new_chat_members: Optional[Sequence[User]] = None,
-        caption: Optional[str] = None,
-        contact: Optional[Contact] = None,
-        location: Optional[Location] = None,
-        venue: Optional[Venue] = None,
-        left_chat_member: Optional[User] = None,
-        new_chat_title: Optional[str] = None,
-        new_chat_photo: Optional[Sequence[PhotoSize]] = None,
-        delete_chat_photo: Optional[bool] = None,
-        group_chat_created: Optional[bool] = None,
-        supergroup_chat_created: Optional[bool] = None,
-        channel_chat_created: Optional[bool] = None,
-        migrate_to_chat_id: Optional[int] = None,
-        migrate_from_chat_id: Optional[int] = None,
-        pinned_message: Optional[MaybeInaccessibleMessage] = None,
-        invoice: Optional[Invoice] = None,
-        successful_payment: Optional[SuccessfulPayment] = None,
-        author_signature: Optional[str] = None,
-        media_group_id: Optional[str] = None,
-        connected_website: Optional[str] = None,
-        animation: Optional[Animation] = None,
-        passport_data: Optional[PassportData] = None,
-        poll: Optional[Poll] = None,
-        reply_markup: Optional[InlineKeyboardMarkup] = None,
-        dice: Optional[Dice] = None,
-        via_bot: Optional[User] = None,
-        proximity_alert_triggered: Optional[ProximityAlertTriggered] = None,
-        sender_chat: Optional[Chat] = None,
-        video_chat_started: Optional[VideoChatStarted] = None,
-        video_chat_ended: Optional[VideoChatEnded] = None,
-        video_chat_participants_invited: Optional[VideoChatParticipantsInvited] = None,
-        message_auto_delete_timer_changed: Optional[MessageAutoDeleteTimerChanged] = None,
-        video_chat_scheduled: Optional[VideoChatScheduled] = None,
-        is_automatic_forward: Optional[bool] = None,
-        has_protected_content: Optional[bool] = None,
-        web_app_data: Optional[WebAppData] = None,
-        is_topic_message: Optional[bool] = None,
-        message_thread_id: Optional[int] = None,
-        forum_topic_created: Optional[ForumTopicCreated] = None,
-        forum_topic_closed: Optional[ForumTopicClosed] = None,
-        forum_topic_reopened: Optional[ForumTopicReopened] = None,
-        forum_topic_edited: Optional[ForumTopicEdited] = None,
-        general_forum_topic_hidden: Optional[GeneralForumTopicHidden] = None,
-        general_forum_topic_unhidden: Optional[GeneralForumTopicUnhidden] = None,
-        write_access_allowed: Optional[WriteAccessAllowed] = None,
-        has_media_spoiler: Optional[bool] = None,
-        chat_shared: Optional[ChatShared] = None,
-        story: Optional[Story] = None,
-        giveaway: Optional["Giveaway"] = None,
-        giveaway_completed: Optional["GiveawayCompleted"] = None,
-        giveaway_created: Optional["GiveawayCreated"] = None,
-        giveaway_winners: Optional["GiveawayWinners"] = None,
-        users_shared: Optional[UsersShared] = None,
-        link_preview_options: Optional[LinkPreviewOptions] = None,
-        external_reply: Optional["ExternalReplyInfo"] = None,
-        quote: Optional["TextQuote"] = None,
-        forward_origin: Optional["MessageOrigin"] = None,
-        reply_to_story: Optional[Story] = None,
-        boost_added: Optional[ChatBoostAdded] = None,
-        sender_boost_count: Optional[int] = None,
-        business_connection_id: Optional[str] = None,
-        sender_business_bot: Optional[User] = None,
-        is_from_offline: Optional[bool] = None,
-        chat_background_set: Optional[ChatBackground] = None,
-        effect_id: Optional[str] = None,
-        show_caption_above_media: Optional[bool] = None,
-        paid_media: Optional[PaidMediaInfo] = None,
-        refunded_payment: Optional[RefundedPayment] = None,
-        *,
-        api_kwargs: Optional[JSONDict] = None,
-    ):
-        super().__init__(chat=chat, message_id=message_id, date=date, api_kwargs=api_kwargs)
-
-        with self._unfrozen():
-            # Required
-            self.message_id: int = message_id
-            # Optionals
-            self.from_user: Optional[User] = from_user
-            self.sender_chat: Optional[Chat] = sender_chat
-            self.date: dtm.datetime = date
-            self.chat: Chat = chat
-            self.is_automatic_forward: Optional[bool] = is_automatic_forward
-            self.reply_to_message: Optional[Message] = reply_to_message
-            self.edit_date: Optional[dtm.datetime] = edit_date
-            self.has_protected_content: Optional[bool] = has_protected_content
-            self.text: Optional[str] = text
-            self.entities: tuple[MessageEntity, ...] = parse_sequence_arg(entities)
-            self.caption_entities: tuple[MessageEntity, ...] = parse_sequence_arg(caption_entities)
-            self.audio: Optional[Audio] = audio
-            self.game: Optional[Game] = game
-            self.document: Optional[Document] = document
-            self.photo: tuple[PhotoSize, ...] = parse_sequence_arg(photo)
-            self.sticker: Optional[Sticker] = sticker
-            self.video: Optional[Video] = video
-            self.voice: Optional[Voice] = voice
-            self.video_note: Optional[VideoNote] = video_note
-            self.caption: Optional[str] = caption
-            self.contact: Optional[Contact] = contact
-            self.location: Optional[Location] = location
-            self.venue: Optional[Venue] = venue
-            self.new_chat_members: tuple[User, ...] = parse_sequence_arg(new_chat_members)
-            self.left_chat_member: Optional[User] = left_chat_member
-            self.new_chat_title: Optional[str] = new_chat_title
-            self.new_chat_photo: tuple[PhotoSize, ...] = parse_sequence_arg(new_chat_photo)
-            self.delete_chat_photo: Optional[bool] = bool(delete_chat_photo)
-            self.group_chat_created: Optional[bool] = bool(group_chat_created)
-            self.supergroup_chat_created: Optional[bool] = bool(supergroup_chat_created)
-            self.migrate_to_chat_id: Optional[int] = migrate_to_chat_id
-            self.migrate_from_chat_id: Optional[int] = migrate_from_chat_id
-            self.channel_chat_created: Optional[bool] = bool(channel_chat_created)
-            self.message_auto_delete_timer_changed: Optional[MessageAutoDeleteTimerChanged] = (
-                message_auto_delete_timer_changed
-            )
-            self.pinned_message: Optional[MaybeInaccessibleMessage] = pinned_message
-            self.invoice: Optional[Invoice] = invoice
-            self.successful_payment: Optional[SuccessfulPayment] = successful_payment
-            self.connected_website: Optional[str] = connected_website
-            self.author_signature: Optional[str] = author_signature
-            self.media_group_id: Optional[str] = media_group_id
-            self.animation: Optional[Animation] = animation
-            self.passport_data: Optional[PassportData] = passport_data
-            self.poll: Optional[Poll] = poll
-            self.dice: Optional[Dice] = dice
-            self.via_bot: Optional[User] = via_bot
-            self.proximity_alert_triggered: Optional[ProximityAlertTriggered] = (
-                proximity_alert_triggered
-            )
-            self.video_chat_scheduled: Optional[VideoChatScheduled] = video_chat_scheduled
-            self.video_chat_started: Optional[VideoChatStarted] = video_chat_started
-            self.video_chat_ended: Optional[VideoChatEnded] = video_chat_ended
-            self.video_chat_participants_invited: Optional[VideoChatParticipantsInvited] = (
-                video_chat_participants_invited
-            )
-            self.reply_markup: Optional[InlineKeyboardMarkup] = reply_markup
-            self.web_app_data: Optional[WebAppData] = web_app_data
-            self.is_topic_message: Optional[bool] = is_topic_message
-            self.message_thread_id: Optional[int] = message_thread_id
-            self.forum_topic_created: Optional[ForumTopicCreated] = forum_topic_created
-            self.forum_topic_closed: Optional[ForumTopicClosed] = forum_topic_closed
-            self.forum_topic_reopened: Optional[ForumTopicReopened] = forum_topic_reopened
-            self.forum_topic_edited: Optional[ForumTopicEdited] = forum_topic_edited
-            self.general_forum_topic_hidden: Optional[GeneralForumTopicHidden] = (
-                general_forum_topic_hidden
-            )
-            self.general_forum_topic_unhidden: Optional[GeneralForumTopicUnhidden] = (
-                general_forum_topic_unhidden
-            )
-            self.write_access_allowed: Optional[WriteAccessAllowed] = write_access_allowed
-            self.has_media_spoiler: Optional[bool] = has_media_spoiler
-            self.users_shared: Optional[UsersShared] = users_shared
-            self.chat_shared: Optional[ChatShared] = chat_shared
-            self.story: Optional[Story] = story
-            self.giveaway: Optional[Giveaway] = giveaway
-            self.giveaway_completed: Optional[GiveawayCompleted] = giveaway_completed
-            self.giveaway_created: Optional[GiveawayCreated] = giveaway_created
-            self.giveaway_winners: Optional[GiveawayWinners] = giveaway_winners
-            self.link_preview_options: Optional[LinkPreviewOptions] = link_preview_options
-            self.external_reply: Optional[ExternalReplyInfo] = external_reply
-            self.quote: Optional[TextQuote] = quote
-            self.forward_origin: Optional[MessageOrigin] = forward_origin
-            self.reply_to_story: Optional[Story] = reply_to_story
-            self.boost_added: Optional[ChatBoostAdded] = boost_added
-            self.sender_boost_count: Optional[int] = sender_boost_count
-            self.business_connection_id: Optional[str] = business_connection_id
-            self.sender_business_bot: Optional[User] = sender_business_bot
-            self.is_from_offline: Optional[bool] = is_from_offline
-            self.chat_background_set: Optional[ChatBackground] = chat_background_set
-            self.effect_id: Optional[str] = effect_id
-            self.show_caption_above_media: Optional[bool] = show_caption_above_media
-            self.paid_media: Optional[PaidMediaInfo] = paid_media
-            self.refunded_payment: Optional[RefundedPayment] = refunded_payment
-
-            self._effective_attachment = DEFAULT_NONE
-
-            self._id_attrs = (self.message_id, self.chat)
-
-    @property
-    def chat_id(self) -> int:
-        """:obj:`int`: Shortcut for :attr:`telegram.Chat.id` for :attr:`chat`."""
-        return self.chat.id
-
-    @property
-    def id(self) -> int:
-        """
-        :obj:`int`: Shortcut for :attr:`message_id`.
-
-            .. versionadded:: 20.0
-        """
-        return self.message_id
-
-    @property
-    def link(self) -> Optional[str]:
-        """:obj:`str`: Convenience property. If the chat of the message is not
-        a private chat or normal group, returns a t.me link of the message.
-
-            .. versionchanged:: 20.3
-                For messages that are replies or part of a forum topic, the link now points
-                to the corresponding thread view.
-        """
-        if self.chat.type not in [Chat.PRIVATE, Chat.GROUP]:
-            # the else block gets rid of leading -100 for supergroups:
-            to_link = self.chat.username if self.chat.username else f"c/{str(self.chat.id)[4:]}"
-            baselink = f"https://t.me/{to_link}/{self.message_id}"
-
-            # adds the thread for topics and replies
-            if (self.is_topic_message and self.message_thread_id) or self.reply_to_message:
-                baselink = f"{baselink}?thread={self.message_thread_id}"
-            return baselink
-        return None
-
-    @classmethod
-    def de_json(cls, data: Optional[JSONDict], bot: Optional["Bot"] = None) -> Optional["Message"]:
-        """See :meth:`telegram.TelegramObject.de_json`."""
-        data = cls._parse_data(data)
-
-        if not data:
-            return None
-
-        # Get the local timezone from the bot if it has defaults
-        loc_tzinfo = extract_tzinfo_from_defaults(bot)
-
-        data["from_user"] = User.de_json(data.pop("from", None), bot)
-        data["sender_chat"] = Chat.de_json(data.get("sender_chat"), bot)
-        data["entities"] = MessageEntity.de_list(data.get("entities"), bot)
-        data["caption_entities"] = MessageEntity.de_list(data.get("caption_entities"), bot)
-        data["reply_to_message"] = Message.de_json(data.get("reply_to_message"), bot)
-        data["edit_date"] = from_timestamp(data.get("edit_date"), tzinfo=loc_tzinfo)
-        data["audio"] = Audio.de_json(data.get("audio"), bot)
-        data["document"] = Document.de_json(data.get("document"), bot)
-        data["animation"] = Animation.de_json(data.get("animation"), bot)
-        data["game"] = Game.de_json(data.get("game"), bot)
-        data["photo"] = PhotoSize.de_list(data.get("photo"), bot)
-        data["sticker"] = Sticker.de_json(data.get("sticker"), bot)
-        data["story"] = Story.de_json(data.get("story"), bot)
-        data["video"] = Video.de_json(data.get("video"), bot)
-        data["voice"] = Voice.de_json(data.get("voice"), bot)
-        data["video_note"] = VideoNote.de_json(data.get("video_note"), bot)
-        data["contact"] = Contact.de_json(data.get("contact"), bot)
-        data["location"] = Location.de_json(data.get("location"), bot)
-        data["venue"] = Venue.de_json(data.get("venue"), bot)
-        data["new_chat_members"] = User.de_list(data.get("new_chat_members"), bot)
-        data["left_chat_member"] = User.de_json(data.get("left_chat_member"), bot)
-        data["new_chat_photo"] = PhotoSize.de_list(data.get("new_chat_photo"), bot)
-        data["message_auto_delete_timer_changed"] = MessageAutoDeleteTimerChanged.de_json(
-            data.get("message_auto_delete_timer_changed"), bot
-        )
-        data["pinned_message"] = MaybeInaccessibleMessage.de_json(data.get("pinned_message"), bot)
-        data["invoice"] = Invoice.de_json(data.get("invoice"), bot)
-        data["successful_payment"] = SuccessfulPayment.de_json(data.get("successful_payment"), bot)
-        data["passport_data"] = PassportData.de_json(data.get("passport_data"), bot)
-        data["poll"] = Poll.de_json(data.get("poll"), bot)
-        data["dice"] = Dice.de_json(data.get("dice"), bot)
-        data["via_bot"] = User.de_json(data.get("via_bot"), bot)
-        data["proximity_alert_triggered"] = ProximityAlertTriggered.de_json(
-            data.get("proximity_alert_triggered"), bot
-        )
-        data["reply_markup"] = InlineKeyboardMarkup.de_json(data.get("reply_markup"), bot)
-        data["video_chat_scheduled"] = VideoChatScheduled.de_json(
-            data.get("video_chat_scheduled"), bot
-        )
-        data["video_chat_started"] = VideoChatStarted.de_json(data.get("video_chat_started"), bot)
-        data["video_chat_ended"] = VideoChatEnded.de_json(data.get("video_chat_ended"), bot)
-        data["video_chat_participants_invited"] = VideoChatParticipantsInvited.de_json(
-            data.get("video_chat_participants_invited"), bot
-        )
-        data["web_app_data"] = WebAppData.de_json(data.get("web_app_data"), bot)
-        data["forum_topic_closed"] = ForumTopicClosed.de_json(data.get("forum_topic_closed"), bot)
-        data["forum_topic_created"] = ForumTopicCreated.de_json(
-            data.get("forum_topic_created"), bot
-        )
-        data["forum_topic_reopened"] = ForumTopicReopened.de_json(
-            data.get("forum_topic_reopened"), bot
-        )
-        data["forum_topic_edited"] = ForumTopicEdited.de_json(data.get("forum_topic_edited"), bot)
-        data["general_forum_topic_hidden"] = GeneralForumTopicHidden.de_json(
-            data.get("general_forum_topic_hidden"), bot
-        )
-        data["general_forum_topic_unhidden"] = GeneralForumTopicUnhidden.de_json(
-            data.get("general_forum_topic_unhidden"), bot
-        )
-        data["write_access_allowed"] = WriteAccessAllowed.de_json(
-            data.get("write_access_allowed"), bot
-        )
-        data["users_shared"] = UsersShared.de_json(data.get("users_shared"), bot)
-        data["chat_shared"] = ChatShared.de_json(data.get("chat_shared"), bot)
-        data["chat_background_set"] = ChatBackground.de_json(data.get("chat_background_set"), bot)
-        data["paid_media"] = PaidMediaInfo.de_json(data.get("paid_media"), bot)
-        data["refunded_payment"] = RefundedPayment.de_json(data.get("refunded_payment"), bot)
-
-        # Unfortunately, this needs to be here due to cyclic imports
-        from telegram._giveaway import (  # pylint: disable=import-outside-toplevel
-            Giveaway,
-            GiveawayCompleted,
-            GiveawayCreated,
-            GiveawayWinners,
-        )
-        from telegram._messageorigin import (  # pylint: disable=import-outside-toplevel
-            MessageOrigin,
-        )
-        from telegram._reply import (  # pylint: disable=import-outside-toplevel
-            ExternalReplyInfo,
-            TextQuote,
-        )
-
-        data["giveaway"] = Giveaway.de_json(data.get("giveaway"), bot)
-        data["giveaway_completed"] = GiveawayCompleted.de_json(data.get("giveaway_completed"), bot)
-        data["giveaway_created"] = GiveawayCreated.de_json(data.get("giveaway_created"), bot)
-        data["giveaway_winners"] = GiveawayWinners.de_json(data.get("giveaway_winners"), bot)
-        data["link_preview_options"] = LinkPreviewOptions.de_json(
-            data.get("link_preview_options"), bot
-        )
-        data["external_reply"] = ExternalReplyInfo.de_json(data.get("external_reply"), bot)
-        data["quote"] = TextQuote.de_json(data.get("quote"), bot)
-        data["forward_origin"] = MessageOrigin.de_json(data.get("forward_origin"), bot)
-        data["reply_to_story"] = Story.de_json(data.get("reply_to_story"), bot)
-        data["boost_added"] = ChatBoostAdded.de_json(data.get("boost_added"), bot)
-        data["sender_business_bot"] = User.de_json(data.get("sender_business_bot"), bot)
-
-        api_kwargs = {}
-        # This is a deprecated field that TG still returns for backwards compatibility
-        # Let's filter it out to speed up the de-json process
-        for key in (
-            "user_shared",
-            "forward_from",
-            "forward_from_chat",
-            "forward_from_message_id",
-            "forward_signature",
-            "forward_sender_name",
-            "forward_date",
-        ):
-            if entry := data.get(key):
-                api_kwargs = {key: entry}
-
-        return super()._de_json(  # type: ignore[return-value]
-            data=data, bot=bot, api_kwargs=api_kwargs
-        )
-
-    @property
-    def effective_attachment(
-        self,
-    ) -> Union[
-        Animation,
-        Audio,
-        Contact,
-        Dice,
-        Document,
-        Game,
-        Invoice,
-        Location,
-        PassportData,
-        Sequence[PhotoSize],
-        PaidMediaInfo,
-        Poll,
-        Sticker,
-        Story,
-        SuccessfulPayment,
-        Venue,
-        Video,
-        VideoNote,
-        Voice,
-        None,
-    ]:
-        """If the message is a user generated content which is not a plain text message, this
-        property is set to this content. It may be one of
-
-        * :class:`telegram.Audio`
-        * :class:`telegram.Dice`
-        * :class:`telegram.Contact`
-        * :class:`telegram.Document`
-        * :class:`telegram.Animation`
-        * :class:`telegram.Game`
-        * :class:`telegram.Invoice`
-        * :class:`telegram.Location`
-        * :class:`telegram.PassportData`
-        * list[:class:`telegram.PhotoSize`]
-        * :class:`telegram.PaidMediaInfo`
-        * :class:`telegram.Poll`
-        * :class:`telegram.Sticker`
-        * :class:`telegram.Story`
-        * :class:`telegram.SuccessfulPayment`
-        * :class:`telegram.Venue`
-        * :class:`telegram.Video`
-        * :class:`telegram.VideoNote`
-        * :class:`telegram.Voice`
-
-        Otherwise :obj:`None` is returned.
-
-        .. seealso:: :wiki:`Working with Files and Media `
-
-        .. versionchanged:: 20.0
-            :attr:`dice`, :attr:`passport_data` and :attr:`poll` are now also considered to be an
-            attachment.
-
-        .. versionchanged:: 21.4
-            :attr:`paid_media` is now also considered to be an attachment.
-
-        .. deprecated:: 21.4
-            :attr:`successful_payment` will be removed in future major versions.
-
-        """
-        if not isinstance(self._effective_attachment, DefaultValue):
-            return self._effective_attachment
-
-        for attachment_type in MessageAttachmentType:
-            if self[attachment_type]:
-                self._effective_attachment = self[attachment_type]  # type: ignore[assignment]
-                if attachment_type == MessageAttachmentType.SUCCESSFUL_PAYMENT:
-                    warn(
-                        PTBDeprecationWarning(
-                            "21.4",
-                            "successful_payment will no longer be considered an attachment in"
-                            " future major versions",
-                        ),
-                        stacklevel=2,
-                    )
-                break
-        else:
-            self._effective_attachment = None
-
-        return self._effective_attachment  # type: ignore[return-value]
-
-    def _quote(
-        self, quote: Optional[bool], reply_to_message_id: Optional[int] = None
-    ) -> Optional[ReplyParameters]:
-        """Modify kwargs for replying with or without quoting."""
-        if reply_to_message_id is not None:
-            return ReplyParameters(reply_to_message_id)
-
-        if quote is not None:
-            if quote:
-                return ReplyParameters(self.message_id)
-
-        else:
-            # Unfortunately we need some ExtBot logic here because it's hard to move shortcut
-            # logic into ExtBot
-            if hasattr(self.get_bot(), "defaults") and self.get_bot().defaults:  # type: ignore
-                default_quote = self.get_bot().defaults.quote  # type: ignore[attr-defined]
-            else:
-                default_quote = None
-            if (default_quote is None and self.chat.type != Chat.PRIVATE) or default_quote:
-                return ReplyParameters(self.message_id)
-
-        return None
-
-    def compute_quote_position_and_entities(
-        self, quote: str, index: Optional[int] = None
-    ) -> tuple[int, Optional[tuple[MessageEntity, ...]]]:
-        """
-        Use this function to compute position and entities of a quote in the message text or
-        caption. Useful for filling the parameters
-        :paramref:`~telegram.ReplyParameters.quote_position` and
-        :paramref:`~telegram.ReplyParameters.quote_entities` of :class:`telegram.ReplyParameters`
-        when replying to a message.
-
-        Example:
-
-            Given a message with the text ``"Hello, world! Hello, world!"``, the following code
-            will return the position and entities of the second occurrence of ``"Hello, world!"``.
-
-            .. code-block:: python
-
-                message.compute_quote_position_and_entities("Hello, world!", 1)
-
-        .. versionadded:: 20.8
-
-        Args:
-            quote (:obj:`str`): Part of the message which is to be quoted. This is
-                expected to have plain text without formatting entities.
-            index (:obj:`int`, optional): 0-based index of the occurrence of the quote in the
-                message. If not specified, the first occurrence is used.
-
-        Returns:
-            tuple[:obj:`int`, :obj:`None` | tuple[:class:`~telegram.MessageEntity`, ...]]: On
-            success, a tuple containing information about quote position and entities is returned.
-
-        Raises:
-            RuntimeError: If the message has neither :attr:`text` nor :attr:`caption`.
-            ValueError: If the requested index of quote doesn't exist in the message.
-        """
-        if not (text := (self.text or self.caption)):
-            raise RuntimeError("This message has neither text nor caption.")
-
-        # Telegram wants the position in UTF-16 code units, so we have to calculate in that space
-        utf16_text = text.encode(TextEncoding.UTF_16_LE)
-        utf16_quote = quote.encode(TextEncoding.UTF_16_LE)
-        effective_index = index or 0
-
-        matches = list(re.finditer(re.escape(utf16_quote), utf16_text))
-        if (length := len(matches)) < effective_index + 1:
-            raise ValueError(
-                f"You requested the {index}-th occurrence of '{quote}', but this text appears "
-                f"only {length} times."
-            )
-
-        position = len(utf16_text[: matches[effective_index].start()]) // 2
-        length = len(utf16_quote) // 2
-        end_position = position + length
-
-        entities = []
-        for entity in self.entities or self.caption_entities:
-            if position <= entity.offset + entity.length and entity.offset <= end_position:
-                # shift the offset by the position of the quote
-                offset = max(0, entity.offset - position)
-                # trim the entity length to the length of the overlap with the quote
-                e_length = min(end_position, entity.offset + entity.length) - max(
-                    position, entity.offset
-                )
-                if e_length <= 0:
-                    continue
-
-                # create a new entity with the correct offset and length
-                # looping over slots rather manually accessing the attributes
-                # is more future-proof
-                kwargs = {attr: getattr(entity, attr) for attr in entity.__slots__}
-                kwargs["offset"] = offset
-                kwargs["length"] = e_length
-                entities.append(MessageEntity(**kwargs))
-
-        return position, tuple(entities) or None
-
-    def build_reply_arguments(
-        self,
-        quote: Optional[str] = None,
-        quote_index: Optional[int] = None,
-        target_chat_id: Optional[Union[int, str]] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-    ) -> _ReplyKwargs:
-        """
-        Builds a dictionary with the keys ``chat_id`` and ``reply_parameters``. This dictionary can
-        be used to reply to a message with the given quote and target chat.
-
-        Examples:
-
-            Usage with :meth:`telegram.Bot.send_message`:
-
-            .. code-block:: python
-
-                await bot.send_message(
-                    text="This is a reply",
-                    **message.build_reply_arguments(quote="Quoted Text")
-                )
-
-            Usage with :meth:`reply_text`, replying in the same chat:
-
-            .. code-block:: python
-
-                await message.reply_text(
-                    "This is a reply",
-                    do_quote=message.build_reply_arguments(quote="Quoted Text")
-                )
-
-            Usage with :meth:`reply_text`, replying in a different chat:
-
-            .. code-block:: python
-
-                await message.reply_text(
-                    "This is a reply",
-                    do_quote=message.build_reply_arguments(
-                        quote="Quoted Text",
-                        target_chat_id=-100123456789
-                    )
-                )
-
-        .. versionadded:: 20.8
-
-        Args:
-            quote (:obj:`str`, optional): Passed in :meth:`compute_quote_position_and_entities`
-                as parameter :paramref:`~compute_quote_position_and_entities.quote` to compute
-                quote entities. Defaults to :obj:`None`.
-            quote_index (:obj:`int`, optional): Passed in
-                :meth:`compute_quote_position_and_entities` as parameter
-                :paramref:`~compute_quote_position_and_entities.quote_index` to compute quote
-                position. Defaults to :obj:`None`.
-            target_chat_id (:obj:`int` | :obj:`str`, optional): |chat_id_channel|
-                Defaults to :attr:`chat_id`.
-            allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply|
-                Will be applied only if the reply happens in the same chat and forum topic.
-            message_thread_id (:obj:`int`, optional): |message_thread_id|
-
-        Returns:
-            :obj:`dict`:
-        """
-        target_chat_is_self = target_chat_id in (None, self.chat_id, f"@{self.chat.username}")
-
-        if target_chat_is_self and message_thread_id in (
-            None,
-            self.message_thread_id,
-        ):
-            # defaults handling will take place in `Bot._insert_defaults`
-            effective_aswr: ODVInput[bool] = allow_sending_without_reply
-        else:
-            effective_aswr = None
-
-        quote_position, quote_entities = (
-            self.compute_quote_position_and_entities(quote, quote_index) if quote else (None, None)
-        )
-        return {  # type: ignore[typeddict-item]
-            "reply_parameters": ReplyParameters(
-                chat_id=None if target_chat_is_self else self.chat_id,
-                message_id=self.message_id,
-                quote=quote,
-                quote_position=quote_position,
-                quote_entities=quote_entities,
-                allow_sending_without_reply=effective_aswr,
-            ),
-            "chat_id": target_chat_id or self.chat_id,
-        }
-
-    async def _parse_quote_arguments(
-        self,
-        do_quote: Optional[Union[bool, _ReplyKwargs]],
-        quote: Optional[bool],
-        reply_to_message_id: Optional[int],
-        reply_parameters: Optional["ReplyParameters"],
-    ) -> tuple[Union[str, int], ReplyParameters]:
-        if quote and do_quote:
-            raise ValueError("The arguments `quote` and `do_quote` are mutually exclusive")
-
-        if reply_to_message_id is not None and reply_parameters is not None:
-            raise ValueError(
-                "`reply_to_message_id` and `reply_parameters` are mutually exclusive."
-            )
-
-        if quote is not None:
-            warn(
-                PTBDeprecationWarning(
-                    "20.8",
-                    "The `quote` parameter is deprecated in favor of the `do_quote` parameter. "
-                    "Please update your code to use `do_quote` instead.",
-                ),
-                stacklevel=2,
-            )
-
-        effective_do_quote = quote or do_quote
-        chat_id: Union[str, int] = self.chat_id
-
-        # reply_parameters and reply_to_message_id overrule the do_quote parameter
-        if reply_parameters is not None:
-            effective_reply_parameters = reply_parameters
-        elif reply_to_message_id is not None:
-            effective_reply_parameters = ReplyParameters(message_id=reply_to_message_id)
-        elif isinstance(effective_do_quote, dict):
-            effective_reply_parameters = effective_do_quote["reply_parameters"]
-            chat_id = effective_do_quote["chat_id"]
-        else:
-            effective_reply_parameters = self._quote(effective_do_quote)
-
-        return chat_id, effective_reply_parameters
-
-    def _parse_message_thread_id(
-        self,
-        chat_id: Union[str, int],
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-    ) -> Optional[int]:
-        # values set by user have the highest priority
-        if not isinstance(message_thread_id, DefaultValue):
-            return message_thread_id
-
-        # self.message_thread_id can be used for send_*.param.message_thread_id only if the
-        # thread is a forum topic. It does not work if the thread is a chain of replies to a
-        # message in a normal group. In that case, self.message_thread_id is just the message_id
-        # of the first message in the chain.
-        if not self.is_topic_message:
-            return None
-
-        # Setting message_thread_id=self.message_thread_id only makes sense if we're replying in
-        # the same chat.
-        return self.message_thread_id if chat_id in {self.chat_id, self.chat.username} else None
-
-    async def reply_text(
-        self,
-        text: str,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-        link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        disable_web_page_preview: Optional[bool] = None,
-        quote: Optional[bool] = None,
-        do_quote: Optional[Union[bool, _ReplyKwargs]] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_message(
-                 update.effective_message.chat_id,
-                 message_thread_id=update.effective_message.message_thread_id,
-                 business_connection_id=self.business_connection_id,
-                 *args,
-                 **kwargs,
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`.
-
-        .. versionchanged:: 21.1
-                |reply_same_thread|
-
-        Keyword Args:
-            quote (:obj:`bool`, optional): |reply_quote|
-
-                .. deprecated:: 20.8
-                    This argument is deprecated in favor of :paramref:`do_quote`
-            do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
-                Mutually exclusive with :paramref:`quote`.
-
-                .. versionadded:: 20.8
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        chat_id, effective_reply_parameters = await self._parse_quote_arguments(
-            do_quote, quote, reply_to_message_id, reply_parameters
-        )
-        message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id)
-        return await self.get_bot().send_message(
-            chat_id=chat_id,
-            text=text,
-            parse_mode=parse_mode,
-            disable_web_page_preview=disable_web_page_preview,
-            link_preview_options=link_preview_options,
-            disable_notification=disable_notification,
-            reply_parameters=effective_reply_parameters,
-            reply_markup=reply_markup,
-            allow_sending_without_reply=allow_sending_without_reply,
-            entities=entities,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=self.business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def reply_markdown(
-        self,
-        text: str,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-        link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        disable_web_page_preview: Optional[bool] = None,
-        quote: Optional[bool] = None,
-        do_quote: Optional[Union[bool, _ReplyKwargs]] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-            await bot.send_message(
-                update.effective_message.chat_id,
-                message_thread_id=update.effective_message.message_thread_id,
-                parse_mode=ParseMode.MARKDOWN,
-                business_connection_id=self.business_connection_id,
-                *args,
-                **kwargs,
-            )
-
-        Sends a message with Markdown version 1 formatting.
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`.
-
-        .. versionchanged:: 21.1
-                |reply_same_thread|
-
-        Note:
-            :tg-const:`telegram.constants.ParseMode.MARKDOWN` is a legacy mode, retained by
-            Telegram for backward compatibility. You should use :meth:`reply_markdown_v2` instead.
-
-        Keyword Args:
-            quote (:obj:`bool`, optional): |reply_quote|
-
-                .. deprecated:: 20.8
-                    This argument is deprecated in favor of :paramref:`do_quote`
-            do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
-                Mutually exclusive with :paramref:`quote`.
-
-                .. versionadded:: 20.8
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-        """
-        chat_id, effective_reply_parameters = await self._parse_quote_arguments(
-            do_quote, quote, reply_to_message_id, reply_parameters
-        )
-        message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id)
-        return await self.get_bot().send_message(
-            chat_id=chat_id,
-            text=text,
-            parse_mode=ParseMode.MARKDOWN,
-            disable_web_page_preview=disable_web_page_preview,
-            link_preview_options=link_preview_options,
-            disable_notification=disable_notification,
-            reply_parameters=effective_reply_parameters,
-            reply_markup=reply_markup,
-            allow_sending_without_reply=allow_sending_without_reply,
-            entities=entities,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=self.business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def reply_markdown_v2(
-        self,
-        text: str,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-        link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        disable_web_page_preview: Optional[bool] = None,
-        quote: Optional[bool] = None,
-        do_quote: Optional[Union[bool, _ReplyKwargs]] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-            await bot.send_message(
-                update.effective_message.chat_id,
-                message_thread_id=update.effective_message.message_thread_id,
-                parse_mode=ParseMode.MARKDOWN_V2,
-                business_connection_id=self.business_connection_id,
-                *args,
-                **kwargs,
-            )
-
-        Sends a message with markdown version 2 formatting.
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`.
-
-        .. versionchanged:: 21.1
-                |reply_same_thread|
-
-        Keyword Args:
-            quote (:obj:`bool`, optional): |reply_quote|
-
-                .. deprecated:: 20.8
-                    This argument is deprecated in favor of :paramref:`do_quote`
-            do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
-                Mutually exclusive with :paramref:`quote`.
-
-                .. versionadded:: 20.8
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-        """
-        chat_id, effective_reply_parameters = await self._parse_quote_arguments(
-            do_quote, quote, reply_to_message_id, reply_parameters
-        )
-        message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id)
-        return await self.get_bot().send_message(
-            chat_id=chat_id,
-            text=text,
-            parse_mode=ParseMode.MARKDOWN_V2,
-            disable_web_page_preview=disable_web_page_preview,
-            link_preview_options=link_preview_options,
-            disable_notification=disable_notification,
-            reply_parameters=effective_reply_parameters,
-            reply_markup=reply_markup,
-            allow_sending_without_reply=allow_sending_without_reply,
-            entities=entities,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=self.business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def reply_html(
-        self,
-        text: str,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-        link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        disable_web_page_preview: Optional[bool] = None,
-        quote: Optional[bool] = None,
-        do_quote: Optional[Union[bool, _ReplyKwargs]] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-            await bot.send_message(
-                update.effective_message.chat_id,
-                message_thread_id=update.effective_message.message_thread_id,
-                parse_mode=ParseMode.HTML,
-                business_connection_id=self.business_connection_id,
-                *args,
-                **kwargs,
-            )
-
-        Sends a message with HTML formatting.
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`.
-
-        .. versionchanged:: 21.1
-                |reply_same_thread|
-
-        Keyword Args:
-            quote (:obj:`bool`, optional): |reply_quote|
-
-                .. deprecated:: 20.8
-                    This argument is deprecated in favor of :paramref:`do_quote`
-            do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
-                Mutually exclusive with :paramref:`quote`.
-
-                .. versionadded:: 20.8
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-        """
-        chat_id, effective_reply_parameters = await self._parse_quote_arguments(
-            do_quote, quote, reply_to_message_id, reply_parameters
-        )
-        message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id)
-        return await self.get_bot().send_message(
-            chat_id=chat_id,
-            text=text,
-            parse_mode=ParseMode.HTML,
-            disable_web_page_preview=disable_web_page_preview,
-            link_preview_options=link_preview_options,
-            disable_notification=disable_notification,
-            reply_parameters=effective_reply_parameters,
-            reply_markup=reply_markup,
-            allow_sending_without_reply=allow_sending_without_reply,
-            entities=entities,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=self.business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def reply_media_group(
-        self,
-        media: Sequence[
-            Union["InputMediaAudio", "InputMediaDocument", "InputMediaPhoto", "InputMediaVideo"]
-        ],
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        quote: Optional[bool] = None,
-        do_quote: Optional[Union[bool, _ReplyKwargs]] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-        caption: Optional[str] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-    ) -> tuple["Message", ...]:
-        """Shortcut for::
-
-             await bot.send_media_group(
-                 update.effective_message.chat_id,
-                 message_thread_id=update.effective_message.message_thread_id,
-                 business_connection_id=self.business_connection_id,
-                 *args,
-                 **kwargs,
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_media_group`.
-
-        .. versionchanged:: 21.1
-                |reply_same_thread|
-
-        Keyword Args:
-            quote (:obj:`bool`, optional): |reply_quote|
-
-                .. deprecated:: 20.8
-                    This argument is deprecated in favor of :paramref:`do_quote`
-            do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
-                Mutually exclusive with :paramref:`quote`.
-
-                .. versionadded:: 20.8
-
-        Returns:
-            tuple[:class:`telegram.Message`]: An array of the sent Messages.
-
-        Raises:
-            :class:`telegram.error.TelegramError`
-        """
-        chat_id, effective_reply_parameters = await self._parse_quote_arguments(
-            do_quote, quote, reply_to_message_id, reply_parameters
-        )
-        message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id)
-        return await self.get_bot().send_media_group(
-            chat_id=chat_id,
-            media=media,
-            disable_notification=disable_notification,
-            reply_parameters=effective_reply_parameters,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            caption=caption,
-            parse_mode=parse_mode,
-            caption_entities=caption_entities,
-            business_connection_id=self.business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def reply_photo(
-        self,
-        photo: Union[FileInput, "PhotoSize"],
-        caption: Optional[str] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-        has_spoiler: Optional[bool] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        show_caption_above_media: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        filename: Optional[str] = None,
-        quote: Optional[bool] = None,
-        do_quote: Optional[Union[bool, _ReplyKwargs]] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_photo(
-                 update.effective_message.chat_id,
-                 message_thread_id=update.effective_message.message_thread_id,
-                 business_connection_id=self.business_connection_id,
-                 *args,
-                 **kwargs,
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_photo`.
-
-        .. versionchanged:: 21.1
-                |reply_same_thread|
-
-        Keyword Args:
-            quote (:obj:`bool`, optional): |reply_quote|
-
-                .. deprecated:: 20.8
-                    This argument is deprecated in favor of :paramref:`do_quote`
-            do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
-                Mutually exclusive with :paramref:`quote`.
-
-                .. versionadded:: 20.8
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        chat_id, effective_reply_parameters = await self._parse_quote_arguments(
-            do_quote, quote, reply_to_message_id, reply_parameters
-        )
-        message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id)
-        return await self.get_bot().send_photo(
-            chat_id=chat_id,
-            photo=photo,
-            caption=caption,
-            disable_notification=disable_notification,
-            reply_parameters=effective_reply_parameters,
-            reply_markup=reply_markup,
-            parse_mode=parse_mode,
-            allow_sending_without_reply=allow_sending_without_reply,
-            caption_entities=caption_entities,
-            filename=filename,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            has_spoiler=has_spoiler,
-            business_connection_id=self.business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-            show_caption_above_media=show_caption_above_media,
-        )
-
-    async def reply_audio(
-        self,
-        audio: Union[FileInput, "Audio"],
-        duration: Optional[int] = None,
-        performer: Optional[str] = None,
-        title: Optional[str] = None,
-        caption: Optional[str] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-        thumbnail: Optional[FileInput] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        filename: Optional[str] = None,
-        quote: Optional[bool] = None,
-        do_quote: Optional[Union[bool, _ReplyKwargs]] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_audio(
-                 update.effective_message.chat_id,
-                 message_thread_id=update.effective_message.message_thread_id,
-                 business_connection_id=self.business_connection_id,
-                 *args,
-                 **kwargs,
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_audio`.
-
-        .. versionchanged:: 21.1
-                |reply_same_thread|
-
-        Keyword Args:
-            quote (:obj:`bool`, optional): |reply_quote|
-
-                .. deprecated:: 20.8
-                    This argument is deprecated in favor of :paramref:`do_quote`
-            do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
-                Mutually exclusive with :paramref:`quote`.
-
-                .. versionadded:: 20.8
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        chat_id, effective_reply_parameters = await self._parse_quote_arguments(
-            do_quote, quote, reply_to_message_id, reply_parameters
-        )
-        message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id)
-        return await self.get_bot().send_audio(
-            chat_id=chat_id,
-            audio=audio,
-            duration=duration,
-            performer=performer,
-            title=title,
-            caption=caption,
-            disable_notification=disable_notification,
-            reply_parameters=effective_reply_parameters,
-            reply_markup=reply_markup,
-            parse_mode=parse_mode,
-            allow_sending_without_reply=allow_sending_without_reply,
-            caption_entities=caption_entities,
-            filename=filename,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            thumbnail=thumbnail,
-            business_connection_id=self.business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def reply_document(
-        self,
-        document: Union[FileInput, "Document"],
-        caption: Optional[str] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        disable_content_type_detection: Optional[bool] = None,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-        thumbnail: Optional[FileInput] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        filename: Optional[str] = None,
-        quote: Optional[bool] = None,
-        do_quote: Optional[Union[bool, _ReplyKwargs]] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_document(
-                 update.effective_message.chat_id,
-                 message_thread_id=update.effective_message.message_thread_id,
-                 business_connection_id=self.business_connection_id,
-                 *args,
-                 **kwargs,
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_document`.
-
-        .. versionchanged:: 21.1
-                |reply_same_thread|
-
-        Keyword Args:
-            quote (:obj:`bool`, optional): |reply_quote|
-
-                .. deprecated:: 20.8
-                    This argument is deprecated in favor of :paramref:`do_quote`
-            do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
-                Mutually exclusive with :paramref:`quote`.
-
-                .. versionadded:: 20.8
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        chat_id, effective_reply_parameters = await self._parse_quote_arguments(
-            do_quote, quote, reply_to_message_id, reply_parameters
-        )
-        message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id)
-        return await self.get_bot().send_document(
-            chat_id=chat_id,
-            document=document,
-            filename=filename,
-            caption=caption,
-            disable_notification=disable_notification,
-            reply_parameters=effective_reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            parse_mode=parse_mode,
-            api_kwargs=api_kwargs,
-            disable_content_type_detection=disable_content_type_detection,
-            allow_sending_without_reply=allow_sending_without_reply,
-            caption_entities=caption_entities,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            thumbnail=thumbnail,
-            business_connection_id=self.business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def reply_animation(
-        self,
-        animation: Union[FileInput, "Animation"],
-        duration: Optional[int] = None,
-        width: Optional[int] = None,
-        height: Optional[int] = None,
-        caption: Optional[str] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-        has_spoiler: Optional[bool] = None,
-        thumbnail: Optional[FileInput] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        show_caption_above_media: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        filename: Optional[str] = None,
-        quote: Optional[bool] = None,
-        do_quote: Optional[Union[bool, _ReplyKwargs]] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_animation(
-                 update.effective_message.chat_id,
-                 message_thread_id=update.effective_message.message_thread_id,
-                 business_connection_id=self.business_connection_id,
-                 *args,
-                 **kwargs,
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_animation`.
-
-        .. versionchanged:: 21.1
-                |reply_same_thread|
-
-        Keyword Args:
-            quote (:obj:`bool`, optional): |reply_quote|
-
-                .. deprecated:: 20.8
-                    This argument is deprecated in favor of :paramref:`do_quote`
-            do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
-                Mutually exclusive with :paramref:`quote`.
-
-                .. versionadded:: 20.8
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        chat_id, effective_reply_parameters = await self._parse_quote_arguments(
-            do_quote, quote, reply_to_message_id, reply_parameters
-        )
-        message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id)
-        return await self.get_bot().send_animation(
-            chat_id=chat_id,
-            animation=animation,
-            duration=duration,
-            width=width,
-            height=height,
-            caption=caption,
-            parse_mode=parse_mode,
-            disable_notification=disable_notification,
-            reply_parameters=effective_reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            allow_sending_without_reply=allow_sending_without_reply,
-            caption_entities=caption_entities,
-            filename=filename,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            has_spoiler=has_spoiler,
-            thumbnail=thumbnail,
-            business_connection_id=self.business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-            show_caption_above_media=show_caption_above_media,
-        )
-
-    async def reply_sticker(
-        self,
-        sticker: Union[FileInput, "Sticker"],
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-        emoji: Optional[str] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        quote: Optional[bool] = None,
-        do_quote: Optional[Union[bool, _ReplyKwargs]] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_sticker(
-                 update.effective_message.chat_id,
-                 message_thread_id=update.effective_message.message_thread_id,
-                 business_connection_id=self.business_connection_id,
-                 *args,
-                 **kwargs,
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_sticker`.
-
-        .. versionchanged:: 21.1
-                |reply_same_thread|
-
-        Keyword Args:
-            quote (:obj:`bool`, optional): |reply_quote|
-
-                .. deprecated:: 20.8
-                    This argument is deprecated in favor of :paramref:`do_quote`
-            do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
-                Mutually exclusive with :paramref:`quote`.
-
-                .. versionadded:: 20.8
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        chat_id, effective_reply_parameters = await self._parse_quote_arguments(
-            do_quote, quote, reply_to_message_id, reply_parameters
-        )
-        message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id)
-        return await self.get_bot().send_sticker(
-            chat_id=chat_id,
-            sticker=sticker,
-            disable_notification=disable_notification,
-            reply_parameters=effective_reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            emoji=emoji,
-            business_connection_id=self.business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def reply_video(
-        self,
-        video: Union[FileInput, "Video"],
-        duration: Optional[int] = None,
-        caption: Optional[str] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        width: Optional[int] = None,
-        height: Optional[int] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        supports_streaming: Optional[bool] = None,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-        has_spoiler: Optional[bool] = None,
-        thumbnail: Optional[FileInput] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        show_caption_above_media: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        filename: Optional[str] = None,
-        quote: Optional[bool] = None,
-        do_quote: Optional[Union[bool, _ReplyKwargs]] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_video(
-                 update.effective_message.chat_id,
-                 message_thread_id=update.effective_message.message_thread_id,
-                 business_connection_id=self.business_connection_id,
-                 *args,
-                 **kwargs,
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_video`.
-
-        .. versionchanged:: 21.1
-                |reply_same_thread|
-
-        Keyword Args:
-            quote (:obj:`bool`, optional): |reply_quote|
-
-                .. deprecated:: 20.8
-                    This argument is deprecated in favor of :paramref:`do_quote`
-            do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
-                Mutually exclusive with :paramref:`quote`.
-
-                .. versionadded:: 20.8
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        chat_id, effective_reply_parameters = await self._parse_quote_arguments(
-            do_quote, quote, reply_to_message_id, reply_parameters
-        )
-        message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id)
-        return await self.get_bot().send_video(
-            chat_id=chat_id,
-            video=video,
-            duration=duration,
-            caption=caption,
-            disable_notification=disable_notification,
-            reply_parameters=effective_reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            width=width,
-            height=height,
-            parse_mode=parse_mode,
-            supports_streaming=supports_streaming,
-            api_kwargs=api_kwargs,
-            allow_sending_without_reply=allow_sending_without_reply,
-            caption_entities=caption_entities,
-            filename=filename,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            has_spoiler=has_spoiler,
-            thumbnail=thumbnail,
-            business_connection_id=self.business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-            show_caption_above_media=show_caption_above_media,
-        )
-
-    async def reply_video_note(
-        self,
-        video_note: Union[FileInput, "VideoNote"],
-        duration: Optional[int] = None,
-        length: Optional[int] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-        thumbnail: Optional[FileInput] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        filename: Optional[str] = None,
-        quote: Optional[bool] = None,
-        do_quote: Optional[Union[bool, _ReplyKwargs]] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_video_note(
-                 update.effective_message.chat_id,
-                 message_thread_id=update.effective_message.message_thread_id,
-                 business_connection_id=self.business_connection_id,
-                 *args,
-                 **kwargs,
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_video_note`.
-
-        .. versionchanged:: 21.1
-                |reply_same_thread|
-
-        Keyword Args:
-            quote (:obj:`bool`, optional): |reply_quote|
-
-                .. deprecated:: 20.8
-                    This argument is deprecated in favor of :paramref:`do_quote`
-            do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
-                Mutually exclusive with :paramref:`quote`.
-
-                .. versionadded:: 20.8
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        chat_id, effective_reply_parameters = await self._parse_quote_arguments(
-            do_quote, quote, reply_to_message_id, reply_parameters
-        )
-        message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id)
-        return await self.get_bot().send_video_note(
-            chat_id=chat_id,
-            video_note=video_note,
-            duration=duration,
-            length=length,
-            disable_notification=disable_notification,
-            reply_parameters=effective_reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            allow_sending_without_reply=allow_sending_without_reply,
-            filename=filename,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            thumbnail=thumbnail,
-            business_connection_id=self.business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def reply_voice(
-        self,
-        voice: Union[FileInput, "Voice"],
-        duration: Optional[int] = None,
-        caption: Optional[str] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        filename: Optional[str] = None,
-        quote: Optional[bool] = None,
-        do_quote: Optional[Union[bool, _ReplyKwargs]] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_voice(
-                 update.effective_message.chat_id,
-                 message_thread_id=update.effective_message.message_thread_id,
-                 business_connection_id=self.business_connection_id,
-                 *args,
-                 **kwargs,
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_voice`.
-
-        .. versionchanged:: 21.1
-                |reply_same_thread|
-
-        Keyword Args:
-            quote (:obj:`bool`, optional): |reply_quote|
-
-                .. deprecated:: 20.8
-                    This argument is deprecated in favor of :paramref:`do_quote`
-            do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
-                Mutually exclusive with :paramref:`quote`.
-
-                .. versionadded:: 20.8
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        chat_id, effective_reply_parameters = await self._parse_quote_arguments(
-            do_quote, quote, reply_to_message_id, reply_parameters
-        )
-        message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id)
-        return await self.get_bot().send_voice(
-            chat_id=chat_id,
-            voice=voice,
-            duration=duration,
-            caption=caption,
-            disable_notification=disable_notification,
-            reply_parameters=effective_reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            parse_mode=parse_mode,
-            api_kwargs=api_kwargs,
-            allow_sending_without_reply=allow_sending_without_reply,
-            caption_entities=caption_entities,
-            filename=filename,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            business_connection_id=self.business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def reply_location(
-        self,
-        latitude: Optional[float] = None,
-        longitude: Optional[float] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        live_period: Optional[int] = None,
-        horizontal_accuracy: Optional[float] = None,
-        heading: Optional[int] = None,
-        proximity_alert_radius: Optional[int] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        location: Optional[Location] = None,
-        quote: Optional[bool] = None,
-        do_quote: Optional[Union[bool, _ReplyKwargs]] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_location(
-                 update.effective_message.chat_id,
-                 message_thread_id=update.effective_message.message_thread_id,
-                 business_connection_id=self.business_connection_id,
-                 *args,
-                 **kwargs,
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_location`.
-
-        .. versionchanged:: 21.1
-                |reply_same_thread|
-
-        Keyword Args:
-            quote (:obj:`bool`, optional): |reply_quote|
-
-                .. deprecated:: 20.8
-                    This argument is deprecated in favor of :paramref:`do_quote`
-            do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
-                Mutually exclusive with :paramref:`quote`.
-
-                .. versionadded:: 20.8
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        chat_id, effective_reply_parameters = await self._parse_quote_arguments(
-            do_quote, quote, reply_to_message_id, reply_parameters
-        )
-        message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id)
-        return await self.get_bot().send_location(
-            chat_id=chat_id,
-            latitude=latitude,
-            longitude=longitude,
-            disable_notification=disable_notification,
-            reply_parameters=effective_reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            location=location,
-            live_period=live_period,
-            api_kwargs=api_kwargs,
-            horizontal_accuracy=horizontal_accuracy,
-            heading=heading,
-            proximity_alert_radius=proximity_alert_radius,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            business_connection_id=self.business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def reply_venue(
-        self,
-        latitude: Optional[float] = None,
-        longitude: Optional[float] = None,
-        title: Optional[str] = None,
-        address: Optional[str] = None,
-        foursquare_id: Optional[str] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        foursquare_type: Optional[str] = None,
-        google_place_id: Optional[str] = None,
-        google_place_type: Optional[str] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        venue: Optional[Venue] = None,
-        quote: Optional[bool] = None,
-        do_quote: Optional[Union[bool, _ReplyKwargs]] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_venue(
-                 update.effective_message.chat_id,
-                 message_thread_id=update.effective_message.message_thread_id,
-                 business_connection_id=self.business_connection_id,
-                 *args,
-                 **kwargs,
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_venue`.
-
-        .. versionchanged:: 21.1
-                |reply_same_thread|
-
-        Keyword Args:
-            quote (:obj:`bool`, optional): |reply_quote|
-
-                .. deprecated:: 20.8
-                    This argument is deprecated in favor of :paramref:`do_quote`
-            do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
-                Mutually exclusive with :paramref:`quote`.
-
-                .. versionadded:: 20.8
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        chat_id, effective_reply_parameters = await self._parse_quote_arguments(
-            do_quote, quote, reply_to_message_id, reply_parameters
-        )
-        message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id)
-        return await self.get_bot().send_venue(
-            chat_id=chat_id,
-            latitude=latitude,
-            longitude=longitude,
-            title=title,
-            address=address,
-            foursquare_id=foursquare_id,
-            disable_notification=disable_notification,
-            reply_parameters=effective_reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            venue=venue,
-            foursquare_type=foursquare_type,
-            api_kwargs=api_kwargs,
-            google_place_id=google_place_id,
-            google_place_type=google_place_type,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            business_connection_id=self.business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def reply_contact(
-        self,
-        phone_number: Optional[str] = None,
-        first_name: Optional[str] = None,
-        last_name: Optional[str] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        vcard: Optional[str] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        contact: Optional[Contact] = None,
-        quote: Optional[bool] = None,
-        do_quote: Optional[Union[bool, _ReplyKwargs]] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_contact(
-                 update.effective_message.chat_id,
-                 message_thread_id=update.effective_message.message_thread_id,
-                 business_connection_id=self.business_connection_id,
-                 *args,
-                 **kwargs,
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_contact`.
-
-        .. versionchanged:: 21.1
-                |reply_same_thread|
-
-        Keyword Args:
-            quote (:obj:`bool`, optional): |reply_quote|
-
-                .. deprecated:: 20.8
-                    This argument is deprecated in favor of :paramref:`do_quote`
-            do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
-                Mutually exclusive with :paramref:`quote`.
-
-                .. versionadded:: 20.8
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        chat_id, effective_reply_parameters = await self._parse_quote_arguments(
-            do_quote, quote, reply_to_message_id, reply_parameters
-        )
-        message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id)
-        return await self.get_bot().send_contact(
-            chat_id=chat_id,
-            phone_number=phone_number,
-            first_name=first_name,
-            last_name=last_name,
-            disable_notification=disable_notification,
-            reply_parameters=effective_reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            contact=contact,
-            vcard=vcard,
-            api_kwargs=api_kwargs,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            business_connection_id=self.business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def reply_poll(
-        self,
-        question: str,
-        options: Sequence[Union[str, "InputPollOption"]],
-        is_anonymous: Optional[bool] = None,
-        type: Optional[str] = None,  # pylint: disable=redefined-builtin
-        allows_multiple_answers: Optional[bool] = None,
-        correct_option_id: Optional[CorrectOptionID] = None,
-        is_closed: Optional[bool] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        explanation: Optional[str] = None,
-        explanation_parse_mode: ODVInput[str] = DEFAULT_NONE,
-        open_period: Optional[int] = None,
-        close_date: Optional[Union[int, dtm.datetime]] = None,
-        explanation_entities: Optional[Sequence["MessageEntity"]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        question_parse_mode: ODVInput[str] = DEFAULT_NONE,
-        question_entities: Optional[Sequence["MessageEntity"]] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        quote: Optional[bool] = None,
-        do_quote: Optional[Union[bool, _ReplyKwargs]] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_poll(
-                 update.effective_message.chat_id,
-                 message_thread_id=update.effective_message.message_thread_id,
-                 business_connection_id=self.business_connection_id,
-                 *args,
-                 **kwargs,
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_poll`.
-
-        .. versionchanged:: 21.1
-                |reply_same_thread|
-
-        Keyword Args:
-            quote (:obj:`bool`, optional): |reply_quote|
-
-                .. deprecated:: 20.8
-                    This argument is deprecated in favor of :paramref:`do_quote`
-            do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
-                Mutually exclusive with :paramref:`quote`.
-
-                .. versionadded:: 20.8
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        chat_id, effective_reply_parameters = await self._parse_quote_arguments(
-            do_quote, quote, reply_to_message_id, reply_parameters
-        )
-        message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id)
-        return await self.get_bot().send_poll(
-            chat_id=chat_id,
-            question=question,
-            options=options,
-            is_anonymous=is_anonymous,
-            type=type,
-            allows_multiple_answers=allows_multiple_answers,
-            correct_option_id=correct_option_id,
-            is_closed=is_closed,
-            disable_notification=disable_notification,
-            reply_parameters=effective_reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            explanation=explanation,
-            explanation_parse_mode=explanation_parse_mode,
-            open_period=open_period,
-            close_date=close_date,
-            api_kwargs=api_kwargs,
-            allow_sending_without_reply=allow_sending_without_reply,
-            explanation_entities=explanation_entities,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            business_connection_id=self.business_connection_id,
-            question_parse_mode=question_parse_mode,
-            question_entities=question_entities,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def reply_dice(
-        self,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        emoji: Optional[str] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        quote: Optional[bool] = None,
-        do_quote: Optional[Union[bool, _ReplyKwargs]] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_dice(
-                 update.effective_message.chat_id,
-                 message_thread_id=update.effective_message.message_thread_id,
-                 business_connection_id=self.business_connection_id,
-                 *args,
-                 **kwargs,
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_dice`.
-
-        .. versionchanged:: 21.1
-                |reply_same_thread|
-
-        Keyword Args:
-            quote (:obj:`bool`, optional): |reply_quote|
-
-                .. deprecated:: 20.8
-                    This argument is deprecated in favor of :paramref:`do_quote`
-            do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
-                Mutually exclusive with :paramref:`quote`.
-
-                .. versionadded:: 20.8
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        chat_id, effective_reply_parameters = await self._parse_quote_arguments(
-            do_quote, quote, reply_to_message_id, reply_parameters
-        )
-        message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id)
-        return await self.get_bot().send_dice(
-            chat_id=chat_id,
-            disable_notification=disable_notification,
-            reply_parameters=effective_reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            emoji=emoji,
-            api_kwargs=api_kwargs,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            business_connection_id=self.business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def reply_chat_action(
-        self,
-        action: str,
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.send_chat_action(
-                 update.effective_message.chat_id,
-                 message_thread_id=update.effective_message.message_thread_id,
-                 business_connection_id=self.business_connection_id,
-                 *args,
-                 **kwargs,
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_chat_action`.
-
-        .. versionchanged:: 21.1
-                |reply_same_thread|
-
-        .. versionadded:: 13.2
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().send_chat_action(
-            chat_id=self.chat_id,
-            message_thread_id=self._parse_message_thread_id(self.chat_id, message_thread_id),
-            action=action,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=self.business_connection_id,
-        )
-
-    async def reply_game(
-        self,
-        game_short_name: str,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        quote: Optional[bool] = None,
-        do_quote: Optional[Union[bool, _ReplyKwargs]] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_game(
-                 update.effective_message.chat_id,
-                 message_thread_id=update.effective_message.message_thread_id,
-                 business_connection_id=self.business_connection_id,
-                 *args,
-                 **kwargs,
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_game`.
-
-        .. versionchanged:: 21.1
-                |reply_same_thread|
-
-        Keyword Args:
-            quote (:obj:`bool`, optional): |reply_quote|
-
-                .. deprecated:: 20.8
-                    This argument is deprecated in favor of :paramref:`do_quote`
-            do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
-                Mutually exclusive with :paramref:`quote`.
-
-                .. versionadded:: 20.8
-
-        .. versionadded:: 13.2
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        chat_id, effective_reply_parameters = await self._parse_quote_arguments(
-            do_quote, quote, reply_to_message_id, reply_parameters
-        )
-        message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id)
-        return await self.get_bot().send_game(
-            chat_id=chat_id,  # type: ignore[arg-type]
-            game_short_name=game_short_name,
-            disable_notification=disable_notification,
-            reply_parameters=effective_reply_parameters,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            allow_sending_without_reply=allow_sending_without_reply,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            business_connection_id=self.business_connection_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def reply_invoice(
-        self,
-        title: str,
-        description: str,
-        payload: str,
-        provider_token: Optional[str],
-        currency: str,
-        prices: Sequence["LabeledPrice"],
-        start_parameter: Optional[str] = None,
-        photo_url: Optional[str] = None,
-        photo_size: Optional[int] = None,
-        photo_width: Optional[int] = None,
-        photo_height: Optional[int] = None,
-        need_name: Optional[bool] = None,
-        need_phone_number: Optional[bool] = None,
-        need_email: Optional[bool] = None,
-        need_shipping_address: Optional[bool] = None,
-        is_flexible: Optional[bool] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        provider_data: Optional[Union[str, object]] = None,
-        send_phone_number_to_provider: Optional[bool] = None,
-        send_email_to_provider: Optional[bool] = None,
-        max_tip_amount: Optional[int] = None,
-        suggested_tip_amounts: Optional[Sequence[int]] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        message_effect_id: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        quote: Optional[bool] = None,
-        do_quote: Optional[Union[bool, _ReplyKwargs]] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_invoice(
-                 update.effective_message.chat_id,
-                 message_thread_id=update.effective_message.message_thread_id,
-                 *args,
-                 **kwargs,
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_invoice`.
-
-        .. versionchanged:: 21.1
-                |reply_same_thread|
-
-        Warning:
-            As of API 5.2 :paramref:`start_parameter `
-            is an optional argument and therefore the
-            order of the arguments had to be changed. Use keyword arguments to make sure that the
-            arguments are passed correctly.
-
-        .. versionadded:: 13.2
-
-        .. versionchanged:: 13.5
-            As of Bot API 5.2, the parameter
-            :paramref:`start_parameter ` is optional.
-
-        Keyword Args:
-            quote (:obj:`bool`, optional): |reply_quote|
-
-                .. deprecated:: 20.8
-                    This argument is deprecated in favor of :paramref:`do_quote`
-            do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
-                Mutually exclusive with :paramref:`quote`.
-
-                .. versionadded:: 20.8
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message posted.
-
-        """
-        chat_id, effective_reply_parameters = await self._parse_quote_arguments(
-            do_quote, quote, reply_to_message_id, reply_parameters
-        )
-        message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id)
-        return await self.get_bot().send_invoice(
-            chat_id=chat_id,
-            title=title,
-            description=description,
-            payload=payload,
-            provider_token=provider_token,
-            currency=currency,
-            prices=prices,
-            start_parameter=start_parameter,
-            photo_url=photo_url,
-            photo_size=photo_size,
-            photo_width=photo_width,
-            photo_height=photo_height,
-            need_name=need_name,
-            need_phone_number=need_phone_number,
-            need_email=need_email,
-            need_shipping_address=need_shipping_address,
-            is_flexible=is_flexible,
-            disable_notification=disable_notification,
-            reply_parameters=effective_reply_parameters,
-            reply_markup=reply_markup,
-            provider_data=provider_data,
-            send_phone_number_to_provider=send_phone_number_to_provider,
-            send_email_to_provider=send_email_to_provider,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            allow_sending_without_reply=allow_sending_without_reply,
-            max_tip_amount=max_tip_amount,
-            suggested_tip_amounts=suggested_tip_amounts,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            message_effect_id=message_effect_id,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def forward(
-        self,
-        chat_id: Union[int, str],
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.forward_message(
-                 from_chat_id=update.effective_message.chat_id,
-                 message_id=update.effective_message.message_id,
-                 *args,
-                 **kwargs
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.forward_message`.
-
-        Note:
-            Since the release of Bot API 5.5 it can be impossible to forward messages from
-            some chats. Use the attributes :attr:`telegram.Message.has_protected_content` and
-            :attr:`telegram.ChatFullInfo.has_protected_content` to check this.
-
-            As a workaround, it is still possible to use :meth:`copy`. However, this
-            behaviour is undocumented and might be changed by Telegram.
-
-        Returns:
-            :class:`telegram.Message`: On success, instance representing the message forwarded.
-
-        """
-        return await self.get_bot().forward_message(
-            chat_id=chat_id,
-            from_chat_id=self.chat_id,
-            message_id=self.message_id,
-            disable_notification=disable_notification,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def copy(
-        self,
-        chat_id: Union[int, str],
-        caption: Optional[str] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: Optional[int] = None,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        show_caption_above_media: Optional[bool] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "MessageId":
-        """Shortcut for::
-
-             await bot.copy_message(
-                 chat_id=chat_id,
-                 from_chat_id=update.effective_message.chat_id,
-                 message_id=update.effective_message.message_id,
-                 *args,
-                 **kwargs
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`.
-
-        Returns:
-            :class:`telegram.MessageId`: On success, returns the MessageId of the sent message.
-
-        """
-        return await self.get_bot().copy_message(
-            chat_id=chat_id,
-            from_chat_id=self.chat_id,
-            message_id=self.message_id,
-            caption=caption,
-            parse_mode=parse_mode,
-            caption_entities=caption_entities,
-            disable_notification=disable_notification,
-            reply_to_message_id=reply_to_message_id,
-            reply_parameters=reply_parameters,
-            allow_sending_without_reply=allow_sending_without_reply,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            show_caption_above_media=show_caption_above_media,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def reply_copy(
-        self,
-        from_chat_id: Union[str, int],
-        message_id: int,
-        caption: Optional[str] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        reply_markup: Optional[ReplyMarkup] = None,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        message_thread_id: ODVInput[int] = DEFAULT_NONE,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        show_caption_above_media: Optional[bool] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        quote: Optional[bool] = None,
-        do_quote: Optional[Union[bool, _ReplyKwargs]] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "MessageId":
-        """Shortcut for::
-
-             await bot.copy_message(
-                 chat_id=message.chat.id,
-                 message_thread_id=update.effective_message.message_thread_id,
-                 message_id=message_id,
-                 *args,
-                 **kwargs
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`.
-
-        .. versionchanged:: 21.1
-                |reply_same_thread|
-
-        Keyword Args:
-            quote (:obj:`bool`, optional): |reply_quote|
-
-                .. versionadded:: 13.1
-                .. deprecated:: 20.8
-                    This argument is deprecated in favor of :paramref:`do_quote`
-            do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
-                Mutually exclusive with :paramref:`quote`.
-
-                .. versionadded:: 20.8
-
-        Returns:
-            :class:`telegram.MessageId`: On success, returns the MessageId of the sent message.
-
-        """
-        chat_id, effective_reply_parameters = await self._parse_quote_arguments(
-            do_quote, quote, reply_to_message_id, reply_parameters
-        )
-        message_thread_id = self._parse_message_thread_id(chat_id, message_thread_id)
-        return await self.get_bot().copy_message(
-            chat_id=chat_id,
-            from_chat_id=from_chat_id,
-            message_id=message_id,
-            caption=caption,
-            parse_mode=parse_mode,
-            caption_entities=caption_entities,
-            disable_notification=disable_notification,
-            reply_parameters=effective_reply_parameters,
-            allow_sending_without_reply=allow_sending_without_reply,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            protect_content=protect_content,
-            message_thread_id=message_thread_id,
-            show_caption_above_media=show_caption_above_media,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def reply_paid_media(
-        self,
-        star_count: int,
-        media: Sequence["InputPaidMedia"],
-        caption: Optional[str] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        show_caption_above_media: Optional[bool] = None,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        protect_content: ODVInput[bool] = DEFAULT_NONE,
-        reply_parameters: Optional["ReplyParameters"] = None,
-        reply_markup: Optional[ReplyMarkup] = None,
-        payload: Optional[str] = None,
-        allow_paid_broadcast: Optional[bool] = None,
-        *,
-        reply_to_message_id: Optional[int] = None,
-        allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
-        do_quote: Optional[Union[bool, _ReplyKwargs]] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> "Message":
-        """Shortcut for::
-
-             await bot.send_paid_media(
-                 chat_id=message.chat.id,
-                 business_connection_id=message.business_connection_id,
-                 *args,
-                 **kwargs
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.send_paid_media`.
-
-        .. versionadded:: 21.7
-
-        Keyword Args:
-            do_quote (:obj:`bool` | :obj:`dict`, optional): |do_quote|
-                Mutually exclusive with :paramref:`quote`.
-
-        Returns:
-            :class:`telegram.Message`: On success, the sent message is returned.
-
-        """
-        chat_id, effective_reply_parameters = await self._parse_quote_arguments(
-            do_quote, None, reply_to_message_id, reply_parameters
-        )
-        return await self.get_bot().send_paid_media(
-            chat_id=chat_id,
-            caption=caption,
-            star_count=star_count,
-            media=media,
-            payload=payload,
-            business_connection_id=self.business_connection_id,
-            parse_mode=parse_mode,
-            caption_entities=caption_entities,
-            disable_notification=disable_notification,
-            reply_parameters=effective_reply_parameters,
-            allow_sending_without_reply=allow_sending_without_reply,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            protect_content=protect_content,
-            show_caption_above_media=show_caption_above_media,
-            allow_paid_broadcast=allow_paid_broadcast,
-        )
-
-    async def edit_text(
-        self,
-        text: str,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        entities: Optional[Sequence["MessageEntity"]] = None,
-        link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE,
-        *,
-        disable_web_page_preview: Optional[bool] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Union["Message", bool]:
-        """Shortcut for::
-
-             await bot.edit_message_text(
-                 chat_id=message.chat_id,
-                 message_id=message.message_id,
-                 business_connection_id=message.business_connection_id,
-                 *args, **kwargs
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.edit_message_text`.
-
-        Note:
-            You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family
-            of methods) or channel posts, if the bot is an admin in that channel. However, this
-            behaviour is undocumented and might be changed by Telegram.
-
-        .. versionchanged:: 21.4
-           Now also passes :attr:`business_connection_id`.
-
-        Returns:
-            :class:`telegram.Message`: On success, if edited message is sent by the bot, the
-            edited Message is returned, otherwise ``True`` is returned.
-
-        """
-        return await self.get_bot().edit_message_text(
-            chat_id=self.chat_id,
-            message_id=self.message_id,
-            text=text,
-            parse_mode=parse_mode,
-            disable_web_page_preview=disable_web_page_preview,
-            link_preview_options=link_preview_options,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            entities=entities,
-            inline_message_id=None,
-            business_connection_id=self.business_connection_id,
-        )
-
-    async def edit_caption(
-        self,
-        caption: Optional[str] = None,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        parse_mode: ODVInput[str] = DEFAULT_NONE,
-        caption_entities: Optional[Sequence["MessageEntity"]] = None,
-        show_caption_above_media: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Union["Message", bool]:
-        """Shortcut for::
-
-             await bot.edit_message_caption(
-                 chat_id=message.chat_id,
-                 message_id=message.message_id,
-                 business_connection_id=message.business_connection_id,
-                 *args, **kwargs
-             )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.edit_message_caption`.
-
-        Note:
-            You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family
-            of methods) or channel posts, if the bot is an admin in that channel. However, this
-            behaviour is undocumented and might be changed by Telegram.
-
-        .. versionchanged:: 21.4
-           Now also passes :attr:`business_connection_id`.
-
-        Returns:
-            :class:`telegram.Message`: On success, if edited message is sent by the bot, the
-            edited Message is returned, otherwise ``True`` is returned.
-
-        """
-        return await self.get_bot().edit_message_caption(
-            chat_id=self.chat_id,
-            message_id=self.message_id,
-            caption=caption,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            parse_mode=parse_mode,
-            api_kwargs=api_kwargs,
-            caption_entities=caption_entities,
-            inline_message_id=None,
-            show_caption_above_media=show_caption_above_media,
-            business_connection_id=self.business_connection_id,
-        )
-
-    async def edit_media(
-        self,
-        media: "InputMedia",
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Union["Message", bool]:
-        """Shortcut for::
-
-             await bot.edit_message_media(
-                 chat_id=message.chat_id,
-                 message_id=message.message_id,
-                 business_connection_id=message.business_connection_id,
-                 *args, **kwargs
-             )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.edit_message_media`.
-
-        Note:
-            You can only edit messages that the bot sent itself(i.e. of the ``bot.send_*`` family
-            of methods) or channel posts, if the bot is an admin in that channel. However, this
-            behaviour is undocumented and might be changed by Telegram.
-
-        .. versionchanged:: 21.4
-           Now also passes :attr:`business_connection_id`.
-
-        Returns:
-            :class:`telegram.Message`: On success, if edited message is not an inline message, the
-            edited Message is returned, otherwise ``True`` is returned.
-
-        """
-        return await self.get_bot().edit_message_media(
-            media=media,
-            chat_id=self.chat_id,
-            message_id=self.message_id,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            inline_message_id=None,
-            business_connection_id=self.business_connection_id,
-        )
-
-    async def edit_reply_markup(
-        self,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Union["Message", bool]:
-        """Shortcut for::
-
-             await bot.edit_message_reply_markup(
-                 chat_id=message.chat_id,
-                 message_id=message.message_id,
-                 business_connection_id=message.business_connection_id,
-                 *args, **kwargs
-             )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.edit_message_reply_markup`.
-
-        Note:
-            You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family
-            of methods) or channel posts, if the bot is an admin in that channel. However, this
-            behaviour is undocumented and might be changed by Telegram.
-
-        .. versionchanged:: 21.4
-           Now also passes :attr:`business_connection_id`.
-
-        Returns:
-            :class:`telegram.Message`: On success, if edited message is sent by the bot, the
-            edited Message is returned, otherwise ``True`` is returned.
-        """
-        return await self.get_bot().edit_message_reply_markup(
-            chat_id=self.chat_id,
-            message_id=self.message_id,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            inline_message_id=None,
-            business_connection_id=self.business_connection_id,
-        )
-
-    async def edit_live_location(
-        self,
-        latitude: Optional[float] = None,
-        longitude: Optional[float] = None,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        horizontal_accuracy: Optional[float] = None,
-        heading: Optional[int] = None,
-        proximity_alert_radius: Optional[int] = None,
-        live_period: Optional[int] = None,
-        *,
-        location: Optional[Location] = None,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Union["Message", bool]:
-        """Shortcut for::
-
-             await bot.edit_message_live_location(
-                 chat_id=message.chat_id,
-                 message_id=message.message_id,
-                 business_connection_id=message.business_connection_id,
-                 *args, **kwargs
-             )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.edit_message_live_location`.
-
-        Note:
-            You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family
-            of methods) or channel posts, if the bot is an admin in that channel. However, this
-            behaviour is undocumented and might be changed by Telegram.
-
-        .. versionchanged:: 21.4
-           Now also passes :attr:`business_connection_id`.
-
-        Returns:
-            :class:`telegram.Message`: On success, if edited message is sent by the bot, the
-            edited Message is returned, otherwise :obj:`True` is returned.
-        """
-        return await self.get_bot().edit_message_live_location(
-            chat_id=self.chat_id,
-            message_id=self.message_id,
-            latitude=latitude,
-            longitude=longitude,
-            location=location,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            horizontal_accuracy=horizontal_accuracy,
-            heading=heading,
-            proximity_alert_radius=proximity_alert_radius,
-            live_period=live_period,
-            inline_message_id=None,
-            business_connection_id=self.business_connection_id,
-        )
-
-    async def stop_live_location(
-        self,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Union["Message", bool]:
-        """Shortcut for::
-
-             await bot.stop_message_live_location(
-                 chat_id=message.chat_id,
-                 message_id=message.message_id,
-                 business_connection_id=message.business_connection_id,
-                 *args, **kwargs
-             )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.stop_message_live_location`.
-
-        Note:
-            You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family
-            of methods) or channel posts, if the bot is an admin in that channel. However, this
-            behaviour is undocumented and might be changed by Telegram.
-
-        .. versionchanged:: 21.4
-           Now also passes :attr:`business_connection_id`.
-
-        Returns:
-            :class:`telegram.Message`: On success, if edited message is sent by the bot, the
-            edited Message is returned, otherwise :obj:`True` is returned.
-        """
-        return await self.get_bot().stop_message_live_location(
-            chat_id=self.chat_id,
-            message_id=self.message_id,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            inline_message_id=None,
-            business_connection_id=self.business_connection_id,
-        )
-
-    async def set_game_score(
-        self,
-        user_id: int,
-        score: int,
-        force: Optional[bool] = None,
-        disable_edit_message: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Union["Message", bool]:
-        """Shortcut for::
-
-             await bot.set_game_score(
-                 chat_id=message.chat_id, message_id=message.message_id, *args, **kwargs
-             )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.set_game_score`.
-
-        Note:
-            You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family
-            of methods) or channel posts, if the bot is an admin in that channel. However, this
-            behaviour is undocumented and might be changed by Telegram.
-
-        Returns:
-            :class:`telegram.Message`: On success, if edited message is sent by the bot, the
-            edited Message is returned, otherwise :obj:`True` is returned.
-        """
-        return await self.get_bot().set_game_score(
-            chat_id=self.chat_id,
-            message_id=self.message_id,
-            user_id=user_id,
-            score=score,
-            force=force,
-            disable_edit_message=disable_edit_message,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            inline_message_id=None,
-        )
-
-    async def get_game_high_scores(
-        self,
-        user_id: int,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> tuple["GameHighScore", ...]:
-        """Shortcut for::
-
-             await bot.get_game_high_scores(
-                 chat_id=message.chat_id, message_id=message.message_id, *args, **kwargs
-             )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.get_game_high_scores`.
-
-        Note:
-            You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family
-            of methods) or channel posts, if the bot is an admin in that channel. However, this
-            behaviour is undocumented and might be changed by Telegram.
-
-        Returns:
-            tuple[:class:`telegram.GameHighScore`]
-        """
-        return await self.get_bot().get_game_high_scores(
-            chat_id=self.chat_id,
-            message_id=self.message_id,
-            user_id=user_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            inline_message_id=None,
-        )
-
-    async def delete(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-              await bot.delete_message(
-                  chat_id=message.chat_id, message_id=message.message_id, *args, **kwargs
-              )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.delete_message`.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().delete_message(
-            chat_id=self.chat_id,
-            message_id=self.message_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def stop_poll(
-        self,
-        reply_markup: Optional["InlineKeyboardMarkup"] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> Poll:
-        """Shortcut for::
-
-              await bot.stop_poll(
-                  chat_id=message.chat_id,
-                  message_id=message.message_id,
-                  business_connection_id=message.business_connection_id,
-                  *args, **kwargs
-              )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.stop_poll`.
-
-        .. versionchanged:: 21.4
-           Now also passes :attr:`business_connection_id`.
-
-        Returns:
-            :class:`telegram.Poll`: On success, the stopped Poll with the final results is
-            returned.
-
-        """
-        return await self.get_bot().stop_poll(
-            chat_id=self.chat_id,
-            message_id=self.message_id,
-            reply_markup=reply_markup,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-            business_connection_id=self.business_connection_id,
-        )
-
-    async def pin(
-        self,
-        disable_notification: ODVInput[bool] = DEFAULT_NONE,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-              await bot.pin_chat_message(
-                  chat_id=message.chat_id,
-                  message_id=message.message_id,
-                  business_connection_id=message.business_connection_id,
-                  *args, **kwargs
-              )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.pin_chat_message`.
-
-        .. versionchanged:: 21.5
-            Now also passes :attr:`business_connection_id` to
-            :meth:`telegram.Bot.pin_chat_message`.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().pin_chat_message(
-            chat_id=self.chat_id,
-            message_id=self.message_id,
-            business_connection_id=self.business_connection_id,
-            disable_notification=disable_notification,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def unpin(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-              await bot.unpin_chat_message(
-                  chat_id=message.chat_id,
-                  message_id=message.message_id,
-                  business_connection_id=message.business_connection_id,
-                  *args, **kwargs
-              )
-
-        For the documentation of the arguments, please see :meth:`telegram.Bot.unpin_chat_message`.
-
-        .. versionchanged:: 21.5
-            Now also passes :attr:`business_connection_id` to
-            :meth:`telegram.Bot.pin_chat_message`.
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-
-        """
-        return await self.get_bot().unpin_chat_message(
-            chat_id=self.chat_id,
-            message_id=self.message_id,
-            business_connection_id=self.business_connection_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def edit_forum_topic(
-        self,
-        name: Optional[str] = None,
-        icon_custom_emoji_id: Optional[str] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.edit_forum_topic(
-                chat_id=message.chat_id, message_thread_id=message.message_thread_id, *args,
-                **kwargs
-             )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.edit_forum_topic`.
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-        """
-        return await self.get_bot().edit_forum_topic(
-            chat_id=self.chat_id,
-            message_thread_id=self.message_thread_id,
-            name=name,
-            icon_custom_emoji_id=icon_custom_emoji_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def close_forum_topic(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.close_forum_topic(
-                chat_id=message.chat_id, message_thread_id=message.message_thread_id, *args,
-                **kwargs
-             )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.close_forum_topic`.
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-        """
-        return await self.get_bot().close_forum_topic(
-            chat_id=self.chat_id,
-            message_thread_id=self.message_thread_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def reopen_forum_topic(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-            await bot.reopen_forum_topic(
-                chat_id=message.chat_id, message_thread_id=message.message_thread_id, *args,
-                **kwargs
-             )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.reopen_forum_topic`.
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-        """
-        return await self.get_bot().reopen_forum_topic(
-            chat_id=self.chat_id,
-            message_thread_id=self.message_thread_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def delete_forum_topic(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.delete_forum_topic(
-                chat_id=message.chat_id, message_thread_id=message.message_thread_id, *args,
-                **kwargs
-             )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.delete_forum_topic`.
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-        """
-        return await self.get_bot().delete_forum_topic(
-            chat_id=self.chat_id,
-            message_thread_id=self.message_thread_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def unpin_all_forum_topic_messages(
-        self,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.unpin_all_forum_topic_messages(
-                chat_id=message.chat_id, message_thread_id=message.message_thread_id, *args,
-                **kwargs
-             )
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.unpin_all_forum_topic_messages`.
-
-        .. versionadded:: 20.0
-
-        Returns:
-            :obj:`bool`: On success, :obj:`True` is returned.
-        """
-        return await self.get_bot().unpin_all_forum_topic_messages(
-            chat_id=self.chat_id,
-            message_thread_id=self.message_thread_id,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    async def set_reaction(
-        self,
-        reaction: Optional[
-            Union[Sequence["ReactionType"], "ReactionType", Sequence[str], str]
-        ] = None,
-        is_big: Optional[bool] = None,
-        *,
-        read_timeout: ODVInput[float] = DEFAULT_NONE,
-        write_timeout: ODVInput[float] = DEFAULT_NONE,
-        connect_timeout: ODVInput[float] = DEFAULT_NONE,
-        pool_timeout: ODVInput[float] = DEFAULT_NONE,
-        api_kwargs: Optional[JSONDict] = None,
-    ) -> bool:
-        """Shortcut for::
-
-             await bot.set_message_reaction(chat_id=message.chat_id, message_id=message.message_id,
-                *args, **kwargs)
-
-        For the documentation of the arguments, please see
-        :meth:`telegram.Bot.set_message_reaction`.
-
-        .. versionadded:: 20.8
-
-        Returns:
-            :obj:`bool` On success, :obj:`True` is returned.
-        """
-        return await self.get_bot().set_message_reaction(
-            chat_id=self.chat_id,
-            message_id=self.message_id,
-            reaction=reaction,
-            is_big=is_big,
-            read_timeout=read_timeout,
-            write_timeout=write_timeout,
-            connect_timeout=connect_timeout,
-            pool_timeout=pool_timeout,
-            api_kwargs=api_kwargs,
-        )
-
-    def parse_entity(self, entity: MessageEntity) -> str:
-        """Returns the text from a given :class:`telegram.MessageEntity`.
-
-        Note:
-            This method is present because Telegram calculates the offset and length in
-            UTF-16 codepoint pairs, which some versions of Python don't handle automatically.
-            (That is, you can't just slice ``Message.text`` with the offset and length.)
-
-        Args:
-            entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must
-                be an entity that belongs to this message.
-
-        Returns:
-            :obj:`str`: The text of the given entity.
-
-        Raises:
-            RuntimeError: If the message has no text.
-
-        """
-        if not self.text:
-            raise RuntimeError("This Message has no 'text'.")
-
-        return parse_message_entity(self.text, entity)
-
-    def parse_caption_entity(self, entity: MessageEntity) -> str:
-        """Returns the text from a given :class:`telegram.MessageEntity`.
-
-        Note:
-            This method is present because Telegram calculates the offset and length in
-            UTF-16 codepoint pairs, which some versions of Python don't handle automatically.
-            (That is, you can't just slice ``Message.caption`` with the offset and length.)
-
-        Args:
-            entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must
-                be an entity that belongs to this message.
-
-        Returns:
-            :obj:`str`: The text of the given entity.
-
-        Raises:
-            RuntimeError: If the message has no caption.
-
-        """
-        if not self.caption:
-            raise RuntimeError("This Message has no 'caption'.")
-
-        return parse_message_entity(self.caption, entity)
-
-    def parse_entities(self, types: Optional[list[str]] = None) -> dict[MessageEntity, str]:
-        """
-        Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`.
-        It contains entities from this message filtered by their
-        :attr:`telegram.MessageEntity.type` attribute as the key, and the text that each entity
-        belongs to as the value of the :obj:`dict`.
-
-        Note:
-            This method should always be used instead of the :attr:`entities` attribute, since it
-            calculates the correct substring from the message text based on UTF-16 codepoints.
-            See :attr:`parse_entity` for more info.
-
-        Args:
-            types (list[:obj:`str`], optional): List of :class:`telegram.MessageEntity` types as
-                strings. If the ``type`` attribute of an entity is contained in this list, it will
-                be returned. Defaults to a list of all types. All types can be found as constants
-                in :class:`telegram.MessageEntity`.
-
-        Returns:
-            dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to
-            the text that belongs to them, calculated based on UTF-16 codepoints.
-
-        """
-        return parse_message_entities(self.text, self.entities, types=types)
-
-    def parse_caption_entities(
-        self, types: Optional[list[str]] = None
-    ) -> dict[MessageEntity, str]:
-        """
-        Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`.
-        It contains entities from this message's caption filtered by their
-        :attr:`telegram.MessageEntity.type` attribute as the key, and the text that each entity
-        belongs to as the value of the :obj:`dict`.
-
-        Note:
-            This method should always be used instead of the :attr:`caption_entities` attribute,
-            since it calculates the correct substring from the message text based on UTF-16
-            codepoints. See :attr:`parse_entity` for more info.
-
-        Args:
-            types (list[:obj:`str`], optional): List of :class:`telegram.MessageEntity` types as
-                strings. If the ``type`` attribute of an entity is contained in this list, it will
-                be returned. Defaults to a list of all types. All types can be found as constants
-                in :class:`telegram.MessageEntity`.
-
-        Returns:
-            dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to
-            the text that belongs to them, calculated based on UTF-16 codepoints.
-
-        """
-        return parse_message_entities(self.caption, self.caption_entities, types=types)
-
-    @classmethod
-    def _parse_html(
-        cls,
-        message_text: Optional[str],
-        entities: dict[MessageEntity, str],
-        urled: bool = False,
-        offset: int = 0,
-    ) -> Optional[str]:
-        if message_text is None:
-            return None
-
-        utf_16_text = message_text.encode(TextEncoding.UTF_16_LE)
-        html_text = ""
-        last_offset = 0
-
-        sorted_entities = sorted(entities.items(), key=lambda item: item[0].offset)
-        parsed_entities = []
-
-        for entity, text in sorted_entities:
-            if entity in parsed_entities:
-                continue
-
-            nested_entities = {
-                e: t
-                for (e, t) in sorted_entities
-                if e.offset >= entity.offset
-                and e.offset + e.length <= entity.offset + entity.length
-                and e != entity
-            }
-            parsed_entities.extend(list(nested_entities.keys()))
-
-            if nested_entities:
-                escaped_text = cls._parse_html(
-                    text, nested_entities, urled=urled, offset=entity.offset
-                )
-            else:
-                escaped_text = escape(text)
-
-            if entity.type == MessageEntity.TEXT_LINK:
-                insert = f'{escaped_text}'
-            elif entity.type == MessageEntity.TEXT_MENTION and entity.user:
-                insert = f'{escaped_text}'
-            elif entity.type == MessageEntity.URL and urled:
-                insert = f'{escaped_text}'
-            elif entity.type == MessageEntity.BLOCKQUOTE:
-                insert = f"
{escaped_text}
" - elif entity.type == MessageEntity.EXPANDABLE_BLOCKQUOTE: - insert = f"
{escaped_text}
" - elif entity.type == MessageEntity.BOLD: - insert = f"{escaped_text}" - elif entity.type == MessageEntity.ITALIC: - insert = f"{escaped_text}" - elif entity.type == MessageEntity.CODE: - insert = f"{escaped_text}" - elif entity.type == MessageEntity.PRE: - if entity.language: - insert = f'
{escaped_text}
' - else: - insert = f"
{escaped_text}
" - elif entity.type == MessageEntity.UNDERLINE: - insert = f"{escaped_text}" - elif entity.type == MessageEntity.STRIKETHROUGH: - insert = f"{escaped_text}" - elif entity.type == MessageEntity.SPOILER: - insert = f'{escaped_text}' - elif entity.type == MessageEntity.CUSTOM_EMOJI: - insert = f'{escaped_text}' - else: - insert = escaped_text - - # Make sure to escape the text that is not part of the entity - # if we're in a nested entity, this is still required, since in that case this - # text is part of the parent entity - html_text += ( - escape( - utf_16_text[last_offset * 2 : (entity.offset - offset) * 2].decode( - TextEncoding.UTF_16_LE - ) - ) - + insert - ) - - last_offset = entity.offset - offset + entity.length - - # see comment above - html_text += escape(utf_16_text[last_offset * 2 :].decode(TextEncoding.UTF_16_LE)) - - return html_text - - @property - def text_html(self) -> str: - """Creates an HTML-formatted string from the markup entities found in the message. - - Use this if you want to retrieve the message text with the entities formatted as HTML in - the same way the original message was formatted. - - Warning: - |text_html| - - .. versionchanged:: 13.10 - Spoiler entities are now formatted as HTML. - - .. versionchanged:: 20.3 - Custom emoji entities are now supported. - - .. versionchanged:: 20.8 - Blockquote entities are now supported. - - Returns: - :obj:`str`: Message text with entities formatted as HTML. - - """ - return self._parse_html(self.text, self.parse_entities(), urled=False) - - @property - def text_html_urled(self) -> str: - """Creates an HTML-formatted string from the markup entities found in the message. - - Use this if you want to retrieve the message text with the entities formatted as HTML. - This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. - - Warning: - |text_html| - - .. versionchanged:: 13.10 - Spoiler entities are now formatted as HTML. - - .. versionchanged:: 20.3 - Custom emoji entities are now supported. - - .. versionchanged:: 20.8 - Blockquote entities are now supported. - - Returns: - :obj:`str`: Message text with entities formatted as HTML. - - """ - return self._parse_html(self.text, self.parse_entities(), urled=True) - - @property - def caption_html(self) -> str: - """Creates an HTML-formatted string from the markup entities found in the message's - caption. - - Use this if you want to retrieve the message caption with the caption entities formatted as - HTML in the same way the original message was formatted. - - Warning: - |text_html| - - .. versionchanged:: 13.10 - Spoiler entities are now formatted as HTML. - - .. versionchanged:: 20.3 - Custom emoji entities are now supported. - - .. versionchanged:: 20.8 - Blockquote entities are now supported. - - Returns: - :obj:`str`: Message caption with caption entities formatted as HTML. - """ - return self._parse_html(self.caption, self.parse_caption_entities(), urled=False) - - @property - def caption_html_urled(self) -> str: - """Creates an HTML-formatted string from the markup entities found in the message's - caption. - - Use this if you want to retrieve the message caption with the caption entities formatted as - HTML. This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. - - Warning: - |text_html| - - .. versionchanged:: 13.10 - Spoiler entities are now formatted as HTML. - - .. versionchanged:: 20.3 - Custom emoji entities are now supported. - - .. versionchanged:: 20.8 - Blockquote entities are now supported. - - Returns: - :obj:`str`: Message caption with caption entities formatted as HTML. - """ - return self._parse_html(self.caption, self.parse_caption_entities(), urled=True) - - @classmethod - def _parse_markdown( - cls, - message_text: Optional[str], - entities: dict[MessageEntity, str], - urled: bool = False, - version: MarkdownVersion = 1, - offset: int = 0, - ) -> Optional[str]: - if version == 1: - for entity_type in ( - MessageEntity.EXPANDABLE_BLOCKQUOTE, - MessageEntity.BLOCKQUOTE, - MessageEntity.CUSTOM_EMOJI, - MessageEntity.SPOILER, - MessageEntity.STRIKETHROUGH, - MessageEntity.UNDERLINE, - ): - if any(entity.type == entity_type for entity in entities): - name = entity_type.name.title().replace("_", " ") # type:ignore[attr-defined] - raise ValueError(f"{name} entities are not supported for Markdown version 1") - - if message_text is None: - return None - - utf_16_text = message_text.encode(TextEncoding.UTF_16_LE) - markdown_text = "" - last_offset = 0 - - sorted_entities = sorted(entities.items(), key=lambda item: item[0].offset) - parsed_entities = [] - - for entity, text in sorted_entities: - if entity in parsed_entities: - continue - - nested_entities = { - e: t - for (e, t) in sorted_entities - if e.offset >= entity.offset - and e.offset + e.length <= entity.offset + entity.length - and e != entity - } - parsed_entities.extend(list(nested_entities.keys())) - - if nested_entities: - if version < 2: - raise ValueError("Nested entities are not supported for Markdown version 1") - - escaped_text = cls._parse_markdown( - text, - nested_entities, - urled=urled, - offset=entity.offset, - version=version, - ) - else: - escaped_text = escape_markdown(text, version=version) - - if entity.type == MessageEntity.TEXT_LINK: - if version == 1: - url = entity.url - else: - # Links need special escaping. Also can't have entities nested within - url = escape_markdown( - entity.url, version=version, entity_type=MessageEntity.TEXT_LINK - ) - insert = f"[{escaped_text}]({url})" - elif entity.type == MessageEntity.TEXT_MENTION and entity.user: - insert = f"[{escaped_text}](tg://user?id={entity.user.id})" - elif entity.type == MessageEntity.URL and urled: - link = text if version == 1 else escaped_text - insert = f"[{link}]({text})" - elif entity.type == MessageEntity.BOLD: - insert = f"*{escaped_text}*" - elif entity.type == MessageEntity.ITALIC: - insert = f"_{escaped_text}_" - elif entity.type == MessageEntity.CODE: - # Monospace needs special escaping. Also can't have entities nested within - insert = f"`{escape_markdown(text, version, MessageEntity.CODE)}`" - elif entity.type == MessageEntity.PRE: - # Monospace needs special escaping. Also can't have entities nested within - code = escape_markdown(text, version=version, entity_type=MessageEntity.PRE) - if entity.language: - prefix = f"```{entity.language}\n" - elif code.startswith("\\"): - prefix = "```" - else: - prefix = "```\n" - insert = f"{prefix}{code}```" - elif entity.type == MessageEntity.UNDERLINE: - insert = f"__{escaped_text}__" - elif entity.type == MessageEntity.STRIKETHROUGH: - insert = f"~{escaped_text}~" - elif entity.type == MessageEntity.SPOILER: - insert = f"||{escaped_text}||" - elif entity.type in (MessageEntity.BLOCKQUOTE, MessageEntity.EXPANDABLE_BLOCKQUOTE): - insert = ">" + "\n>".join(escaped_text.splitlines()) - if entity.type == MessageEntity.EXPANDABLE_BLOCKQUOTE: - insert = f"{insert}||" - elif entity.type == MessageEntity.CUSTOM_EMOJI: - # This should never be needed because ids are numeric but the documentation - # specifically mentions it so here we are - custom_emoji_id = escape_markdown( - entity.custom_emoji_id, - version=version, - entity_type=MessageEntity.CUSTOM_EMOJI, - ) - insert = f"![{escaped_text}](tg://emoji?id={custom_emoji_id})" - else: - insert = escaped_text - - # Make sure to escape the text that is not part of the entity - # if we're in a nested entity, this is still required, since in that case this - # text is part of the parent entity - markdown_text += ( - escape_markdown( - utf_16_text[last_offset * 2 : (entity.offset - offset) * 2].decode( - TextEncoding.UTF_16_LE - ), - version=version, - ) - + insert - ) - - last_offset = entity.offset - offset + entity.length - - # see comment above - markdown_text += escape_markdown( - utf_16_text[last_offset * 2 :].decode(TextEncoding.UTF_16_LE), - version=version, - ) - - return markdown_text - - @property - def text_markdown(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message - using :class:`telegram.constants.ParseMode.MARKDOWN`. - - Use this if you want to retrieve the message text with the entities formatted as Markdown - in the same way the original message was formatted. - - Warning: - |text_markdown| - - Note: - :tg-const:`telegram.constants.ParseMode.MARKDOWN` is a legacy mode, retained by - Telegram for backward compatibility. You should use :meth:`text_markdown_v2` instead. - - .. versionchanged:: 20.5 - |custom_emoji_no_md1_support| - - .. versionchanged:: 20.8 - |blockquote_no_md1_support| - - Returns: - :obj:`str`: Message text with entities formatted as Markdown. - - Raises: - :exc:`ValueError`: If the message contains underline, strikethrough, spoiler, - blockquote or nested entities. - - """ - return self._parse_markdown(self.text, self.parse_entities(), urled=False) - - @property - def text_markdown_v2(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message - using :class:`telegram.constants.ParseMode.MARKDOWN_V2`. - - Use this if you want to retrieve the message text with the entities formatted as Markdown - in the same way the original message was formatted. - - Warning: - |text_markdown| - - .. versionchanged:: 13.10 - Spoiler entities are now formatted as Markdown V2. - - .. versionchanged:: 20.3 - Custom emoji entities are now supported. - - .. versionchanged:: 20.8 - Blockquote entities are now supported. - - Returns: - :obj:`str`: Message text with entities formatted as Markdown. - """ - return self._parse_markdown(self.text, self.parse_entities(), urled=False, version=2) - - @property - def text_markdown_urled(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message - using :class:`telegram.constants.ParseMode.MARKDOWN`. - - Use this if you want to retrieve the message text with the entities formatted as Markdown. - This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. - - Warning: - |text_markdown| - - Note: - :tg-const:`telegram.constants.ParseMode.MARKDOWN` is a legacy mode, retained by - Telegram for backward compatibility. You should use :meth:`text_markdown_v2_urled` - instead. - - .. versionchanged:: 20.5 - |custom_emoji_no_md1_support| - - .. versionchanged:: 20.8 - |blockquote_no_md1_support| - - Returns: - :obj:`str`: Message text with entities formatted as Markdown. - - Raises: - :exc:`ValueError`: If the message contains underline, strikethrough, spoiler, - blockquote or nested entities. - - """ - return self._parse_markdown(self.text, self.parse_entities(), urled=True) - - @property - def text_markdown_v2_urled(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message - using :class:`telegram.constants.ParseMode.MARKDOWN_V2`. - - Use this if you want to retrieve the message text with the entities formatted as Markdown. - This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. - - Warning: - |text_markdown| - - .. versionchanged:: 13.10 - Spoiler entities are now formatted as Markdown V2. - - .. versionchanged:: 20.3 - Custom emoji entities are now supported. - - .. versionchanged:: 20.8 - Blockquote entities are now supported. - - Returns: - :obj:`str`: Message text with entities formatted as Markdown. - """ - return self._parse_markdown(self.text, self.parse_entities(), urled=True, version=2) - - @property - def caption_markdown(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message's - caption using :class:`telegram.constants.ParseMode.MARKDOWN`. - - Use this if you want to retrieve the message caption with the caption entities formatted as - Markdown in the same way the original message was formatted. - - Warning: - |text_markdown| - - Note: - :tg-const:`telegram.constants.ParseMode.MARKDOWN` is a legacy mode, retained by - Telegram for backward compatibility. You should use :meth:`caption_markdown_v2` - .. versionchanged:: 20.5 - |custom_emoji_no_md1_support| - - .. versionchanged:: 20.8 - |blockquote_no_md1_support| - - Returns: - :obj:`str`: Message caption with caption entities formatted as Markdown. - - Raises: - :exc:`ValueError`: If the message contains underline, strikethrough, spoiler, - blockquote or nested entities. - - """ - return self._parse_markdown(self.caption, self.parse_caption_entities(), urled=False) - - @property - def caption_markdown_v2(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message's - caption using :class:`telegram.constants.ParseMode.MARKDOWN_V2`. - - Use this if you want to retrieve the message caption with the caption entities formatted as - Markdown in the same way the original message was formatted. - - Warning: - |text_markdown| - - .. versionchanged:: 13.10 - Spoiler entities are now formatted as Markdown V2. - - .. versionchanged:: 20.3 - Custom emoji entities are now supported. - - .. versionchanged:: 20.8 - Blockquote entities are now supported. - - Returns: - :obj:`str`: Message caption with caption entities formatted as Markdown. - """ - return self._parse_markdown( - self.caption, self.parse_caption_entities(), urled=False, version=2 - ) - - @property - def caption_markdown_urled(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message's - caption using :class:`telegram.constants.ParseMode.MARKDOWN`. - - Use this if you want to retrieve the message caption with the caption entities formatted as - Markdown. This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. - - Warning: - |text_markdown| - - Note: - :tg-const:`telegram.constants.ParseMode.MARKDOWN` is a legacy mode, retained by - Telegram for backward compatibility. You should use - :meth:`caption_markdown_v2_urled` instead. - - .. versionchanged:: 20.5 - |custom_emoji_no_md1_support| - - .. versionchanged:: 20.8 - |blockquote_no_md1_support| - - Returns: - :obj:`str`: Message caption with caption entities formatted as Markdown. - - Raises: - :exc:`ValueError`: If the message contains underline, strikethrough, spoiler, - blockquote or nested entities. - - """ - return self._parse_markdown(self.caption, self.parse_caption_entities(), urled=True) - - @property - def caption_markdown_v2_urled(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message's - caption using :class:`telegram.constants.ParseMode.MARKDOWN_V2`. - - Use this if you want to retrieve the message caption with the caption entities formatted as - Markdown. This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. - - Warning: - |text_markdown| - - .. versionchanged:: 13.10 - Spoiler entities are now formatted as Markdown V2. - - .. versionchanged:: 20.3 - Custom emoji entities are now supported. - - .. versionchanged:: 20.8 - Blockquote entities are now supported. - - Returns: - :obj:`str`: Message caption with caption entities formatted as Markdown. - """ - return self._parse_markdown( - self.caption, self.parse_caption_entities(), urled=True, version=2 - ) diff --git a/venv/lib/python3.11/site-packages/telegram/_messageautodeletetimerchanged.py b/venv/lib/python3.11/site-packages/telegram/_messageautodeletetimerchanged.py deleted file mode 100755 index 1653c05..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_messageautodeletetimerchanged.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a change in the Telegram message auto -deletion. -""" - -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class MessageAutoDeleteTimerChanged(TelegramObject): - """This object represents a service message about a change in auto-delete timer settings. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`message_auto_delete_time` is equal. - - .. versionadded:: 13.4 - - Args: - message_auto_delete_time (:obj:`int`): New auto-delete time for messages in the - chat. - - Attributes: - message_auto_delete_time (:obj:`int`): New auto-delete time for messages in the - chat. - - """ - - __slots__ = ("message_auto_delete_time",) - - def __init__( - self, - message_auto_delete_time: int, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - self.message_auto_delete_time: int = message_auto_delete_time - - self._id_attrs = (self.message_auto_delete_time,) - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_messageentity.py b/venv/lib/python3.11/site-packages/telegram/_messageentity.py deleted file mode 100755 index 852c496..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_messageentity.py +++ /dev/null @@ -1,414 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram MessageEntity.""" - -import copy -import itertools -from collections.abc import Sequence -from typing import TYPE_CHECKING, Final, Optional, Union - -from telegram import constants -from telegram._telegramobject import TelegramObject -from telegram._user import User -from telegram._utils import enum -from telegram._utils.strings import TextEncoding -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - -_SEM = Sequence["MessageEntity"] - - -class MessageEntity(TelegramObject): - """ - This object represents one special entity in a text message. For example, hashtags, - usernames, URLs, etc. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`type`, :attr:`offset` and :attr:`length` are equal. - - Args: - type (:obj:`str`): Type of the entity. Can be :attr:`MENTION` (``@username``), - :attr:`HASHTAG` (``#hashtag`` or ``#hashtag@chatusername``), :attr:`CASHTAG` (``$USD`` - or ``USD@chatusername``), :attr:`BOT_COMMAND` (``/start@jobs_bot``), :attr:`URL` - (``https://telegram.org``), :attr:`EMAIL` (``do-not-reply@telegram.org``), - :attr:`PHONE_NUMBER` (``+1-212-555-0123``), - :attr:`BOLD` (**bold text**), :attr:`ITALIC` (*italic text*), :attr:`UNDERLINE` - (underlined text), :attr:`STRIKETHROUGH`, :attr:`SPOILER` (spoiler message), - :attr:`BLOCKQUOTE` (block quotation), :attr:`CODE` (monowidth string), :attr:`PRE` - (monowidth block), :attr:`TEXT_LINK` (for clickable text URLs), :attr:`TEXT_MENTION` - (for users without usernames), :attr:`CUSTOM_EMOJI` (for inline custom emoji stickers). - - .. versionadded:: 20.0 - Added inline custom emoji - - .. versionadded:: 20.8 - Added block quotation - offset (:obj:`int`): Offset in UTF-16 code units to the start of the entity. - length (:obj:`int`): Length of the entity in UTF-16 code units. - url (:obj:`str`, optional): For :attr:`TEXT_LINK` only, url that will be opened after - user taps on the text. - user (:class:`telegram.User`, optional): For :attr:`TEXT_MENTION` only, the mentioned - user. - language (:obj:`str`, optional): For :attr:`PRE` only, the programming language of - the entity text. - custom_emoji_id (:obj:`str`, optional): For :attr:`CUSTOM_EMOJI` only, unique identifier - of the custom emoji. Use :meth:`telegram.Bot.get_custom_emoji_stickers` to get full - information about the sticker. - - .. versionadded:: 20.0 - Attributes: - type (:obj:`str`): Type of the entity. Can be :attr:`MENTION` (``@username``), - :attr:`HASHTAG` (``#hashtag`` or ``#hashtag@chatusername``), :attr:`CASHTAG` (``$USD`` - or ``USD@chatusername``), :attr:`BOT_COMMAND` (``/start@jobs_bot``), :attr:`URL` - (``https://telegram.org``), :attr:`EMAIL` (``do-not-reply@telegram.org``), - :attr:`PHONE_NUMBER` (``+1-212-555-0123``), - :attr:`BOLD` (**bold text**), :attr:`ITALIC` (*italic text*), :attr:`UNDERLINE` - (underlined text), :attr:`STRIKETHROUGH`, :attr:`SPOILER` (spoiler message), - :attr:`BLOCKQUOTE` (block quotation), :attr:`CODE` (monowidth string), :attr:`PRE` - (monowidth block), :attr:`TEXT_LINK` (for clickable text URLs), :attr:`TEXT_MENTION` - (for users without usernames), :attr:`CUSTOM_EMOJI` (for inline custom emoji stickers). - - .. versionadded:: 20.0 - Added inline custom emoji - - .. versionadded:: 20.8 - Added block quotation - offset (:obj:`int`): Offset in UTF-16 code units to the start of the entity. - length (:obj:`int`): Length of the entity in UTF-16 code units. - url (:obj:`str`): Optional. For :attr:`TEXT_LINK` only, url that will be opened after - user taps on the text. - user (:class:`telegram.User`): Optional. For :attr:`TEXT_MENTION` only, the mentioned - user. - language (:obj:`str`): Optional. For :attr:`PRE` only, the programming language of - the entity text. - custom_emoji_id (:obj:`str`): Optional. For :attr:`CUSTOM_EMOJI` only, unique identifier - of the custom emoji. Use :meth:`telegram.Bot.get_custom_emoji_stickers` to get full - information about the sticker. - - .. versionadded:: 20.0 - - """ - - __slots__ = ("custom_emoji_id", "language", "length", "offset", "type", "url", "user") - - def __init__( - self, - type: str, # pylint: disable=redefined-builtin - offset: int, - length: int, - url: Optional[str] = None, - user: Optional[User] = None, - language: Optional[str] = None, - custom_emoji_id: Optional[str] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.type: str = enum.get_member(constants.MessageEntityType, type, type) - self.offset: int = offset - self.length: int = length - # Optionals - self.url: Optional[str] = url - self.user: Optional[User] = user - self.language: Optional[str] = language - self.custom_emoji_id: Optional[str] = custom_emoji_id - - self._id_attrs = (self.type, self.offset, self.length) - - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["MessageEntity"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data["user"] = User.de_json(data.get("user"), bot) - - return super().de_json(data=data, bot=bot) - - @staticmethod - def adjust_message_entities_to_utf_16(text: str, entities: _SEM) -> _SEM: - """Utility functionality for converting the offset and length of entities from - Unicode (:obj:`str`) to UTF-16 (``utf-16-le`` encoded :obj:`bytes`). - - Tip: - Only the offsets and lengths calulated in UTF-16 is acceptable by the Telegram Bot API. - If they are calculated using the Unicode string (:obj:`str` object), errors may occur - when the text contains characters that are not in the Basic Multilingual Plane (BMP). - For more information, see `Unicode `_ and - `Plane (Unicode) `_. - - .. versionadded:: 21.4 - - Examples: - Below is a snippet of code that demonstrates how to use this function to convert - entities from Unicode to UTF-16 space. The ``unicode_entities`` are calculated in - Unicode and the `utf_16_entities` are calculated in UTF-16. - - .. code-block:: python - - text = "𠌕 bold 𝄢 italic underlined: 𝛙𝌢𑁍" - unicode_entities = [ - MessageEntity(offset=2, length=4, type=MessageEntity.BOLD), - MessageEntity(offset=9, length=6, type=MessageEntity.ITALIC), - MessageEntity(offset=28, length=3, type=MessageEntity.UNDERLINE), - ] - utf_16_entities = MessageEntity.adjust_message_entities_to_utf_16( - text, unicode_entities - ) - await bot.send_message( - chat_id=123, - text=text, - entities=utf_16_entities, - ) - # utf_16_entities[0]: offset=3, length=4 - # utf_16_entities[1]: offset=11, length=6 - # utf_16_entities[2]: offset=30, length=6 - - Args: - text (:obj:`str`): The text that the entities belong to - entities (Sequence[:class:`telegram.MessageEntity`]): Sequence of entities - with offset and length calculated in Unicode - - Returns: - Sequence[:class:`telegram.MessageEntity`]: Sequence of entities - with offset and length calculated in UTF-16 encoding - """ - # get sorted positions - positions = sorted(itertools.chain(*((x.offset, x.offset + x.length) for x in entities))) - accumulated_length = 0 - # calculate the length of each slice text[:position] in utf-16 accordingly, - # store the position translations - position_translation: dict[int, int] = {} - for i, position in enumerate(positions): - last_position = positions[i - 1] if i > 0 else 0 - text_slice = text[last_position:position] - accumulated_length += len(text_slice.encode(TextEncoding.UTF_16_LE)) // 2 - position_translation[position] = accumulated_length - # get the final output entities - out = [] - for entity in entities: - translated_positions = position_translation[entity.offset] - translated_length = ( - position_translation[entity.offset + entity.length] - translated_positions - ) - new_entity = copy.copy(entity) - with new_entity._unfrozen(): - new_entity.offset = translated_positions - new_entity.length = translated_length - out.append(new_entity) - return out - - @staticmethod - def shift_entities(by: Union[str, int], entities: _SEM) -> _SEM: - """Utility functionality for shifting the offset of entities by a given amount. - - Examples: - Shifting by an integer amount: - - .. code-block:: python - - text = "Hello, world!" - entities = [ - MessageEntity(offset=0, length=5, type=MessageEntity.BOLD), - MessageEntity(offset=7, length=5, type=MessageEntity.ITALIC), - ] - shifted_entities = MessageEntity.shift_entities(1, entities) - await bot.send_message( - chat_id=123, - text="!" + text, - entities=shifted_entities, - ) - - Shifting using a string: - - .. code-block:: python - - text = "Hello, world!" - prefix = "𝄢" - entities = [ - MessageEntity(offset=0, length=5, type=MessageEntity.BOLD), - MessageEntity(offset=7, length=5, type=MessageEntity.ITALIC), - ] - shifted_entities = MessageEntity.shift_entities(prefix, entities) - await bot.send_message( - chat_id=123, - text=prefix + text, - entities=shifted_entities, - ) - - Tip: - The :paramref:`entities` are *not* modified in place. The function returns a sequence - of new objects. - - .. versionadded:: 21.5 - - Args: - by (:obj:`str` | :obj:`int`): Either the amount to shift the offset by or - a string whose length will be used as the amount to shift the offset by. In this - case, UTF-16 encoding will be used to calculate the length. - entities (Sequence[:class:`telegram.MessageEntity`]): Sequence of entities - - Returns: - Sequence[:class:`telegram.MessageEntity`]: Sequence of entities with the offset shifted - """ - effective_shift = by if isinstance(by, int) else len(by.encode("utf-16-le")) // 2 - - out = [] - for entity in entities: - new_entity = copy.copy(entity) - with new_entity._unfrozen(): - new_entity.offset += effective_shift - out.append(new_entity) - return out - - @classmethod - def concatenate( - cls, - *args: Union[tuple[str, _SEM], tuple[str, _SEM, bool]], - ) -> tuple[str, _SEM]: - """Utility functionality for concatenating two text along with their formatting entities. - - Tip: - This function is useful for prefixing an already formatted text with a new text and its - formatting entities. In particular, it automatically correctly handles UTF-16 encoding. - - Examples: - This example shows a callback function that can be used to add a prefix and suffix to - the message in a :class:`~telegram.ext.CallbackQueryHandler`: - - .. code-block:: python - - async def prefix_message(update: Update, context: ContextTypes.DEFAULT_TYPE): - prefix = "𠌕 bold 𝄢 italic underlined: 𝛙𝌢𑁍 | " - prefix_entities = [ - MessageEntity(offset=2, length=4, type=MessageEntity.BOLD), - MessageEntity(offset=9, length=6, type=MessageEntity.ITALIC), - MessageEntity(offset=28, length=3, type=MessageEntity.UNDERLINE), - ] - suffix = " | 𠌕 bold 𝄢 italic underlined: 𝛙𝌢𑁍" - suffix_entities = [ - MessageEntity(offset=5, length=4, type=MessageEntity.BOLD), - MessageEntity(offset=12, length=6, type=MessageEntity.ITALIC), - MessageEntity(offset=31, length=3, type=MessageEntity.UNDERLINE), - ] - - message = update.effective_message - first = (prefix, prefix_entities, True) - second = (message.text, message.entities) - third = (suffix, suffix_entities, True) - - new_text, new_entities = MessageEntity.concatenate(first, second, third) - await update.callback_query.edit_message_text( - text=new_text, - entities=new_entities, - ) - - Hint: - The entities are *not* modified in place. The function returns a - new sequence of objects. - - .. versionadded:: 21.5 - - Args: - *args (tuple[:obj:`str`, Sequence[:class:`telegram.MessageEntity`]] | \ - tuple[:obj:`str`, Sequence[:class:`telegram.MessageEntity`], :obj:`bool`]): - Arbitrary number of tuples containing the text and its entities to concatenate. - If the last element of the tuple is a :obj:`bool`, it is used to determine whether - to adjust the entities to UTF-16 via - :meth:`adjust_message_entities_to_utf_16`. UTF-16 adjustment is disabled by - default. - - Returns: - tuple[:obj:`str`, Sequence[:class:`telegram.MessageEntity`]]: The concatenated text - and its entities - """ - output_text = "" - output_entities: list[MessageEntity] = [] - for arg in args: - text, entities = arg[0], arg[1] - - if len(arg) > 2 and arg[2] is True: - entities = cls.adjust_message_entities_to_utf_16(text, entities) - - output_entities.extend(cls.shift_entities(output_text, entities)) - output_text += text - - return output_text, output_entities - - ALL_TYPES: Final[list[str]] = list(constants.MessageEntityType) - """list[:obj:`str`]: A list of all available message entity types.""" - BLOCKQUOTE: Final[str] = constants.MessageEntityType.BLOCKQUOTE - """:const:`telegram.constants.MessageEntityType.BLOCKQUOTE` - - .. versionadded:: 20.8 - """ - BOLD: Final[str] = constants.MessageEntityType.BOLD - """:const:`telegram.constants.MessageEntityType.BOLD`""" - BOT_COMMAND: Final[str] = constants.MessageEntityType.BOT_COMMAND - """:const:`telegram.constants.MessageEntityType.BOT_COMMAND`""" - CASHTAG: Final[str] = constants.MessageEntityType.CASHTAG - """:const:`telegram.constants.MessageEntityType.CASHTAG`""" - CODE: Final[str] = constants.MessageEntityType.CODE - """:const:`telegram.constants.MessageEntityType.CODE`""" - CUSTOM_EMOJI: Final[str] = constants.MessageEntityType.CUSTOM_EMOJI - """:const:`telegram.constants.MessageEntityType.CUSTOM_EMOJI` - - .. versionadded:: 20.0 - """ - EMAIL: Final[str] = constants.MessageEntityType.EMAIL - """:const:`telegram.constants.MessageEntityType.EMAIL`""" - EXPANDABLE_BLOCKQUOTE: Final[str] = constants.MessageEntityType.EXPANDABLE_BLOCKQUOTE - """:const:`telegram.constants.MessageEntityType.EXPANDABLE_BLOCKQUOTE` - - .. versionadded:: 21.3 - """ - HASHTAG: Final[str] = constants.MessageEntityType.HASHTAG - """:const:`telegram.constants.MessageEntityType.HASHTAG`""" - ITALIC: Final[str] = constants.MessageEntityType.ITALIC - """:const:`telegram.constants.MessageEntityType.ITALIC`""" - MENTION: Final[str] = constants.MessageEntityType.MENTION - """:const:`telegram.constants.MessageEntityType.MENTION`""" - PHONE_NUMBER: Final[str] = constants.MessageEntityType.PHONE_NUMBER - """:const:`telegram.constants.MessageEntityType.PHONE_NUMBER`""" - PRE: Final[str] = constants.MessageEntityType.PRE - """:const:`telegram.constants.MessageEntityType.PRE`""" - SPOILER: Final[str] = constants.MessageEntityType.SPOILER - """:const:`telegram.constants.MessageEntityType.SPOILER` - - .. versionadded:: 13.10 - """ - STRIKETHROUGH: Final[str] = constants.MessageEntityType.STRIKETHROUGH - """:const:`telegram.constants.MessageEntityType.STRIKETHROUGH`""" - TEXT_LINK: Final[str] = constants.MessageEntityType.TEXT_LINK - """:const:`telegram.constants.MessageEntityType.TEXT_LINK`""" - TEXT_MENTION: Final[str] = constants.MessageEntityType.TEXT_MENTION - """:const:`telegram.constants.MessageEntityType.TEXT_MENTION`""" - UNDERLINE: Final[str] = constants.MessageEntityType.UNDERLINE - """:const:`telegram.constants.MessageEntityType.UNDERLINE`""" - URL: Final[str] = constants.MessageEntityType.URL - """:const:`telegram.constants.MessageEntityType.URL`""" diff --git a/venv/lib/python3.11/site-packages/telegram/_messageid.py b/venv/lib/python3.11/site-packages/telegram/_messageid.py deleted file mode 100755 index ac550fc..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_messageid.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents an instance of a Telegram MessageId.""" - -from typing import Optional - -from telegram._telegramobject import TelegramObject -from telegram._utils.types import JSONDict - - -class MessageId(TelegramObject): - """This object represents a unique message identifier. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`message_id` is equal. - - Args: - message_id (:obj:`int`): Unique message identifier. In specific instances - (e.g., message containing a video sent to a big chat), the server might automatically - schedule a message instead of sending it immediately. In such cases, this field will be - ``0`` and the relevant message will be unusable until it is actually sent. - - Attributes: - message_id (:obj:`int`): Unique message identifier. In specific instances - (e.g., message containing a video sent to a big chat), the server might automatically - schedule a message instead of sending it immediately. In such cases, this field will be - ``0`` and the relevant message will be unusable until it is actually sent. - """ - - __slots__ = ("message_id",) - - def __init__(self, message_id: int, *, api_kwargs: Optional[JSONDict] = None): - super().__init__(api_kwargs=api_kwargs) - self.message_id: int = message_id - - self._id_attrs = (self.message_id,) - - self._freeze() diff --git a/venv/lib/python3.11/site-packages/telegram/_messageorigin.py b/venv/lib/python3.11/site-packages/telegram/_messageorigin.py deleted file mode 100755 index 0982d65..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_messageorigin.py +++ /dev/null @@ -1,286 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes that represent Telegram MessageOigin.""" -import datetime as dtm -from typing import TYPE_CHECKING, Final, Optional - -from telegram import constants -from telegram._chat import Chat -from telegram._telegramobject import TelegramObject -from telegram._user import User -from telegram._utils import enum -from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class MessageOrigin(TelegramObject): - """ - Base class for telegram MessageOrigin object, it can be one of: - - * :class:`MessageOriginUser` - * :class:`MessageOriginHiddenUser` - * :class:`MessageOriginChat` - * :class:`MessageOriginChannel` - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`type` and :attr:`date` are equal. - - .. versionadded:: 20.8 - - Args: - type (:obj:`str`): Type of the message origin, can be on of: - :attr:`~telegram.MessageOrigin.USER`, :attr:`~telegram.MessageOrigin.HIDDEN_USER`, - :attr:`~telegram.MessageOrigin.CHAT`, or :attr:`~telegram.MessageOrigin.CHANNEL`. - date (:obj:`datetime.datetime`): Date the message was sent originally. - |datetime_localization| - - Attributes: - type (:obj:`str`): Type of the message origin, can be on of: - :attr:`~telegram.MessageOrigin.USER`, :attr:`~telegram.MessageOrigin.HIDDEN_USER`, - :attr:`~telegram.MessageOrigin.CHAT`, or :attr:`~telegram.MessageOrigin.CHANNEL`. - date (:obj:`datetime.datetime`): Date the message was sent originally. - |datetime_localization| - """ - - __slots__ = ( - "date", - "type", - ) - - USER: Final[str] = constants.MessageOriginType.USER - """:const:`telegram.constants.MessageOriginType.USER`""" - HIDDEN_USER: Final[str] = constants.MessageOriginType.HIDDEN_USER - """:const:`telegram.constants.MessageOriginType.HIDDEN_USER`""" - CHAT: Final[str] = constants.MessageOriginType.CHAT - """:const:`telegram.constants.MessageOriginType.CHAT`""" - CHANNEL: Final[str] = constants.MessageOriginType.CHANNEL - """:const:`telegram.constants.MessageOriginType.CHANNEL`""" - - def __init__( - self, - type: str, # pylint: disable=W0622 - date: dtm.datetime, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required by all subclasses - self.type: str = enum.get_member(constants.MessageOriginType, type, type) - self.date: dtm.datetime = date - - self._id_attrs = ( - self.type, - self.date, - ) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["MessageOrigin"]: - """Converts JSON data to the appropriate :class:`MessageOrigin` object, i.e. takes - care of selecting the correct subclass. - """ - data = cls._parse_data(data) - - if not data: - return None - - _class_mapping: dict[str, type[MessageOrigin]] = { - cls.USER: MessageOriginUser, - cls.HIDDEN_USER: MessageOriginHiddenUser, - cls.CHAT: MessageOriginChat, - cls.CHANNEL: MessageOriginChannel, - } - if cls is MessageOrigin and data.get("type") in _class_mapping: - return _class_mapping[data.pop("type")].de_json(data=data, bot=bot) - - loc_tzinfo = extract_tzinfo_from_defaults(bot) - data["date"] = from_timestamp(data.get("date"), tzinfo=loc_tzinfo) - - if "sender_user" in data: - data["sender_user"] = User.de_json(data.get("sender_user"), bot) - - if "sender_chat" in data: - data["sender_chat"] = Chat.de_json(data.get("sender_chat"), bot) - - if "chat" in data: - data["chat"] = Chat.de_json(data.get("chat"), bot) - - return super().de_json(data=data, bot=bot) - - -class MessageOriginUser(MessageOrigin): - """ - The message was originally sent by a known user. - - .. versionadded:: 20.8 - - Args: - date (:obj:`datetime.datetime`): Date the message was sent originally. - |datetime_localization| - sender_user (:class:`telegram.User`): User that sent the message originally. - - Attributes: - type (:obj:`str`): Type of the message origin. Always - :tg-const:`~telegram.MessageOrigin.USER`. - date (:obj:`datetime.datetime`): Date the message was sent originally. - |datetime_localization| - sender_user (:class:`telegram.User`): User that sent the message originally. - """ - - __slots__ = ("sender_user",) - - def __init__( - self, - date: dtm.datetime, - sender_user: User, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(type=self.USER, date=date, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.sender_user: User = sender_user - - -class MessageOriginHiddenUser(MessageOrigin): - """ - The message was originally sent by an unknown user. - - .. versionadded:: 20.8 - - Args: - date (:obj:`datetime.datetime`): Date the message was sent originally. - |datetime_localization| - sender_user_name (:obj:`str`): Name of the user that sent the message originally. - - Attributes: - type (:obj:`str`): Type of the message origin. Always - :tg-const:`~telegram.MessageOrigin.HIDDEN_USER`. - date (:obj:`datetime.datetime`): Date the message was sent originally. - |datetime_localization| - sender_user_name (:obj:`str`): Name of the user that sent the message originally. - """ - - __slots__ = ("sender_user_name",) - - def __init__( - self, - date: dtm.datetime, - sender_user_name: str, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(type=self.HIDDEN_USER, date=date, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.sender_user_name: str = sender_user_name - - -class MessageOriginChat(MessageOrigin): - """ - The message was originally sent on behalf of a chat to a group chat. - - .. versionadded:: 20.8 - - Args: - date (:obj:`datetime.datetime`): Date the message was sent originally. - |datetime_localization| - sender_chat (:class:`telegram.Chat`): Chat that sent the message originally. - author_signature (:obj:`str`, optional): For messages originally sent by an anonymous chat - administrator, original message author signature - - Attributes: - type (:obj:`str`): Type of the message origin. Always - :tg-const:`~telegram.MessageOrigin.CHAT`. - date (:obj:`datetime.datetime`): Date the message was sent originally. - |datetime_localization| - sender_chat (:class:`telegram.Chat`): Chat that sent the message originally. - author_signature (:obj:`str`): Optional. For messages originally sent by an anonymous chat - administrator, original message author signature - """ - - __slots__ = ( - "author_signature", - "sender_chat", - ) - - def __init__( - self, - date: dtm.datetime, - sender_chat: Chat, - author_signature: Optional[str] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(type=self.CHAT, date=date, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.sender_chat: Chat = sender_chat - self.author_signature: Optional[str] = author_signature - - -class MessageOriginChannel(MessageOrigin): - """ - The message was originally sent to a channel chat. - - .. versionadded:: 20.8 - - Args: - date (:obj:`datetime.datetime`): Date the message was sent originally. - |datetime_localization| - chat (:class:`telegram.Chat`): Channel chat to which the message was originally sent. - message_id (:obj:`int`): Unique message identifier inside the chat. - author_signature (:obj:`str`, optional): Signature of the original post author. - - Attributes: - type (:obj:`str`): Type of the message origin. Always - :tg-const:`~telegram.MessageOrigin.CHANNEL`. - date (:obj:`datetime.datetime`): Date the message was sent originally. - |datetime_localization| - chat (:class:`telegram.Chat`): Channel chat to which the message was originally sent. - message_id (:obj:`int`): Unique message identifier inside the chat. - author_signature (:obj:`str`): Optional. Signature of the original post author. - """ - - __slots__ = ( - "author_signature", - "chat", - "message_id", - ) - - def __init__( - self, - date: dtm.datetime, - chat: Chat, - message_id: int, - author_signature: Optional[str] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(type=self.CHANNEL, date=date, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.chat: Chat = chat - self.message_id: int = message_id - self.author_signature: Optional[str] = author_signature diff --git a/venv/lib/python3.11/site-packages/telegram/_messagereactionupdated.py b/venv/lib/python3.11/site-packages/telegram/_messagereactionupdated.py deleted file mode 100755 index 105362a..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_messagereactionupdated.py +++ /dev/null @@ -1,209 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram MessageReaction Update.""" -import datetime as dtm -from collections.abc import Sequence -from typing import TYPE_CHECKING, Optional - -from telegram._chat import Chat -from telegram._reaction import ReactionCount, ReactionType -from telegram._telegramobject import TelegramObject -from telegram._user import User -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.datetime import extract_tzinfo_from_defaults, from_timestamp -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class MessageReactionCountUpdated(TelegramObject): - """This class represents reaction changes on a message with anonymous reactions. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if the :attr:`chat`, :attr:`message_id`, :attr:`date` and :attr:`reactions` - is equal. - - .. versionadded:: 20.8 - - Args: - chat (:class:`telegram.Chat`): The chat containing the message. - message_id (:obj:`int`): Unique message identifier inside the chat. - date (:class:`datetime.datetime`): Date of the change in Unix time - |datetime_localization| - reactions (Sequence[:class:`telegram.ReactionCount`]): List of reactions that are present - on the message - - Attributes: - chat (:class:`telegram.Chat`): The chat containing the message. - message_id (:obj:`int`): Unique message identifier inside the chat. - date (:class:`datetime.datetime`): Date of the change in Unix time - |datetime_localization| - reactions (tuple[:class:`telegram.ReactionCount`]): List of reactions that are present on - the message - """ - - __slots__ = ( - "chat", - "date", - "message_id", - "reactions", - ) - - def __init__( - self, - chat: Chat, - message_id: int, - date: dtm.datetime, - reactions: Sequence[ReactionCount], - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.chat: Chat = chat - self.message_id: int = message_id - self.date: dtm.datetime = date - self.reactions: tuple[ReactionCount, ...] = parse_sequence_arg(reactions) - - self._id_attrs = (self.chat, self.message_id, self.date, self.reactions) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["MessageReactionCountUpdated"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - # Get the local timezone from the bot if it has defaults - loc_tzinfo = extract_tzinfo_from_defaults(bot) - - data["date"] = from_timestamp(data.get("date"), tzinfo=loc_tzinfo) - data["chat"] = Chat.de_json(data.get("chat"), bot) - data["reactions"] = ReactionCount.de_list(data.get("reactions"), bot) - - return super().de_json(data=data, bot=bot) - - -class MessageReactionUpdated(TelegramObject): - """This class represents a change of a reaction on a message performed by a user. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if the :attr:`chat`, :attr:`message_id`, :attr:`date`, :attr:`old_reaction` - and :attr:`new_reaction` is equal. - - .. versionadded:: 20.8 - - Args: - chat (:class:`telegram.Chat`): The chat containing the message. - message_id (:obj:`int`): Unique message identifier inside the chat. - date (:class:`datetime.datetime`): Date of the change in Unix time. - |datetime_localization| - old_reaction (Sequence[:class:`telegram.ReactionType`]): Previous list of reaction types - that were set by the user. - new_reaction (Sequence[:class:`telegram.ReactionType`]): New list of reaction types that - were set by the user. - user (:class:`telegram.User`, optional): The user that changed the reaction, if the user - isn't anonymous. - actor_chat (:class:`telegram.Chat`, optional): The chat on behalf of which the reaction was - changed, if the user is anonymous. - - Attributes: - chat (:class:`telegram.Chat`): The chat containing the message. - message_id (:obj:`int`): Unique message identifier inside the chat. - date (:class:`datetime.datetime`): Date of the change in Unix time. - |datetime_localization| - old_reaction (tuple[:class:`telegram.ReactionType`]): Previous list of reaction types - that were set by the user. - new_reaction (tuple[:class:`telegram.ReactionType`]): New list of reaction types that - were set by the user. - user (:class:`telegram.User`): Optional. The user that changed the reaction, if the user - isn't anonymous. - actor_chat (:class:`telegram.Chat`): Optional. The chat on behalf of which the reaction was - changed, if the user is anonymous. - """ - - __slots__ = ( - "actor_chat", - "chat", - "date", - "message_id", - "new_reaction", - "old_reaction", - "user", - ) - - def __init__( - self, - chat: Chat, - message_id: int, - date: dtm.datetime, - old_reaction: Sequence[ReactionType], - new_reaction: Sequence[ReactionType], - user: Optional[User] = None, - actor_chat: Optional[Chat] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(api_kwargs=api_kwargs) - # Required - self.chat: Chat = chat - self.message_id: int = message_id - self.date: dtm.datetime = date - self.old_reaction: tuple[ReactionType, ...] = parse_sequence_arg(old_reaction) - self.new_reaction: tuple[ReactionType, ...] = parse_sequence_arg(new_reaction) - - # Optional - self.user: Optional[User] = user - self.actor_chat: Optional[Chat] = actor_chat - - self._id_attrs = ( - self.chat, - self.message_id, - self.date, - self.old_reaction, - self.new_reaction, - ) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["MessageReactionUpdated"]: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - # Get the local timezone from the bot if it has defaults - loc_tzinfo = extract_tzinfo_from_defaults(bot) - - data["date"] = from_timestamp(data.get("date"), tzinfo=loc_tzinfo) - data["chat"] = Chat.de_json(data.get("chat"), bot) - data["old_reaction"] = ReactionType.de_list(data.get("old_reaction"), bot) - data["new_reaction"] = ReactionType.de_list(data.get("new_reaction"), bot) - data["user"] = User.de_json(data.get("user"), bot) - data["actor_chat"] = Chat.de_json(data.get("actor_chat"), bot) - - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_paidmedia.py b/venv/lib/python3.11/site-packages/telegram/_paidmedia.py deleted file mode 100755 index b649c7e..0000000 --- a/venv/lib/python3.11/site-packages/telegram/_paidmedia.py +++ /dev/null @@ -1,341 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2025 -# Leandro Toledo de Souza -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains objects that represent paid media in Telegram.""" - -from collections.abc import Sequence -from typing import TYPE_CHECKING, Final, Optional - -from telegram import constants -from telegram._files.photosize import PhotoSize -from telegram._files.video import Video -from telegram._telegramobject import TelegramObject -from telegram._user import User -from telegram._utils import enum -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class PaidMedia(TelegramObject): - """Describes the paid media added to a message. Currently, it can be one of: - - * :class:`telegram.PaidMediaPreview` - * :class:`telegram.PaidMediaPhoto` - * :class:`telegram.PaidMediaVideo` - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`type` is equal. - - .. versionadded:: 21.4 - - Args: - type (:obj:`str`): Type of the paid media. - - Attributes: - type (:obj:`str`): Type of the paid media. - """ - - __slots__ = ("type",) - - PREVIEW: Final[str] = constants.PaidMediaType.PREVIEW - """:const:`telegram.constants.PaidMediaType.PREVIEW`""" - PHOTO: Final[str] = constants.PaidMediaType.PHOTO - """:const:`telegram.constants.PaidMediaType.PHOTO`""" - VIDEO: Final[str] = constants.PaidMediaType.VIDEO - """:const:`telegram.constants.PaidMediaType.VIDEO`""" - - def __init__( - self, - type: str, # pylint: disable=redefined-builtin - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(api_kwargs=api_kwargs) - self.type: str = enum.get_member(constants.PaidMediaType, type, type) - - self._id_attrs = (self.type,) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["PaidMedia"]: - """Converts JSON data to the appropriate :class:`PaidMedia` object, i.e. takes - care of selecting the correct subclass. - - Args: - data (dict[:obj:`str`, ...]): The JSON data. - bot (:class:`telegram.Bot`, optional): The bot associated with this object. - - Returns: - The Telegram object. - - """ - data = cls._parse_data(data) - - if data is None: - return None - - if not data and cls is PaidMedia: - return None - - _class_mapping: dict[str, type[PaidMedia]] = { - cls.PREVIEW: PaidMediaPreview, - cls.PHOTO: PaidMediaPhoto, - cls.VIDEO: PaidMediaVideo, - } - - if cls is PaidMedia and data.get("type") in _class_mapping: - return _class_mapping[data.pop("type")].de_json(data=data, bot=bot) - - return super().de_json(data=data, bot=bot) - - -class PaidMediaPreview(PaidMedia): - """The paid media isn't available before the payment. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`width`, :attr:`height`, and :attr:`duration` - are equal. - - .. versionadded:: 21.4 - - Args: - type (:obj:`str`): Type of the paid media, always :tg-const:`telegram.PaidMedia.PREVIEW`. - width (:obj:`int`, optional): Media width as defined by the sender. - height (:obj:`int`, optional): Media height as defined by the sender. - duration (:obj:`int`, optional): Duration of the media in seconds as defined by the sender. - - Attributes: - type (:obj:`str`): Type of the paid media, always :tg-const:`telegram.PaidMedia.PREVIEW`. - width (:obj:`int`): Optional. Media width as defined by the sender. - height (:obj:`int`): Optional. Media height as defined by the sender. - duration (:obj:`int`): Optional. Duration of the media in seconds as defined by the sender. - """ - - __slots__ = ("duration", "height", "width") - - def __init__( - self, - width: Optional[int] = None, - height: Optional[int] = None, - duration: Optional[int] = None, - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(type=PaidMedia.PREVIEW, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.width: Optional[int] = width - self.height: Optional[int] = height - self.duration: Optional[int] = duration - - self._id_attrs = (self.type, self.width, self.height, self.duration) - - -class PaidMediaPhoto(PaidMedia): - """ - The paid media is a photo. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`photo` are equal. - - .. versionadded:: 21.4 - - Args: - type (:obj:`str`): Type of the paid media, always :tg-const:`telegram.PaidMedia.PHOTO`. - photo (Sequence[:class:`telegram.PhotoSize`]): The photo. - - Attributes: - type (:obj:`str`): Type of the paid media, always :tg-const:`telegram.PaidMedia.PHOTO`. - photo (tuple[:class:`telegram.PhotoSize`]): The photo. - """ - - __slots__ = ("photo",) - - def __init__( - self, - photo: Sequence["PhotoSize"], - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(type=PaidMedia.PHOTO, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.photo: tuple[PhotoSize, ...] = parse_sequence_arg(photo) - - self._id_attrs = (self.type, self.photo) - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["PaidMediaPhoto"]: - data = cls._parse_data(data) - - if not data: - return None - - data["photo"] = PhotoSize.de_list(data.get("photo"), bot=bot) - return super().de_json(data=data, bot=bot) # type: ignore[return-value] - - -class PaidMediaVideo(PaidMedia): - """ - The paid media is a video. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`video` are equal. - - .. versionadded:: 21.4 - - Args: - type (:obj:`str`): Type of the paid media, always :tg-const:`telegram.PaidMedia.VIDEO`. - video (:class:`telegram.Video`): The video. - - Attributes: - type (:obj:`str`): Type of the paid media, always :tg-const:`telegram.PaidMedia.VIDEO`. - video (:class:`telegram.Video`): The video. - """ - - __slots__ = ("video",) - - def __init__( - self, - video: Video, - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(type=PaidMedia.VIDEO, api_kwargs=api_kwargs) - - with self._unfrozen(): - self.video: Video = video - - self._id_attrs = (self.type, self.video) - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["PaidMediaVideo"]: - data = cls._parse_data(data) - - if not data: - return None - - data["video"] = Video.de_json(data.get("video"), bot=bot) - return super().de_json(data=data, bot=bot) # type: ignore[return-value] - - -class PaidMediaInfo(TelegramObject): - """ - Describes the paid media added to a message. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`star_count` and :attr:`paid_media` are equal. - - .. versionadded:: 21.4 - - Args: - star_count (:obj:`int`): The number of Telegram Stars that must be paid to buy access to - the media. - paid_media (Sequence[:class:`telegram.PaidMedia`]): Information about the paid media. - - Attributes: - star_count (:obj:`int`): The number of Telegram Stars that must be paid to buy access to - the media. - paid_media (tuple[:class:`telegram.PaidMedia`]): Information about the paid media. - """ - - __slots__ = ("paid_media", "star_count") - - def __init__( - self, - star_count: int, - paid_media: Sequence[PaidMedia], - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(api_kwargs=api_kwargs) - self.star_count: int = star_count - self.paid_media: tuple[PaidMedia, ...] = parse_sequence_arg(paid_media) - - self._id_attrs = (self.star_count, self.paid_media) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["PaidMediaInfo"]: - data = cls._parse_data(data) - - if not data: - return None - - data["paid_media"] = PaidMedia.de_list(data.get("paid_media"), bot=bot) - return super().de_json(data=data, bot=bot) - - -class PaidMediaPurchased(TelegramObject): - """This object contains information about a paid media purchase. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`from_user` and :attr:`paid_media_payload` are equal. - - Note: - In Python :keyword:`from` is a reserved word. Use :paramref:`from_user` instead. - - .. versionadded:: 21.6 - - Args: - from_user (:class:`telegram.User`): User who purchased the media. - paid_media_payload (:obj:`str`): Bot-specified paid media payload. - - Attributes: - from_user (:class:`telegram.User`): User who purchased the media. - paid_media_payload (:obj:`str`): Bot-specified paid media payload. - """ - - __slots__ = ("from_user", "paid_media_payload") - - def __init__( - self, - from_user: "User", - paid_media_payload: str, - *, - api_kwargs: Optional[JSONDict] = None, - ) -> None: - super().__init__(api_kwargs=api_kwargs) - self.from_user: User = from_user - self.paid_media_payload: str = paid_media_payload - - self._id_attrs = (self.from_user, self.paid_media_payload) - self._freeze() - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: Optional["Bot"] = None - ) -> Optional["PaidMediaPurchased"]: - data = cls._parse_data(data) - - if not data: - return None - - data["from_user"] = User.de_json(data=data.pop("from"), bot=bot) - return super().de_json(data=data, bot=bot) diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/__init__.py b/venv/lib/python3.11/site-packages/telegram/_passport/__init__.py deleted file mode 100755 index e69de29..0000000 diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/__init__.cpython-311.pyc deleted file mode 100755 index 45e8674..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/credentials.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/credentials.cpython-311.pyc deleted file mode 100755 index f75e047..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/credentials.cpython-311.pyc and /dev/null differ diff --git a/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/data.cpython-311.pyc b/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/data.cpython-311.pyc deleted file mode 100755 index a1ecd96..0000000 Binary files a/venv/lib/python3.11/site-packages/telegram/_passport/__pycache__/data.cpython-311.pyc and /dev/null differ