diff --git a/.gitattributes b/.gitattributes index eb29b6d22d365827d93107b94daa93c48b4a6094..6c104ebc609828fe0b3dd12b46022876affd2b7f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -46,3 +46,4 @@ tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/distl tuning-competition-baseline/.venv/lib/python3.11/site-packages/Cython/Utils.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/__pycache__/typing_extensions.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text tuning-competition-baseline/.venv/lib/python3.11/site-packages/Cython/Compiler/__pycache__/Optimize.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text +tuning-competition-baseline/.venv/lib/python3.11/site-packages/Cython/Tempita/_tempita.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/Cython/Tempita/_tempita.cpython-311-x86_64-linux-gnu.so b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/Cython/Tempita/_tempita.cpython-311-x86_64-linux-gnu.so new file mode 100644 index 0000000000000000000000000000000000000000..a235ca2f249ce5a43b45d87b82a5571b99b058e8 --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/Cython/Tempita/_tempita.cpython-311-x86_64-linux-gnu.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0477f20b0dfa19f79dc484a4a92c0ba4ae204d074ad171452e1d7de8bbd4d6cf +size 595904 diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/conftest.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/conftest.py new file mode 100644 index 0000000000000000000000000000000000000000..6874a42c4895c3c7b973dc5d63fd4488a4e60b44 --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/conftest.py @@ -0,0 +1,55 @@ +import os +import shutil +import subprocess +import sys +import time + +import pytest + +import fsspec +from fsspec.implementations.cached import CachingFileSystem + + +@pytest.fixture() +def m(): + """ + Fixture providing a memory filesystem. + """ + m = fsspec.filesystem("memory") + m.store.clear() + m.pseudo_dirs.clear() + m.pseudo_dirs.append("") + try: + yield m + finally: + m.store.clear() + m.pseudo_dirs.clear() + m.pseudo_dirs.append("") + + +@pytest.fixture +def ftp_writable(tmpdir): + """ + Fixture providing a writable FTP filesystem. + """ + pytest.importorskip("pyftpdlib") + from fsspec.implementations.ftp import FTPFileSystem + + FTPFileSystem.clear_instance_cache() # remove lingering connections + CachingFileSystem.clear_instance_cache() + d = str(tmpdir) + with open(os.path.join(d, "out"), "wb") as f: + f.write(b"hello" * 10000) + P = subprocess.Popen( + [sys.executable, "-m", "pyftpdlib", "-d", d, "-u", "user", "-P", "pass", "-w"] + ) + try: + time.sleep(1) + yield "localhost", 2121, "user", "pass" + finally: + P.terminate() + P.wait() + try: + shutil.rmtree(tmpdir) + except Exception: + pass diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/__init__.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c0a1f6a07ca745c6203511f598141a53cb1e3ed9 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/__init__.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/arrow.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/arrow.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9ad24f2fc9d35174ebea0c99b33ae4b3bfde5354 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/arrow.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/cache_mapper.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/cache_mapper.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a38c64f29b320ed18b533ce94a62a875f4c1dd16 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/cache_mapper.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/cache_metadata.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/cache_metadata.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d71969d6578d75c29053ee73e9aaab94913e8955 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/cache_metadata.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/data.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/data.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a2bff8e9b49ec423b3d479464e679eaf56cfb4b3 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/data.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/dirfs.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/dirfs.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6d05e353b0f8c9c4f8240240eb63acf121bb3a99 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/dirfs.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/github.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/github.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..38d81ad44ca9407af83b153c906bf442f91a8282 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/github.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/http.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/http.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a59e3d6fa1383c579d183b37e671b5ff17130884 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/http.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/memory.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/memory.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..95dc8b56ee149671954573e83f7fafef10a05c51 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/memory.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/smb.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/smb.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4438a2acc598312630c75a558144f9cbcba60e49 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/__pycache__/smb.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/github.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/github.py new file mode 100644 index 0000000000000000000000000000000000000000..e8fe7a2f67d7d9648e75b82d5f0b5cf2bf7a4868 --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/implementations/github.py @@ -0,0 +1,227 @@ +import requests + +from ..spec import AbstractFileSystem +from ..utils import infer_storage_options +from .memory import MemoryFile + +# TODO: add GIST backend, would be very similar + + +class GithubFileSystem(AbstractFileSystem): + """Interface to files in github + + An instance of this class provides the files residing within a remote github + repository. You may specify a point in the repos history, by SHA, branch + or tag (default is current master). + + Given that code files tend to be small, and that github does not support + retrieving partial content, we always fetch whole files. + + When using fsspec.open, allows URIs of the form: + + - "github://path/file", in which case you must specify org, repo and + may specify sha in the extra args + - 'github://org:repo@/precip/catalog.yml', where the org and repo are + part of the URI + - 'github://org:repo@sha/precip/catalog.yml', where the sha is also included + + ``sha`` can be the full or abbreviated hex of the commit you want to fetch + from, or a branch or tag name (so long as it doesn't contain special characters + like "/", "?", which would have to be HTTP-encoded). + + For authorised access, you must provide username and token, which can be made + at https://github.com/settings/tokens + """ + + url = "https://api.github.com/repos/{org}/{repo}/git/trees/{sha}" + rurl = "https://raw.githubusercontent.com/{org}/{repo}/{sha}/{path}" + protocol = "github" + timeout = (60, 60) # connect, read timeouts + + def __init__( + self, org, repo, sha=None, username=None, token=None, timeout=None, **kwargs + ): + super().__init__(**kwargs) + self.org = org + self.repo = repo + if (username is None) ^ (token is None): + raise ValueError("Auth required both username and token") + self.username = username + self.token = token + if timeout is not None: + self.timeout = timeout + if sha is None: + # look up default branch (not necessarily "master") + u = "https://api.github.com/repos/{org}/{repo}" + r = requests.get( + u.format(org=org, repo=repo), timeout=self.timeout, **self.kw + ) + r.raise_for_status() + sha = r.json()["default_branch"] + + self.root = sha + self.ls("") + + @property + def kw(self): + if self.username: + return {"auth": (self.username, self.token)} + return {} + + @classmethod + def repos(cls, org_or_user, is_org=True): + """List repo names for given org or user + + This may become the top level of the FS + + Parameters + ---------- + org_or_user: str + Name of the github org or user to query + is_org: bool (default True) + Whether the name is an organisation (True) or user (False) + + Returns + ------- + List of string + """ + r = requests.get( + f"https://api.github.com/{['users', 'orgs'][is_org]}/{org_or_user}/repos", + timeout=cls.timeout, + ) + r.raise_for_status() + return [repo["name"] for repo in r.json()] + + @property + def tags(self): + """Names of tags in the repo""" + r = requests.get( + f"https://api.github.com/repos/{self.org}/{self.repo}/tags", + timeout=self.timeout, + **self.kw, + ) + r.raise_for_status() + return [t["name"] for t in r.json()] + + @property + def branches(self): + """Names of branches in the repo""" + r = requests.get( + f"https://api.github.com/repos/{self.org}/{self.repo}/branches", + timeout=self.timeout, + **self.kw, + ) + r.raise_for_status() + return [t["name"] for t in r.json()] + + @property + def refs(self): + """Named references, tags and branches""" + return {"tags": self.tags, "branches": self.branches} + + def ls(self, path, detail=False, sha=None, _sha=None, **kwargs): + """List files at given path + + Parameters + ---------- + path: str + Location to list, relative to repo root + detail: bool + If True, returns list of dicts, one per file; if False, returns + list of full filenames only + sha: str (optional) + List at the given point in the repo history, branch or tag name or commit + SHA + _sha: str (optional) + List this specific tree object (used internally to descend into trees) + """ + path = self._strip_protocol(path) + if path == "": + _sha = sha or self.root + if _sha is None: + parts = path.rstrip("/").split("/") + so_far = "" + _sha = sha or self.root + for part in parts: + out = self.ls(so_far, True, sha=sha, _sha=_sha) + so_far += "/" + part if so_far else part + out = [o for o in out if o["name"] == so_far] + if not out: + raise FileNotFoundError(path) + out = out[0] + if out["type"] == "file": + if detail: + return [out] + else: + return path + _sha = out["sha"] + if path not in self.dircache or sha not in [self.root, None]: + r = requests.get( + self.url.format(org=self.org, repo=self.repo, sha=_sha), + timeout=self.timeout, + **self.kw, + ) + if r.status_code == 404: + raise FileNotFoundError(path) + r.raise_for_status() + types = {"blob": "file", "tree": "directory"} + out = [ + { + "name": path + "/" + f["path"] if path else f["path"], + "mode": f["mode"], + "type": types[f["type"]], + "size": f.get("size", 0), + "sha": f["sha"], + } + for f in r.json()["tree"] + if f["type"] in types + ] + if sha in [self.root, None]: + self.dircache[path] = out + else: + out = self.dircache[path] + if detail: + return out + else: + return sorted([f["name"] for f in out]) + + def invalidate_cache(self, path=None): + self.dircache.clear() + + @classmethod + def _strip_protocol(cls, path): + opts = infer_storage_options(path) + if "username" not in opts: + return super()._strip_protocol(path) + return opts["path"].lstrip("/") + + @staticmethod + def _get_kwargs_from_urls(path): + opts = infer_storage_options(path) + if "username" not in opts: + return {} + out = {"org": opts["username"], "repo": opts["password"]} + if opts["host"]: + out["sha"] = opts["host"] + return out + + def _open( + self, + path, + mode="rb", + block_size=None, + autocommit=True, + cache_options=None, + sha=None, + **kwargs, + ): + if mode != "rb": + raise NotImplementedError + url = self.rurl.format( + org=self.org, repo=self.repo, path=path, sha=sha or self.root + ) + r = requests.get(url, timeout=self.timeout, **self.kw) + if r.status_code == 404: + raise FileNotFoundError(path) + r.raise_for_status() + return MemoryFile(None, None, r.content) diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/registry.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/registry.py new file mode 100644 index 0000000000000000000000000000000000000000..db9d3d577e9f9490fdbdc70802b2c9f19ac6c964 --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/registry.py @@ -0,0 +1,299 @@ +from __future__ import annotations + +import importlib +import types +import warnings + +__all__ = ["registry", "get_filesystem_class", "default"] + +# internal, mutable +_registry: dict[str, type] = {} + +# external, immutable +registry = types.MappingProxyType(_registry) +default = "file" + + +def register_implementation(name, cls, clobber=False, errtxt=None): + """Add implementation class to the registry + + Parameters + ---------- + name: str + Protocol name to associate with the class + cls: class or str + if a class: fsspec-compliant implementation class (normally inherits from + ``fsspec.AbstractFileSystem``, gets added straight to the registry. If a + str, the full path to an implementation class like package.module.class, + which gets added to known_implementations, + so the import is deferred until the filesystem is actually used. + clobber: bool (optional) + Whether to overwrite a protocol with the same name; if False, will raise + instead. + errtxt: str (optional) + If given, then a failure to import the given class will result in this + text being given. + """ + if isinstance(cls, str): + if name in known_implementations and clobber is False: + if cls != known_implementations[name]["class"]: + raise ValueError( + f"Name ({name}) already in the known_implementations and clobber " + f"is False" + ) + else: + known_implementations[name] = { + "class": cls, + "err": errtxt or f"{cls} import failed for protocol {name}", + } + + else: + if name in registry and clobber is False: + if _registry[name] is not cls: + raise ValueError( + f"Name ({name}) already in the registry and clobber is False" + ) + else: + _registry[name] = cls + + +# protocols mapped to the class which implements them. This dict can be +# updated with register_implementation +known_implementations = { + "data": {"class": "fsspec.implementations.data.DataFileSystem"}, + "file": {"class": "fsspec.implementations.local.LocalFileSystem"}, + "local": {"class": "fsspec.implementations.local.LocalFileSystem"}, + "memory": {"class": "fsspec.implementations.memory.MemoryFileSystem"}, + "dropbox": { + "class": "dropboxdrivefs.DropboxDriveFileSystem", + "err": ( + 'DropboxFileSystem requires "dropboxdrivefs",' + '"requests" and "dropbox" to be installed' + ), + }, + "http": { + "class": "fsspec.implementations.http.HTTPFileSystem", + "err": 'HTTPFileSystem requires "requests" and "aiohttp" to be installed', + }, + "https": { + "class": "fsspec.implementations.http.HTTPFileSystem", + "err": 'HTTPFileSystem requires "requests" and "aiohttp" to be installed', + }, + "zip": {"class": "fsspec.implementations.zip.ZipFileSystem"}, + "tar": {"class": "fsspec.implementations.tar.TarFileSystem"}, + "gcs": { + "class": "gcsfs.GCSFileSystem", + "err": "Please install gcsfs to access Google Storage", + }, + "gs": { + "class": "gcsfs.GCSFileSystem", + "err": "Please install gcsfs to access Google Storage", + }, + "gdrive": { + "class": "gdrivefs.GoogleDriveFileSystem", + "err": "Please install gdrivefs for access to Google Drive", + }, + "sftp": { + "class": "fsspec.implementations.sftp.SFTPFileSystem", + "err": 'SFTPFileSystem requires "paramiko" to be installed', + }, + "ssh": { + "class": "fsspec.implementations.sftp.SFTPFileSystem", + "err": 'SFTPFileSystem requires "paramiko" to be installed', + }, + "ftp": {"class": "fsspec.implementations.ftp.FTPFileSystem"}, + "hdfs": { + "class": "fsspec.implementations.arrow.HadoopFileSystem", + "err": "pyarrow and local java libraries required for HDFS", + }, + "arrow_hdfs": { + "class": "fsspec.implementations.arrow.HadoopFileSystem", + "err": "pyarrow and local java libraries required for HDFS", + }, + "webhdfs": { + "class": "fsspec.implementations.webhdfs.WebHDFS", + "err": 'webHDFS access requires "requests" to be installed', + }, + "s3": {"class": "s3fs.S3FileSystem", "err": "Install s3fs to access S3"}, + "s3a": {"class": "s3fs.S3FileSystem", "err": "Install s3fs to access S3"}, + "wandb": {"class": "wandbfs.WandbFS", "err": "Install wandbfs to access wandb"}, + "oci": { + "class": "ocifs.OCIFileSystem", + "err": "Install ocifs to access OCI Object Storage", + }, + "ocilake": { + "class": "ocifs.OCIFileSystem", + "err": "Install ocifs to access OCI Data Lake", + }, + "asynclocal": { + "class": "morefs.asyn_local.AsyncLocalFileSystem", + "err": "Install 'morefs[asynclocalfs]' to use AsyncLocalFileSystem", + }, + "adl": { + "class": "adlfs.AzureDatalakeFileSystem", + "err": "Install adlfs to access Azure Datalake Gen1", + }, + "abfs": { + "class": "adlfs.AzureBlobFileSystem", + "err": "Install adlfs to access Azure Datalake Gen2 and Azure Blob Storage", + }, + "az": { + "class": "adlfs.AzureBlobFileSystem", + "err": "Install adlfs to access Azure Datalake Gen2 and Azure Blob Storage", + }, + "cached": {"class": "fsspec.implementations.cached.CachingFileSystem"}, + "blockcache": {"class": "fsspec.implementations.cached.CachingFileSystem"}, + "filecache": {"class": "fsspec.implementations.cached.WholeFileCacheFileSystem"}, + "simplecache": {"class": "fsspec.implementations.cached.SimpleCacheFileSystem"}, + "dask": { + "class": "fsspec.implementations.dask.DaskWorkerFileSystem", + "err": "Install dask distributed to access worker file system", + }, + "dbfs": { + "class": "fsspec.implementations.dbfs.DatabricksFileSystem", + "err": "Install the requests package to use the DatabricksFileSystem", + }, + "github": { + "class": "fsspec.implementations.github.GithubFileSystem", + "err": "Install the requests package to use the github FS", + }, + "git": { + "class": "fsspec.implementations.git.GitFileSystem", + "err": "Install pygit2 to browse local git repos", + }, + "smb": { + "class": "fsspec.implementations.smb.SMBFileSystem", + "err": 'SMB requires "smbprotocol" or "smbprotocol[kerberos]" installed', + }, + "jupyter": { + "class": "fsspec.implementations.jupyter.JupyterFileSystem", + "err": "Jupyter FS requires requests to be installed", + }, + "jlab": { + "class": "fsspec.implementations.jupyter.JupyterFileSystem", + "err": "Jupyter FS requires requests to be installed", + }, + "libarchive": { + "class": "fsspec.implementations.libarchive.LibArchiveFileSystem", + "err": "LibArchive requires to be installed", + }, + "reference": {"class": "fsspec.implementations.reference.ReferenceFileSystem"}, + "generic": {"class": "fsspec.generic.GenericFileSystem"}, + "oss": { + "class": "ossfs.OSSFileSystem", + "err": "Install ossfs to access Alibaba Object Storage System", + }, + "webdav": { + "class": "webdav4.fsspec.WebdavFileSystem", + "err": "Install webdav4 to access WebDAV", + }, + "dvc": { + "class": "dvc.api.DVCFileSystem", + "err": "Install dvc to access DVCFileSystem", + }, + "hf": { + "class": "huggingface_hub.HfFileSystem", + "err": "Install huggingface_hub to access HfFileSystem", + }, + "root": { + "class": "fsspec_xrootd.XRootDFileSystem", + "err": "Install fsspec-xrootd to access xrootd storage system." + + " Note: 'root' is the protocol name for xrootd storage systems," + + " not referring to root directories", + }, + "dir": {"class": "fsspec.implementations.dirfs.DirFileSystem"}, + "box": { + "class": "boxfs.BoxFileSystem", + "err": "Please install boxfs to access BoxFileSystem", + }, + "lakefs": { + "class": "lakefs_spec.LakeFSFileSystem", + "err": "Please install lakefs-spec to access LakeFSFileSystem", + }, +} + + +def get_filesystem_class(protocol): + """Fetch named protocol implementation from the registry + + The dict ``known_implementations`` maps protocol names to the locations + of classes implementing the corresponding file-system. When used for the + first time, appropriate imports will happen and the class will be placed in + the registry. All subsequent calls will fetch directly from the registry. + + Some protocol implementations require additional dependencies, and so the + import may fail. In this case, the string in the "err" field of the + ``known_implementations`` will be given as the error message. + """ + if not protocol: + protocol = default + + if protocol not in registry: + if protocol not in known_implementations: + raise ValueError(f"Protocol not known: {protocol}") + bit = known_implementations[protocol] + try: + register_implementation(protocol, _import_class(bit["class"])) + except ImportError as e: + raise ImportError(bit["err"]) from e + cls = registry[protocol] + if getattr(cls, "protocol", None) in ("abstract", None): + cls.protocol = protocol + + return cls + + +s3_msg = """Your installed version of s3fs is very old and known to cause +severe performance issues, see also https://github.com/dask/dask/issues/10276 + +To fix, you should specify a lower version bound on s3fs, or +update the current installation. +""" + + +def _import_class(cls, minv=None): + """Take a string FQP and return the imported class or identifier + + clas is of the form "package.module.klass" or "package.module:subobject.klass" + """ + if ":" in cls: + mod, name = cls.rsplit(":", 1) + s3 = mod == "s3fs" + mod = importlib.import_module(mod) + if s3 and mod.__version__.split(".") < ["0", "5"]: + warnings.warn(s3_msg) + for part in name.split("."): + mod = getattr(mod, part) + return mod + else: + mod, name = cls.rsplit(".", 1) + s3 = mod == "s3fs" + mod = importlib.import_module(mod) + if s3 and mod.__version__.split(".") < ["0", "5"]: + warnings.warn(s3_msg) + return getattr(mod, name) + + +def filesystem(protocol, **storage_options): + """Instantiate filesystems for given protocol and arguments + + ``storage_options`` are specific to the protocol being chosen, and are + passed directly to the class. + """ + if protocol == "arrow_hdfs": + warnings.warn( + "The 'arrow_hdfs' protocol has been deprecated and will be " + "removed in the future. Specify it as 'hdfs'.", + DeprecationWarning, + ) + + cls = get_filesystem_class(protocol) + return cls(**storage_options) + + +def available_protocols(): + """Return a list of the implemented protocols. + + Note that any given protocol may require extra packages to be importable. + """ + return list(known_implementations) diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/transaction.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/transaction.py new file mode 100644 index 0000000000000000000000000000000000000000..67584d61e8f5f86b22e19beb609ffe49ce7cc689 --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/fsspec/transaction.py @@ -0,0 +1,85 @@ +from collections import deque + + +class Transaction: + """Filesystem transaction write context + + Gathers files for deferred commit or discard, so that several write + operations can be finalized semi-atomically. This works by having this + instance as the ``.transaction`` attribute of the given filesystem + """ + + def __init__(self, fs): + """ + Parameters + ---------- + fs: FileSystem instance + """ + self.fs = fs + self.files = deque() + + def __enter__(self): + self.start() + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + """End transaction and commit, if exit is not due to exception""" + # only commit if there was no exception + self.complete(commit=exc_type is None) + self.fs._intrans = False + self.fs._transaction = None + + def start(self): + """Start a transaction on this FileSystem""" + self.files = deque() # clean up after previous failed completions + self.fs._intrans = True + + def complete(self, commit=True): + """Finish transaction: commit or discard all deferred files""" + while self.files: + f = self.files.popleft() + if commit: + f.commit() + else: + f.discard() + self.fs._intrans = False + + +class FileActor: + def __init__(self): + self.files = [] + + def commit(self): + for f in self.files: + f.commit() + self.files.clear() + + def discard(self): + for f in self.files: + f.discard() + self.files.clear() + + def append(self, f): + self.files.append(f) + + +class DaskTransaction(Transaction): + def __init__(self, fs): + """ + Parameters + ---------- + fs: FileSystem instance + """ + import distributed + + super().__init__(fs) + client = distributed.default_client() + self.files = client.submit(FileActor, actor=True).result() + + def complete(self, commit=True): + """Finish transaction: commit or discard all deferred files""" + if commit: + self.files.commit().result() + else: + self.files.discard().result() + self.fs._intrans = False diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/functorch/dim/__init__.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/functorch/dim/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..519a7cb271cdc3eef40ccd76c94c504ed1a325e8 --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/functorch/dim/__init__.py @@ -0,0 +1,179 @@ +import dis +import inspect +from typing import Sequence, Union + +import torch + +import functorch._C +from functorch._C import dim as _C +from .tree_map import tree_flatten, tree_map +from .wrap_type import wrap_type + +_C._patch_tensor_class() +dims, DimList, dimlists = _C.dims, _C.DimList, _C.dimlists + + +class DimensionMismatchError(Exception): + pass + + +class DimensionBindError(Exception): + pass + + +from . import op_properties + +# use dict to avoid writing C++ bindings for set +pointwise = dict.fromkeys(op_properties.pointwise, True) + +use_c = True +if not use_c: + from . import reference + + +class _Tensor: + # fast path around slow wrapping/unwrapping logic for simply queries used + # by the implementation... + + @property + def dims(self): + return tuple(d for d in self._levels if isinstance(d, Dim)) + + def dim(self): + return self.ndim + + if use_c: + __torch_function__ = classmethod(_C.__torch_function__) + expand = _C._instancemethod(_C.expand) + else: + __torch_function__ = reference.__torch_function__ + expand = reference.expand + + index = _C._instancemethod(_C.index) + + def __repr__(self): + tensor, levels, ndim = self._tensor, self._levels, self.ndim + return f"{tensor}\nwith dims={tuple(l + ndim if isinstance(l, int) else l for l in levels)} sizes={tuple(tensor.size())}" + + +TensorLike = (_Tensor, torch.Tensor) + + +class Dim(_C.Dim, _Tensor): + # note that _C.Dim comes before tensor because we want the Dim API for things like size to take precendence. + # Tensor defines format, but we want to print Dims with special formatting + __format__ = object.__format__ + + +class Tensor(_Tensor, _C.Tensor): + if not use_c: + from_batched = staticmethod(_C.Tensor_from_batched) + from_positional = staticmethod(_C.Tensor_from_positional) + sum = _C._instancemethod(_C.Tensor_sum) + + +def cat(tensors, dim, new_dim): + n = dims() + return stack(tensors, n, dim).index([n, dim], new_dim) + + +if use_c: + _wrap = _C._wrap + + def _def(name, *args, **kwargs): + orig = getattr(torch.Tensor, name) + setattr(_Tensor, name, _C._instancemethod(_wrap(orig, *args, **kwargs))) + + t__getitem__ = _C._instancemethod(_C.__getitem__) + stack = _C.stack + split = _C._instancemethod(_C.split) +else: + _wrap, _def = reference._wrap, reference._def + t__getitem__ = reference.t__getitem__ + stack = reference.stack + split = reference.split + +# note: there is no python reference +t__setitem__ = _C._instancemethod(_C.__setitem__) +# this is patched in the C API because otherwise torch.Tensor will +# no longer be considered a sequence and things will break +# torch.Tensor.__getitem__ = t__getitem__ + +_Tensor.__getitem__ = t__getitem__ +# torch.Tensor.__setitem__ = t__setitem__ +_Tensor.__setitem__ = t__setitem__ + +torch.Tensor.split = split +_Tensor.split = split +torch.Tensor.expand = _C._instancemethod(_C.expand) +torch.Tensor.index = _C._instancemethod(_C.index) +wrap_type(use_c, _Tensor, torch.Tensor, _Tensor.__torch_function__) +del _Tensor.ndim + +if use_c: + _Tensor.order = _C._instancemethod(_C.order) +else: + _Tensor.order = reference.positional + +_def("mean") +_def("sum") +_def("all") +_def("amax") +_def("amin") +_def("aminmax") +_def("any") +_def("count_nonzero") +_def("logsumexp") +_def("nanmean") +_def("nansum") +_def("prod") +_def("std", keepdim_offset=2) +_def("var", keepdim_offset=2) +_def("max", single_dim=True) +_def("min", single_dim=True) +_def("argmax", single_dim=True) +_def("argmin", single_dim=True) +_def("kthvalue", single_dim=True) +_def("median", single_dim=True) +_def("nanmedian", single_dim=True) +_def("mode", single_dim=True) +_def("sort", reduce=False) +_def("argsort", reduce=False) +_def("unbind", single_dim=True) +_def("chunk", dim_offset=1, reduce=False) +_def("cummax", single_dim=True, reduce=False) +_def("cummin", single_dim=True, reduce=False) +_def("cumprod", single_dim=True, reduce=False) +_def("cumprod_", single_dim=True, reduce=False) +_def("cumsum", single_dim=True, reduce=False) +_def("cumsum_", single_dim=True, reduce=False) +_def("logcumsumexp", single_dim=True, reduce=False) +_def("renorm", dim_offset=1, single_dim=True, reduce=False) +_def("softmax", single_dim=True, reduce=False) +softmax = _wrap(torch.nn.functional.softmax, single_dim=True, reduce=False) + +# stuff to handle in the future, because they require special +# binding logic for dims +# cross +# diag_embed +# diagonal +# diagonal_scatter +# diff +# nanquantile +# quantile +# roll +# rot90 +# topk (new dimes on output) +# should these all be subsumed by inplace indexing? +# index_add_ +# index_add +# index_copy +# index_copy_ +# index_fill +# index_fill_ +# index_select +# scatter +# scatter_ +# scatter_add +# scatter_add_ +# scatter_reduce diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/functorch/dim/__pycache__/batch_tensor.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/functorch/dim/__pycache__/batch_tensor.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9783253371ed6c01c075b0d59524d87ead6c8f2e Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/functorch/dim/__pycache__/batch_tensor.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/functorch/dim/__pycache__/delayed_mul_tensor.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/functorch/dim/__pycache__/delayed_mul_tensor.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0c20c7dfecc400876df495bf0b0407020e8a0392 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/functorch/dim/__pycache__/delayed_mul_tensor.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/functorch/dim/__pycache__/op_properties.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/functorch/dim/__pycache__/op_properties.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..72399dd8b211317774644a123e85e6e0a48cf8c5 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/functorch/dim/__pycache__/op_properties.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/functorch/dim/__pycache__/tree_map.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/functorch/dim/__pycache__/tree_map.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..632c309a5e1f28fb943337b903f59280f774b981 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/functorch/dim/__pycache__/tree_map.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/functorch/dim/__pycache__/wrap_type.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/functorch/dim/__pycache__/wrap_type.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..39b076ad4eef74aabe15b7f53224bc008e123432 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/functorch/dim/__pycache__/wrap_type.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/functorch/dim/batch_tensor.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/functorch/dim/batch_tensor.py new file mode 100644 index 0000000000000000000000000000000000000000..0fc17f2492d5344821071a726a0e3a0e9d5dea95 --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/functorch/dim/batch_tensor.py @@ -0,0 +1,25 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. +from contextlib import contextmanager + +from torch._C._functorch import _vmap_add_layers, _vmap_remove_layers + +_enabled = False + + +@contextmanager +def _enable_layers(dims): + global _enabled + assert not _enabled + input = sorted((d._level, d.size) for d in dims if not isinstance(d, int)) + n = len(input) + try: + _vmap_add_layers(input) + _enabled = True + yield + finally: + _enabled = False + _vmap_remove_layers(n) diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/ctx_base.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/ctx_base.py new file mode 100644 index 0000000000000000000000000000000000000000..1946f8daf4dbe165b3943be09af361812828aab1 --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/ctx_base.py @@ -0,0 +1,494 @@ +from operator import gt, lt + +from .libmp.backend import xrange + +from .functions.functions import SpecialFunctions +from .functions.rszeta import RSCache +from .calculus.quadrature import QuadratureMethods +from .calculus.inverselaplace import LaplaceTransformInversionMethods +from .calculus.calculus import CalculusMethods +from .calculus.optimization import OptimizationMethods +from .calculus.odes import ODEMethods +from .matrices.matrices import MatrixMethods +from .matrices.calculus import MatrixCalculusMethods +from .matrices.linalg import LinearAlgebraMethods +from .matrices.eigen import Eigen +from .identification import IdentificationMethods +from .visualization import VisualizationMethods + +from . import libmp + +class Context(object): + pass + +class StandardBaseContext(Context, + SpecialFunctions, + RSCache, + QuadratureMethods, + LaplaceTransformInversionMethods, + CalculusMethods, + MatrixMethods, + MatrixCalculusMethods, + LinearAlgebraMethods, + Eigen, + IdentificationMethods, + OptimizationMethods, + ODEMethods, + VisualizationMethods): + + NoConvergence = libmp.NoConvergence + ComplexResult = libmp.ComplexResult + + def __init__(ctx): + ctx._aliases = {} + # Call those that need preinitialization (e.g. for wrappers) + SpecialFunctions.__init__(ctx) + RSCache.__init__(ctx) + QuadratureMethods.__init__(ctx) + LaplaceTransformInversionMethods.__init__(ctx) + CalculusMethods.__init__(ctx) + MatrixMethods.__init__(ctx) + + def _init_aliases(ctx): + for alias, value in ctx._aliases.items(): + try: + setattr(ctx, alias, getattr(ctx, value)) + except AttributeError: + pass + + _fixed_precision = False + + # XXX + verbose = False + + def warn(ctx, msg): + print("Warning:", msg) + + def bad_domain(ctx, msg): + raise ValueError(msg) + + def _re(ctx, x): + if hasattr(x, "real"): + return x.real + return x + + def _im(ctx, x): + if hasattr(x, "imag"): + return x.imag + return ctx.zero + + def _as_points(ctx, x): + return x + + def fneg(ctx, x, **kwargs): + return -ctx.convert(x) + + def fadd(ctx, x, y, **kwargs): + return ctx.convert(x)+ctx.convert(y) + + def fsub(ctx, x, y, **kwargs): + return ctx.convert(x)-ctx.convert(y) + + def fmul(ctx, x, y, **kwargs): + return ctx.convert(x)*ctx.convert(y) + + def fdiv(ctx, x, y, **kwargs): + return ctx.convert(x)/ctx.convert(y) + + def fsum(ctx, args, absolute=False, squared=False): + if absolute: + if squared: + return sum((abs(x)**2 for x in args), ctx.zero) + return sum((abs(x) for x in args), ctx.zero) + if squared: + return sum((x**2 for x in args), ctx.zero) + return sum(args, ctx.zero) + + def fdot(ctx, xs, ys=None, conjugate=False): + if ys is not None: + xs = zip(xs, ys) + if conjugate: + cf = ctx.conj + return sum((x*cf(y) for (x,y) in xs), ctx.zero) + else: + return sum((x*y for (x,y) in xs), ctx.zero) + + def fprod(ctx, args): + prod = ctx.one + for arg in args: + prod *= arg + return prod + + def nprint(ctx, x, n=6, **kwargs): + """ + Equivalent to ``print(nstr(x, n))``. + """ + print(ctx.nstr(x, n, **kwargs)) + + def chop(ctx, x, tol=None): + """ + Chops off small real or imaginary parts, or converts + numbers close to zero to exact zeros. The input can be a + single number or an iterable:: + + >>> from mpmath import * + >>> mp.dps = 15; mp.pretty = False + >>> chop(5+1e-10j, tol=1e-9) + mpf('5.0') + >>> nprint(chop([1.0, 1e-20, 3+1e-18j, -4, 2])) + [1.0, 0.0, 3.0, -4.0, 2.0] + + The tolerance defaults to ``100*eps``. + """ + if tol is None: + tol = 100*ctx.eps + try: + x = ctx.convert(x) + absx = abs(x) + if abs(x) < tol: + return ctx.zero + if ctx._is_complex_type(x): + #part_tol = min(tol, absx*tol) + part_tol = max(tol, absx*tol) + if abs(x.imag) < part_tol: + return x.real + if abs(x.real) < part_tol: + return ctx.mpc(0, x.imag) + except TypeError: + if isinstance(x, ctx.matrix): + return x.apply(lambda a: ctx.chop(a, tol)) + if hasattr(x, "__iter__"): + return [ctx.chop(a, tol) for a in x] + return x + + def almosteq(ctx, s, t, rel_eps=None, abs_eps=None): + r""" + Determine whether the difference between `s` and `t` is smaller + than a given epsilon, either relatively or absolutely. + + Both a maximum relative difference and a maximum difference + ('epsilons') may be specified. The absolute difference is + defined as `|s-t|` and the relative difference is defined + as `|s-t|/\max(|s|, |t|)`. + + If only one epsilon is given, both are set to the same value. + If none is given, both epsilons are set to `2^{-p+m}` where + `p` is the current working precision and `m` is a small + integer. The default setting typically allows :func:`~mpmath.almosteq` + to be used to check for mathematical equality + in the presence of small rounding errors. + + **Examples** + + >>> from mpmath import * + >>> mp.dps = 15 + >>> almosteq(3.141592653589793, 3.141592653589790) + True + >>> almosteq(3.141592653589793, 3.141592653589700) + False + >>> almosteq(3.141592653589793, 3.141592653589700, 1e-10) + True + >>> almosteq(1e-20, 2e-20) + True + >>> almosteq(1e-20, 2e-20, rel_eps=0, abs_eps=0) + False + + """ + t = ctx.convert(t) + if abs_eps is None and rel_eps is None: + rel_eps = abs_eps = ctx.ldexp(1, -ctx.prec+4) + if abs_eps is None: + abs_eps = rel_eps + elif rel_eps is None: + rel_eps = abs_eps + diff = abs(s-t) + if diff <= abs_eps: + return True + abss = abs(s) + abst = abs(t) + if abss < abst: + err = diff/abst + else: + err = diff/abss + return err <= rel_eps + + def arange(ctx, *args): + r""" + This is a generalized version of Python's :func:`~mpmath.range` function + that accepts fractional endpoints and step sizes and + returns a list of ``mpf`` instances. Like :func:`~mpmath.range`, + :func:`~mpmath.arange` can be called with 1, 2 or 3 arguments: + + ``arange(b)`` + `[0, 1, 2, \ldots, x]` + ``arange(a, b)`` + `[a, a+1, a+2, \ldots, x]` + ``arange(a, b, h)`` + `[a, a+h, a+h, \ldots, x]` + + where `b-1 \le x < b` (in the third case, `b-h \le x < b`). + + Like Python's :func:`~mpmath.range`, the endpoint is not included. To + produce ranges where the endpoint is included, :func:`~mpmath.linspace` + is more convenient. + + **Examples** + + >>> from mpmath import * + >>> mp.dps = 15; mp.pretty = False + >>> arange(4) + [mpf('0.0'), mpf('1.0'), mpf('2.0'), mpf('3.0')] + >>> arange(1, 2, 0.25) + [mpf('1.0'), mpf('1.25'), mpf('1.5'), mpf('1.75')] + >>> arange(1, -1, -0.75) + [mpf('1.0'), mpf('0.25'), mpf('-0.5')] + + """ + if not len(args) <= 3: + raise TypeError('arange expected at most 3 arguments, got %i' + % len(args)) + if not len(args) >= 1: + raise TypeError('arange expected at least 1 argument, got %i' + % len(args)) + # set default + a = 0 + dt = 1 + # interpret arguments + if len(args) == 1: + b = args[0] + elif len(args) >= 2: + a = args[0] + b = args[1] + if len(args) == 3: + dt = args[2] + a, b, dt = ctx.mpf(a), ctx.mpf(b), ctx.mpf(dt) + assert a + dt != a, 'dt is too small and would cause an infinite loop' + # adapt code for sign of dt + if a > b: + if dt > 0: + return [] + op = gt + else: + if dt < 0: + return [] + op = lt + # create list + result = [] + i = 0 + t = a + while 1: + t = a + dt*i + i += 1 + if op(t, b): + result.append(t) + else: + break + return result + + def linspace(ctx, *args, **kwargs): + """ + ``linspace(a, b, n)`` returns a list of `n` evenly spaced + samples from `a` to `b`. The syntax ``linspace(mpi(a,b), n)`` + is also valid. + + This function is often more convenient than :func:`~mpmath.arange` + for partitioning an interval into subintervals, since + the endpoint is included:: + + >>> from mpmath import * + >>> mp.dps = 15; mp.pretty = False + >>> linspace(1, 4, 4) + [mpf('1.0'), mpf('2.0'), mpf('3.0'), mpf('4.0')] + + You may also provide the keyword argument ``endpoint=False``:: + + >>> linspace(1, 4, 4, endpoint=False) + [mpf('1.0'), mpf('1.75'), mpf('2.5'), mpf('3.25')] + + """ + if len(args) == 3: + a = ctx.mpf(args[0]) + b = ctx.mpf(args[1]) + n = int(args[2]) + elif len(args) == 2: + assert hasattr(args[0], '_mpi_') + a = args[0].a + b = args[0].b + n = int(args[1]) + else: + raise TypeError('linspace expected 2 or 3 arguments, got %i' \ + % len(args)) + if n < 1: + raise ValueError('n must be greater than 0') + if not 'endpoint' in kwargs or kwargs['endpoint']: + if n == 1: + return [ctx.mpf(a)] + step = (b - a) / ctx.mpf(n - 1) + y = [i*step + a for i in xrange(n)] + y[-1] = b + else: + step = (b - a) / ctx.mpf(n) + y = [i*step + a for i in xrange(n)] + return y + + def cos_sin(ctx, z, **kwargs): + return ctx.cos(z, **kwargs), ctx.sin(z, **kwargs) + + def cospi_sinpi(ctx, z, **kwargs): + return ctx.cospi(z, **kwargs), ctx.sinpi(z, **kwargs) + + def _default_hyper_maxprec(ctx, p): + return int(1000 * p**0.25 + 4*p) + + _gcd = staticmethod(libmp.gcd) + list_primes = staticmethod(libmp.list_primes) + isprime = staticmethod(libmp.isprime) + bernfrac = staticmethod(libmp.bernfrac) + moebius = staticmethod(libmp.moebius) + _ifac = staticmethod(libmp.ifac) + _eulernum = staticmethod(libmp.eulernum) + _stirling1 = staticmethod(libmp.stirling1) + _stirling2 = staticmethod(libmp.stirling2) + + def sum_accurately(ctx, terms, check_step=1): + prec = ctx.prec + try: + extraprec = 10 + while 1: + ctx.prec = prec + extraprec + 5 + max_mag = ctx.ninf + s = ctx.zero + k = 0 + for term in terms(): + s += term + if (not k % check_step) and term: + term_mag = ctx.mag(term) + max_mag = max(max_mag, term_mag) + sum_mag = ctx.mag(s) + if sum_mag - term_mag > ctx.prec: + break + k += 1 + cancellation = max_mag - sum_mag + if cancellation != cancellation: + break + if cancellation < extraprec or ctx._fixed_precision: + break + extraprec += min(ctx.prec, cancellation) + return s + finally: + ctx.prec = prec + + def mul_accurately(ctx, factors, check_step=1): + prec = ctx.prec + try: + extraprec = 10 + while 1: + ctx.prec = prec + extraprec + 5 + max_mag = ctx.ninf + one = ctx.one + s = one + k = 0 + for factor in factors(): + s *= factor + term = factor - one + if (not k % check_step): + term_mag = ctx.mag(term) + max_mag = max(max_mag, term_mag) + sum_mag = ctx.mag(s-one) + #if sum_mag - term_mag > ctx.prec: + # break + if -term_mag > ctx.prec: + break + k += 1 + cancellation = max_mag - sum_mag + if cancellation != cancellation: + break + if cancellation < extraprec or ctx._fixed_precision: + break + extraprec += min(ctx.prec, cancellation) + return s + finally: + ctx.prec = prec + + def power(ctx, x, y): + r"""Converts `x` and `y` to mpmath numbers and evaluates + `x^y = \exp(y \log(x))`:: + + >>> from mpmath import * + >>> mp.dps = 30; mp.pretty = True + >>> power(2, 0.5) + 1.41421356237309504880168872421 + + This shows the leading few digits of a large Mersenne prime + (performing the exact calculation ``2**43112609-1`` and + displaying the result in Python would be very slow):: + + >>> power(2, 43112609)-1 + 3.16470269330255923143453723949e+12978188 + """ + return ctx.convert(x) ** ctx.convert(y) + + def _zeta_int(ctx, n): + return ctx.zeta(n) + + def maxcalls(ctx, f, N): + """ + Return a wrapped copy of *f* that raises ``NoConvergence`` when *f* + has been called more than *N* times:: + + >>> from mpmath import * + >>> mp.dps = 15 + >>> f = maxcalls(sin, 10) + >>> print(sum(f(n) for n in range(10))) + 1.95520948210738 + >>> f(10) # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + NoConvergence: maxcalls: function evaluated 10 times + + """ + counter = [0] + def f_maxcalls_wrapped(*args, **kwargs): + counter[0] += 1 + if counter[0] > N: + raise ctx.NoConvergence("maxcalls: function evaluated %i times" % N) + return f(*args, **kwargs) + return f_maxcalls_wrapped + + def memoize(ctx, f): + """ + Return a wrapped copy of *f* that caches computed values, i.e. + a memoized copy of *f*. Values are only reused if the cached precision + is equal to or higher than the working precision:: + + >>> from mpmath import * + >>> mp.dps = 15; mp.pretty = True + >>> f = memoize(maxcalls(sin, 1)) + >>> f(2) + 0.909297426825682 + >>> f(2) + 0.909297426825682 + >>> mp.dps = 25 + >>> f(2) # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + NoConvergence: maxcalls: function evaluated 1 times + + """ + f_cache = {} + def f_cached(*args, **kwargs): + if kwargs: + key = args, tuple(kwargs.items()) + else: + key = args + prec = ctx.prec + if key in f_cache: + cprec, cvalue = f_cache[key] + if cprec >= prec: + return +cvalue + value = f(*args, **kwargs) + f_cache[key] = (prec, value) + return value + f_cached.__name__ = f.__name__ + f_cached.__doc__ = f.__doc__ + return f_cached diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/ctx_fp.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/ctx_fp.py new file mode 100644 index 0000000000000000000000000000000000000000..aa72ea5b03fde4da66b0d8fbf8ffa4012e3f6178 --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/ctx_fp.py @@ -0,0 +1,253 @@ +from .ctx_base import StandardBaseContext + +import math +import cmath +from . import math2 + +from . import function_docs + +from .libmp import mpf_bernoulli, to_float, int_types +from . import libmp + +class FPContext(StandardBaseContext): + """ + Context for fast low-precision arithmetic (53-bit precision, giving at most + about 15-digit accuracy), using Python's builtin float and complex. + """ + + def __init__(ctx): + StandardBaseContext.__init__(ctx) + + # Override SpecialFunctions implementation + ctx.loggamma = math2.loggamma + ctx._bernoulli_cache = {} + ctx.pretty = False + + ctx._init_aliases() + + _mpq = lambda cls, x: float(x[0])/x[1] + + NoConvergence = libmp.NoConvergence + + def _get_prec(ctx): return 53 + def _set_prec(ctx, p): return + def _get_dps(ctx): return 15 + def _set_dps(ctx, p): return + + _fixed_precision = True + + prec = property(_get_prec, _set_prec) + dps = property(_get_dps, _set_dps) + + zero = 0.0 + one = 1.0 + eps = math2.EPS + inf = math2.INF + ninf = math2.NINF + nan = math2.NAN + j = 1j + + # Called by SpecialFunctions.__init__() + @classmethod + def _wrap_specfun(cls, name, f, wrap): + if wrap: + def f_wrapped(ctx, *args, **kwargs): + convert = ctx.convert + args = [convert(a) for a in args] + return f(ctx, *args, **kwargs) + else: + f_wrapped = f + f_wrapped.__doc__ = function_docs.__dict__.get(name, f.__doc__) + setattr(cls, name, f_wrapped) + + def bernoulli(ctx, n): + cache = ctx._bernoulli_cache + if n in cache: + return cache[n] + cache[n] = to_float(mpf_bernoulli(n, 53, 'n'), strict=True) + return cache[n] + + pi = math2.pi + e = math2.e + euler = math2.euler + sqrt2 = 1.4142135623730950488 + sqrt5 = 2.2360679774997896964 + phi = 1.6180339887498948482 + ln2 = 0.69314718055994530942 + ln10 = 2.302585092994045684 + euler = 0.57721566490153286061 + catalan = 0.91596559417721901505 + khinchin = 2.6854520010653064453 + apery = 1.2020569031595942854 + glaisher = 1.2824271291006226369 + + absmin = absmax = abs + + def is_special(ctx, x): + return x - x != 0.0 + + def isnan(ctx, x): + return x != x + + def isinf(ctx, x): + return abs(x) == math2.INF + + def isnormal(ctx, x): + if x: + return x - x == 0.0 + return False + + def isnpint(ctx, x): + if type(x) is complex: + if x.imag: + return False + x = x.real + return x <= 0.0 and round(x) == x + + mpf = float + mpc = complex + + def convert(ctx, x): + try: + return float(x) + except: + return complex(x) + + power = staticmethod(math2.pow) + sqrt = staticmethod(math2.sqrt) + exp = staticmethod(math2.exp) + ln = log = staticmethod(math2.log) + cos = staticmethod(math2.cos) + sin = staticmethod(math2.sin) + tan = staticmethod(math2.tan) + cos_sin = staticmethod(math2.cos_sin) + acos = staticmethod(math2.acos) + asin = staticmethod(math2.asin) + atan = staticmethod(math2.atan) + cosh = staticmethod(math2.cosh) + sinh = staticmethod(math2.sinh) + tanh = staticmethod(math2.tanh) + gamma = staticmethod(math2.gamma) + rgamma = staticmethod(math2.rgamma) + fac = factorial = staticmethod(math2.factorial) + floor = staticmethod(math2.floor) + ceil = staticmethod(math2.ceil) + cospi = staticmethod(math2.cospi) + sinpi = staticmethod(math2.sinpi) + cbrt = staticmethod(math2.cbrt) + _nthroot = staticmethod(math2.nthroot) + _ei = staticmethod(math2.ei) + _e1 = staticmethod(math2.e1) + _zeta = _zeta_int = staticmethod(math2.zeta) + + # XXX: math2 + def arg(ctx, z): + z = complex(z) + return math.atan2(z.imag, z.real) + + def expj(ctx, x): + return ctx.exp(ctx.j*x) + + def expjpi(ctx, x): + return ctx.exp(ctx.j*ctx.pi*x) + + ldexp = math.ldexp + frexp = math.frexp + + def mag(ctx, z): + if z: + return ctx.frexp(abs(z))[1] + return ctx.ninf + + def isint(ctx, z): + if hasattr(z, "imag"): # float/int don't have .real/.imag in py2.5 + if z.imag: + return False + z = z.real + try: + return z == int(z) + except: + return False + + def nint_distance(ctx, z): + if hasattr(z, "imag"): # float/int don't have .real/.imag in py2.5 + n = round(z.real) + else: + n = round(z) + if n == z: + return n, ctx.ninf + return n, ctx.mag(abs(z-n)) + + def _convert_param(ctx, z): + if type(z) is tuple: + p, q = z + return ctx.mpf(p) / q, 'R' + if hasattr(z, "imag"): # float/int don't have .real/.imag in py2.5 + intz = int(z.real) + else: + intz = int(z) + if z == intz: + return intz, 'Z' + return z, 'R' + + def _is_real_type(ctx, z): + return isinstance(z, float) or isinstance(z, int_types) + + def _is_complex_type(ctx, z): + return isinstance(z, complex) + + def hypsum(ctx, p, q, types, coeffs, z, maxterms=6000, **kwargs): + coeffs = list(coeffs) + num = range(p) + den = range(p,p+q) + tol = ctx.eps + s = t = 1.0 + k = 0 + while 1: + for i in num: t *= (coeffs[i]+k) + for i in den: t /= (coeffs[i]+k) + k += 1; t /= k; t *= z; s += t + if abs(t) < tol: + return s + if k > maxterms: + raise ctx.NoConvergence + + def atan2(ctx, x, y): + return math.atan2(x, y) + + def psi(ctx, m, z): + m = int(m) + if m == 0: + return ctx.digamma(z) + return (-1)**(m+1) * ctx.fac(m) * ctx.zeta(m+1, z) + + digamma = staticmethod(math2.digamma) + + def harmonic(ctx, x): + x = ctx.convert(x) + if x == 0 or x == 1: + return x + return ctx.digamma(x+1) + ctx.euler + + nstr = str + + def to_fixed(ctx, x, prec): + return int(math.ldexp(x, prec)) + + def rand(ctx): + import random + return random.random() + + _erf = staticmethod(math2.erf) + _erfc = staticmethod(math2.erfc) + + def sum_accurately(ctx, terms, check_step=1): + s = ctx.zero + k = 0 + for term in terms(): + s += term + if (not k % check_step) and term: + if abs(term) <= 1e-18*abs(s): + break + k += 1 + return s diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/ctx_iv.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/ctx_iv.py new file mode 100644 index 0000000000000000000000000000000000000000..c038e00a5677e318d222b63c22d225e3045e1c2b --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/ctx_iv.py @@ -0,0 +1,551 @@ +import operator + +from . import libmp + +from .libmp.backend import basestring + +from .libmp import ( + int_types, MPZ_ONE, + prec_to_dps, dps_to_prec, repr_dps, + round_floor, round_ceiling, + fzero, finf, fninf, fnan, + mpf_le, mpf_neg, + from_int, from_float, from_str, from_rational, + mpi_mid, mpi_delta, mpi_str, + mpi_abs, mpi_pos, mpi_neg, mpi_add, mpi_sub, + mpi_mul, mpi_div, mpi_pow_int, mpi_pow, + mpi_from_str, + mpci_pos, mpci_neg, mpci_add, mpci_sub, mpci_mul, mpci_div, mpci_pow, + mpci_abs, mpci_pow, mpci_exp, mpci_log, + ComplexResult, + mpf_hash, mpc_hash) +from .matrices.matrices import _matrix + +mpi_zero = (fzero, fzero) + +from .ctx_base import StandardBaseContext + +new = object.__new__ + +def convert_mpf_(x, prec, rounding): + if hasattr(x, "_mpf_"): return x._mpf_ + if isinstance(x, int_types): return from_int(x, prec, rounding) + if isinstance(x, float): return from_float(x, prec, rounding) + if isinstance(x, basestring): return from_str(x, prec, rounding) + raise NotImplementedError + + +class ivmpf(object): + """ + Interval arithmetic class. Precision is controlled by iv.prec. + """ + + def __new__(cls, x=0): + return cls.ctx.convert(x) + + def cast(self, cls, f_convert): + a, b = self._mpi_ + if a == b: + return cls(f_convert(a)) + raise ValueError + + def __int__(self): + return self.cast(int, libmp.to_int) + + def __float__(self): + return self.cast(float, libmp.to_float) + + def __complex__(self): + return self.cast(complex, libmp.to_float) + + def __hash__(self): + a, b = self._mpi_ + if a == b: + return mpf_hash(a) + else: + return hash(self._mpi_) + + @property + def real(self): return self + + @property + def imag(self): return self.ctx.zero + + def conjugate(self): return self + + @property + def a(self): + a, b = self._mpi_ + return self.ctx.make_mpf((a, a)) + + @property + def b(self): + a, b = self._mpi_ + return self.ctx.make_mpf((b, b)) + + @property + def mid(self): + ctx = self.ctx + v = mpi_mid(self._mpi_, ctx.prec) + return ctx.make_mpf((v, v)) + + @property + def delta(self): + ctx = self.ctx + v = mpi_delta(self._mpi_, ctx.prec) + return ctx.make_mpf((v,v)) + + @property + def _mpci_(self): + return self._mpi_, mpi_zero + + def _compare(*args): + raise TypeError("no ordering relation is defined for intervals") + + __gt__ = _compare + __le__ = _compare + __gt__ = _compare + __ge__ = _compare + + def __contains__(self, t): + t = self.ctx.mpf(t) + return (self.a <= t.a) and (t.b <= self.b) + + def __str__(self): + return mpi_str(self._mpi_, self.ctx.prec) + + def __repr__(self): + if self.ctx.pretty: + return str(self) + a, b = self._mpi_ + n = repr_dps(self.ctx.prec) + a = libmp.to_str(a, n) + b = libmp.to_str(b, n) + return "mpi(%r, %r)" % (a, b) + + def _compare(s, t, cmpfun): + if not hasattr(t, "_mpi_"): + try: + t = s.ctx.convert(t) + except: + return NotImplemented + return cmpfun(s._mpi_, t._mpi_) + + def __eq__(s, t): return s._compare(t, libmp.mpi_eq) + def __ne__(s, t): return s._compare(t, libmp.mpi_ne) + def __lt__(s, t): return s._compare(t, libmp.mpi_lt) + def __le__(s, t): return s._compare(t, libmp.mpi_le) + def __gt__(s, t): return s._compare(t, libmp.mpi_gt) + def __ge__(s, t): return s._compare(t, libmp.mpi_ge) + + def __abs__(self): + return self.ctx.make_mpf(mpi_abs(self._mpi_, self.ctx.prec)) + def __pos__(self): + return self.ctx.make_mpf(mpi_pos(self._mpi_, self.ctx.prec)) + def __neg__(self): + return self.ctx.make_mpf(mpi_neg(self._mpi_, self.ctx.prec)) + + def ae(s, t, rel_eps=None, abs_eps=None): + return s.ctx.almosteq(s, t, rel_eps, abs_eps) + +class ivmpc(object): + + def __new__(cls, re=0, im=0): + re = cls.ctx.convert(re) + im = cls.ctx.convert(im) + y = new(cls) + y._mpci_ = re._mpi_, im._mpi_ + return y + + def __hash__(self): + (a, b), (c,d) = self._mpci_ + if a == b and c == d: + return mpc_hash((a, c)) + else: + return hash(self._mpci_) + + def __repr__(s): + if s.ctx.pretty: + return str(s) + return "iv.mpc(%s, %s)" % (repr(s.real), repr(s.imag)) + + def __str__(s): + return "(%s + %s*j)" % (str(s.real), str(s.imag)) + + @property + def a(self): + (a, b), (c,d) = self._mpci_ + return self.ctx.make_mpf((a, a)) + + @property + def b(self): + (a, b), (c,d) = self._mpci_ + return self.ctx.make_mpf((b, b)) + + @property + def c(self): + (a, b), (c,d) = self._mpci_ + return self.ctx.make_mpf((c, c)) + + @property + def d(self): + (a, b), (c,d) = self._mpci_ + return self.ctx.make_mpf((d, d)) + + @property + def real(s): + return s.ctx.make_mpf(s._mpci_[0]) + + @property + def imag(s): + return s.ctx.make_mpf(s._mpci_[1]) + + def conjugate(s): + a, b = s._mpci_ + return s.ctx.make_mpc((a, mpf_neg(b))) + + def overlap(s, t): + t = s.ctx.convert(t) + real_overlap = (s.a <= t.a <= s.b) or (s.a <= t.b <= s.b) or (t.a <= s.a <= t.b) or (t.a <= s.b <= t.b) + imag_overlap = (s.c <= t.c <= s.d) or (s.c <= t.d <= s.d) or (t.c <= s.c <= t.d) or (t.c <= s.d <= t.d) + return real_overlap and imag_overlap + + def __contains__(s, t): + t = s.ctx.convert(t) + return t.real in s.real and t.imag in s.imag + + def _compare(s, t, ne=False): + if not isinstance(t, s.ctx._types): + try: + t = s.ctx.convert(t) + except: + return NotImplemented + if hasattr(t, '_mpi_'): + tval = t._mpi_, mpi_zero + elif hasattr(t, '_mpci_'): + tval = t._mpci_ + if ne: + return s._mpci_ != tval + return s._mpci_ == tval + + def __eq__(s, t): return s._compare(t) + def __ne__(s, t): return s._compare(t, True) + + def __lt__(s, t): raise TypeError("complex intervals cannot be ordered") + __le__ = __gt__ = __ge__ = __lt__ + + def __neg__(s): return s.ctx.make_mpc(mpci_neg(s._mpci_, s.ctx.prec)) + def __pos__(s): return s.ctx.make_mpc(mpci_pos(s._mpci_, s.ctx.prec)) + def __abs__(s): return s.ctx.make_mpf(mpci_abs(s._mpci_, s.ctx.prec)) + + def ae(s, t, rel_eps=None, abs_eps=None): + return s.ctx.almosteq(s, t, rel_eps, abs_eps) + +def _binary_op(f_real, f_complex): + def g_complex(ctx, sval, tval): + return ctx.make_mpc(f_complex(sval, tval, ctx.prec)) + def g_real(ctx, sval, tval): + try: + return ctx.make_mpf(f_real(sval, tval, ctx.prec)) + except ComplexResult: + sval = (sval, mpi_zero) + tval = (tval, mpi_zero) + return g_complex(ctx, sval, tval) + def lop_real(s, t): + if isinstance(t, _matrix): return NotImplemented + ctx = s.ctx + if not isinstance(t, ctx._types): t = ctx.convert(t) + if hasattr(t, "_mpi_"): return g_real(ctx, s._mpi_, t._mpi_) + if hasattr(t, "_mpci_"): return g_complex(ctx, (s._mpi_, mpi_zero), t._mpci_) + return NotImplemented + def rop_real(s, t): + ctx = s.ctx + if not isinstance(t, ctx._types): t = ctx.convert(t) + if hasattr(t, "_mpi_"): return g_real(ctx, t._mpi_, s._mpi_) + if hasattr(t, "_mpci_"): return g_complex(ctx, t._mpci_, (s._mpi_, mpi_zero)) + return NotImplemented + def lop_complex(s, t): + if isinstance(t, _matrix): return NotImplemented + ctx = s.ctx + if not isinstance(t, s.ctx._types): + try: + t = s.ctx.convert(t) + except (ValueError, TypeError): + return NotImplemented + return g_complex(ctx, s._mpci_, t._mpci_) + def rop_complex(s, t): + ctx = s.ctx + if not isinstance(t, s.ctx._types): + t = s.ctx.convert(t) + return g_complex(ctx, t._mpci_, s._mpci_) + return lop_real, rop_real, lop_complex, rop_complex + +ivmpf.__add__, ivmpf.__radd__, ivmpc.__add__, ivmpc.__radd__ = _binary_op(mpi_add, mpci_add) +ivmpf.__sub__, ivmpf.__rsub__, ivmpc.__sub__, ivmpc.__rsub__ = _binary_op(mpi_sub, mpci_sub) +ivmpf.__mul__, ivmpf.__rmul__, ivmpc.__mul__, ivmpc.__rmul__ = _binary_op(mpi_mul, mpci_mul) +ivmpf.__div__, ivmpf.__rdiv__, ivmpc.__div__, ivmpc.__rdiv__ = _binary_op(mpi_div, mpci_div) +ivmpf.__pow__, ivmpf.__rpow__, ivmpc.__pow__, ivmpc.__rpow__ = _binary_op(mpi_pow, mpci_pow) + +ivmpf.__truediv__ = ivmpf.__div__; ivmpf.__rtruediv__ = ivmpf.__rdiv__ +ivmpc.__truediv__ = ivmpc.__div__; ivmpc.__rtruediv__ = ivmpc.__rdiv__ + +class ivmpf_constant(ivmpf): + def __new__(cls, f): + self = new(cls) + self._f = f + return self + def _get_mpi_(self): + prec = self.ctx._prec[0] + a = self._f(prec, round_floor) + b = self._f(prec, round_ceiling) + return a, b + _mpi_ = property(_get_mpi_) + +class MPIntervalContext(StandardBaseContext): + + def __init__(ctx): + ctx.mpf = type('ivmpf', (ivmpf,), {}) + ctx.mpc = type('ivmpc', (ivmpc,), {}) + ctx._types = (ctx.mpf, ctx.mpc) + ctx._constant = type('ivmpf_constant', (ivmpf_constant,), {}) + ctx._prec = [53] + ctx._set_prec(53) + ctx._constant._ctxdata = ctx.mpf._ctxdata = ctx.mpc._ctxdata = [ctx.mpf, new, ctx._prec] + ctx._constant.ctx = ctx.mpf.ctx = ctx.mpc.ctx = ctx + ctx.pretty = False + StandardBaseContext.__init__(ctx) + ctx._init_builtins() + + def _mpi(ctx, a, b=None): + if b is None: + return ctx.mpf(a) + return ctx.mpf((a,b)) + + def _init_builtins(ctx): + ctx.one = ctx.mpf(1) + ctx.zero = ctx.mpf(0) + ctx.inf = ctx.mpf('inf') + ctx.ninf = -ctx.inf + ctx.nan = ctx.mpf('nan') + ctx.j = ctx.mpc(0,1) + ctx.exp = ctx._wrap_mpi_function(libmp.mpi_exp, libmp.mpci_exp) + ctx.sqrt = ctx._wrap_mpi_function(libmp.mpi_sqrt) + ctx.ln = ctx._wrap_mpi_function(libmp.mpi_log, libmp.mpci_log) + ctx.cos = ctx._wrap_mpi_function(libmp.mpi_cos, libmp.mpci_cos) + ctx.sin = ctx._wrap_mpi_function(libmp.mpi_sin, libmp.mpci_sin) + ctx.tan = ctx._wrap_mpi_function(libmp.mpi_tan) + ctx.gamma = ctx._wrap_mpi_function(libmp.mpi_gamma, libmp.mpci_gamma) + ctx.loggamma = ctx._wrap_mpi_function(libmp.mpi_loggamma, libmp.mpci_loggamma) + ctx.rgamma = ctx._wrap_mpi_function(libmp.mpi_rgamma, libmp.mpci_rgamma) + ctx.factorial = ctx._wrap_mpi_function(libmp.mpi_factorial, libmp.mpci_factorial) + ctx.fac = ctx.factorial + + ctx.eps = ctx._constant(lambda prec, rnd: (0, MPZ_ONE, 1-prec, 1)) + ctx.pi = ctx._constant(libmp.mpf_pi) + ctx.e = ctx._constant(libmp.mpf_e) + ctx.ln2 = ctx._constant(libmp.mpf_ln2) + ctx.ln10 = ctx._constant(libmp.mpf_ln10) + ctx.phi = ctx._constant(libmp.mpf_phi) + ctx.euler = ctx._constant(libmp.mpf_euler) + ctx.catalan = ctx._constant(libmp.mpf_catalan) + ctx.glaisher = ctx._constant(libmp.mpf_glaisher) + ctx.khinchin = ctx._constant(libmp.mpf_khinchin) + ctx.twinprime = ctx._constant(libmp.mpf_twinprime) + + def _wrap_mpi_function(ctx, f_real, f_complex=None): + def g(x, **kwargs): + if kwargs: + prec = kwargs.get('prec', ctx._prec[0]) + else: + prec = ctx._prec[0] + x = ctx.convert(x) + if hasattr(x, "_mpi_"): + return ctx.make_mpf(f_real(x._mpi_, prec)) + if hasattr(x, "_mpci_"): + return ctx.make_mpc(f_complex(x._mpci_, prec)) + raise ValueError + return g + + @classmethod + def _wrap_specfun(cls, name, f, wrap): + if wrap: + def f_wrapped(ctx, *args, **kwargs): + convert = ctx.convert + args = [convert(a) for a in args] + prec = ctx.prec + try: + ctx.prec += 10 + retval = f(ctx, *args, **kwargs) + finally: + ctx.prec = prec + return +retval + else: + f_wrapped = f + setattr(cls, name, f_wrapped) + + def _set_prec(ctx, n): + ctx._prec[0] = max(1, int(n)) + ctx._dps = prec_to_dps(n) + + def _set_dps(ctx, n): + ctx._prec[0] = dps_to_prec(n) + ctx._dps = max(1, int(n)) + + prec = property(lambda ctx: ctx._prec[0], _set_prec) + dps = property(lambda ctx: ctx._dps, _set_dps) + + def make_mpf(ctx, v): + a = new(ctx.mpf) + a._mpi_ = v + return a + + def make_mpc(ctx, v): + a = new(ctx.mpc) + a._mpci_ = v + return a + + def _mpq(ctx, pq): + p, q = pq + a = libmp.from_rational(p, q, ctx.prec, round_floor) + b = libmp.from_rational(p, q, ctx.prec, round_ceiling) + return ctx.make_mpf((a, b)) + + def convert(ctx, x): + if isinstance(x, (ctx.mpf, ctx.mpc)): + return x + if isinstance(x, ctx._constant): + return +x + if isinstance(x, complex) or hasattr(x, "_mpc_"): + re = ctx.convert(x.real) + im = ctx.convert(x.imag) + return ctx.mpc(re,im) + if isinstance(x, basestring): + v = mpi_from_str(x, ctx.prec) + return ctx.make_mpf(v) + if hasattr(x, "_mpi_"): + a, b = x._mpi_ + else: + try: + a, b = x + except (TypeError, ValueError): + a = b = x + if hasattr(a, "_mpi_"): + a = a._mpi_[0] + else: + a = convert_mpf_(a, ctx.prec, round_floor) + if hasattr(b, "_mpi_"): + b = b._mpi_[1] + else: + b = convert_mpf_(b, ctx.prec, round_ceiling) + if a == fnan or b == fnan: + a = fninf + b = finf + assert mpf_le(a, b), "endpoints must be properly ordered" + return ctx.make_mpf((a, b)) + + def nstr(ctx, x, n=5, **kwargs): + x = ctx.convert(x) + if hasattr(x, "_mpi_"): + return libmp.mpi_to_str(x._mpi_, n, **kwargs) + if hasattr(x, "_mpci_"): + re = libmp.mpi_to_str(x._mpci_[0], n, **kwargs) + im = libmp.mpi_to_str(x._mpci_[1], n, **kwargs) + return "(%s + %s*j)" % (re, im) + + def mag(ctx, x): + x = ctx.convert(x) + if isinstance(x, ctx.mpc): + return max(ctx.mag(x.real), ctx.mag(x.imag)) + 1 + a, b = libmp.mpi_abs(x._mpi_) + sign, man, exp, bc = b + if man: + return exp+bc + if b == fzero: + return ctx.ninf + if b == fnan: + return ctx.nan + return ctx.inf + + def isnan(ctx, x): + return False + + def isinf(ctx, x): + return x == ctx.inf + + def isint(ctx, x): + x = ctx.convert(x) + a, b = x._mpi_ + if a == b: + sign, man, exp, bc = a + if man: + return exp >= 0 + return a == fzero + return None + + def ldexp(ctx, x, n): + a, b = ctx.convert(x)._mpi_ + a = libmp.mpf_shift(a, n) + b = libmp.mpf_shift(b, n) + return ctx.make_mpf((a,b)) + + def absmin(ctx, x): + return abs(ctx.convert(x)).a + + def absmax(ctx, x): + return abs(ctx.convert(x)).b + + def atan2(ctx, y, x): + y = ctx.convert(y)._mpi_ + x = ctx.convert(x)._mpi_ + return ctx.make_mpf(libmp.mpi_atan2(y,x,ctx.prec)) + + def _convert_param(ctx, x): + if isinstance(x, libmp.int_types): + return x, 'Z' + if isinstance(x, tuple): + p, q = x + return (ctx.mpf(p) / ctx.mpf(q), 'R') + x = ctx.convert(x) + if isinstance(x, ctx.mpf): + return x, 'R' + if isinstance(x, ctx.mpc): + return x, 'C' + raise ValueError + + def _is_real_type(ctx, z): + return isinstance(z, ctx.mpf) or isinstance(z, int_types) + + def _is_complex_type(ctx, z): + return isinstance(z, ctx.mpc) + + def hypsum(ctx, p, q, types, coeffs, z, maxterms=6000, **kwargs): + coeffs = list(coeffs) + num = range(p) + den = range(p,p+q) + #tol = ctx.eps + s = t = ctx.one + k = 0 + while 1: + for i in num: t *= (coeffs[i]+k) + for i in den: t /= (coeffs[i]+k) + k += 1; t /= k; t *= z; s += t + if t == 0: + return s + #if abs(t) < tol: + # return s + if k > maxterms: + raise ctx.NoConvergence + + +# Register with "numbers" ABC +# We do not subclass, hence we do not use the @abstractmethod checks. While +# this is less invasive it may turn out that we do not actually support +# parts of the expected interfaces. See +# http://docs.python.org/2/library/numbers.html for list of abstract +# methods. +try: + import numbers + numbers.Complex.register(ivmpc) + numbers.Real.register(ivmpf) +except ImportError: + pass diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/ctx_mp.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/ctx_mp.py new file mode 100644 index 0000000000000000000000000000000000000000..93594dd44474a415c74e4b0beb83bd7012666c9d --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/ctx_mp.py @@ -0,0 +1,1339 @@ +""" +This module defines the mpf, mpc classes, and standard functions for +operating with them. +""" +__docformat__ = 'plaintext' + +import functools + +import re + +from .ctx_base import StandardBaseContext + +from .libmp.backend import basestring, BACKEND + +from . import libmp + +from .libmp import (MPZ, MPZ_ZERO, MPZ_ONE, int_types, repr_dps, + round_floor, round_ceiling, dps_to_prec, round_nearest, prec_to_dps, + ComplexResult, to_pickable, from_pickable, normalize, + from_int, from_float, from_str, to_int, to_float, to_str, + from_rational, from_man_exp, + fone, fzero, finf, fninf, fnan, + mpf_abs, mpf_pos, mpf_neg, mpf_add, mpf_sub, mpf_mul, mpf_mul_int, + mpf_div, mpf_rdiv_int, mpf_pow_int, mpf_mod, + mpf_eq, mpf_cmp, mpf_lt, mpf_gt, mpf_le, mpf_ge, + mpf_hash, mpf_rand, + mpf_sum, + bitcount, to_fixed, + mpc_to_str, + mpc_to_complex, mpc_hash, mpc_pos, mpc_is_nonzero, mpc_neg, mpc_conjugate, + mpc_abs, mpc_add, mpc_add_mpf, mpc_sub, mpc_sub_mpf, mpc_mul, mpc_mul_mpf, + mpc_mul_int, mpc_div, mpc_div_mpf, mpc_pow, mpc_pow_mpf, mpc_pow_int, + mpc_mpf_div, + mpf_pow, + mpf_pi, mpf_degree, mpf_e, mpf_phi, mpf_ln2, mpf_ln10, + mpf_euler, mpf_catalan, mpf_apery, mpf_khinchin, + mpf_glaisher, mpf_twinprime, mpf_mertens, + int_types) + +from . import function_docs +from . import rational + +new = object.__new__ + +get_complex = re.compile(r'^\(?(?P[\+\-]?\d*(\.\d*)?(e[\+\-]?\d+)?)??' + r'(?P[\+\-]?\d*(\.\d*)?(e[\+\-]?\d+)?j)?\)?$') + +if BACKEND == 'sage': + from sage.libs.mpmath.ext_main import Context as BaseMPContext + # pickle hack + import sage.libs.mpmath.ext_main as _mpf_module +else: + from .ctx_mp_python import PythonMPContext as BaseMPContext + from . import ctx_mp_python as _mpf_module + +from .ctx_mp_python import _mpf, _mpc, mpnumeric + +class MPContext(BaseMPContext, StandardBaseContext): + """ + Context for multiprecision arithmetic with a global precision. + """ + + def __init__(ctx): + BaseMPContext.__init__(ctx) + ctx.trap_complex = False + ctx.pretty = False + ctx.types = [ctx.mpf, ctx.mpc, ctx.constant] + ctx._mpq = rational.mpq + ctx.default() + StandardBaseContext.__init__(ctx) + + ctx.mpq = rational.mpq + ctx.init_builtins() + + ctx.hyp_summators = {} + + ctx._init_aliases() + + # XXX: automate + try: + ctx.bernoulli.im_func.func_doc = function_docs.bernoulli + ctx.primepi.im_func.func_doc = function_docs.primepi + ctx.psi.im_func.func_doc = function_docs.psi + ctx.atan2.im_func.func_doc = function_docs.atan2 + except AttributeError: + # python 3 + ctx.bernoulli.__func__.func_doc = function_docs.bernoulli + ctx.primepi.__func__.func_doc = function_docs.primepi + ctx.psi.__func__.func_doc = function_docs.psi + ctx.atan2.__func__.func_doc = function_docs.atan2 + + ctx.digamma.func_doc = function_docs.digamma + ctx.cospi.func_doc = function_docs.cospi + ctx.sinpi.func_doc = function_docs.sinpi + + def init_builtins(ctx): + + mpf = ctx.mpf + mpc = ctx.mpc + + # Exact constants + ctx.one = ctx.make_mpf(fone) + ctx.zero = ctx.make_mpf(fzero) + ctx.j = ctx.make_mpc((fzero,fone)) + ctx.inf = ctx.make_mpf(finf) + ctx.ninf = ctx.make_mpf(fninf) + ctx.nan = ctx.make_mpf(fnan) + + eps = ctx.constant(lambda prec, rnd: (0, MPZ_ONE, 1-prec, 1), + "epsilon of working precision", "eps") + ctx.eps = eps + + # Approximate constants + ctx.pi = ctx.constant(mpf_pi, "pi", "pi") + ctx.ln2 = ctx.constant(mpf_ln2, "ln(2)", "ln2") + ctx.ln10 = ctx.constant(mpf_ln10, "ln(10)", "ln10") + ctx.phi = ctx.constant(mpf_phi, "Golden ratio phi", "phi") + ctx.e = ctx.constant(mpf_e, "e = exp(1)", "e") + ctx.euler = ctx.constant(mpf_euler, "Euler's constant", "euler") + ctx.catalan = ctx.constant(mpf_catalan, "Catalan's constant", "catalan") + ctx.khinchin = ctx.constant(mpf_khinchin, "Khinchin's constant", "khinchin") + ctx.glaisher = ctx.constant(mpf_glaisher, "Glaisher's constant", "glaisher") + ctx.apery = ctx.constant(mpf_apery, "Apery's constant", "apery") + ctx.degree = ctx.constant(mpf_degree, "1 deg = pi / 180", "degree") + ctx.twinprime = ctx.constant(mpf_twinprime, "Twin prime constant", "twinprime") + ctx.mertens = ctx.constant(mpf_mertens, "Mertens' constant", "mertens") + + # Standard functions + ctx.sqrt = ctx._wrap_libmp_function(libmp.mpf_sqrt, libmp.mpc_sqrt) + ctx.cbrt = ctx._wrap_libmp_function(libmp.mpf_cbrt, libmp.mpc_cbrt) + ctx.ln = ctx._wrap_libmp_function(libmp.mpf_log, libmp.mpc_log) + ctx.atan = ctx._wrap_libmp_function(libmp.mpf_atan, libmp.mpc_atan) + ctx.exp = ctx._wrap_libmp_function(libmp.mpf_exp, libmp.mpc_exp) + ctx.expj = ctx._wrap_libmp_function(libmp.mpf_expj, libmp.mpc_expj) + ctx.expjpi = ctx._wrap_libmp_function(libmp.mpf_expjpi, libmp.mpc_expjpi) + ctx.sin = ctx._wrap_libmp_function(libmp.mpf_sin, libmp.mpc_sin) + ctx.cos = ctx._wrap_libmp_function(libmp.mpf_cos, libmp.mpc_cos) + ctx.tan = ctx._wrap_libmp_function(libmp.mpf_tan, libmp.mpc_tan) + ctx.sinh = ctx._wrap_libmp_function(libmp.mpf_sinh, libmp.mpc_sinh) + ctx.cosh = ctx._wrap_libmp_function(libmp.mpf_cosh, libmp.mpc_cosh) + ctx.tanh = ctx._wrap_libmp_function(libmp.mpf_tanh, libmp.mpc_tanh) + ctx.asin = ctx._wrap_libmp_function(libmp.mpf_asin, libmp.mpc_asin) + ctx.acos = ctx._wrap_libmp_function(libmp.mpf_acos, libmp.mpc_acos) + ctx.atan = ctx._wrap_libmp_function(libmp.mpf_atan, libmp.mpc_atan) + ctx.asinh = ctx._wrap_libmp_function(libmp.mpf_asinh, libmp.mpc_asinh) + ctx.acosh = ctx._wrap_libmp_function(libmp.mpf_acosh, libmp.mpc_acosh) + ctx.atanh = ctx._wrap_libmp_function(libmp.mpf_atanh, libmp.mpc_atanh) + ctx.sinpi = ctx._wrap_libmp_function(libmp.mpf_sin_pi, libmp.mpc_sin_pi) + ctx.cospi = ctx._wrap_libmp_function(libmp.mpf_cos_pi, libmp.mpc_cos_pi) + ctx.floor = ctx._wrap_libmp_function(libmp.mpf_floor, libmp.mpc_floor) + ctx.ceil = ctx._wrap_libmp_function(libmp.mpf_ceil, libmp.mpc_ceil) + ctx.nint = ctx._wrap_libmp_function(libmp.mpf_nint, libmp.mpc_nint) + ctx.frac = ctx._wrap_libmp_function(libmp.mpf_frac, libmp.mpc_frac) + ctx.fib = ctx.fibonacci = ctx._wrap_libmp_function(libmp.mpf_fibonacci, libmp.mpc_fibonacci) + + ctx.gamma = ctx._wrap_libmp_function(libmp.mpf_gamma, libmp.mpc_gamma) + ctx.rgamma = ctx._wrap_libmp_function(libmp.mpf_rgamma, libmp.mpc_rgamma) + ctx.loggamma = ctx._wrap_libmp_function(libmp.mpf_loggamma, libmp.mpc_loggamma) + ctx.fac = ctx.factorial = ctx._wrap_libmp_function(libmp.mpf_factorial, libmp.mpc_factorial) + + ctx.digamma = ctx._wrap_libmp_function(libmp.mpf_psi0, libmp.mpc_psi0) + ctx.harmonic = ctx._wrap_libmp_function(libmp.mpf_harmonic, libmp.mpc_harmonic) + ctx.ei = ctx._wrap_libmp_function(libmp.mpf_ei, libmp.mpc_ei) + ctx.e1 = ctx._wrap_libmp_function(libmp.mpf_e1, libmp.mpc_e1) + ctx._ci = ctx._wrap_libmp_function(libmp.mpf_ci, libmp.mpc_ci) + ctx._si = ctx._wrap_libmp_function(libmp.mpf_si, libmp.mpc_si) + ctx.ellipk = ctx._wrap_libmp_function(libmp.mpf_ellipk, libmp.mpc_ellipk) + ctx._ellipe = ctx._wrap_libmp_function(libmp.mpf_ellipe, libmp.mpc_ellipe) + ctx.agm1 = ctx._wrap_libmp_function(libmp.mpf_agm1, libmp.mpc_agm1) + ctx._erf = ctx._wrap_libmp_function(libmp.mpf_erf, None) + ctx._erfc = ctx._wrap_libmp_function(libmp.mpf_erfc, None) + ctx._zeta = ctx._wrap_libmp_function(libmp.mpf_zeta, libmp.mpc_zeta) + ctx._altzeta = ctx._wrap_libmp_function(libmp.mpf_altzeta, libmp.mpc_altzeta) + + # Faster versions + ctx.sqrt = getattr(ctx, "_sage_sqrt", ctx.sqrt) + ctx.exp = getattr(ctx, "_sage_exp", ctx.exp) + ctx.ln = getattr(ctx, "_sage_ln", ctx.ln) + ctx.cos = getattr(ctx, "_sage_cos", ctx.cos) + ctx.sin = getattr(ctx, "_sage_sin", ctx.sin) + + def to_fixed(ctx, x, prec): + return x.to_fixed(prec) + + def hypot(ctx, x, y): + r""" + Computes the Euclidean norm of the vector `(x, y)`, equal + to `\sqrt{x^2 + y^2}`. Both `x` and `y` must be real.""" + x = ctx.convert(x) + y = ctx.convert(y) + return ctx.make_mpf(libmp.mpf_hypot(x._mpf_, y._mpf_, *ctx._prec_rounding)) + + def _gamma_upper_int(ctx, n, z): + n = int(ctx._re(n)) + if n == 0: + return ctx.e1(z) + if not hasattr(z, '_mpf_'): + raise NotImplementedError + prec, rounding = ctx._prec_rounding + real, imag = libmp.mpf_expint(n, z._mpf_, prec, rounding, gamma=True) + if imag is None: + return ctx.make_mpf(real) + else: + return ctx.make_mpc((real, imag)) + + def _expint_int(ctx, n, z): + n = int(n) + if n == 1: + return ctx.e1(z) + if not hasattr(z, '_mpf_'): + raise NotImplementedError + prec, rounding = ctx._prec_rounding + real, imag = libmp.mpf_expint(n, z._mpf_, prec, rounding) + if imag is None: + return ctx.make_mpf(real) + else: + return ctx.make_mpc((real, imag)) + + def _nthroot(ctx, x, n): + if hasattr(x, '_mpf_'): + try: + return ctx.make_mpf(libmp.mpf_nthroot(x._mpf_, n, *ctx._prec_rounding)) + except ComplexResult: + if ctx.trap_complex: + raise + x = (x._mpf_, libmp.fzero) + else: + x = x._mpc_ + return ctx.make_mpc(libmp.mpc_nthroot(x, n, *ctx._prec_rounding)) + + def _besselj(ctx, n, z): + prec, rounding = ctx._prec_rounding + if hasattr(z, '_mpf_'): + return ctx.make_mpf(libmp.mpf_besseljn(n, z._mpf_, prec, rounding)) + elif hasattr(z, '_mpc_'): + return ctx.make_mpc(libmp.mpc_besseljn(n, z._mpc_, prec, rounding)) + + def _agm(ctx, a, b=1): + prec, rounding = ctx._prec_rounding + if hasattr(a, '_mpf_') and hasattr(b, '_mpf_'): + try: + v = libmp.mpf_agm(a._mpf_, b._mpf_, prec, rounding) + return ctx.make_mpf(v) + except ComplexResult: + pass + if hasattr(a, '_mpf_'): a = (a._mpf_, libmp.fzero) + else: a = a._mpc_ + if hasattr(b, '_mpf_'): b = (b._mpf_, libmp.fzero) + else: b = b._mpc_ + return ctx.make_mpc(libmp.mpc_agm(a, b, prec, rounding)) + + def bernoulli(ctx, n): + return ctx.make_mpf(libmp.mpf_bernoulli(int(n), *ctx._prec_rounding)) + + def _zeta_int(ctx, n): + return ctx.make_mpf(libmp.mpf_zeta_int(int(n), *ctx._prec_rounding)) + + def atan2(ctx, y, x): + x = ctx.convert(x) + y = ctx.convert(y) + return ctx.make_mpf(libmp.mpf_atan2(y._mpf_, x._mpf_, *ctx._prec_rounding)) + + def psi(ctx, m, z): + z = ctx.convert(z) + m = int(m) + if ctx._is_real_type(z): + return ctx.make_mpf(libmp.mpf_psi(m, z._mpf_, *ctx._prec_rounding)) + else: + return ctx.make_mpc(libmp.mpc_psi(m, z._mpc_, *ctx._prec_rounding)) + + def cos_sin(ctx, x, **kwargs): + if type(x) not in ctx.types: + x = ctx.convert(x) + prec, rounding = ctx._parse_prec(kwargs) + if hasattr(x, '_mpf_'): + c, s = libmp.mpf_cos_sin(x._mpf_, prec, rounding) + return ctx.make_mpf(c), ctx.make_mpf(s) + elif hasattr(x, '_mpc_'): + c, s = libmp.mpc_cos_sin(x._mpc_, prec, rounding) + return ctx.make_mpc(c), ctx.make_mpc(s) + else: + return ctx.cos(x, **kwargs), ctx.sin(x, **kwargs) + + def cospi_sinpi(ctx, x, **kwargs): + if type(x) not in ctx.types: + x = ctx.convert(x) + prec, rounding = ctx._parse_prec(kwargs) + if hasattr(x, '_mpf_'): + c, s = libmp.mpf_cos_sin_pi(x._mpf_, prec, rounding) + return ctx.make_mpf(c), ctx.make_mpf(s) + elif hasattr(x, '_mpc_'): + c, s = libmp.mpc_cos_sin_pi(x._mpc_, prec, rounding) + return ctx.make_mpc(c), ctx.make_mpc(s) + else: + return ctx.cos(x, **kwargs), ctx.sin(x, **kwargs) + + def clone(ctx): + """ + Create a copy of the context, with the same working precision. + """ + a = ctx.__class__() + a.prec = ctx.prec + return a + + # Several helper methods + # TODO: add more of these, make consistent, write docstrings, ... + + def _is_real_type(ctx, x): + if hasattr(x, '_mpc_') or type(x) is complex: + return False + return True + + def _is_complex_type(ctx, x): + if hasattr(x, '_mpc_') or type(x) is complex: + return True + return False + + def isnan(ctx, x): + """ + Return *True* if *x* is a NaN (not-a-number), or for a complex + number, whether either the real or complex part is NaN; + otherwise return *False*:: + + >>> from mpmath import * + >>> isnan(3.14) + False + >>> isnan(nan) + True + >>> isnan(mpc(3.14,2.72)) + False + >>> isnan(mpc(3.14,nan)) + True + + """ + if hasattr(x, "_mpf_"): + return x._mpf_ == fnan + if hasattr(x, "_mpc_"): + return fnan in x._mpc_ + if isinstance(x, int_types) or isinstance(x, rational.mpq): + return False + x = ctx.convert(x) + if hasattr(x, '_mpf_') or hasattr(x, '_mpc_'): + return ctx.isnan(x) + raise TypeError("isnan() needs a number as input") + + def isfinite(ctx, x): + """ + Return *True* if *x* is a finite number, i.e. neither + an infinity or a NaN. + + >>> from mpmath import * + >>> isfinite(inf) + False + >>> isfinite(-inf) + False + >>> isfinite(3) + True + >>> isfinite(nan) + False + >>> isfinite(3+4j) + True + >>> isfinite(mpc(3,inf)) + False + >>> isfinite(mpc(nan,3)) + False + + """ + if ctx.isinf(x) or ctx.isnan(x): + return False + return True + + def isnpint(ctx, x): + """ + Determine if *x* is a nonpositive integer. + """ + if not x: + return True + if hasattr(x, '_mpf_'): + sign, man, exp, bc = x._mpf_ + return sign and exp >= 0 + if hasattr(x, '_mpc_'): + return not x.imag and ctx.isnpint(x.real) + if type(x) in int_types: + return x <= 0 + if isinstance(x, ctx.mpq): + p, q = x._mpq_ + if not p: + return True + return q == 1 and p <= 0 + return ctx.isnpint(ctx.convert(x)) + + def __str__(ctx): + lines = ["Mpmath settings:", + (" mp.prec = %s" % ctx.prec).ljust(30) + "[default: 53]", + (" mp.dps = %s" % ctx.dps).ljust(30) + "[default: 15]", + (" mp.trap_complex = %s" % ctx.trap_complex).ljust(30) + "[default: False]", + ] + return "\n".join(lines) + + @property + def _repr_digits(ctx): + return repr_dps(ctx._prec) + + @property + def _str_digits(ctx): + return ctx._dps + + def extraprec(ctx, n, normalize_output=False): + """ + The block + + with extraprec(n): + + + increases the precision n bits, executes , and then + restores the precision. + + extraprec(n)(f) returns a decorated version of the function f + that increases the working precision by n bits before execution, + and restores the parent precision afterwards. With + normalize_output=True, it rounds the return value to the parent + precision. + """ + return PrecisionManager(ctx, lambda p: p + n, None, normalize_output) + + def extradps(ctx, n, normalize_output=False): + """ + This function is analogous to extraprec (see documentation) + but changes the decimal precision instead of the number of bits. + """ + return PrecisionManager(ctx, None, lambda d: d + n, normalize_output) + + def workprec(ctx, n, normalize_output=False): + """ + The block + + with workprec(n): + + + sets the precision to n bits, executes , and then restores + the precision. + + workprec(n)(f) returns a decorated version of the function f + that sets the precision to n bits before execution, + and restores the precision afterwards. With normalize_output=True, + it rounds the return value to the parent precision. + """ + return PrecisionManager(ctx, lambda p: n, None, normalize_output) + + def workdps(ctx, n, normalize_output=False): + """ + This function is analogous to workprec (see documentation) + but changes the decimal precision instead of the number of bits. + """ + return PrecisionManager(ctx, None, lambda d: n, normalize_output) + + def autoprec(ctx, f, maxprec=None, catch=(), verbose=False): + r""" + Return a wrapped copy of *f* that repeatedly evaluates *f* + with increasing precision until the result converges to the + full precision used at the point of the call. + + This heuristically protects against rounding errors, at the cost of + roughly a 2x slowdown compared to manually setting the optimal + precision. This method can, however, easily be fooled if the results + from *f* depend "discontinuously" on the precision, for instance + if catastrophic cancellation can occur. Therefore, :func:`~mpmath.autoprec` + should be used judiciously. + + **Examples** + + Many functions are sensitive to perturbations of the input arguments. + If the arguments are decimal numbers, they may have to be converted + to binary at a much higher precision. If the amount of required + extra precision is unknown, :func:`~mpmath.autoprec` is convenient:: + + >>> from mpmath import * + >>> mp.dps = 15 + >>> mp.pretty = True + >>> besselj(5, 125 * 10**28) # Exact input + -8.03284785591801e-17 + >>> besselj(5, '1.25e30') # Bad + 7.12954868316652e-16 + >>> autoprec(besselj)(5, '1.25e30') # Good + -8.03284785591801e-17 + + The following fails to converge because `\sin(\pi) = 0` whereas all + finite-precision approximations of `\pi` give nonzero values:: + + >>> autoprec(sin)(pi) # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + NoConvergence: autoprec: prec increased to 2910 without convergence + + As the following example shows, :func:`~mpmath.autoprec` can protect against + cancellation, but is fooled by too severe cancellation:: + + >>> x = 1e-10 + >>> exp(x)-1; expm1(x); autoprec(lambda t: exp(t)-1)(x) + 1.00000008274037e-10 + 1.00000000005e-10 + 1.00000000005e-10 + >>> x = 1e-50 + >>> exp(x)-1; expm1(x); autoprec(lambda t: exp(t)-1)(x) + 0.0 + 1.0e-50 + 0.0 + + With *catch*, an exception or list of exceptions to intercept + may be specified. The raised exception is interpreted + as signaling insufficient precision. This permits, for example, + evaluating a function where a too low precision results in a + division by zero:: + + >>> f = lambda x: 1/(exp(x)-1) + >>> f(1e-30) + Traceback (most recent call last): + ... + ZeroDivisionError + >>> autoprec(f, catch=ZeroDivisionError)(1e-30) + 1.0e+30 + + + """ + def f_autoprec_wrapped(*args, **kwargs): + prec = ctx.prec + if maxprec is None: + maxprec2 = ctx._default_hyper_maxprec(prec) + else: + maxprec2 = maxprec + try: + ctx.prec = prec + 10 + try: + v1 = f(*args, **kwargs) + except catch: + v1 = ctx.nan + prec2 = prec + 20 + while 1: + ctx.prec = prec2 + try: + v2 = f(*args, **kwargs) + except catch: + v2 = ctx.nan + if v1 == v2: + break + err = ctx.mag(v2-v1) - ctx.mag(v2) + if err < (-prec): + break + if verbose: + print("autoprec: target=%s, prec=%s, accuracy=%s" \ + % (prec, prec2, -err)) + v1 = v2 + if prec2 >= maxprec2: + raise ctx.NoConvergence(\ + "autoprec: prec increased to %i without convergence"\ + % prec2) + prec2 += int(prec2*2) + prec2 = min(prec2, maxprec2) + finally: + ctx.prec = prec + return +v2 + return f_autoprec_wrapped + + def nstr(ctx, x, n=6, **kwargs): + """ + Convert an ``mpf`` or ``mpc`` to a decimal string literal with *n* + significant digits. The small default value for *n* is chosen to + make this function useful for printing collections of numbers + (lists, matrices, etc). + + If *x* is a list or tuple, :func:`~mpmath.nstr` is applied recursively + to each element. For unrecognized classes, :func:`~mpmath.nstr` + simply returns ``str(x)``. + + The companion function :func:`~mpmath.nprint` prints the result + instead of returning it. + + The keyword arguments *strip_zeros*, *min_fixed*, *max_fixed* + and *show_zero_exponent* are forwarded to :func:`~mpmath.libmp.to_str`. + + The number will be printed in fixed-point format if the position + of the leading digit is strictly between min_fixed + (default = min(-dps/3,-5)) and max_fixed (default = dps). + + To force fixed-point format always, set min_fixed = -inf, + max_fixed = +inf. To force floating-point format, set + min_fixed >= max_fixed. + + >>> from mpmath import * + >>> nstr([+pi, ldexp(1,-500)]) + '[3.14159, 3.05494e-151]' + >>> nprint([+pi, ldexp(1,-500)]) + [3.14159, 3.05494e-151] + >>> nstr(mpf("5e-10"), 5) + '5.0e-10' + >>> nstr(mpf("5e-10"), 5, strip_zeros=False) + '5.0000e-10' + >>> nstr(mpf("5e-10"), 5, strip_zeros=False, min_fixed=-11) + '0.00000000050000' + >>> nstr(mpf(0), 5, show_zero_exponent=True) + '0.0e+0' + + """ + if isinstance(x, list): + return "[%s]" % (", ".join(ctx.nstr(c, n, **kwargs) for c in x)) + if isinstance(x, tuple): + return "(%s)" % (", ".join(ctx.nstr(c, n, **kwargs) for c in x)) + if hasattr(x, '_mpf_'): + return to_str(x._mpf_, n, **kwargs) + if hasattr(x, '_mpc_'): + return "(" + mpc_to_str(x._mpc_, n, **kwargs) + ")" + if isinstance(x, basestring): + return repr(x) + if isinstance(x, ctx.matrix): + return x.__nstr__(n, **kwargs) + return str(x) + + def _convert_fallback(ctx, x, strings): + if strings and isinstance(x, basestring): + if 'j' in x.lower(): + x = x.lower().replace(' ', '') + match = get_complex.match(x) + re = match.group('re') + if not re: + re = 0 + im = match.group('im').rstrip('j') + return ctx.mpc(ctx.convert(re), ctx.convert(im)) + if hasattr(x, "_mpi_"): + a, b = x._mpi_ + if a == b: + return ctx.make_mpf(a) + else: + raise ValueError("can only create mpf from zero-width interval") + raise TypeError("cannot create mpf from " + repr(x)) + + def mpmathify(ctx, *args, **kwargs): + return ctx.convert(*args, **kwargs) + + def _parse_prec(ctx, kwargs): + if kwargs: + if kwargs.get('exact'): + return 0, 'f' + prec, rounding = ctx._prec_rounding + if 'rounding' in kwargs: + rounding = kwargs['rounding'] + if 'prec' in kwargs: + prec = kwargs['prec'] + if prec == ctx.inf: + return 0, 'f' + else: + prec = int(prec) + elif 'dps' in kwargs: + dps = kwargs['dps'] + if dps == ctx.inf: + return 0, 'f' + prec = dps_to_prec(dps) + return prec, rounding + return ctx._prec_rounding + + _exact_overflow_msg = "the exact result does not fit in memory" + + _hypsum_msg = """hypsum() failed to converge to the requested %i bits of accuracy +using a working precision of %i bits. Try with a higher maxprec, +maxterms, or set zeroprec.""" + + def hypsum(ctx, p, q, flags, coeffs, z, accurate_small=True, **kwargs): + if hasattr(z, "_mpf_"): + key = p, q, flags, 'R' + v = z._mpf_ + elif hasattr(z, "_mpc_"): + key = p, q, flags, 'C' + v = z._mpc_ + if key not in ctx.hyp_summators: + ctx.hyp_summators[key] = libmp.make_hyp_summator(key)[1] + summator = ctx.hyp_summators[key] + prec = ctx.prec + maxprec = kwargs.get('maxprec', ctx._default_hyper_maxprec(prec)) + extraprec = 50 + epsshift = 25 + # Jumps in magnitude occur when parameters are close to negative + # integers. We must ensure that these terms are included in + # the sum and added accurately + magnitude_check = {} + max_total_jump = 0 + for i, c in enumerate(coeffs): + if flags[i] == 'Z': + if i >= p and c <= 0: + ok = False + for ii, cc in enumerate(coeffs[:p]): + # Note: c <= cc or c < cc, depending on convention + if flags[ii] == 'Z' and cc <= 0 and c <= cc: + ok = True + if not ok: + raise ZeroDivisionError("pole in hypergeometric series") + continue + n, d = ctx.nint_distance(c) + n = -int(n) + d = -d + if i >= p and n >= 0 and d > 4: + if n in magnitude_check: + magnitude_check[n] += d + else: + magnitude_check[n] = d + extraprec = max(extraprec, d - prec + 60) + max_total_jump += abs(d) + while 1: + if extraprec > maxprec: + raise ValueError(ctx._hypsum_msg % (prec, prec+extraprec)) + wp = prec + extraprec + if magnitude_check: + mag_dict = dict((n,None) for n in magnitude_check) + else: + mag_dict = {} + zv, have_complex, magnitude = summator(coeffs, v, prec, wp, \ + epsshift, mag_dict, **kwargs) + cancel = -magnitude + jumps_resolved = True + if extraprec < max_total_jump: + for n in mag_dict.values(): + if (n is None) or (n < prec): + jumps_resolved = False + break + accurate = (cancel < extraprec-25-5 or not accurate_small) + if jumps_resolved: + if accurate: + break + # zero? + zeroprec = kwargs.get('zeroprec') + if zeroprec is not None: + if cancel > zeroprec: + if have_complex: + return ctx.mpc(0) + else: + return ctx.zero + + # Some near-singularities were not included, so increase + # precision and repeat until they are + extraprec *= 2 + # Possible workaround for bad roundoff in fixed-point arithmetic + epsshift += 5 + extraprec += 5 + + if type(zv) is tuple: + if have_complex: + return ctx.make_mpc(zv) + else: + return ctx.make_mpf(zv) + else: + return zv + + def ldexp(ctx, x, n): + r""" + Computes `x 2^n` efficiently. No rounding is performed. + The argument `x` must be a real floating-point number (or + possible to convert into one) and `n` must be a Python ``int``. + + >>> from mpmath import * + >>> mp.dps = 15; mp.pretty = False + >>> ldexp(1, 10) + mpf('1024.0') + >>> ldexp(1, -3) + mpf('0.125') + + """ + x = ctx.convert(x) + return ctx.make_mpf(libmp.mpf_shift(x._mpf_, n)) + + def frexp(ctx, x): + r""" + Given a real number `x`, returns `(y, n)` with `y \in [0.5, 1)`, + `n` a Python integer, and such that `x = y 2^n`. No rounding is + performed. + + >>> from mpmath import * + >>> mp.dps = 15; mp.pretty = False + >>> frexp(7.5) + (mpf('0.9375'), 3) + + """ + x = ctx.convert(x) + y, n = libmp.mpf_frexp(x._mpf_) + return ctx.make_mpf(y), n + + def fneg(ctx, x, **kwargs): + """ + Negates the number *x*, giving a floating-point result, optionally + using a custom precision and rounding mode. + + See the documentation of :func:`~mpmath.fadd` for a detailed description + of how to specify precision and rounding. + + **Examples** + + An mpmath number is returned:: + + >>> from mpmath import * + >>> mp.dps = 15; mp.pretty = False + >>> fneg(2.5) + mpf('-2.5') + >>> fneg(-5+2j) + mpc(real='5.0', imag='-2.0') + + Precise control over rounding is possible:: + + >>> x = fadd(2, 1e-100, exact=True) + >>> fneg(x) + mpf('-2.0') + >>> fneg(x, rounding='f') + mpf('-2.0000000000000004') + + Negating with and without roundoff:: + + >>> n = 200000000000000000000001 + >>> print(int(-mpf(n))) + -200000000000000016777216 + >>> print(int(fneg(n))) + -200000000000000016777216 + >>> print(int(fneg(n, prec=log(n,2)+1))) + -200000000000000000000001 + >>> print(int(fneg(n, dps=log(n,10)+1))) + -200000000000000000000001 + >>> print(int(fneg(n, prec=inf))) + -200000000000000000000001 + >>> print(int(fneg(n, dps=inf))) + -200000000000000000000001 + >>> print(int(fneg(n, exact=True))) + -200000000000000000000001 + + """ + prec, rounding = ctx._parse_prec(kwargs) + x = ctx.convert(x) + if hasattr(x, '_mpf_'): + return ctx.make_mpf(mpf_neg(x._mpf_, prec, rounding)) + if hasattr(x, '_mpc_'): + return ctx.make_mpc(mpc_neg(x._mpc_, prec, rounding)) + raise ValueError("Arguments need to be mpf or mpc compatible numbers") + + def fadd(ctx, x, y, **kwargs): + """ + Adds the numbers *x* and *y*, giving a floating-point result, + optionally using a custom precision and rounding mode. + + The default precision is the working precision of the context. + You can specify a custom precision in bits by passing the *prec* keyword + argument, or by providing an equivalent decimal precision with the *dps* + keyword argument. If the precision is set to ``+inf``, or if the flag + *exact=True* is passed, an exact addition with no rounding is performed. + + When the precision is finite, the optional *rounding* keyword argument + specifies the direction of rounding. Valid options are ``'n'`` for + nearest (default), ``'f'`` for floor, ``'c'`` for ceiling, ``'d'`` + for down, ``'u'`` for up. + + **Examples** + + Using :func:`~mpmath.fadd` with precision and rounding control:: + + >>> from mpmath import * + >>> mp.dps = 15; mp.pretty = False + >>> fadd(2, 1e-20) + mpf('2.0') + >>> fadd(2, 1e-20, rounding='u') + mpf('2.0000000000000004') + >>> nprint(fadd(2, 1e-20, prec=100), 25) + 2.00000000000000000001 + >>> nprint(fadd(2, 1e-20, dps=15), 25) + 2.0 + >>> nprint(fadd(2, 1e-20, dps=25), 25) + 2.00000000000000000001 + >>> nprint(fadd(2, 1e-20, exact=True), 25) + 2.00000000000000000001 + + Exact addition avoids cancellation errors, enforcing familiar laws + of numbers such as `x+y-x = y`, which don't hold in floating-point + arithmetic with finite precision:: + + >>> x, y = mpf(2), mpf('1e-1000') + >>> print(x + y - x) + 0.0 + >>> print(fadd(x, y, prec=inf) - x) + 1.0e-1000 + >>> print(fadd(x, y, exact=True) - x) + 1.0e-1000 + + Exact addition can be inefficient and may be impossible to perform + with large magnitude differences:: + + >>> fadd(1, '1e-100000000000000000000', prec=inf) + Traceback (most recent call last): + ... + OverflowError: the exact result does not fit in memory + + """ + prec, rounding = ctx._parse_prec(kwargs) + x = ctx.convert(x) + y = ctx.convert(y) + try: + if hasattr(x, '_mpf_'): + if hasattr(y, '_mpf_'): + return ctx.make_mpf(mpf_add(x._mpf_, y._mpf_, prec, rounding)) + if hasattr(y, '_mpc_'): + return ctx.make_mpc(mpc_add_mpf(y._mpc_, x._mpf_, prec, rounding)) + if hasattr(x, '_mpc_'): + if hasattr(y, '_mpf_'): + return ctx.make_mpc(mpc_add_mpf(x._mpc_, y._mpf_, prec, rounding)) + if hasattr(y, '_mpc_'): + return ctx.make_mpc(mpc_add(x._mpc_, y._mpc_, prec, rounding)) + except (ValueError, OverflowError): + raise OverflowError(ctx._exact_overflow_msg) + raise ValueError("Arguments need to be mpf or mpc compatible numbers") + + def fsub(ctx, x, y, **kwargs): + """ + Subtracts the numbers *x* and *y*, giving a floating-point result, + optionally using a custom precision and rounding mode. + + See the documentation of :func:`~mpmath.fadd` for a detailed description + of how to specify precision and rounding. + + **Examples** + + Using :func:`~mpmath.fsub` with precision and rounding control:: + + >>> from mpmath import * + >>> mp.dps = 15; mp.pretty = False + >>> fsub(2, 1e-20) + mpf('2.0') + >>> fsub(2, 1e-20, rounding='d') + mpf('1.9999999999999998') + >>> nprint(fsub(2, 1e-20, prec=100), 25) + 1.99999999999999999999 + >>> nprint(fsub(2, 1e-20, dps=15), 25) + 2.0 + >>> nprint(fsub(2, 1e-20, dps=25), 25) + 1.99999999999999999999 + >>> nprint(fsub(2, 1e-20, exact=True), 25) + 1.99999999999999999999 + + Exact subtraction avoids cancellation errors, enforcing familiar laws + of numbers such as `x-y+y = x`, which don't hold in floating-point + arithmetic with finite precision:: + + >>> x, y = mpf(2), mpf('1e1000') + >>> print(x - y + y) + 0.0 + >>> print(fsub(x, y, prec=inf) + y) + 2.0 + >>> print(fsub(x, y, exact=True) + y) + 2.0 + + Exact addition can be inefficient and may be impossible to perform + with large magnitude differences:: + + >>> fsub(1, '1e-100000000000000000000', prec=inf) + Traceback (most recent call last): + ... + OverflowError: the exact result does not fit in memory + + """ + prec, rounding = ctx._parse_prec(kwargs) + x = ctx.convert(x) + y = ctx.convert(y) + try: + if hasattr(x, '_mpf_'): + if hasattr(y, '_mpf_'): + return ctx.make_mpf(mpf_sub(x._mpf_, y._mpf_, prec, rounding)) + if hasattr(y, '_mpc_'): + return ctx.make_mpc(mpc_sub((x._mpf_, fzero), y._mpc_, prec, rounding)) + if hasattr(x, '_mpc_'): + if hasattr(y, '_mpf_'): + return ctx.make_mpc(mpc_sub_mpf(x._mpc_, y._mpf_, prec, rounding)) + if hasattr(y, '_mpc_'): + return ctx.make_mpc(mpc_sub(x._mpc_, y._mpc_, prec, rounding)) + except (ValueError, OverflowError): + raise OverflowError(ctx._exact_overflow_msg) + raise ValueError("Arguments need to be mpf or mpc compatible numbers") + + def fmul(ctx, x, y, **kwargs): + """ + Multiplies the numbers *x* and *y*, giving a floating-point result, + optionally using a custom precision and rounding mode. + + See the documentation of :func:`~mpmath.fadd` for a detailed description + of how to specify precision and rounding. + + **Examples** + + The result is an mpmath number:: + + >>> from mpmath import * + >>> mp.dps = 15; mp.pretty = False + >>> fmul(2, 5.0) + mpf('10.0') + >>> fmul(0.5j, 0.5) + mpc(real='0.0', imag='0.25') + + Avoiding roundoff:: + + >>> x, y = 10**10+1, 10**15+1 + >>> print(x*y) + 10000000001000010000000001 + >>> print(mpf(x) * mpf(y)) + 1.0000000001e+25 + >>> print(int(mpf(x) * mpf(y))) + 10000000001000011026399232 + >>> print(int(fmul(x, y))) + 10000000001000011026399232 + >>> print(int(fmul(x, y, dps=25))) + 10000000001000010000000001 + >>> print(int(fmul(x, y, exact=True))) + 10000000001000010000000001 + + Exact multiplication with complex numbers can be inefficient and may + be impossible to perform with large magnitude differences between + real and imaginary parts:: + + >>> x = 1+2j + >>> y = mpc(2, '1e-100000000000000000000') + >>> fmul(x, y) + mpc(real='2.0', imag='4.0') + >>> fmul(x, y, rounding='u') + mpc(real='2.0', imag='4.0000000000000009') + >>> fmul(x, y, exact=True) + Traceback (most recent call last): + ... + OverflowError: the exact result does not fit in memory + + """ + prec, rounding = ctx._parse_prec(kwargs) + x = ctx.convert(x) + y = ctx.convert(y) + try: + if hasattr(x, '_mpf_'): + if hasattr(y, '_mpf_'): + return ctx.make_mpf(mpf_mul(x._mpf_, y._mpf_, prec, rounding)) + if hasattr(y, '_mpc_'): + return ctx.make_mpc(mpc_mul_mpf(y._mpc_, x._mpf_, prec, rounding)) + if hasattr(x, '_mpc_'): + if hasattr(y, '_mpf_'): + return ctx.make_mpc(mpc_mul_mpf(x._mpc_, y._mpf_, prec, rounding)) + if hasattr(y, '_mpc_'): + return ctx.make_mpc(mpc_mul(x._mpc_, y._mpc_, prec, rounding)) + except (ValueError, OverflowError): + raise OverflowError(ctx._exact_overflow_msg) + raise ValueError("Arguments need to be mpf or mpc compatible numbers") + + def fdiv(ctx, x, y, **kwargs): + """ + Divides the numbers *x* and *y*, giving a floating-point result, + optionally using a custom precision and rounding mode. + + See the documentation of :func:`~mpmath.fadd` for a detailed description + of how to specify precision and rounding. + + **Examples** + + The result is an mpmath number:: + + >>> from mpmath import * + >>> mp.dps = 15; mp.pretty = False + >>> fdiv(3, 2) + mpf('1.5') + >>> fdiv(2, 3) + mpf('0.66666666666666663') + >>> fdiv(2+4j, 0.5) + mpc(real='4.0', imag='8.0') + + The rounding direction and precision can be controlled:: + + >>> fdiv(2, 3, dps=3) # Should be accurate to at least 3 digits + mpf('0.6666259765625') + >>> fdiv(2, 3, rounding='d') + mpf('0.66666666666666663') + >>> fdiv(2, 3, prec=60) + mpf('0.66666666666666667') + >>> fdiv(2, 3, rounding='u') + mpf('0.66666666666666674') + + Checking the error of a division by performing it at higher precision:: + + >>> fdiv(2, 3) - fdiv(2, 3, prec=100) + mpf('-3.7007434154172148e-17') + + Unlike :func:`~mpmath.fadd`, :func:`~mpmath.fmul`, etc., exact division is not + allowed since the quotient of two floating-point numbers generally + does not have an exact floating-point representation. (In the + future this might be changed to allow the case where the division + is actually exact.) + + >>> fdiv(2, 3, exact=True) + Traceback (most recent call last): + ... + ValueError: division is not an exact operation + + """ + prec, rounding = ctx._parse_prec(kwargs) + if not prec: + raise ValueError("division is not an exact operation") + x = ctx.convert(x) + y = ctx.convert(y) + if hasattr(x, '_mpf_'): + if hasattr(y, '_mpf_'): + return ctx.make_mpf(mpf_div(x._mpf_, y._mpf_, prec, rounding)) + if hasattr(y, '_mpc_'): + return ctx.make_mpc(mpc_div((x._mpf_, fzero), y._mpc_, prec, rounding)) + if hasattr(x, '_mpc_'): + if hasattr(y, '_mpf_'): + return ctx.make_mpc(mpc_div_mpf(x._mpc_, y._mpf_, prec, rounding)) + if hasattr(y, '_mpc_'): + return ctx.make_mpc(mpc_div(x._mpc_, y._mpc_, prec, rounding)) + raise ValueError("Arguments need to be mpf or mpc compatible numbers") + + def nint_distance(ctx, x): + r""" + Return `(n,d)` where `n` is the nearest integer to `x` and `d` is + an estimate of `\log_2(|x-n|)`. If `d < 0`, `-d` gives the precision + (measured in bits) lost to cancellation when computing `x-n`. + + >>> from mpmath import * + >>> n, d = nint_distance(5) + >>> print(n); print(d) + 5 + -inf + >>> n, d = nint_distance(mpf(5)) + >>> print(n); print(d) + 5 + -inf + >>> n, d = nint_distance(mpf(5.00000001)) + >>> print(n); print(d) + 5 + -26 + >>> n, d = nint_distance(mpf(4.99999999)) + >>> print(n); print(d) + 5 + -26 + >>> n, d = nint_distance(mpc(5,10)) + >>> print(n); print(d) + 5 + 4 + >>> n, d = nint_distance(mpc(5,0.000001)) + >>> print(n); print(d) + 5 + -19 + + """ + typx = type(x) + if typx in int_types: + return int(x), ctx.ninf + elif typx is rational.mpq: + p, q = x._mpq_ + n, r = divmod(p, q) + if 2*r >= q: + n += 1 + elif not r: + return n, ctx.ninf + # log(p/q-n) = log((p-nq)/q) = log(p-nq) - log(q) + d = bitcount(abs(p-n*q)) - bitcount(q) + return n, d + if hasattr(x, "_mpf_"): + re = x._mpf_ + im_dist = ctx.ninf + elif hasattr(x, "_mpc_"): + re, im = x._mpc_ + isign, iman, iexp, ibc = im + if iman: + im_dist = iexp + ibc + elif im == fzero: + im_dist = ctx.ninf + else: + raise ValueError("requires a finite number") + else: + x = ctx.convert(x) + if hasattr(x, "_mpf_") or hasattr(x, "_mpc_"): + return ctx.nint_distance(x) + else: + raise TypeError("requires an mpf/mpc") + sign, man, exp, bc = re + mag = exp+bc + # |x| < 0.5 + if mag < 0: + n = 0 + re_dist = mag + elif man: + # exact integer + if exp >= 0: + n = man << exp + re_dist = ctx.ninf + # exact half-integer + elif exp == -1: + n = (man>>1)+1 + re_dist = 0 + else: + d = (-exp-1) + t = man >> d + if t & 1: + t += 1 + man = (t<>1 # int(t)>>1 + re_dist = exp+bitcount(man) + if sign: + n = -n + elif re == fzero: + re_dist = ctx.ninf + n = 0 + else: + raise ValueError("requires a finite number") + return n, max(re_dist, im_dist) + + def fprod(ctx, factors): + r""" + Calculates a product containing a finite number of factors (for + infinite products, see :func:`~mpmath.nprod`). The factors will be + converted to mpmath numbers. + + >>> from mpmath import * + >>> mp.dps = 15; mp.pretty = False + >>> fprod([1, 2, 0.5, 7]) + mpf('7.0') + + """ + orig = ctx.prec + try: + v = ctx.one + for p in factors: + v *= p + finally: + ctx.prec = orig + return +v + + def rand(ctx): + """ + Returns an ``mpf`` with value chosen randomly from `[0, 1)`. + The number of randomly generated bits in the mantissa is equal + to the working precision. + """ + return ctx.make_mpf(mpf_rand(ctx._prec)) + + def fraction(ctx, p, q): + """ + Given Python integers `(p, q)`, returns a lazy ``mpf`` representing + the fraction `p/q`. The value is updated with the precision. + + >>> from mpmath import * + >>> mp.dps = 15 + >>> a = fraction(1,100) + >>> b = mpf(1)/100 + >>> print(a); print(b) + 0.01 + 0.01 + >>> mp.dps = 30 + >>> print(a); print(b) # a will be accurate + 0.01 + 0.0100000000000000002081668171172 + >>> mp.dps = 15 + """ + return ctx.constant(lambda prec, rnd: from_rational(p, q, prec, rnd), + '%s/%s' % (p, q)) + + def absmin(ctx, x): + return abs(ctx.convert(x)) + + def absmax(ctx, x): + return abs(ctx.convert(x)) + + def _as_points(ctx, x): + # XXX: remove this? + if hasattr(x, '_mpi_'): + a, b = x._mpi_ + return [ctx.make_mpf(a), ctx.make_mpf(b)] + return x + + ''' + def _zetasum(ctx, s, a, b): + """ + Computes sum of k^(-s) for k = a, a+1, ..., b with a, b both small + integers. + """ + a = int(a) + b = int(b) + s = ctx.convert(s) + prec, rounding = ctx._prec_rounding + if hasattr(s, '_mpf_'): + v = ctx.make_mpf(libmp.mpf_zetasum(s._mpf_, a, b, prec)) + elif hasattr(s, '_mpc_'): + v = ctx.make_mpc(libmp.mpc_zetasum(s._mpc_, a, b, prec)) + return v + ''' + + def _zetasum_fast(ctx, s, a, n, derivatives=[0], reflect=False): + if not (ctx.isint(a) and hasattr(s, "_mpc_")): + raise NotImplementedError + a = int(a) + prec = ctx._prec + xs, ys = libmp.mpc_zetasum(s._mpc_, a, n, derivatives, reflect, prec) + xs = [ctx.make_mpc(x) for x in xs] + ys = [ctx.make_mpc(y) for y in ys] + return xs, ys + +class PrecisionManager: + def __init__(self, ctx, precfun, dpsfun, normalize_output=False): + self.ctx = ctx + self.precfun = precfun + self.dpsfun = dpsfun + self.normalize_output = normalize_output + def __call__(self, f): + @functools.wraps(f) + def g(*args, **kwargs): + orig = self.ctx.prec + try: + if self.precfun: + self.ctx.prec = self.precfun(self.ctx.prec) + else: + self.ctx.dps = self.dpsfun(self.ctx.dps) + if self.normalize_output: + v = f(*args, **kwargs) + if type(v) is tuple: + return tuple([+a for a in v]) + return +v + else: + return f(*args, **kwargs) + finally: + self.ctx.prec = orig + return g + def __enter__(self): + self.origp = self.ctx.prec + if self.precfun: + self.ctx.prec = self.precfun(self.ctx.prec) + else: + self.ctx.dps = self.dpsfun(self.ctx.dps) + def __exit__(self, exc_type, exc_val, exc_tb): + self.ctx.prec = self.origp + return False + + +if __name__ == '__main__': + import doctest + doctest.testmod() diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/ctx_mp_python.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/ctx_mp_python.py new file mode 100644 index 0000000000000000000000000000000000000000..cfbd72fb8300bf840069c38529b7b41418d26eeb --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/ctx_mp_python.py @@ -0,0 +1,1149 @@ +#from ctx_base import StandardBaseContext + +from .libmp.backend import basestring, exec_ + +from .libmp import (MPZ, MPZ_ZERO, MPZ_ONE, int_types, repr_dps, + round_floor, round_ceiling, dps_to_prec, round_nearest, prec_to_dps, + ComplexResult, to_pickable, from_pickable, normalize, + from_int, from_float, from_npfloat, from_Decimal, from_str, to_int, to_float, to_str, + from_rational, from_man_exp, + fone, fzero, finf, fninf, fnan, + mpf_abs, mpf_pos, mpf_neg, mpf_add, mpf_sub, mpf_mul, mpf_mul_int, + mpf_div, mpf_rdiv_int, mpf_pow_int, mpf_mod, + mpf_eq, mpf_cmp, mpf_lt, mpf_gt, mpf_le, mpf_ge, + mpf_hash, mpf_rand, + mpf_sum, + bitcount, to_fixed, + mpc_to_str, + mpc_to_complex, mpc_hash, mpc_pos, mpc_is_nonzero, mpc_neg, mpc_conjugate, + mpc_abs, mpc_add, mpc_add_mpf, mpc_sub, mpc_sub_mpf, mpc_mul, mpc_mul_mpf, + mpc_mul_int, mpc_div, mpc_div_mpf, mpc_pow, mpc_pow_mpf, mpc_pow_int, + mpc_mpf_div, + mpf_pow, + mpf_pi, mpf_degree, mpf_e, mpf_phi, mpf_ln2, mpf_ln10, + mpf_euler, mpf_catalan, mpf_apery, mpf_khinchin, + mpf_glaisher, mpf_twinprime, mpf_mertens, + int_types) + +from . import rational +from . import function_docs + +new = object.__new__ + +class mpnumeric(object): + """Base class for mpf and mpc.""" + __slots__ = [] + def __new__(cls, val): + raise NotImplementedError + +class _mpf(mpnumeric): + """ + An mpf instance holds a real-valued floating-point number. mpf:s + work analogously to Python floats, but support arbitrary-precision + arithmetic. + """ + __slots__ = ['_mpf_'] + + def __new__(cls, val=fzero, **kwargs): + """A new mpf can be created from a Python float, an int, a + or a decimal string representing a number in floating-point + format.""" + prec, rounding = cls.context._prec_rounding + if kwargs: + prec = kwargs.get('prec', prec) + if 'dps' in kwargs: + prec = dps_to_prec(kwargs['dps']) + rounding = kwargs.get('rounding', rounding) + if type(val) is cls: + sign, man, exp, bc = val._mpf_ + if (not man) and exp: + return val + v = new(cls) + v._mpf_ = normalize(sign, man, exp, bc, prec, rounding) + return v + elif type(val) is tuple: + if len(val) == 2: + v = new(cls) + v._mpf_ = from_man_exp(val[0], val[1], prec, rounding) + return v + if len(val) == 4: + if val not in (finf, fninf, fnan): + sign, man, exp, bc = val + val = normalize(sign, MPZ(man), exp, bc, prec, rounding) + v = new(cls) + v._mpf_ = val + return v + raise ValueError + else: + v = new(cls) + v._mpf_ = mpf_pos(cls.mpf_convert_arg(val, prec, rounding), prec, rounding) + return v + + @classmethod + def mpf_convert_arg(cls, x, prec, rounding): + if isinstance(x, int_types): return from_int(x) + if isinstance(x, float): return from_float(x) + if isinstance(x, basestring): return from_str(x, prec, rounding) + if isinstance(x, cls.context.constant): return x.func(prec, rounding) + if hasattr(x, '_mpf_'): return x._mpf_ + if hasattr(x, '_mpmath_'): + t = cls.context.convert(x._mpmath_(prec, rounding)) + if hasattr(t, '_mpf_'): + return t._mpf_ + if hasattr(x, '_mpi_'): + a, b = x._mpi_ + if a == b: + return a + raise ValueError("can only create mpf from zero-width interval") + raise TypeError("cannot create mpf from " + repr(x)) + + @classmethod + def mpf_convert_rhs(cls, x): + if isinstance(x, int_types): return from_int(x) + if isinstance(x, float): return from_float(x) + if isinstance(x, complex_types): return cls.context.mpc(x) + if isinstance(x, rational.mpq): + p, q = x._mpq_ + return from_rational(p, q, cls.context.prec) + if hasattr(x, '_mpf_'): return x._mpf_ + if hasattr(x, '_mpmath_'): + t = cls.context.convert(x._mpmath_(*cls.context._prec_rounding)) + if hasattr(t, '_mpf_'): + return t._mpf_ + return t + return NotImplemented + + @classmethod + def mpf_convert_lhs(cls, x): + x = cls.mpf_convert_rhs(x) + if type(x) is tuple: + return cls.context.make_mpf(x) + return x + + man_exp = property(lambda self: self._mpf_[1:3]) + man = property(lambda self: self._mpf_[1]) + exp = property(lambda self: self._mpf_[2]) + bc = property(lambda self: self._mpf_[3]) + + real = property(lambda self: self) + imag = property(lambda self: self.context.zero) + + conjugate = lambda self: self + + def __getstate__(self): return to_pickable(self._mpf_) + def __setstate__(self, val): self._mpf_ = from_pickable(val) + + def __repr__(s): + if s.context.pretty: + return str(s) + return "mpf('%s')" % to_str(s._mpf_, s.context._repr_digits) + + def __str__(s): return to_str(s._mpf_, s.context._str_digits) + def __hash__(s): return mpf_hash(s._mpf_) + def __int__(s): return int(to_int(s._mpf_)) + def __long__(s): return long(to_int(s._mpf_)) + def __float__(s): return to_float(s._mpf_, rnd=s.context._prec_rounding[1]) + def __complex__(s): return complex(float(s)) + def __nonzero__(s): return s._mpf_ != fzero + + __bool__ = __nonzero__ + + def __abs__(s): + cls, new, (prec, rounding) = s._ctxdata + v = new(cls) + v._mpf_ = mpf_abs(s._mpf_, prec, rounding) + return v + + def __pos__(s): + cls, new, (prec, rounding) = s._ctxdata + v = new(cls) + v._mpf_ = mpf_pos(s._mpf_, prec, rounding) + return v + + def __neg__(s): + cls, new, (prec, rounding) = s._ctxdata + v = new(cls) + v._mpf_ = mpf_neg(s._mpf_, prec, rounding) + return v + + def _cmp(s, t, func): + if hasattr(t, '_mpf_'): + t = t._mpf_ + else: + t = s.mpf_convert_rhs(t) + if t is NotImplemented: + return t + return func(s._mpf_, t) + + def __cmp__(s, t): return s._cmp(t, mpf_cmp) + def __lt__(s, t): return s._cmp(t, mpf_lt) + def __gt__(s, t): return s._cmp(t, mpf_gt) + def __le__(s, t): return s._cmp(t, mpf_le) + def __ge__(s, t): return s._cmp(t, mpf_ge) + + def __ne__(s, t): + v = s.__eq__(t) + if v is NotImplemented: + return v + return not v + + def __rsub__(s, t): + cls, new, (prec, rounding) = s._ctxdata + if type(t) in int_types: + v = new(cls) + v._mpf_ = mpf_sub(from_int(t), s._mpf_, prec, rounding) + return v + t = s.mpf_convert_lhs(t) + if t is NotImplemented: + return t + return t - s + + def __rdiv__(s, t): + cls, new, (prec, rounding) = s._ctxdata + if isinstance(t, int_types): + v = new(cls) + v._mpf_ = mpf_rdiv_int(t, s._mpf_, prec, rounding) + return v + t = s.mpf_convert_lhs(t) + if t is NotImplemented: + return t + return t / s + + def __rpow__(s, t): + t = s.mpf_convert_lhs(t) + if t is NotImplemented: + return t + return t ** s + + def __rmod__(s, t): + t = s.mpf_convert_lhs(t) + if t is NotImplemented: + return t + return t % s + + def sqrt(s): + return s.context.sqrt(s) + + def ae(s, t, rel_eps=None, abs_eps=None): + return s.context.almosteq(s, t, rel_eps, abs_eps) + + def to_fixed(self, prec): + return to_fixed(self._mpf_, prec) + + def __round__(self, *args): + return round(float(self), *args) + +mpf_binary_op = """ +def %NAME%(self, other): + mpf, new, (prec, rounding) = self._ctxdata + sval = self._mpf_ + if hasattr(other, '_mpf_'): + tval = other._mpf_ + %WITH_MPF% + ttype = type(other) + if ttype in int_types: + %WITH_INT% + elif ttype is float: + tval = from_float(other) + %WITH_MPF% + elif hasattr(other, '_mpc_'): + tval = other._mpc_ + mpc = type(other) + %WITH_MPC% + elif ttype is complex: + tval = from_float(other.real), from_float(other.imag) + mpc = self.context.mpc + %WITH_MPC% + if isinstance(other, mpnumeric): + return NotImplemented + try: + other = mpf.context.convert(other, strings=False) + except TypeError: + return NotImplemented + return self.%NAME%(other) +""" + +return_mpf = "; obj = new(mpf); obj._mpf_ = val; return obj" +return_mpc = "; obj = new(mpc); obj._mpc_ = val; return obj" + +mpf_pow_same = """ + try: + val = mpf_pow(sval, tval, prec, rounding) %s + except ComplexResult: + if mpf.context.trap_complex: + raise + mpc = mpf.context.mpc + val = mpc_pow((sval, fzero), (tval, fzero), prec, rounding) %s +""" % (return_mpf, return_mpc) + +def binary_op(name, with_mpf='', with_int='', with_mpc=''): + code = mpf_binary_op + code = code.replace("%WITH_INT%", with_int) + code = code.replace("%WITH_MPC%", with_mpc) + code = code.replace("%WITH_MPF%", with_mpf) + code = code.replace("%NAME%", name) + np = {} + exec_(code, globals(), np) + return np[name] + +_mpf.__eq__ = binary_op('__eq__', + 'return mpf_eq(sval, tval)', + 'return mpf_eq(sval, from_int(other))', + 'return (tval[1] == fzero) and mpf_eq(tval[0], sval)') + +_mpf.__add__ = binary_op('__add__', + 'val = mpf_add(sval, tval, prec, rounding)' + return_mpf, + 'val = mpf_add(sval, from_int(other), prec, rounding)' + return_mpf, + 'val = mpc_add_mpf(tval, sval, prec, rounding)' + return_mpc) + +_mpf.__sub__ = binary_op('__sub__', + 'val = mpf_sub(sval, tval, prec, rounding)' + return_mpf, + 'val = mpf_sub(sval, from_int(other), prec, rounding)' + return_mpf, + 'val = mpc_sub((sval, fzero), tval, prec, rounding)' + return_mpc) + +_mpf.__mul__ = binary_op('__mul__', + 'val = mpf_mul(sval, tval, prec, rounding)' + return_mpf, + 'val = mpf_mul_int(sval, other, prec, rounding)' + return_mpf, + 'val = mpc_mul_mpf(tval, sval, prec, rounding)' + return_mpc) + +_mpf.__div__ = binary_op('__div__', + 'val = mpf_div(sval, tval, prec, rounding)' + return_mpf, + 'val = mpf_div(sval, from_int(other), prec, rounding)' + return_mpf, + 'val = mpc_mpf_div(sval, tval, prec, rounding)' + return_mpc) + +_mpf.__mod__ = binary_op('__mod__', + 'val = mpf_mod(sval, tval, prec, rounding)' + return_mpf, + 'val = mpf_mod(sval, from_int(other), prec, rounding)' + return_mpf, + 'raise NotImplementedError("complex modulo")') + +_mpf.__pow__ = binary_op('__pow__', + mpf_pow_same, + 'val = mpf_pow_int(sval, other, prec, rounding)' + return_mpf, + 'val = mpc_pow((sval, fzero), tval, prec, rounding)' + return_mpc) + +_mpf.__radd__ = _mpf.__add__ +_mpf.__rmul__ = _mpf.__mul__ +_mpf.__truediv__ = _mpf.__div__ +_mpf.__rtruediv__ = _mpf.__rdiv__ + + +class _constant(_mpf): + """Represents a mathematical constant with dynamic precision. + When printed or used in an arithmetic operation, a constant + is converted to a regular mpf at the working precision. A + regular mpf can also be obtained using the operation +x.""" + + def __new__(cls, func, name, docname=''): + a = object.__new__(cls) + a.name = name + a.func = func + a.__doc__ = getattr(function_docs, docname, '') + return a + + def __call__(self, prec=None, dps=None, rounding=None): + prec2, rounding2 = self.context._prec_rounding + if not prec: prec = prec2 + if not rounding: rounding = rounding2 + if dps: prec = dps_to_prec(dps) + return self.context.make_mpf(self.func(prec, rounding)) + + @property + def _mpf_(self): + prec, rounding = self.context._prec_rounding + return self.func(prec, rounding) + + def __repr__(self): + return "<%s: %s~>" % (self.name, self.context.nstr(self(dps=15))) + + +class _mpc(mpnumeric): + """ + An mpc represents a complex number using a pair of mpf:s (one + for the real part and another for the imaginary part.) The mpc + class behaves fairly similarly to Python's complex type. + """ + + __slots__ = ['_mpc_'] + + def __new__(cls, real=0, imag=0): + s = object.__new__(cls) + if isinstance(real, complex_types): + real, imag = real.real, real.imag + elif hasattr(real, '_mpc_'): + s._mpc_ = real._mpc_ + return s + real = cls.context.mpf(real) + imag = cls.context.mpf(imag) + s._mpc_ = (real._mpf_, imag._mpf_) + return s + + real = property(lambda self: self.context.make_mpf(self._mpc_[0])) + imag = property(lambda self: self.context.make_mpf(self._mpc_[1])) + + def __getstate__(self): + return to_pickable(self._mpc_[0]), to_pickable(self._mpc_[1]) + + def __setstate__(self, val): + self._mpc_ = from_pickable(val[0]), from_pickable(val[1]) + + def __repr__(s): + if s.context.pretty: + return str(s) + r = repr(s.real)[4:-1] + i = repr(s.imag)[4:-1] + return "%s(real=%s, imag=%s)" % (type(s).__name__, r, i) + + def __str__(s): + return "(%s)" % mpc_to_str(s._mpc_, s.context._str_digits) + + def __complex__(s): + return mpc_to_complex(s._mpc_, rnd=s.context._prec_rounding[1]) + + def __pos__(s): + cls, new, (prec, rounding) = s._ctxdata + v = new(cls) + v._mpc_ = mpc_pos(s._mpc_, prec, rounding) + return v + + def __abs__(s): + prec, rounding = s.context._prec_rounding + v = new(s.context.mpf) + v._mpf_ = mpc_abs(s._mpc_, prec, rounding) + return v + + def __neg__(s): + cls, new, (prec, rounding) = s._ctxdata + v = new(cls) + v._mpc_ = mpc_neg(s._mpc_, prec, rounding) + return v + + def conjugate(s): + cls, new, (prec, rounding) = s._ctxdata + v = new(cls) + v._mpc_ = mpc_conjugate(s._mpc_, prec, rounding) + return v + + def __nonzero__(s): + return mpc_is_nonzero(s._mpc_) + + __bool__ = __nonzero__ + + def __hash__(s): + return mpc_hash(s._mpc_) + + @classmethod + def mpc_convert_lhs(cls, x): + try: + y = cls.context.convert(x) + return y + except TypeError: + return NotImplemented + + def __eq__(s, t): + if not hasattr(t, '_mpc_'): + if isinstance(t, str): + return False + t = s.mpc_convert_lhs(t) + if t is NotImplemented: + return t + return s.real == t.real and s.imag == t.imag + + def __ne__(s, t): + b = s.__eq__(t) + if b is NotImplemented: + return b + return not b + + def _compare(*args): + raise TypeError("no ordering relation is defined for complex numbers") + + __gt__ = _compare + __le__ = _compare + __gt__ = _compare + __ge__ = _compare + + def __add__(s, t): + cls, new, (prec, rounding) = s._ctxdata + if not hasattr(t, '_mpc_'): + t = s.mpc_convert_lhs(t) + if t is NotImplemented: + return t + if hasattr(t, '_mpf_'): + v = new(cls) + v._mpc_ = mpc_add_mpf(s._mpc_, t._mpf_, prec, rounding) + return v + v = new(cls) + v._mpc_ = mpc_add(s._mpc_, t._mpc_, prec, rounding) + return v + + def __sub__(s, t): + cls, new, (prec, rounding) = s._ctxdata + if not hasattr(t, '_mpc_'): + t = s.mpc_convert_lhs(t) + if t is NotImplemented: + return t + if hasattr(t, '_mpf_'): + v = new(cls) + v._mpc_ = mpc_sub_mpf(s._mpc_, t._mpf_, prec, rounding) + return v + v = new(cls) + v._mpc_ = mpc_sub(s._mpc_, t._mpc_, prec, rounding) + return v + + def __mul__(s, t): + cls, new, (prec, rounding) = s._ctxdata + if not hasattr(t, '_mpc_'): + if isinstance(t, int_types): + v = new(cls) + v._mpc_ = mpc_mul_int(s._mpc_, t, prec, rounding) + return v + t = s.mpc_convert_lhs(t) + if t is NotImplemented: + return t + if hasattr(t, '_mpf_'): + v = new(cls) + v._mpc_ = mpc_mul_mpf(s._mpc_, t._mpf_, prec, rounding) + return v + t = s.mpc_convert_lhs(t) + v = new(cls) + v._mpc_ = mpc_mul(s._mpc_, t._mpc_, prec, rounding) + return v + + def __div__(s, t): + cls, new, (prec, rounding) = s._ctxdata + if not hasattr(t, '_mpc_'): + t = s.mpc_convert_lhs(t) + if t is NotImplemented: + return t + if hasattr(t, '_mpf_'): + v = new(cls) + v._mpc_ = mpc_div_mpf(s._mpc_, t._mpf_, prec, rounding) + return v + v = new(cls) + v._mpc_ = mpc_div(s._mpc_, t._mpc_, prec, rounding) + return v + + def __pow__(s, t): + cls, new, (prec, rounding) = s._ctxdata + if isinstance(t, int_types): + v = new(cls) + v._mpc_ = mpc_pow_int(s._mpc_, t, prec, rounding) + return v + t = s.mpc_convert_lhs(t) + if t is NotImplemented: + return t + v = new(cls) + if hasattr(t, '_mpf_'): + v._mpc_ = mpc_pow_mpf(s._mpc_, t._mpf_, prec, rounding) + else: + v._mpc_ = mpc_pow(s._mpc_, t._mpc_, prec, rounding) + return v + + __radd__ = __add__ + + def __rsub__(s, t): + t = s.mpc_convert_lhs(t) + if t is NotImplemented: + return t + return t - s + + def __rmul__(s, t): + cls, new, (prec, rounding) = s._ctxdata + if isinstance(t, int_types): + v = new(cls) + v._mpc_ = mpc_mul_int(s._mpc_, t, prec, rounding) + return v + t = s.mpc_convert_lhs(t) + if t is NotImplemented: + return t + return t * s + + def __rdiv__(s, t): + t = s.mpc_convert_lhs(t) + if t is NotImplemented: + return t + return t / s + + def __rpow__(s, t): + t = s.mpc_convert_lhs(t) + if t is NotImplemented: + return t + return t ** s + + __truediv__ = __div__ + __rtruediv__ = __rdiv__ + + def ae(s, t, rel_eps=None, abs_eps=None): + return s.context.almosteq(s, t, rel_eps, abs_eps) + + +complex_types = (complex, _mpc) + + +class PythonMPContext(object): + + def __init__(ctx): + ctx._prec_rounding = [53, round_nearest] + ctx.mpf = type('mpf', (_mpf,), {}) + ctx.mpc = type('mpc', (_mpc,), {}) + ctx.mpf._ctxdata = [ctx.mpf, new, ctx._prec_rounding] + ctx.mpc._ctxdata = [ctx.mpc, new, ctx._prec_rounding] + ctx.mpf.context = ctx + ctx.mpc.context = ctx + ctx.constant = type('constant', (_constant,), {}) + ctx.constant._ctxdata = [ctx.mpf, new, ctx._prec_rounding] + ctx.constant.context = ctx + + def make_mpf(ctx, v): + a = new(ctx.mpf) + a._mpf_ = v + return a + + def make_mpc(ctx, v): + a = new(ctx.mpc) + a._mpc_ = v + return a + + def default(ctx): + ctx._prec = ctx._prec_rounding[0] = 53 + ctx._dps = 15 + ctx.trap_complex = False + + def _set_prec(ctx, n): + ctx._prec = ctx._prec_rounding[0] = max(1, int(n)) + ctx._dps = prec_to_dps(n) + + def _set_dps(ctx, n): + ctx._prec = ctx._prec_rounding[0] = dps_to_prec(n) + ctx._dps = max(1, int(n)) + + prec = property(lambda ctx: ctx._prec, _set_prec) + dps = property(lambda ctx: ctx._dps, _set_dps) + + def convert(ctx, x, strings=True): + """ + Converts *x* to an ``mpf`` or ``mpc``. If *x* is of type ``mpf``, + ``mpc``, ``int``, ``float``, ``complex``, the conversion + will be performed losslessly. + + If *x* is a string, the result will be rounded to the present + working precision. Strings representing fractions or complex + numbers are permitted. + + >>> from mpmath import * + >>> mp.dps = 15; mp.pretty = False + >>> mpmathify(3.5) + mpf('3.5') + >>> mpmathify('2.1') + mpf('2.1000000000000001') + >>> mpmathify('3/4') + mpf('0.75') + >>> mpmathify('2+3j') + mpc(real='2.0', imag='3.0') + + """ + if type(x) in ctx.types: return x + if isinstance(x, int_types): return ctx.make_mpf(from_int(x)) + if isinstance(x, float): return ctx.make_mpf(from_float(x)) + if isinstance(x, complex): + return ctx.make_mpc((from_float(x.real), from_float(x.imag))) + if type(x).__module__ == 'numpy': return ctx.npconvert(x) + if isinstance(x, numbers.Rational): # e.g. Fraction + try: x = rational.mpq(int(x.numerator), int(x.denominator)) + except: pass + prec, rounding = ctx._prec_rounding + if isinstance(x, rational.mpq): + p, q = x._mpq_ + return ctx.make_mpf(from_rational(p, q, prec)) + if strings and isinstance(x, basestring): + try: + _mpf_ = from_str(x, prec, rounding) + return ctx.make_mpf(_mpf_) + except ValueError: + pass + if hasattr(x, '_mpf_'): return ctx.make_mpf(x._mpf_) + if hasattr(x, '_mpc_'): return ctx.make_mpc(x._mpc_) + if hasattr(x, '_mpmath_'): + return ctx.convert(x._mpmath_(prec, rounding)) + if type(x).__module__ == 'decimal': + try: return ctx.make_mpf(from_Decimal(x, prec, rounding)) + except: pass + return ctx._convert_fallback(x, strings) + + def npconvert(ctx, x): + """ + Converts *x* to an ``mpf`` or ``mpc``. *x* should be a numpy + scalar. + """ + import numpy as np + if isinstance(x, np.integer): return ctx.make_mpf(from_int(int(x))) + if isinstance(x, np.floating): return ctx.make_mpf(from_npfloat(x)) + if isinstance(x, np.complexfloating): + return ctx.make_mpc((from_npfloat(x.real), from_npfloat(x.imag))) + raise TypeError("cannot create mpf from " + repr(x)) + + def isnan(ctx, x): + """ + Return *True* if *x* is a NaN (not-a-number), or for a complex + number, whether either the real or complex part is NaN; + otherwise return *False*:: + + >>> from mpmath import * + >>> isnan(3.14) + False + >>> isnan(nan) + True + >>> isnan(mpc(3.14,2.72)) + False + >>> isnan(mpc(3.14,nan)) + True + + """ + if hasattr(x, "_mpf_"): + return x._mpf_ == fnan + if hasattr(x, "_mpc_"): + return fnan in x._mpc_ + if isinstance(x, int_types) or isinstance(x, rational.mpq): + return False + x = ctx.convert(x) + if hasattr(x, '_mpf_') or hasattr(x, '_mpc_'): + return ctx.isnan(x) + raise TypeError("isnan() needs a number as input") + + def isinf(ctx, x): + """ + Return *True* if the absolute value of *x* is infinite; + otherwise return *False*:: + + >>> from mpmath import * + >>> isinf(inf) + True + >>> isinf(-inf) + True + >>> isinf(3) + False + >>> isinf(3+4j) + False + >>> isinf(mpc(3,inf)) + True + >>> isinf(mpc(inf,3)) + True + + """ + if hasattr(x, "_mpf_"): + return x._mpf_ in (finf, fninf) + if hasattr(x, "_mpc_"): + re, im = x._mpc_ + return re in (finf, fninf) or im in (finf, fninf) + if isinstance(x, int_types) or isinstance(x, rational.mpq): + return False + x = ctx.convert(x) + if hasattr(x, '_mpf_') or hasattr(x, '_mpc_'): + return ctx.isinf(x) + raise TypeError("isinf() needs a number as input") + + def isnormal(ctx, x): + """ + Determine whether *x* is "normal" in the sense of floating-point + representation; that is, return *False* if *x* is zero, an + infinity or NaN; otherwise return *True*. By extension, a + complex number *x* is considered "normal" if its magnitude is + normal:: + + >>> from mpmath import * + >>> isnormal(3) + True + >>> isnormal(0) + False + >>> isnormal(inf); isnormal(-inf); isnormal(nan) + False + False + False + >>> isnormal(0+0j) + False + >>> isnormal(0+3j) + True + >>> isnormal(mpc(2,nan)) + False + """ + if hasattr(x, "_mpf_"): + return bool(x._mpf_[1]) + if hasattr(x, "_mpc_"): + re, im = x._mpc_ + re_normal = bool(re[1]) + im_normal = bool(im[1]) + if re == fzero: return im_normal + if im == fzero: return re_normal + return re_normal and im_normal + if isinstance(x, int_types) or isinstance(x, rational.mpq): + return bool(x) + x = ctx.convert(x) + if hasattr(x, '_mpf_') or hasattr(x, '_mpc_'): + return ctx.isnormal(x) + raise TypeError("isnormal() needs a number as input") + + def isint(ctx, x, gaussian=False): + """ + Return *True* if *x* is integer-valued; otherwise return + *False*:: + + >>> from mpmath import * + >>> isint(3) + True + >>> isint(mpf(3)) + True + >>> isint(3.2) + False + >>> isint(inf) + False + + Optionally, Gaussian integers can be checked for:: + + >>> isint(3+0j) + True + >>> isint(3+2j) + False + >>> isint(3+2j, gaussian=True) + True + + """ + if isinstance(x, int_types): + return True + if hasattr(x, "_mpf_"): + sign, man, exp, bc = xval = x._mpf_ + return bool((man and exp >= 0) or xval == fzero) + if hasattr(x, "_mpc_"): + re, im = x._mpc_ + rsign, rman, rexp, rbc = re + isign, iman, iexp, ibc = im + re_isint = (rman and rexp >= 0) or re == fzero + if gaussian: + im_isint = (iman and iexp >= 0) or im == fzero + return re_isint and im_isint + return re_isint and im == fzero + if isinstance(x, rational.mpq): + p, q = x._mpq_ + return p % q == 0 + x = ctx.convert(x) + if hasattr(x, '_mpf_') or hasattr(x, '_mpc_'): + return ctx.isint(x, gaussian) + raise TypeError("isint() needs a number as input") + + def fsum(ctx, terms, absolute=False, squared=False): + """ + Calculates a sum containing a finite number of terms (for infinite + series, see :func:`~mpmath.nsum`). The terms will be converted to + mpmath numbers. For len(terms) > 2, this function is generally + faster and produces more accurate results than the builtin + Python function :func:`sum`. + + >>> from mpmath import * + >>> mp.dps = 15; mp.pretty = False + >>> fsum([1, 2, 0.5, 7]) + mpf('10.5') + + With squared=True each term is squared, and with absolute=True + the absolute value of each term is used. + """ + prec, rnd = ctx._prec_rounding + real = [] + imag = [] + for term in terms: + reval = imval = 0 + if hasattr(term, "_mpf_"): + reval = term._mpf_ + elif hasattr(term, "_mpc_"): + reval, imval = term._mpc_ + else: + term = ctx.convert(term) + if hasattr(term, "_mpf_"): + reval = term._mpf_ + elif hasattr(term, "_mpc_"): + reval, imval = term._mpc_ + else: + raise NotImplementedError + if imval: + if squared: + if absolute: + real.append(mpf_mul(reval,reval)) + real.append(mpf_mul(imval,imval)) + else: + reval, imval = mpc_pow_int((reval,imval),2,prec+10) + real.append(reval) + imag.append(imval) + elif absolute: + real.append(mpc_abs((reval,imval), prec)) + else: + real.append(reval) + imag.append(imval) + else: + if squared: + reval = mpf_mul(reval, reval) + elif absolute: + reval = mpf_abs(reval) + real.append(reval) + s = mpf_sum(real, prec, rnd, absolute) + if imag: + s = ctx.make_mpc((s, mpf_sum(imag, prec, rnd))) + else: + s = ctx.make_mpf(s) + return s + + def fdot(ctx, A, B=None, conjugate=False): + r""" + Computes the dot product of the iterables `A` and `B`, + + .. math :: + + \sum_{k=0} A_k B_k. + + Alternatively, :func:`~mpmath.fdot` accepts a single iterable of pairs. + In other words, ``fdot(A,B)`` and ``fdot(zip(A,B))`` are equivalent. + The elements are automatically converted to mpmath numbers. + + With ``conjugate=True``, the elements in the second vector + will be conjugated: + + .. math :: + + \sum_{k=0} A_k \overline{B_k} + + **Examples** + + >>> from mpmath import * + >>> mp.dps = 15; mp.pretty = False + >>> A = [2, 1.5, 3] + >>> B = [1, -1, 2] + >>> fdot(A, B) + mpf('6.5') + >>> list(zip(A, B)) + [(2, 1), (1.5, -1), (3, 2)] + >>> fdot(_) + mpf('6.5') + >>> A = [2, 1.5, 3j] + >>> B = [1+j, 3, -1-j] + >>> fdot(A, B) + mpc(real='9.5', imag='-1.0') + >>> fdot(A, B, conjugate=True) + mpc(real='3.5', imag='-5.0') + + """ + if B is not None: + A = zip(A, B) + prec, rnd = ctx._prec_rounding + real = [] + imag = [] + hasattr_ = hasattr + types = (ctx.mpf, ctx.mpc) + for a, b in A: + if type(a) not in types: a = ctx.convert(a) + if type(b) not in types: b = ctx.convert(b) + a_real = hasattr_(a, "_mpf_") + b_real = hasattr_(b, "_mpf_") + if a_real and b_real: + real.append(mpf_mul(a._mpf_, b._mpf_)) + continue + a_complex = hasattr_(a, "_mpc_") + b_complex = hasattr_(b, "_mpc_") + if a_real and b_complex: + aval = a._mpf_ + bre, bim = b._mpc_ + if conjugate: + bim = mpf_neg(bim) + real.append(mpf_mul(aval, bre)) + imag.append(mpf_mul(aval, bim)) + elif b_real and a_complex: + are, aim = a._mpc_ + bval = b._mpf_ + real.append(mpf_mul(are, bval)) + imag.append(mpf_mul(aim, bval)) + elif a_complex and b_complex: + #re, im = mpc_mul(a._mpc_, b._mpc_, prec+20) + are, aim = a._mpc_ + bre, bim = b._mpc_ + if conjugate: + bim = mpf_neg(bim) + real.append(mpf_mul(are, bre)) + real.append(mpf_neg(mpf_mul(aim, bim))) + imag.append(mpf_mul(are, bim)) + imag.append(mpf_mul(aim, bre)) + else: + raise NotImplementedError + s = mpf_sum(real, prec, rnd) + if imag: + s = ctx.make_mpc((s, mpf_sum(imag, prec, rnd))) + else: + s = ctx.make_mpf(s) + return s + + def _wrap_libmp_function(ctx, mpf_f, mpc_f=None, mpi_f=None, doc=""): + """ + Given a low-level mpf_ function, and optionally similar functions + for mpc_ and mpi_, defines the function as a context method. + + It is assumed that the return type is the same as that of + the input; the exception is that propagation from mpf to mpc is possible + by raising ComplexResult. + + """ + def f(x, **kwargs): + if type(x) not in ctx.types: + x = ctx.convert(x) + prec, rounding = ctx._prec_rounding + if kwargs: + prec = kwargs.get('prec', prec) + if 'dps' in kwargs: + prec = dps_to_prec(kwargs['dps']) + rounding = kwargs.get('rounding', rounding) + if hasattr(x, '_mpf_'): + try: + return ctx.make_mpf(mpf_f(x._mpf_, prec, rounding)) + except ComplexResult: + # Handle propagation to complex + if ctx.trap_complex: + raise + return ctx.make_mpc(mpc_f((x._mpf_, fzero), prec, rounding)) + elif hasattr(x, '_mpc_'): + return ctx.make_mpc(mpc_f(x._mpc_, prec, rounding)) + raise NotImplementedError("%s of a %s" % (name, type(x))) + name = mpf_f.__name__[4:] + f.__doc__ = function_docs.__dict__.get(name, "Computes the %s of x" % doc) + return f + + # Called by SpecialFunctions.__init__() + @classmethod + def _wrap_specfun(cls, name, f, wrap): + if wrap: + def f_wrapped(ctx, *args, **kwargs): + convert = ctx.convert + args = [convert(a) for a in args] + prec = ctx.prec + try: + ctx.prec += 10 + retval = f(ctx, *args, **kwargs) + finally: + ctx.prec = prec + return +retval + else: + f_wrapped = f + f_wrapped.__doc__ = function_docs.__dict__.get(name, f.__doc__) + setattr(cls, name, f_wrapped) + + def _convert_param(ctx, x): + if hasattr(x, "_mpc_"): + v, im = x._mpc_ + if im != fzero: + return x, 'C' + elif hasattr(x, "_mpf_"): + v = x._mpf_ + else: + if type(x) in int_types: + return int(x), 'Z' + p = None + if isinstance(x, tuple): + p, q = x + elif hasattr(x, '_mpq_'): + p, q = x._mpq_ + elif isinstance(x, basestring) and '/' in x: + p, q = x.split('/') + p = int(p) + q = int(q) + if p is not None: + if not p % q: + return p // q, 'Z' + return ctx.mpq(p,q), 'Q' + x = ctx.convert(x) + if hasattr(x, "_mpc_"): + v, im = x._mpc_ + if im != fzero: + return x, 'C' + elif hasattr(x, "_mpf_"): + v = x._mpf_ + else: + return x, 'U' + sign, man, exp, bc = v + if man: + if exp >= -4: + if sign: + man = -man + if exp >= 0: + return int(man) << exp, 'Z' + if exp >= -4: + p, q = int(man), (1<<(-exp)) + return ctx.mpq(p,q), 'Q' + x = ctx.make_mpf(v) + return x, 'R' + elif not exp: + return 0, 'Z' + else: + return x, 'U' + + def _mpf_mag(ctx, x): + sign, man, exp, bc = x + if man: + return exp+bc + if x == fzero: + return ctx.ninf + if x == finf or x == fninf: + return ctx.inf + return ctx.nan + + def mag(ctx, x): + """ + Quick logarithmic magnitude estimate of a number. Returns an + integer or infinity `m` such that `|x| <= 2^m`. It is not + guaranteed that `m` is an optimal bound, but it will never + be too large by more than 2 (and probably not more than 1). + + **Examples** + + >>> from mpmath import * + >>> mp.pretty = True + >>> mag(10), mag(10.0), mag(mpf(10)), int(ceil(log(10,2))) + (4, 4, 4, 4) + >>> mag(10j), mag(10+10j) + (4, 5) + >>> mag(0.01), int(ceil(log(0.01,2))) + (-6, -6) + >>> mag(0), mag(inf), mag(-inf), mag(nan) + (-inf, +inf, +inf, nan) + + """ + if hasattr(x, "_mpf_"): + return ctx._mpf_mag(x._mpf_) + elif hasattr(x, "_mpc_"): + r, i = x._mpc_ + if r == fzero: + return ctx._mpf_mag(i) + if i == fzero: + return ctx._mpf_mag(r) + return 1+max(ctx._mpf_mag(r), ctx._mpf_mag(i)) + elif isinstance(x, int_types): + if x: + return bitcount(abs(x)) + return ctx.ninf + elif isinstance(x, rational.mpq): + p, q = x._mpq_ + if p: + return 1 + bitcount(abs(p)) - bitcount(q) + return ctx.ninf + else: + x = ctx.convert(x) + if hasattr(x, "_mpf_") or hasattr(x, "_mpc_"): + return ctx.mag(x) + else: + raise TypeError("requires an mpf/mpc") + + +# Register with "numbers" ABC +# We do not subclass, hence we do not use the @abstractmethod checks. While +# this is less invasive it may turn out that we do not actually support +# parts of the expected interfaces. See +# http://docs.python.org/2/library/numbers.html for list of abstract +# methods. +try: + import numbers + numbers.Complex.register(_mpc) + numbers.Real.register(_mpf) +except ImportError: + pass diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/identification.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/identification.py new file mode 100644 index 0000000000000000000000000000000000000000..226f62d3fe9cacedbd9ba2b1e66ff0ad017fa604 --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/identification.py @@ -0,0 +1,844 @@ +""" +Implements the PSLQ algorithm for integer relation detection, +and derivative algorithms for constant recognition. +""" + +from .libmp.backend import xrange +from .libmp import int_types, sqrt_fixed + +# round to nearest integer (can be done more elegantly...) +def round_fixed(x, prec): + return ((x + (1<<(prec-1))) >> prec) << prec + +class IdentificationMethods(object): + pass + + +def pslq(ctx, x, tol=None, maxcoeff=1000, maxsteps=100, verbose=False): + r""" + Given a vector of real numbers `x = [x_0, x_1, ..., x_n]`, ``pslq(x)`` + uses the PSLQ algorithm to find a list of integers + `[c_0, c_1, ..., c_n]` such that + + .. math :: + + |c_1 x_1 + c_2 x_2 + ... + c_n x_n| < \mathrm{tol} + + and such that `\max |c_k| < \mathrm{maxcoeff}`. If no such vector + exists, :func:`~mpmath.pslq` returns ``None``. The tolerance defaults to + 3/4 of the working precision. + + **Examples** + + Find rational approximations for `\pi`:: + + >>> from mpmath import * + >>> mp.dps = 15; mp.pretty = True + >>> pslq([-1, pi], tol=0.01) + [22, 7] + >>> pslq([-1, pi], tol=0.001) + [355, 113] + >>> mpf(22)/7; mpf(355)/113; +pi + 3.14285714285714 + 3.14159292035398 + 3.14159265358979 + + Pi is not a rational number with denominator less than 1000:: + + >>> pslq([-1, pi]) + >>> + + To within the standard precision, it can however be approximated + by at least one rational number with denominator less than `10^{12}`:: + + >>> p, q = pslq([-1, pi], maxcoeff=10**12) + >>> print(p); print(q) + 238410049439 + 75888275702 + >>> mpf(p)/q + 3.14159265358979 + + The PSLQ algorithm can be applied to long vectors. For example, + we can investigate the rational (in)dependence of integer square + roots:: + + >>> mp.dps = 30 + >>> pslq([sqrt(n) for n in range(2, 5+1)]) + >>> + >>> pslq([sqrt(n) for n in range(2, 6+1)]) + >>> + >>> pslq([sqrt(n) for n in range(2, 8+1)]) + [2, 0, 0, 0, 0, 0, -1] + + **Machin formulas** + + A famous formula for `\pi` is Machin's, + + .. math :: + + \frac{\pi}{4} = 4 \operatorname{acot} 5 - \operatorname{acot} 239 + + There are actually infinitely many formulas of this type. Two + others are + + .. math :: + + \frac{\pi}{4} = \operatorname{acot} 1 + + \frac{\pi}{4} = 12 \operatorname{acot} 49 + 32 \operatorname{acot} 57 + + 5 \operatorname{acot} 239 + 12 \operatorname{acot} 110443 + + We can easily verify the formulas using the PSLQ algorithm:: + + >>> mp.dps = 30 + >>> pslq([pi/4, acot(1)]) + [1, -1] + >>> pslq([pi/4, acot(5), acot(239)]) + [1, -4, 1] + >>> pslq([pi/4, acot(49), acot(57), acot(239), acot(110443)]) + [1, -12, -32, 5, -12] + + We could try to generate a custom Machin-like formula by running + the PSLQ algorithm with a few inverse cotangent values, for example + acot(2), acot(3) ... acot(10). Unfortunately, there is a linear + dependence among these values, resulting in only that dependence + being detected, with a zero coefficient for `\pi`:: + + >>> pslq([pi] + [acot(n) for n in range(2,11)]) + [0, 1, -1, 0, 0, 0, -1, 0, 0, 0] + + We get better luck by removing linearly dependent terms:: + + >>> pslq([pi] + [acot(n) for n in range(2,11) if n not in (3, 5)]) + [1, -8, 0, 0, 4, 0, 0, 0] + + In other words, we found the following formula:: + + >>> 8*acot(2) - 4*acot(7) + 3.14159265358979323846264338328 + >>> +pi + 3.14159265358979323846264338328 + + **Algorithm** + + This is a fairly direct translation to Python of the pseudocode given by + David Bailey, "The PSLQ Integer Relation Algorithm": + http://www.cecm.sfu.ca/organics/papers/bailey/paper/html/node3.html + + The present implementation uses fixed-point instead of floating-point + arithmetic, since this is significantly (about 7x) faster. + """ + + n = len(x) + if n < 2: + raise ValueError("n cannot be less than 2") + + # At too low precision, the algorithm becomes meaningless + prec = ctx.prec + if prec < 53: + raise ValueError("prec cannot be less than 53") + + if verbose and prec // max(2,n) < 5: + print("Warning: precision for PSLQ may be too low") + + target = int(prec * 0.75) + + if tol is None: + tol = ctx.mpf(2)**(-target) + else: + tol = ctx.convert(tol) + + extra = 60 + prec += extra + + if verbose: + print("PSLQ using prec %i and tol %s" % (prec, ctx.nstr(tol))) + + tol = ctx.to_fixed(tol, prec) + assert tol + + # Convert to fixed-point numbers. The dummy None is added so we can + # use 1-based indexing. (This just allows us to be consistent with + # Bailey's indexing. The algorithm is 100 lines long, so debugging + # a single wrong index can be painful.) + x = [None] + [ctx.to_fixed(ctx.mpf(xk), prec) for xk in x] + + # Sanity check on magnitudes + minx = min(abs(xx) for xx in x[1:]) + if not minx: + raise ValueError("PSLQ requires a vector of nonzero numbers") + if minx < tol//100: + if verbose: + print("STOPPING: (one number is too small)") + return None + + g = sqrt_fixed((4<> prec) + s[k] = sqrt_fixed(t, prec) + t = s[1] + y = x[:] + for k in xrange(1, n+1): + y[k] = (x[k] << prec) // t + s[k] = (s[k] << prec) // t + # step 3 + for i in xrange(1, n+1): + for j in xrange(i+1, n): + H[i,j] = 0 + if i <= n-1: + if s[i]: + H[i,i] = (s[i+1] << prec) // s[i] + else: + H[i,i] = 0 + for j in range(1, i): + sjj1 = s[j]*s[j+1] + if sjj1: + H[i,j] = ((-y[i]*y[j])<> prec) + for k in xrange(1, j+1): + H[i,k] = H[i,k] - (t*H[j,k] >> prec) + for k in xrange(1, n+1): + A[i,k] = A[i,k] - (t*A[j,k] >> prec) + B[k,j] = B[k,j] + (t*B[k,i] >> prec) + # Main algorithm + for REP in range(maxsteps): + # Step 1 + m = -1 + szmax = -1 + for i in range(1, n): + h = H[i,i] + sz = (g**i * abs(h)) >> (prec*(i-1)) + if sz > szmax: + m = i + szmax = sz + # Step 2 + y[m], y[m+1] = y[m+1], y[m] + for i in xrange(1,n+1): H[m,i], H[m+1,i] = H[m+1,i], H[m,i] + for i in xrange(1,n+1): A[m,i], A[m+1,i] = A[m+1,i], A[m,i] + for i in xrange(1,n+1): B[i,m], B[i,m+1] = B[i,m+1], B[i,m] + # Step 3 + if m <= n - 2: + t0 = sqrt_fixed((H[m,m]**2 + H[m,m+1]**2)>>prec, prec) + # A zero element probably indicates that the precision has + # been exhausted. XXX: this could be spurious, due to + # using fixed-point arithmetic + if not t0: + break + t1 = (H[m,m] << prec) // t0 + t2 = (H[m,m+1] << prec) // t0 + for i in xrange(m, n+1): + t3 = H[i,m] + t4 = H[i,m+1] + H[i,m] = (t1*t3+t2*t4) >> prec + H[i,m+1] = (-t2*t3+t1*t4) >> prec + # Step 4 + for i in xrange(m+1, n+1): + for j in xrange(min(i-1, m+1), 0, -1): + try: + t = round_fixed((H[i,j] << prec)//H[j,j], prec) + # Precision probably exhausted + except ZeroDivisionError: + break + y[j] = y[j] + ((t*y[i]) >> prec) + for k in xrange(1, j+1): + H[i,k] = H[i,k] - (t*H[j,k] >> prec) + for k in xrange(1, n+1): + A[i,k] = A[i,k] - (t*A[j,k] >> prec) + B[k,j] = B[k,j] + (t*B[k,i] >> prec) + # Until a relation is found, the error typically decreases + # slowly (e.g. a factor 1-10) with each step TODO: we could + # compare err from two successive iterations. If there is a + # large drop (several orders of magnitude), that indicates a + # "high quality" relation was detected. Reporting this to + # the user somehow might be useful. + best_err = maxcoeff<> prec) for j in \ + range(1,n+1)] + if max(abs(v) for v in vec) < maxcoeff: + if verbose: + print("FOUND relation at iter %i/%i, error: %s" % \ + (REP, maxsteps, ctx.nstr(err / ctx.mpf(2)**prec, 1))) + return vec + best_err = min(err, best_err) + # Calculate a lower bound for the norm. We could do this + # more exactly (using the Euclidean norm) but there is probably + # no practical benefit. + recnorm = max(abs(h) for h in H.values()) + if recnorm: + norm = ((1 << (2*prec)) // recnorm) >> prec + norm //= 100 + else: + norm = ctx.inf + if verbose: + print("%i/%i: Error: %8s Norm: %s" % \ + (REP, maxsteps, ctx.nstr(best_err / ctx.mpf(2)**prec, 1), norm)) + if norm >= maxcoeff: + break + if verbose: + print("CANCELLING after step %i/%i." % (REP, maxsteps)) + print("Could not find an integer relation. Norm bound: %s" % norm) + return None + +def findpoly(ctx, x, n=1, **kwargs): + r""" + ``findpoly(x, n)`` returns the coefficients of an integer + polynomial `P` of degree at most `n` such that `P(x) \approx 0`. + If no polynomial having `x` as a root can be found, + :func:`~mpmath.findpoly` returns ``None``. + + :func:`~mpmath.findpoly` works by successively calling :func:`~mpmath.pslq` with + the vectors `[1, x]`, `[1, x, x^2]`, `[1, x, x^2, x^3]`, ..., + `[1, x, x^2, .., x^n]` as input. Keyword arguments given to + :func:`~mpmath.findpoly` are forwarded verbatim to :func:`~mpmath.pslq`. In + particular, you can specify a tolerance for `P(x)` with ``tol`` + and a maximum permitted coefficient size with ``maxcoeff``. + + For large values of `n`, it is recommended to run :func:`~mpmath.findpoly` + at high precision; preferably 50 digits or more. + + **Examples** + + By default (degree `n = 1`), :func:`~mpmath.findpoly` simply finds a linear + polynomial with a rational root:: + + >>> from mpmath import * + >>> mp.dps = 15; mp.pretty = True + >>> findpoly(0.7) + [-10, 7] + + The generated coefficient list is valid input to ``polyval`` and + ``polyroots``:: + + >>> nprint(polyval(findpoly(phi, 2), phi), 1) + -2.0e-16 + >>> for r in polyroots(findpoly(phi, 2)): + ... print(r) + ... + -0.618033988749895 + 1.61803398874989 + + Numbers of the form `m + n \sqrt p` for integers `(m, n, p)` are + solutions to quadratic equations. As we find here, `1+\sqrt 2` + is a root of the polynomial `x^2 - 2x - 1`:: + + >>> findpoly(1+sqrt(2), 2) + [1, -2, -1] + >>> findroot(lambda x: x**2 - 2*x - 1, 1) + 2.4142135623731 + + Despite only containing square roots, the following number results + in a polynomial of degree 4:: + + >>> findpoly(sqrt(2)+sqrt(3), 4) + [1, 0, -10, 0, 1] + + In fact, `x^4 - 10x^2 + 1` is the *minimal polynomial* of + `r = \sqrt 2 + \sqrt 3`, meaning that a rational polynomial of + lower degree having `r` as a root does not exist. Given sufficient + precision, :func:`~mpmath.findpoly` will usually find the correct + minimal polynomial of a given algebraic number. + + **Non-algebraic numbers** + + If :func:`~mpmath.findpoly` fails to find a polynomial with given + coefficient size and tolerance constraints, that means no such + polynomial exists. + + We can verify that `\pi` is not an algebraic number of degree 3 with + coefficients less than 1000:: + + >>> mp.dps = 15 + >>> findpoly(pi, 3) + >>> + + It is always possible to find an algebraic approximation of a number + using one (or several) of the following methods: + + 1. Increasing the permitted degree + 2. Allowing larger coefficients + 3. Reducing the tolerance + + One example of each method is shown below:: + + >>> mp.dps = 15 + >>> findpoly(pi, 4) + [95, -545, 863, -183, -298] + >>> findpoly(pi, 3, maxcoeff=10000) + [836, -1734, -2658, -457] + >>> findpoly(pi, 3, tol=1e-7) + [-4, 22, -29, -2] + + It is unknown whether Euler's constant is transcendental (or even + irrational). We can use :func:`~mpmath.findpoly` to check that if is + an algebraic number, its minimal polynomial must have degree + at least 7 and a coefficient of magnitude at least 1000000:: + + >>> mp.dps = 200 + >>> findpoly(euler, 6, maxcoeff=10**6, tol=1e-100, maxsteps=1000) + >>> + + Note that the high precision and strict tolerance is necessary + for such high-degree runs, since otherwise unwanted low-accuracy + approximations will be detected. It may also be necessary to set + maxsteps high to prevent a premature exit (before the coefficient + bound has been reached). Running with ``verbose=True`` to get an + idea what is happening can be useful. + """ + x = ctx.mpf(x) + if n < 1: + raise ValueError("n cannot be less than 1") + if x == 0: + return [1, 0] + xs = [ctx.mpf(1)] + for i in range(1,n+1): + xs.append(x**i) + a = ctx.pslq(xs, **kwargs) + if a is not None: + return a[::-1] + +def fracgcd(p, q): + x, y = p, q + while y: + x, y = y, x % y + if x != 1: + p //= x + q //= x + if q == 1: + return p + return p, q + +def pslqstring(r, constants): + q = r[0] + r = r[1:] + s = [] + for i in range(len(r)): + p = r[i] + if p: + z = fracgcd(-p,q) + cs = constants[i][1] + if cs == '1': + cs = '' + else: + cs = '*' + cs + if isinstance(z, int_types): + if z > 0: term = str(z) + cs + else: term = ("(%s)" % z) + cs + else: + term = ("(%s/%s)" % z) + cs + s.append(term) + s = ' + '.join(s) + if '+' in s or '*' in s: + s = '(' + s + ')' + return s or '0' + +def prodstring(r, constants): + q = r[0] + r = r[1:] + num = [] + den = [] + for i in range(len(r)): + p = r[i] + if p: + z = fracgcd(-p,q) + cs = constants[i][1] + if isinstance(z, int_types): + if abs(z) == 1: t = cs + else: t = '%s**%s' % (cs, abs(z)) + ([num,den][z<0]).append(t) + else: + t = '%s**(%s/%s)' % (cs, abs(z[0]), z[1]) + ([num,den][z[0]<0]).append(t) + num = '*'.join(num) + den = '*'.join(den) + if num and den: return "(%s)/(%s)" % (num, den) + if num: return num + if den: return "1/(%s)" % den + +def quadraticstring(ctx,t,a,b,c): + if c < 0: + a,b,c = -a,-b,-c + u1 = (-b+ctx.sqrt(b**2-4*a*c))/(2*c) + u2 = (-b-ctx.sqrt(b**2-4*a*c))/(2*c) + if abs(u1-t) < abs(u2-t): + if b: s = '((%s+sqrt(%s))/%s)' % (-b,b**2-4*a*c,2*c) + else: s = '(sqrt(%s)/%s)' % (-4*a*c,2*c) + else: + if b: s = '((%s-sqrt(%s))/%s)' % (-b,b**2-4*a*c,2*c) + else: s = '(-sqrt(%s)/%s)' % (-4*a*c,2*c) + return s + +# Transformation y = f(x,c), with inverse function x = f(y,c) +# The third entry indicates whether the transformation is +# redundant when c = 1 +transforms = [ + (lambda ctx,x,c: x*c, '$y/$c', 0), + (lambda ctx,x,c: x/c, '$c*$y', 1), + (lambda ctx,x,c: c/x, '$c/$y', 0), + (lambda ctx,x,c: (x*c)**2, 'sqrt($y)/$c', 0), + (lambda ctx,x,c: (x/c)**2, '$c*sqrt($y)', 1), + (lambda ctx,x,c: (c/x)**2, '$c/sqrt($y)', 0), + (lambda ctx,x,c: c*x**2, 'sqrt($y)/sqrt($c)', 1), + (lambda ctx,x,c: x**2/c, 'sqrt($c)*sqrt($y)', 1), + (lambda ctx,x,c: c/x**2, 'sqrt($c)/sqrt($y)', 1), + (lambda ctx,x,c: ctx.sqrt(x*c), '$y**2/$c', 0), + (lambda ctx,x,c: ctx.sqrt(x/c), '$c*$y**2', 1), + (lambda ctx,x,c: ctx.sqrt(c/x), '$c/$y**2', 0), + (lambda ctx,x,c: c*ctx.sqrt(x), '$y**2/$c**2', 1), + (lambda ctx,x,c: ctx.sqrt(x)/c, '$c**2*$y**2', 1), + (lambda ctx,x,c: c/ctx.sqrt(x), '$c**2/$y**2', 1), + (lambda ctx,x,c: ctx.exp(x*c), 'log($y)/$c', 0), + (lambda ctx,x,c: ctx.exp(x/c), '$c*log($y)', 1), + (lambda ctx,x,c: ctx.exp(c/x), '$c/log($y)', 0), + (lambda ctx,x,c: c*ctx.exp(x), 'log($y/$c)', 1), + (lambda ctx,x,c: ctx.exp(x)/c, 'log($c*$y)', 1), + (lambda ctx,x,c: c/ctx.exp(x), 'log($c/$y)', 0), + (lambda ctx,x,c: ctx.ln(x*c), 'exp($y)/$c', 0), + (lambda ctx,x,c: ctx.ln(x/c), '$c*exp($y)', 1), + (lambda ctx,x,c: ctx.ln(c/x), '$c/exp($y)', 0), + (lambda ctx,x,c: c*ctx.ln(x), 'exp($y/$c)', 1), + (lambda ctx,x,c: ctx.ln(x)/c, 'exp($c*$y)', 1), + (lambda ctx,x,c: c/ctx.ln(x), 'exp($c/$y)', 0), +] + +def identify(ctx, x, constants=[], tol=None, maxcoeff=1000, full=False, + verbose=False): + r""" + Given a real number `x`, ``identify(x)`` attempts to find an exact + formula for `x`. This formula is returned as a string. If no match + is found, ``None`` is returned. With ``full=True``, a list of + matching formulas is returned. + + As a simple example, :func:`~mpmath.identify` will find an algebraic + formula for the golden ratio:: + + >>> from mpmath import * + >>> mp.dps = 15; mp.pretty = True + >>> identify(phi) + '((1+sqrt(5))/2)' + + :func:`~mpmath.identify` can identify simple algebraic numbers and simple + combinations of given base constants, as well as certain basic + transformations thereof. More specifically, :func:`~mpmath.identify` + looks for the following: + + 1. Fractions + 2. Quadratic algebraic numbers + 3. Rational linear combinations of the base constants + 4. Any of the above after first transforming `x` into `f(x)` where + `f(x)` is `1/x`, `\sqrt x`, `x^2`, `\log x` or `\exp x`, either + directly or with `x` or `f(x)` multiplied or divided by one of + the base constants + 5. Products of fractional powers of the base constants and + small integers + + Base constants can be given as a list of strings representing mpmath + expressions (:func:`~mpmath.identify` will ``eval`` the strings to numerical + values and use the original strings for the output), or as a dict of + formula:value pairs. + + In order not to produce spurious results, :func:`~mpmath.identify` should + be used with high precision; preferably 50 digits or more. + + **Examples** + + Simple identifications can be performed safely at standard + precision. Here the default recognition of rational, algebraic, + and exp/log of algebraic numbers is demonstrated:: + + >>> mp.dps = 15 + >>> identify(0.22222222222222222) + '(2/9)' + >>> identify(1.9662210973805663) + 'sqrt(((24+sqrt(48))/8))' + >>> identify(4.1132503787829275) + 'exp((sqrt(8)/2))' + >>> identify(0.881373587019543) + 'log(((2+sqrt(8))/2))' + + By default, :func:`~mpmath.identify` does not recognize `\pi`. At standard + precision it finds a not too useful approximation. At slightly + increased precision, this approximation is no longer accurate + enough and :func:`~mpmath.identify` more correctly returns ``None``:: + + >>> identify(pi) + '(2**(176/117)*3**(20/117)*5**(35/39))/(7**(92/117))' + >>> mp.dps = 30 + >>> identify(pi) + >>> + + Numbers such as `\pi`, and simple combinations of user-defined + constants, can be identified if they are provided explicitly:: + + >>> identify(3*pi-2*e, ['pi', 'e']) + '(3*pi + (-2)*e)' + + Here is an example using a dict of constants. Note that the + constants need not be "atomic"; :func:`~mpmath.identify` can just + as well express the given number in terms of expressions + given by formulas:: + + >>> identify(pi+e, {'a':pi+2, 'b':2*e}) + '((-2) + 1*a + (1/2)*b)' + + Next, we attempt some identifications with a set of base constants. + It is necessary to increase the precision a bit. + + >>> mp.dps = 50 + >>> base = ['sqrt(2)','pi','log(2)'] + >>> identify(0.25, base) + '(1/4)' + >>> identify(3*pi + 2*sqrt(2) + 5*log(2)/7, base) + '(2*sqrt(2) + 3*pi + (5/7)*log(2))' + >>> identify(exp(pi+2), base) + 'exp((2 + 1*pi))' + >>> identify(1/(3+sqrt(2)), base) + '((3/7) + (-1/7)*sqrt(2))' + >>> identify(sqrt(2)/(3*pi+4), base) + 'sqrt(2)/(4 + 3*pi)' + >>> identify(5**(mpf(1)/3)*pi*log(2)**2, base) + '5**(1/3)*pi*log(2)**2' + + An example of an erroneous solution being found when too low + precision is used:: + + >>> mp.dps = 15 + >>> identify(1/(3*pi-4*e+sqrt(8)), ['pi', 'e', 'sqrt(2)']) + '((11/25) + (-158/75)*pi + (76/75)*e + (44/15)*sqrt(2))' + >>> mp.dps = 50 + >>> identify(1/(3*pi-4*e+sqrt(8)), ['pi', 'e', 'sqrt(2)']) + '1/(3*pi + (-4)*e + 2*sqrt(2))' + + **Finding approximate solutions** + + The tolerance ``tol`` defaults to 3/4 of the working precision. + Lowering the tolerance is useful for finding approximate matches. + We can for example try to generate approximations for pi:: + + >>> mp.dps = 15 + >>> identify(pi, tol=1e-2) + '(22/7)' + >>> identify(pi, tol=1e-3) + '(355/113)' + >>> identify(pi, tol=1e-10) + '(5**(339/269))/(2**(64/269)*3**(13/269)*7**(92/269))' + + With ``full=True``, and by supplying a few base constants, + ``identify`` can generate almost endless lists of approximations + for any number (the output below has been truncated to show only + the first few):: + + >>> for p in identify(pi, ['e', 'catalan'], tol=1e-5, full=True): + ... print(p) + ... # doctest: +ELLIPSIS + e/log((6 + (-4/3)*e)) + (3**3*5*e*catalan**2)/(2*7**2) + sqrt(((-13) + 1*e + 22*catalan)) + log(((-6) + 24*e + 4*catalan)/e) + exp(catalan*((-1/5) + (8/15)*e)) + catalan*(6 + (-6)*e + 15*catalan) + sqrt((5 + 26*e + (-3)*catalan))/e + e*sqrt(((-27) + 2*e + 25*catalan)) + log(((-1) + (-11)*e + 59*catalan)) + ((3/20) + (21/20)*e + (3/20)*catalan) + ... + + The numerical values are roughly as close to `\pi` as permitted by the + specified tolerance: + + >>> e/log(6-4*e/3) + 3.14157719846001 + >>> 135*e*catalan**2/98 + 3.14166950419369 + >>> sqrt(e-13+22*catalan) + 3.14158000062992 + >>> log(24*e-6+4*catalan)-1 + 3.14158791577159 + + **Symbolic processing** + + The output formula can be evaluated as a Python expression. + Note however that if fractions (like '2/3') are present in + the formula, Python's :func:`~mpmath.eval()` may erroneously perform + integer division. Note also that the output is not necessarily + in the algebraically simplest form:: + + >>> identify(sqrt(2)) + '(sqrt(8)/2)' + + As a solution to both problems, consider using SymPy's + :func:`~mpmath.sympify` to convert the formula into a symbolic expression. + SymPy can be used to pretty-print or further simplify the formula + symbolically:: + + >>> from sympy import sympify # doctest: +SKIP + >>> sympify(identify(sqrt(2))) # doctest: +SKIP + 2**(1/2) + + Sometimes :func:`~mpmath.identify` can simplify an expression further than + a symbolic algorithm:: + + >>> from sympy import simplify # doctest: +SKIP + >>> x = sympify('-1/(-3/2+(1/2)*5**(1/2))*(3/2-1/2*5**(1/2))**(1/2)') # doctest: +SKIP + >>> x # doctest: +SKIP + (3/2 - 5**(1/2)/2)**(-1/2) + >>> x = simplify(x) # doctest: +SKIP + >>> x # doctest: +SKIP + 2/(6 - 2*5**(1/2))**(1/2) + >>> mp.dps = 30 # doctest: +SKIP + >>> x = sympify(identify(x.evalf(30))) # doctest: +SKIP + >>> x # doctest: +SKIP + 1/2 + 5**(1/2)/2 + + (In fact, this functionality is available directly in SymPy as the + function :func:`~mpmath.nsimplify`, which is essentially a wrapper for + :func:`~mpmath.identify`.) + + **Miscellaneous issues and limitations** + + The input `x` must be a real number. All base constants must be + positive real numbers and must not be rationals or rational linear + combinations of each other. + + The worst-case computation time grows quickly with the number of + base constants. Already with 3 or 4 base constants, + :func:`~mpmath.identify` may require several seconds to finish. To search + for relations among a large number of constants, you should + consider using :func:`~mpmath.pslq` directly. + + The extended transformations are applied to x, not the constants + separately. As a result, ``identify`` will for example be able to + recognize ``exp(2*pi+3)`` with ``pi`` given as a base constant, but + not ``2*exp(pi)+3``. It will be able to recognize the latter if + ``exp(pi)`` is given explicitly as a base constant. + + """ + + solutions = [] + + def addsolution(s): + if verbose: print("Found: ", s) + solutions.append(s) + + x = ctx.mpf(x) + + # Further along, x will be assumed positive + if x == 0: + if full: return ['0'] + else: return '0' + if x < 0: + sol = ctx.identify(-x, constants, tol, maxcoeff, full, verbose) + if sol is None: + return sol + if full: + return ["-(%s)"%s for s in sol] + else: + return "-(%s)" % sol + + if tol: + tol = ctx.mpf(tol) + else: + tol = ctx.eps**0.7 + M = maxcoeff + + if constants: + if isinstance(constants, dict): + constants = [(ctx.mpf(v), name) for (name, v) in sorted(constants.items())] + else: + namespace = dict((name, getattr(ctx,name)) for name in dir(ctx)) + constants = [(eval(p, namespace), p) for p in constants] + else: + constants = [] + + # We always want to find at least rational terms + if 1 not in [value for (name, value) in constants]: + constants = [(ctx.mpf(1), '1')] + constants + + # PSLQ with simple algebraic and functional transformations + for ft, ftn, red in transforms: + for c, cn in constants: + if red and cn == '1': + continue + t = ft(ctx,x,c) + # Prevent exponential transforms from wreaking havoc + if abs(t) > M**2 or abs(t) < tol: + continue + # Linear combination of base constants + r = ctx.pslq([t] + [a[0] for a in constants], tol, M) + s = None + if r is not None and max(abs(uw) for uw in r) <= M and r[0]: + s = pslqstring(r, constants) + # Quadratic algebraic numbers + else: + q = ctx.pslq([ctx.one, t, t**2], tol, M) + if q is not None and len(q) == 3 and q[2]: + aa, bb, cc = q + if max(abs(aa),abs(bb),abs(cc)) <= M: + s = quadraticstring(ctx,t,aa,bb,cc) + if s: + if cn == '1' and ('/$c' in ftn): + s = ftn.replace('$y', s).replace('/$c', '') + else: + s = ftn.replace('$y', s).replace('$c', cn) + addsolution(s) + if not full: return solutions[0] + + if verbose: + print(".") + + # Check for a direct multiplicative formula + if x != 1: + # Allow fractional powers of fractions + ilogs = [2,3,5,7] + # Watch out for existing fractional powers of fractions + logs = [] + for a, s in constants: + if not sum(bool(ctx.findpoly(ctx.ln(a)/ctx.ln(i),1)) for i in ilogs): + logs.append((ctx.ln(a), s)) + logs = [(ctx.ln(i),str(i)) for i in ilogs] + logs + r = ctx.pslq([ctx.ln(x)] + [a[0] for a in logs], tol, M) + if r is not None and max(abs(uw) for uw in r) <= M and r[0]: + addsolution(prodstring(r, logs)) + if not full: return solutions[0] + + if full: + return sorted(solutions, key=len) + else: + return None + +IdentificationMethods.pslq = pslq +IdentificationMethods.findpoly = findpoly +IdentificationMethods.identify = identify + + +if __name__ == '__main__': + import doctest + doctest.testmod() diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/rational.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/rational.py new file mode 100644 index 0000000000000000000000000000000000000000..58745205319ac3548ad5feb49371d2d154b2d3c8 --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/rational.py @@ -0,0 +1,240 @@ +import operator +import sys +from .libmp import int_types, mpf_hash, bitcount, from_man_exp, HASH_MODULUS + +new = object.__new__ + +def create_reduced(p, q, _cache={}): + key = p, q + if key in _cache: + return _cache[key] + x, y = p, q + while y: + x, y = y, x % y + if x != 1: + p //= x + q //= x + v = new(mpq) + v._mpq_ = p, q + # Speedup integers, half-integers and other small fractions + if q <= 4 and abs(key[0]) < 100: + _cache[key] = v + return v + +class mpq(object): + """ + Exact rational type, currently only intended for internal use. + """ + + __slots__ = ["_mpq_"] + + def __new__(cls, p, q=1): + if type(p) is tuple: + p, q = p + elif hasattr(p, '_mpq_'): + p, q = p._mpq_ + return create_reduced(p, q) + + def __repr__(s): + return "mpq(%s,%s)" % s._mpq_ + + def __str__(s): + return "(%s/%s)" % s._mpq_ + + def __int__(s): + a, b = s._mpq_ + return a // b + + def __nonzero__(s): + return bool(s._mpq_[0]) + + __bool__ = __nonzero__ + + def __hash__(s): + a, b = s._mpq_ + if sys.version_info >= (3, 2): + inverse = pow(b, HASH_MODULUS-2, HASH_MODULUS) + if not inverse: + h = sys.hash_info.inf + else: + h = (abs(a) * inverse) % HASH_MODULUS + if a < 0: h = -h + if h == -1: h = -2 + return h + else: + if b == 1: + return hash(a) + # Power of two: mpf compatible hash + if not (b & (b-1)): + return mpf_hash(from_man_exp(a, 1-bitcount(b))) + return hash((a,b)) + + def __eq__(s, t): + ttype = type(t) + if ttype is mpq: + return s._mpq_ == t._mpq_ + if ttype in int_types: + a, b = s._mpq_ + if b != 1: + return False + return a == t + return NotImplemented + + def __ne__(s, t): + ttype = type(t) + if ttype is mpq: + return s._mpq_ != t._mpq_ + if ttype in int_types: + a, b = s._mpq_ + if b != 1: + return True + return a != t + return NotImplemented + + def _cmp(s, t, op): + ttype = type(t) + if ttype in int_types: + a, b = s._mpq_ + return op(a, t*b) + if ttype is mpq: + a, b = s._mpq_ + c, d = t._mpq_ + return op(a*d, b*c) + return NotImplementedError + + def __lt__(s, t): return s._cmp(t, operator.lt) + def __le__(s, t): return s._cmp(t, operator.le) + def __gt__(s, t): return s._cmp(t, operator.gt) + def __ge__(s, t): return s._cmp(t, operator.ge) + + def __abs__(s): + a, b = s._mpq_ + if a >= 0: + return s + v = new(mpq) + v._mpq_ = -a, b + return v + + def __neg__(s): + a, b = s._mpq_ + v = new(mpq) + v._mpq_ = -a, b + return v + + def __pos__(s): + return s + + def __add__(s, t): + ttype = type(t) + if ttype is mpq: + a, b = s._mpq_ + c, d = t._mpq_ + return create_reduced(a*d+b*c, b*d) + if ttype in int_types: + a, b = s._mpq_ + v = new(mpq) + v._mpq_ = a+b*t, b + return v + return NotImplemented + + __radd__ = __add__ + + def __sub__(s, t): + ttype = type(t) + if ttype is mpq: + a, b = s._mpq_ + c, d = t._mpq_ + return create_reduced(a*d-b*c, b*d) + if ttype in int_types: + a, b = s._mpq_ + v = new(mpq) + v._mpq_ = a-b*t, b + return v + return NotImplemented + + def __rsub__(s, t): + ttype = type(t) + if ttype is mpq: + a, b = s._mpq_ + c, d = t._mpq_ + return create_reduced(b*c-a*d, b*d) + if ttype in int_types: + a, b = s._mpq_ + v = new(mpq) + v._mpq_ = b*t-a, b + return v + return NotImplemented + + def __mul__(s, t): + ttype = type(t) + if ttype is mpq: + a, b = s._mpq_ + c, d = t._mpq_ + return create_reduced(a*c, b*d) + if ttype in int_types: + a, b = s._mpq_ + return create_reduced(a*t, b) + return NotImplemented + + __rmul__ = __mul__ + + def __div__(s, t): + ttype = type(t) + if ttype is mpq: + a, b = s._mpq_ + c, d = t._mpq_ + return create_reduced(a*d, b*c) + if ttype in int_types: + a, b = s._mpq_ + return create_reduced(a, b*t) + return NotImplemented + + def __rdiv__(s, t): + ttype = type(t) + if ttype is mpq: + a, b = s._mpq_ + c, d = t._mpq_ + return create_reduced(b*c, a*d) + if ttype in int_types: + a, b = s._mpq_ + return create_reduced(b*t, a) + return NotImplemented + + def __pow__(s, t): + ttype = type(t) + if ttype in int_types: + a, b = s._mpq_ + if t: + if t < 0: + a, b, t = b, a, -t + v = new(mpq) + v._mpq_ = a**t, b**t + return v + raise ZeroDivisionError + return NotImplemented + + +mpq_1 = mpq((1,1)) +mpq_0 = mpq((0,1)) +mpq_1_2 = mpq((1,2)) +mpq_3_2 = mpq((3,2)) +mpq_1_4 = mpq((1,4)) +mpq_1_16 = mpq((1,16)) +mpq_3_16 = mpq((3,16)) +mpq_5_2 = mpq((5,2)) +mpq_3_4 = mpq((3,4)) +mpq_7_4 = mpq((7,4)) +mpq_5_4 = mpq((5,4)) + + +# Register with "numbers" ABC +# We do not subclass, hence we do not use the @abstractmethod checks. While +# this is less invasive it may turn out that we do not actually support +# parts of the expected interfaces. See +# http://docs.python.org/2/library/numbers.html for list of abstract +# methods. +try: + import numbers + numbers.Rational.register(mpq) +except ImportError: + pass diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/usertools.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/usertools.py new file mode 100644 index 0000000000000000000000000000000000000000..8028a4c46f1c635a6857f1f2de48ac6675d3c6d3 --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/usertools.py @@ -0,0 +1,93 @@ + +def monitor(f, input='print', output='print'): + """ + Returns a wrapped copy of *f* that monitors evaluation by calling + *input* with every input (*args*, *kwargs*) passed to *f* and + *output* with every value returned from *f*. The default action + (specify using the special string value ``'print'``) is to print + inputs and outputs to stdout, along with the total evaluation + count:: + + >>> from mpmath import * + >>> mp.dps = 5; mp.pretty = False + >>> diff(monitor(exp), 1) # diff will eval f(x-h) and f(x+h) + in 0 (mpf('0.99999999906867742538452148'),) {} + out 0 mpf('2.7182818259274480055282064') + in 1 (mpf('1.0000000009313225746154785'),) {} + out 1 mpf('2.7182818309906424675501024') + mpf('2.7182808') + + To disable either the input or the output handler, you may + pass *None* as argument. + + Custom input and output handlers may be used e.g. to store + results for later analysis:: + + >>> mp.dps = 15 + >>> input = [] + >>> output = [] + >>> findroot(monitor(sin, input.append, output.append), 3.0) + mpf('3.1415926535897932') + >>> len(input) # Count number of evaluations + 9 + >>> print(input[3]); print(output[3]) + ((mpf('3.1415076583334066'),), {}) + 8.49952562843408e-5 + >>> print(input[4]); print(output[4]) + ((mpf('3.1415928201669122'),), {}) + -1.66577118985331e-7 + + """ + if not input: + input = lambda v: None + elif input == 'print': + incount = [0] + def input(value): + args, kwargs = value + print("in %s %r %r" % (incount[0], args, kwargs)) + incount[0] += 1 + if not output: + output = lambda v: None + elif output == 'print': + outcount = [0] + def output(value): + print("out %s %r" % (outcount[0], value)) + outcount[0] += 1 + def f_monitored(*args, **kwargs): + input((args, kwargs)) + v = f(*args, **kwargs) + output(v) + return v + return f_monitored + +def timing(f, *args, **kwargs): + """ + Returns time elapsed for evaluating ``f()``. Optionally arguments + may be passed to time the execution of ``f(*args, **kwargs)``. + + If the first call is very quick, ``f`` is called + repeatedly and the best time is returned. + """ + once = kwargs.get('once') + if 'once' in kwargs: + del kwargs['once'] + if args or kwargs: + if len(args) == 1 and not kwargs: + arg = args[0] + g = lambda: f(arg) + else: + g = lambda: f(*args, **kwargs) + else: + g = f + from timeit import default_timer as clock + t1=clock(); v=g(); t2=clock(); t=t2-t1 + if t > 0.05 or once: + return t + for i in range(3): + t1=clock(); + # Evaluate multiple times because the timer function + # has a significant overhead + g();g();g();g();g();g();g();g();g();g() + t2=clock() + t=min(t,(t2-t1)/10) + return t diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/visualization.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/visualization.py new file mode 100644 index 0000000000000000000000000000000000000000..17e12e97bead4f2977b59361a4de7672f0e9b75f --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/mpmath/visualization.py @@ -0,0 +1,313 @@ +""" +Plotting (requires matplotlib) +""" + +from colorsys import hsv_to_rgb, hls_to_rgb +from .libmp import NoConvergence +from .libmp.backend import xrange + +class VisualizationMethods(object): + plot_ignore = (ValueError, ArithmeticError, ZeroDivisionError, NoConvergence) + +def plot(ctx, f, xlim=[-5,5], ylim=None, points=200, file=None, dpi=None, + singularities=[], axes=None): + r""" + Shows a simple 2D plot of a function `f(x)` or list of functions + `[f_0(x), f_1(x), \ldots, f_n(x)]` over a given interval + specified by *xlim*. Some examples:: + + plot(lambda x: exp(x)*li(x), [1, 4]) + plot([cos, sin], [-4, 4]) + plot([fresnels, fresnelc], [-4, 4]) + plot([sqrt, cbrt], [-4, 4]) + plot(lambda t: zeta(0.5+t*j), [-20, 20]) + plot([floor, ceil, abs, sign], [-5, 5]) + + Points where the function raises a numerical exception or + returns an infinite value are removed from the graph. + Singularities can also be excluded explicitly + as follows (useful for removing erroneous vertical lines):: + + plot(cot, ylim=[-5, 5]) # bad + plot(cot, ylim=[-5, 5], singularities=[-pi, 0, pi]) # good + + For parts where the function assumes complex values, the + real part is plotted with dashes and the imaginary part + is plotted with dots. + + .. note :: This function requires matplotlib (pylab). + """ + if file: + axes = None + fig = None + if not axes: + import pylab + fig = pylab.figure() + axes = fig.add_subplot(111) + if not isinstance(f, (tuple, list)): + f = [f] + a, b = xlim + colors = ['b', 'r', 'g', 'm', 'k'] + for n, func in enumerate(f): + x = ctx.arange(a, b, (b-a)/float(points)) + segments = [] + segment = [] + in_complex = False + for i in xrange(len(x)): + try: + if i != 0: + for sing in singularities: + if x[i-1] <= sing and x[i] >= sing: + raise ValueError + v = func(x[i]) + if ctx.isnan(v) or abs(v) > 1e300: + raise ValueError + if hasattr(v, "imag") and v.imag: + re = float(v.real) + im = float(v.imag) + if not in_complex: + in_complex = True + segments.append(segment) + segment = [] + segment.append((float(x[i]), re, im)) + else: + if in_complex: + in_complex = False + segments.append(segment) + segment = [] + if hasattr(v, "real"): + v = v.real + segment.append((float(x[i]), v)) + except ctx.plot_ignore: + if segment: + segments.append(segment) + segment = [] + if segment: + segments.append(segment) + for segment in segments: + x = [s[0] for s in segment] + y = [s[1] for s in segment] + if not x: + continue + c = colors[n % len(colors)] + if len(segment[0]) == 3: + z = [s[2] for s in segment] + axes.plot(x, y, '--'+c, linewidth=3) + axes.plot(x, z, ':'+c, linewidth=3) + else: + axes.plot(x, y, c, linewidth=3) + axes.set_xlim([float(_) for _ in xlim]) + if ylim: + axes.set_ylim([float(_) for _ in ylim]) + axes.set_xlabel('x') + axes.set_ylabel('f(x)') + axes.grid(True) + if fig: + if file: + pylab.savefig(file, dpi=dpi) + else: + pylab.show() + +def default_color_function(ctx, z): + if ctx.isinf(z): + return (1.0, 1.0, 1.0) + if ctx.isnan(z): + return (0.5, 0.5, 0.5) + pi = 3.1415926535898 + a = (float(ctx.arg(z)) + ctx.pi) / (2*ctx.pi) + a = (a + 0.5) % 1.0 + b = 1.0 - float(1/(1.0+abs(z)**0.3)) + return hls_to_rgb(a, b, 0.8) + +blue_orange_colors = [ + (-1.0, (0.0, 0.0, 0.0)), + (-0.95, (0.1, 0.2, 0.5)), # dark blue + (-0.5, (0.0, 0.5, 1.0)), # blueish + (-0.05, (0.4, 0.8, 0.8)), # cyanish + ( 0.0, (1.0, 1.0, 1.0)), + ( 0.05, (1.0, 0.9, 0.3)), # yellowish + ( 0.5, (0.9, 0.5, 0.0)), # orangeish + ( 0.95, (0.7, 0.1, 0.0)), # redish + ( 1.0, (0.0, 0.0, 0.0)), + ( 2.0, (0.0, 0.0, 0.0)), +] + +def phase_color_function(ctx, z): + if ctx.isinf(z): + return (1.0, 1.0, 1.0) + if ctx.isnan(z): + return (0.5, 0.5, 0.5) + pi = 3.1415926535898 + w = float(ctx.arg(z)) / pi + w = max(min(w, 1.0), -1.0) + for i in range(1,len(blue_orange_colors)): + if blue_orange_colors[i][0] > w: + a, (ra, ga, ba) = blue_orange_colors[i-1] + b, (rb, gb, bb) = blue_orange_colors[i] + s = (w-a) / (b-a) + return ra+(rb-ra)*s, ga+(gb-ga)*s, ba+(bb-ba)*s + +def cplot(ctx, f, re=[-5,5], im=[-5,5], points=2000, color=None, + verbose=False, file=None, dpi=None, axes=None): + """ + Plots the given complex-valued function *f* over a rectangular part + of the complex plane specified by the pairs of intervals *re* and *im*. + For example:: + + cplot(lambda z: z, [-2, 2], [-10, 10]) + cplot(exp) + cplot(zeta, [0, 1], [0, 50]) + + By default, the complex argument (phase) is shown as color (hue) and + the magnitude is show as brightness. You can also supply a + custom color function (*color*). This function should take a + complex number as input and return an RGB 3-tuple containing + floats in the range 0.0-1.0. + + Alternatively, you can select a builtin color function by passing + a string as *color*: + + * "default" - default color scheme + * "phase" - a color scheme that only renders the phase of the function, + with white for positive reals, black for negative reals, gold in the + upper half plane, and blue in the lower half plane. + + To obtain a sharp image, the number of points may need to be + increased to 100,000 or thereabout. Since evaluating the + function that many times is likely to be slow, the 'verbose' + option is useful to display progress. + + .. note :: This function requires matplotlib (pylab). + """ + if color is None or color == "default": + color = ctx.default_color_function + if color == "phase": + color = ctx.phase_color_function + import pylab + if file: + axes = None + fig = None + if not axes: + fig = pylab.figure() + axes = fig.add_subplot(111) + rea, reb = re + ima, imb = im + dre = reb - rea + dim = imb - ima + M = int(ctx.sqrt(points*dre/dim)+1) + N = int(ctx.sqrt(points*dim/dre)+1) + x = pylab.linspace(rea, reb, M) + y = pylab.linspace(ima, imb, N) + # Note: we have to be careful to get the right rotation. + # Test with these plots: + # cplot(lambda z: z if z.real < 0 else 0) + # cplot(lambda z: z if z.imag < 0 else 0) + w = pylab.zeros((N, M, 3)) + for n in xrange(N): + for m in xrange(M): + z = ctx.mpc(x[m], y[n]) + try: + v = color(f(z)) + except ctx.plot_ignore: + v = (0.5, 0.5, 0.5) + w[n,m] = v + if verbose: + print(str(n) + ' of ' + str(N)) + rea, reb, ima, imb = [float(_) for _ in [rea, reb, ima, imb]] + axes.imshow(w, extent=(rea, reb, ima, imb), origin='lower') + axes.set_xlabel('Re(z)') + axes.set_ylabel('Im(z)') + if fig: + if file: + pylab.savefig(file, dpi=dpi) + else: + pylab.show() + +def splot(ctx, f, u=[-5,5], v=[-5,5], points=100, keep_aspect=True, \ + wireframe=False, file=None, dpi=None, axes=None): + """ + Plots the surface defined by `f`. + + If `f` returns a single component, then this plots the surface + defined by `z = f(x,y)` over the rectangular domain with + `x = u` and `y = v`. + + If `f` returns three components, then this plots the parametric + surface `x, y, z = f(u,v)` over the pairs of intervals `u` and `v`. + + For example, to plot a simple function:: + + >>> from mpmath import * + >>> f = lambda x, y: sin(x+y)*cos(y) + >>> splot(f, [-pi,pi], [-pi,pi]) # doctest: +SKIP + + Plotting a donut:: + + >>> r, R = 1, 2.5 + >>> f = lambda u, v: [r*cos(u), (R+r*sin(u))*cos(v), (R+r*sin(u))*sin(v)] + >>> splot(f, [0, 2*pi], [0, 2*pi]) # doctest: +SKIP + + .. note :: This function requires matplotlib (pylab) 0.98.5.3 or higher. + """ + import pylab + import mpl_toolkits.mplot3d as mplot3d + if file: + axes = None + fig = None + if not axes: + fig = pylab.figure() + axes = mplot3d.axes3d.Axes3D(fig) + ua, ub = u + va, vb = v + du = ub - ua + dv = vb - va + if not isinstance(points, (list, tuple)): + points = [points, points] + M, N = points + u = pylab.linspace(ua, ub, M) + v = pylab.linspace(va, vb, N) + x, y, z = [pylab.zeros((M, N)) for i in xrange(3)] + xab, yab, zab = [[0, 0] for i in xrange(3)] + for n in xrange(N): + for m in xrange(M): + fdata = f(ctx.convert(u[m]), ctx.convert(v[n])) + try: + x[m,n], y[m,n], z[m,n] = fdata + except TypeError: + x[m,n], y[m,n], z[m,n] = u[m], v[n], fdata + for c, cab in [(x[m,n], xab), (y[m,n], yab), (z[m,n], zab)]: + if c < cab[0]: + cab[0] = c + if c > cab[1]: + cab[1] = c + if wireframe: + axes.plot_wireframe(x, y, z, rstride=4, cstride=4) + else: + axes.plot_surface(x, y, z, rstride=4, cstride=4) + axes.set_xlabel('x') + axes.set_ylabel('y') + axes.set_zlabel('z') + if keep_aspect: + dx, dy, dz = [cab[1] - cab[0] for cab in [xab, yab, zab]] + maxd = max(dx, dy, dz) + if dx < maxd: + delta = maxd - dx + axes.set_xlim3d(xab[0] - delta / 2.0, xab[1] + delta / 2.0) + if dy < maxd: + delta = maxd - dy + axes.set_ylim3d(yab[0] - delta / 2.0, yab[1] + delta / 2.0) + if dz < maxd: + delta = maxd - dz + axes.set_zlim3d(zab[0] - delta / 2.0, zab[1] + delta / 2.0) + if fig: + if file: + pylab.savefig(file, dpi=dpi) + else: + pylab.show() + + +VisualizationMethods.plot = plot +VisualizationMethods.default_color_function = default_color_function +VisualizationMethods.phase_color_function = phase_color_function +VisualizationMethods.cplot = cplot +VisualizationMethods.splot = splot diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/locations/__init__.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/locations/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..32382be7fe5f6781047e9774679aa8bcf5bbce8a --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/locations/__init__.py @@ -0,0 +1,456 @@ +import functools +import logging +import os +import pathlib +import sys +import sysconfig +from typing import Any, Dict, Generator, Optional, Tuple + +from pip._internal.models.scheme import SCHEME_KEYS, Scheme +from pip._internal.utils.compat import WINDOWS +from pip._internal.utils.deprecation import deprecated +from pip._internal.utils.virtualenv import running_under_virtualenv + +from . import _sysconfig +from .base import ( + USER_CACHE_DIR, + get_major_minor_version, + get_src_prefix, + is_osx_framework, + site_packages, + user_site, +) + +__all__ = [ + "USER_CACHE_DIR", + "get_bin_prefix", + "get_bin_user", + "get_major_minor_version", + "get_platlib", + "get_purelib", + "get_scheme", + "get_src_prefix", + "site_packages", + "user_site", +] + + +logger = logging.getLogger(__name__) + + +_PLATLIBDIR: str = getattr(sys, "platlibdir", "lib") + +_USE_SYSCONFIG_DEFAULT = sys.version_info >= (3, 10) + + +def _should_use_sysconfig() -> bool: + """This function determines the value of _USE_SYSCONFIG. + + By default, pip uses sysconfig on Python 3.10+. + But Python distributors can override this decision by setting: + sysconfig._PIP_USE_SYSCONFIG = True / False + Rationale in https://github.com/pypa/pip/issues/10647 + + This is a function for testability, but should be constant during any one + run. + """ + return bool(getattr(sysconfig, "_PIP_USE_SYSCONFIG", _USE_SYSCONFIG_DEFAULT)) + + +_USE_SYSCONFIG = _should_use_sysconfig() + +if not _USE_SYSCONFIG: + # Import distutils lazily to avoid deprecation warnings, + # but import it soon enough that it is in memory and available during + # a pip reinstall. + from . import _distutils + +# Be noisy about incompatibilities if this platforms "should" be using +# sysconfig, but is explicitly opting out and using distutils instead. +if _USE_SYSCONFIG_DEFAULT and not _USE_SYSCONFIG: + _MISMATCH_LEVEL = logging.WARNING +else: + _MISMATCH_LEVEL = logging.DEBUG + + +def _looks_like_bpo_44860() -> bool: + """The resolution to bpo-44860 will change this incorrect platlib. + + See . + """ + from distutils.command.install import INSTALL_SCHEMES + + try: + unix_user_platlib = INSTALL_SCHEMES["unix_user"]["platlib"] + except KeyError: + return False + return unix_user_platlib == "$usersite" + + +def _looks_like_red_hat_patched_platlib_purelib(scheme: Dict[str, str]) -> bool: + platlib = scheme["platlib"] + if "/$platlibdir/" in platlib: + platlib = platlib.replace("/$platlibdir/", f"/{_PLATLIBDIR}/") + if "/lib64/" not in platlib: + return False + unpatched = platlib.replace("/lib64/", "/lib/") + return unpatched.replace("$platbase/", "$base/") == scheme["purelib"] + + +@functools.lru_cache(maxsize=None) +def _looks_like_red_hat_lib() -> bool: + """Red Hat patches platlib in unix_prefix and unix_home, but not purelib. + + This is the only way I can see to tell a Red Hat-patched Python. + """ + from distutils.command.install import INSTALL_SCHEMES + + return all( + k in INSTALL_SCHEMES + and _looks_like_red_hat_patched_platlib_purelib(INSTALL_SCHEMES[k]) + for k in ("unix_prefix", "unix_home") + ) + + +@functools.lru_cache(maxsize=None) +def _looks_like_debian_scheme() -> bool: + """Debian adds two additional schemes.""" + from distutils.command.install import INSTALL_SCHEMES + + return "deb_system" in INSTALL_SCHEMES and "unix_local" in INSTALL_SCHEMES + + +@functools.lru_cache(maxsize=None) +def _looks_like_red_hat_scheme() -> bool: + """Red Hat patches ``sys.prefix`` and ``sys.exec_prefix``. + + Red Hat's ``00251-change-user-install-location.patch`` changes the install + command's ``prefix`` and ``exec_prefix`` to append ``"/local"``. This is + (fortunately?) done quite unconditionally, so we create a default command + object without any configuration to detect this. + """ + from distutils.command.install import install + from distutils.dist import Distribution + + cmd: Any = install(Distribution()) + cmd.finalize_options() + return ( + cmd.exec_prefix == f"{os.path.normpath(sys.exec_prefix)}/local" + and cmd.prefix == f"{os.path.normpath(sys.prefix)}/local" + ) + + +@functools.lru_cache(maxsize=None) +def _looks_like_slackware_scheme() -> bool: + """Slackware patches sysconfig but fails to patch distutils and site. + + Slackware changes sysconfig's user scheme to use ``"lib64"`` for the lib + path, but does not do the same to the site module. + """ + if user_site is None: # User-site not available. + return False + try: + paths = sysconfig.get_paths(scheme="posix_user", expand=False) + except KeyError: # User-site not available. + return False + return "/lib64/" in paths["purelib"] and "/lib64/" not in user_site + + +@functools.lru_cache(maxsize=None) +def _looks_like_msys2_mingw_scheme() -> bool: + """MSYS2 patches distutils and sysconfig to use a UNIX-like scheme. + + However, MSYS2 incorrectly patches sysconfig ``nt`` scheme. The fix is + likely going to be included in their 3.10 release, so we ignore the warning. + See msys2/MINGW-packages#9319. + + MSYS2 MINGW's patch uses lowercase ``"lib"`` instead of the usual uppercase, + and is missing the final ``"site-packages"``. + """ + paths = sysconfig.get_paths("nt", expand=False) + return all( + "Lib" not in p and "lib" in p and not p.endswith("site-packages") + for p in (paths[key] for key in ("platlib", "purelib")) + ) + + +def _fix_abiflags(parts: Tuple[str]) -> Generator[str, None, None]: + ldversion = sysconfig.get_config_var("LDVERSION") + abiflags = getattr(sys, "abiflags", None) + + # LDVERSION does not end with sys.abiflags. Just return the path unchanged. + if not ldversion or not abiflags or not ldversion.endswith(abiflags): + yield from parts + return + + # Strip sys.abiflags from LDVERSION-based path components. + for part in parts: + if part.endswith(ldversion): + part = part[: (0 - len(abiflags))] + yield part + + +@functools.lru_cache(maxsize=None) +def _warn_mismatched(old: pathlib.Path, new: pathlib.Path, *, key: str) -> None: + issue_url = "https://github.com/pypa/pip/issues/10151" + message = ( + "Value for %s does not match. Please report this to <%s>" + "\ndistutils: %s" + "\nsysconfig: %s" + ) + logger.log(_MISMATCH_LEVEL, message, key, issue_url, old, new) + + +def _warn_if_mismatch(old: pathlib.Path, new: pathlib.Path, *, key: str) -> bool: + if old == new: + return False + _warn_mismatched(old, new, key=key) + return True + + +@functools.lru_cache(maxsize=None) +def _log_context( + *, + user: bool = False, + home: Optional[str] = None, + root: Optional[str] = None, + prefix: Optional[str] = None, +) -> None: + parts = [ + "Additional context:", + "user = %r", + "home = %r", + "root = %r", + "prefix = %r", + ] + + logger.log(_MISMATCH_LEVEL, "\n".join(parts), user, home, root, prefix) + + +def get_scheme( + dist_name: str, + user: bool = False, + home: Optional[str] = None, + root: Optional[str] = None, + isolated: bool = False, + prefix: Optional[str] = None, +) -> Scheme: + new = _sysconfig.get_scheme( + dist_name, + user=user, + home=home, + root=root, + isolated=isolated, + prefix=prefix, + ) + if _USE_SYSCONFIG: + return new + + old = _distutils.get_scheme( + dist_name, + user=user, + home=home, + root=root, + isolated=isolated, + prefix=prefix, + ) + + warning_contexts = [] + for k in SCHEME_KEYS: + old_v = pathlib.Path(getattr(old, k)) + new_v = pathlib.Path(getattr(new, k)) + + if old_v == new_v: + continue + + # distutils incorrectly put PyPy packages under ``site-packages/python`` + # in the ``posix_home`` scheme, but PyPy devs said they expect the + # directory name to be ``pypy`` instead. So we treat this as a bug fix + # and not warn about it. See bpo-43307 and python/cpython#24628. + skip_pypy_special_case = ( + sys.implementation.name == "pypy" + and home is not None + and k in ("platlib", "purelib") + and old_v.parent == new_v.parent + and old_v.name.startswith("python") + and new_v.name.startswith("pypy") + ) + if skip_pypy_special_case: + continue + + # sysconfig's ``osx_framework_user`` does not include ``pythonX.Y`` in + # the ``include`` value, but distutils's ``headers`` does. We'll let + # CPython decide whether this is a bug or feature. See bpo-43948. + skip_osx_framework_user_special_case = ( + user + and is_osx_framework() + and k == "headers" + and old_v.parent.parent == new_v.parent + and old_v.parent.name.startswith("python") + ) + if skip_osx_framework_user_special_case: + continue + + # On Red Hat and derived Linux distributions, distutils is patched to + # use "lib64" instead of "lib" for platlib. + if k == "platlib" and _looks_like_red_hat_lib(): + continue + + # On Python 3.9+, sysconfig's posix_user scheme sets platlib against + # sys.platlibdir, but distutils's unix_user incorrectly coninutes + # using the same $usersite for both platlib and purelib. This creates a + # mismatch when sys.platlibdir is not "lib". + skip_bpo_44860 = ( + user + and k == "platlib" + and not WINDOWS + and sys.version_info >= (3, 9) + and _PLATLIBDIR != "lib" + and _looks_like_bpo_44860() + ) + if skip_bpo_44860: + continue + + # Slackware incorrectly patches posix_user to use lib64 instead of lib, + # but not usersite to match the location. + skip_slackware_user_scheme = ( + user + and k in ("platlib", "purelib") + and not WINDOWS + and _looks_like_slackware_scheme() + ) + if skip_slackware_user_scheme: + continue + + # Both Debian and Red Hat patch Python to place the system site under + # /usr/local instead of /usr. Debian also places lib in dist-packages + # instead of site-packages, but the /usr/local check should cover it. + skip_linux_system_special_case = ( + not (user or home or prefix or running_under_virtualenv()) + and old_v.parts[1:3] == ("usr", "local") + and len(new_v.parts) > 1 + and new_v.parts[1] == "usr" + and (len(new_v.parts) < 3 or new_v.parts[2] != "local") + and (_looks_like_red_hat_scheme() or _looks_like_debian_scheme()) + ) + if skip_linux_system_special_case: + continue + + # MSYS2 MINGW's sysconfig patch does not include the "site-packages" + # part of the path. This is incorrect and will be fixed in MSYS. + skip_msys2_mingw_bug = ( + WINDOWS and k in ("platlib", "purelib") and _looks_like_msys2_mingw_scheme() + ) + if skip_msys2_mingw_bug: + continue + + # CPython's POSIX install script invokes pip (via ensurepip) against the + # interpreter located in the source tree, not the install site. This + # triggers special logic in sysconfig that's not present in distutils. + # https://github.com/python/cpython/blob/8c21941ddaf/Lib/sysconfig.py#L178-L194 + skip_cpython_build = ( + sysconfig.is_python_build(check_home=True) + and not WINDOWS + and k in ("headers", "include", "platinclude") + ) + if skip_cpython_build: + continue + + warning_contexts.append((old_v, new_v, f"scheme.{k}")) + + if not warning_contexts: + return old + + # Check if this path mismatch is caused by distutils config files. Those + # files will no longer work once we switch to sysconfig, so this raises a + # deprecation message for them. + default_old = _distutils.distutils_scheme( + dist_name, + user, + home, + root, + isolated, + prefix, + ignore_config_files=True, + ) + if any(default_old[k] != getattr(old, k) for k in SCHEME_KEYS): + deprecated( + reason=( + "Configuring installation scheme with distutils config files " + "is deprecated and will no longer work in the near future. If you " + "are using a Homebrew or Linuxbrew Python, please see discussion " + "at https://github.com/Homebrew/homebrew-core/issues/76621" + ), + replacement=None, + gone_in=None, + ) + return old + + # Post warnings about this mismatch so user can report them back. + for old_v, new_v, key in warning_contexts: + _warn_mismatched(old_v, new_v, key=key) + _log_context(user=user, home=home, root=root, prefix=prefix) + + return old + + +def get_bin_prefix() -> str: + new = _sysconfig.get_bin_prefix() + if _USE_SYSCONFIG: + return new + + old = _distutils.get_bin_prefix() + if _warn_if_mismatch(pathlib.Path(old), pathlib.Path(new), key="bin_prefix"): + _log_context() + return old + + +def get_bin_user() -> str: + return _sysconfig.get_scheme("", user=True).scripts + + +def _looks_like_deb_system_dist_packages(value: str) -> bool: + """Check if the value is Debian's APT-controlled dist-packages. + + Debian's ``distutils.sysconfig.get_python_lib()`` implementation returns the + default package path controlled by APT, but does not patch ``sysconfig`` to + do the same. This is similar to the bug worked around in ``get_scheme()``, + but here the default is ``deb_system`` instead of ``unix_local``. Ultimately + we can't do anything about this Debian bug, and this detection allows us to + skip the warning when needed. + """ + if not _looks_like_debian_scheme(): + return False + if value == "/usr/lib/python3/dist-packages": + return True + return False + + +def get_purelib() -> str: + """Return the default pure-Python lib location.""" + new = _sysconfig.get_purelib() + if _USE_SYSCONFIG: + return new + + old = _distutils.get_purelib() + if _looks_like_deb_system_dist_packages(old): + return old + if _warn_if_mismatch(pathlib.Path(old), pathlib.Path(new), key="purelib"): + _log_context() + return old + + +def get_platlib() -> str: + """Return the default platform-shared lib location.""" + new = _sysconfig.get_platlib() + if _USE_SYSCONFIG: + return new + + from . import _distutils + + old = _distutils.get_platlib() + if _looks_like_deb_system_dist_packages(old): + return old + if _warn_if_mismatch(pathlib.Path(old), pathlib.Path(new), key="platlib"): + _log_context() + return old diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..19380799a40c55018ea5316f517324b5ebe36b31 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/locations/__pycache__/_sysconfig.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/locations/__pycache__/_sysconfig.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8d2fd87b4669c01e7b93cb262b28d7070a44fb63 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/locations/__pycache__/_sysconfig.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/locations/_sysconfig.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/locations/_sysconfig.py new file mode 100644 index 0000000000000000000000000000000000000000..ca860ea562c2c0c30982ba6cff654355e9f21c8a --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/locations/_sysconfig.py @@ -0,0 +1,214 @@ +import logging +import os +import sys +import sysconfig +import typing + +from pip._internal.exceptions import InvalidSchemeCombination, UserInstallationInvalid +from pip._internal.models.scheme import SCHEME_KEYS, Scheme +from pip._internal.utils.virtualenv import running_under_virtualenv + +from .base import change_root, get_major_minor_version, is_osx_framework + +logger = logging.getLogger(__name__) + + +# Notes on _infer_* functions. +# Unfortunately ``get_default_scheme()`` didn't exist before 3.10, so there's no +# way to ask things like "what is the '_prefix' scheme on this platform". These +# functions try to answer that with some heuristics while accounting for ad-hoc +# platforms not covered by CPython's default sysconfig implementation. If the +# ad-hoc implementation does not fully implement sysconfig, we'll fall back to +# a POSIX scheme. + +_AVAILABLE_SCHEMES = set(sysconfig.get_scheme_names()) + +_PREFERRED_SCHEME_API = getattr(sysconfig, "get_preferred_scheme", None) + + +def _should_use_osx_framework_prefix() -> bool: + """Check for Apple's ``osx_framework_library`` scheme. + + Python distributed by Apple's Command Line Tools has this special scheme + that's used when: + + * This is a framework build. + * We are installing into the system prefix. + + This does not account for ``pip install --prefix`` (also means we're not + installing to the system prefix), which should use ``posix_prefix``, but + logic here means ``_infer_prefix()`` outputs ``osx_framework_library``. But + since ``prefix`` is not available for ``sysconfig.get_default_scheme()``, + which is the stdlib replacement for ``_infer_prefix()``, presumably Apple + wouldn't be able to magically switch between ``osx_framework_library`` and + ``posix_prefix``. ``_infer_prefix()`` returning ``osx_framework_library`` + means its behavior is consistent whether we use the stdlib implementation + or our own, and we deal with this special case in ``get_scheme()`` instead. + """ + return ( + "osx_framework_library" in _AVAILABLE_SCHEMES + and not running_under_virtualenv() + and is_osx_framework() + ) + + +def _infer_prefix() -> str: + """Try to find a prefix scheme for the current platform. + + This tries: + + * A special ``osx_framework_library`` for Python distributed by Apple's + Command Line Tools, when not running in a virtual environment. + * Implementation + OS, used by PyPy on Windows (``pypy_nt``). + * Implementation without OS, used by PyPy on POSIX (``pypy``). + * OS + "prefix", used by CPython on POSIX (``posix_prefix``). + * Just the OS name, used by CPython on Windows (``nt``). + + If none of the above works, fall back to ``posix_prefix``. + """ + if _PREFERRED_SCHEME_API: + return _PREFERRED_SCHEME_API("prefix") + if _should_use_osx_framework_prefix(): + return "osx_framework_library" + implementation_suffixed = f"{sys.implementation.name}_{os.name}" + if implementation_suffixed in _AVAILABLE_SCHEMES: + return implementation_suffixed + if sys.implementation.name in _AVAILABLE_SCHEMES: + return sys.implementation.name + suffixed = f"{os.name}_prefix" + if suffixed in _AVAILABLE_SCHEMES: + return suffixed + if os.name in _AVAILABLE_SCHEMES: # On Windows, prefx is just called "nt". + return os.name + return "posix_prefix" + + +def _infer_user() -> str: + """Try to find a user scheme for the current platform.""" + if _PREFERRED_SCHEME_API: + return _PREFERRED_SCHEME_API("user") + if is_osx_framework() and not running_under_virtualenv(): + suffixed = "osx_framework_user" + else: + suffixed = f"{os.name}_user" + if suffixed in _AVAILABLE_SCHEMES: + return suffixed + if "posix_user" not in _AVAILABLE_SCHEMES: # User scheme unavailable. + raise UserInstallationInvalid() + return "posix_user" + + +def _infer_home() -> str: + """Try to find a home for the current platform.""" + if _PREFERRED_SCHEME_API: + return _PREFERRED_SCHEME_API("home") + suffixed = f"{os.name}_home" + if suffixed in _AVAILABLE_SCHEMES: + return suffixed + return "posix_home" + + +# Update these keys if the user sets a custom home. +_HOME_KEYS = [ + "installed_base", + "base", + "installed_platbase", + "platbase", + "prefix", + "exec_prefix", +] +if sysconfig.get_config_var("userbase") is not None: + _HOME_KEYS.append("userbase") + + +def get_scheme( + dist_name: str, + user: bool = False, + home: typing.Optional[str] = None, + root: typing.Optional[str] = None, + isolated: bool = False, + prefix: typing.Optional[str] = None, +) -> Scheme: + """ + Get the "scheme" corresponding to the input parameters. + + :param dist_name: the name of the package to retrieve the scheme for, used + in the headers scheme path + :param user: indicates to use the "user" scheme + :param home: indicates to use the "home" scheme + :param root: root under which other directories are re-based + :param isolated: ignored, but kept for distutils compatibility (where + this controls whether the user-site pydistutils.cfg is honored) + :param prefix: indicates to use the "prefix" scheme and provides the + base directory for the same + """ + if user and prefix: + raise InvalidSchemeCombination("--user", "--prefix") + if home and prefix: + raise InvalidSchemeCombination("--home", "--prefix") + + if home is not None: + scheme_name = _infer_home() + elif user: + scheme_name = _infer_user() + else: + scheme_name = _infer_prefix() + + # Special case: When installing into a custom prefix, use posix_prefix + # instead of osx_framework_library. See _should_use_osx_framework_prefix() + # docstring for details. + if prefix is not None and scheme_name == "osx_framework_library": + scheme_name = "posix_prefix" + + if home is not None: + variables = {k: home for k in _HOME_KEYS} + elif prefix is not None: + variables = {k: prefix for k in _HOME_KEYS} + else: + variables = {} + + paths = sysconfig.get_paths(scheme=scheme_name, vars=variables) + + # Logic here is very arbitrary, we're doing it for compatibility, don't ask. + # 1. Pip historically uses a special header path in virtual environments. + # 2. If the distribution name is not known, distutils uses 'UNKNOWN'. We + # only do the same when not running in a virtual environment because + # pip's historical header path logic (see point 1) did not do this. + if running_under_virtualenv(): + if user: + base = variables.get("userbase", sys.prefix) + else: + base = variables.get("base", sys.prefix) + python_xy = f"python{get_major_minor_version()}" + paths["include"] = os.path.join(base, "include", "site", python_xy) + elif not dist_name: + dist_name = "UNKNOWN" + + scheme = Scheme( + platlib=paths["platlib"], + purelib=paths["purelib"], + headers=os.path.join(paths["include"], dist_name), + scripts=paths["scripts"], + data=paths["data"], + ) + if root is not None: + converted_keys = {} + for key in SCHEME_KEYS: + converted_keys[key] = change_root(root, getattr(scheme, key)) + scheme = Scheme(**converted_keys) + return scheme + + +def get_bin_prefix() -> str: + # Forcing to use /usr/local/bin for standard macOS framework installs. + if sys.platform[:6] == "darwin" and sys.prefix[:16] == "/System/Library/": + return "/usr/local/bin" + return sysconfig.get_paths()["scripts"] + + +def get_purelib() -> str: + return sysconfig.get_paths()["purelib"] + + +def get_platlib() -> str: + return sysconfig.get_paths()["platlib"] diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/metadata/importlib/__pycache__/_compat.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/metadata/importlib/__pycache__/_compat.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5ba88b046e098b2d92bacac1d5fdfb5002242da6 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/metadata/importlib/__pycache__/_compat.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/network/__init__.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/network/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..b51bde91b2e5b4e557ed9b70fc113843cc3d49ae --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/network/__init__.py @@ -0,0 +1,2 @@ +"""Contains purely network-related utilities. +""" diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/network/session.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/network/session.py new file mode 100644 index 0000000000000000000000000000000000000000..1765b4f6bd74cb10ca7af93f819c6a6f063f3a84 --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/network/session.py @@ -0,0 +1,522 @@ +"""PipSession and supporting code, containing all pip-specific +network request configuration and behavior. +""" + +import email.utils +import functools +import io +import ipaddress +import json +import logging +import mimetypes +import os +import platform +import shutil +import subprocess +import sys +import urllib.parse +import warnings +from typing import ( + TYPE_CHECKING, + Any, + Dict, + Generator, + List, + Mapping, + Optional, + Sequence, + Tuple, + Union, +) + +from pip._vendor import requests, urllib3 +from pip._vendor.cachecontrol import CacheControlAdapter as _BaseCacheControlAdapter +from pip._vendor.requests.adapters import DEFAULT_POOLBLOCK, BaseAdapter +from pip._vendor.requests.adapters import HTTPAdapter as _BaseHTTPAdapter +from pip._vendor.requests.models import PreparedRequest, Response +from pip._vendor.requests.structures import CaseInsensitiveDict +from pip._vendor.urllib3.connectionpool import ConnectionPool +from pip._vendor.urllib3.exceptions import InsecureRequestWarning + +from pip import __version__ +from pip._internal.metadata import get_default_environment +from pip._internal.models.link import Link +from pip._internal.network.auth import MultiDomainBasicAuth +from pip._internal.network.cache import SafeFileCache + +# Import ssl from compat so the initial import occurs in only one place. +from pip._internal.utils.compat import has_tls +from pip._internal.utils.glibc import libc_ver +from pip._internal.utils.misc import build_url_from_netloc, parse_netloc +from pip._internal.utils.urls import url_to_path + +if TYPE_CHECKING: + from ssl import SSLContext + + from pip._vendor.urllib3.poolmanager import PoolManager + + +logger = logging.getLogger(__name__) + +SecureOrigin = Tuple[str, str, Optional[Union[int, str]]] + + +# Ignore warning raised when using --trusted-host. +warnings.filterwarnings("ignore", category=InsecureRequestWarning) + + +SECURE_ORIGINS: List[SecureOrigin] = [ + # protocol, hostname, port + # Taken from Chrome's list of secure origins (See: http://bit.ly/1qrySKC) + ("https", "*", "*"), + ("*", "localhost", "*"), + ("*", "127.0.0.0/8", "*"), + ("*", "::1/128", "*"), + ("file", "*", None), + # ssh is always secure. + ("ssh", "*", "*"), +] + + +# These are environment variables present when running under various +# CI systems. For each variable, some CI systems that use the variable +# are indicated. The collection was chosen so that for each of a number +# of popular systems, at least one of the environment variables is used. +# This list is used to provide some indication of and lower bound for +# CI traffic to PyPI. Thus, it is okay if the list is not comprehensive. +# For more background, see: https://github.com/pypa/pip/issues/5499 +CI_ENVIRONMENT_VARIABLES = ( + # Azure Pipelines + "BUILD_BUILDID", + # Jenkins + "BUILD_ID", + # AppVeyor, CircleCI, Codeship, Gitlab CI, Shippable, Travis CI + "CI", + # Explicit environment variable. + "PIP_IS_CI", +) + + +def looks_like_ci() -> bool: + """ + Return whether it looks like pip is running under CI. + """ + # We don't use the method of checking for a tty (e.g. using isatty()) + # because some CI systems mimic a tty (e.g. Travis CI). Thus that + # method doesn't provide definitive information in either direction. + return any(name in os.environ for name in CI_ENVIRONMENT_VARIABLES) + + +@functools.lru_cache(maxsize=1) +def user_agent() -> str: + """ + Return a string representing the user agent. + """ + data: Dict[str, Any] = { + "installer": {"name": "pip", "version": __version__}, + "python": platform.python_version(), + "implementation": { + "name": platform.python_implementation(), + }, + } + + if data["implementation"]["name"] == "CPython": + data["implementation"]["version"] = platform.python_version() + elif data["implementation"]["name"] == "PyPy": + pypy_version_info = sys.pypy_version_info # type: ignore + if pypy_version_info.releaselevel == "final": + pypy_version_info = pypy_version_info[:3] + data["implementation"]["version"] = ".".join( + [str(x) for x in pypy_version_info] + ) + elif data["implementation"]["name"] == "Jython": + # Complete Guess + data["implementation"]["version"] = platform.python_version() + elif data["implementation"]["name"] == "IronPython": + # Complete Guess + data["implementation"]["version"] = platform.python_version() + + if sys.platform.startswith("linux"): + from pip._vendor import distro + + linux_distribution = distro.name(), distro.version(), distro.codename() + distro_infos: Dict[str, Any] = dict( + filter( + lambda x: x[1], + zip(["name", "version", "id"], linux_distribution), + ) + ) + libc = dict( + filter( + lambda x: x[1], + zip(["lib", "version"], libc_ver()), + ) + ) + if libc: + distro_infos["libc"] = libc + if distro_infos: + data["distro"] = distro_infos + + if sys.platform.startswith("darwin") and platform.mac_ver()[0]: + data["distro"] = {"name": "macOS", "version": platform.mac_ver()[0]} + + if platform.system(): + data.setdefault("system", {})["name"] = platform.system() + + if platform.release(): + data.setdefault("system", {})["release"] = platform.release() + + if platform.machine(): + data["cpu"] = platform.machine() + + if has_tls(): + import _ssl as ssl + + data["openssl_version"] = ssl.OPENSSL_VERSION + + setuptools_dist = get_default_environment().get_distribution("setuptools") + if setuptools_dist is not None: + data["setuptools_version"] = str(setuptools_dist.version) + + if shutil.which("rustc") is not None: + # If for any reason `rustc --version` fails, silently ignore it + try: + rustc_output = subprocess.check_output( + ["rustc", "--version"], stderr=subprocess.STDOUT, timeout=0.5 + ) + except Exception: + pass + else: + if rustc_output.startswith(b"rustc "): + # The format of `rustc --version` is: + # `b'rustc 1.52.1 (9bc8c42bb 2021-05-09)\n'` + # We extract just the middle (1.52.1) part + data["rustc_version"] = rustc_output.split(b" ")[1].decode() + + # Use None rather than False so as not to give the impression that + # pip knows it is not being run under CI. Rather, it is a null or + # inconclusive result. Also, we include some value rather than no + # value to make it easier to know that the check has been run. + data["ci"] = True if looks_like_ci() else None + + user_data = os.environ.get("PIP_USER_AGENT_USER_DATA") + if user_data is not None: + data["user_data"] = user_data + + return "{data[installer][name]}/{data[installer][version]} {json}".format( + data=data, + json=json.dumps(data, separators=(",", ":"), sort_keys=True), + ) + + +class LocalFSAdapter(BaseAdapter): + def send( + self, + request: PreparedRequest, + stream: bool = False, + timeout: Optional[Union[float, Tuple[float, float]]] = None, + verify: Union[bool, str] = True, + cert: Optional[Union[str, Tuple[str, str]]] = None, + proxies: Optional[Mapping[str, str]] = None, + ) -> Response: + pathname = url_to_path(request.url) + + resp = Response() + resp.status_code = 200 + resp.url = request.url + + try: + stats = os.stat(pathname) + except OSError as exc: + # format the exception raised as a io.BytesIO object, + # to return a better error message: + resp.status_code = 404 + resp.reason = type(exc).__name__ + resp.raw = io.BytesIO(f"{resp.reason}: {exc}".encode()) + else: + modified = email.utils.formatdate(stats.st_mtime, usegmt=True) + content_type = mimetypes.guess_type(pathname)[0] or "text/plain" + resp.headers = CaseInsensitiveDict( + { + "Content-Type": content_type, + "Content-Length": stats.st_size, + "Last-Modified": modified, + } + ) + + resp.raw = open(pathname, "rb") + resp.close = resp.raw.close + + return resp + + def close(self) -> None: + pass + + +class _SSLContextAdapterMixin: + """Mixin to add the ``ssl_context`` constructor argument to HTTP adapters. + + The additional argument is forwarded directly to the pool manager. This allows us + to dynamically decide what SSL store to use at runtime, which is used to implement + the optional ``truststore`` backend. + """ + + def __init__( + self, + *, + ssl_context: Optional["SSLContext"] = None, + **kwargs: Any, + ) -> None: + self._ssl_context = ssl_context + super().__init__(**kwargs) + + def init_poolmanager( + self, + connections: int, + maxsize: int, + block: bool = DEFAULT_POOLBLOCK, + **pool_kwargs: Any, + ) -> "PoolManager": + if self._ssl_context is not None: + pool_kwargs.setdefault("ssl_context", self._ssl_context) + return super().init_poolmanager( # type: ignore[misc] + connections=connections, + maxsize=maxsize, + block=block, + **pool_kwargs, + ) + + +class HTTPAdapter(_SSLContextAdapterMixin, _BaseHTTPAdapter): + pass + + +class CacheControlAdapter(_SSLContextAdapterMixin, _BaseCacheControlAdapter): + pass + + +class InsecureHTTPAdapter(HTTPAdapter): + def cert_verify( + self, + conn: ConnectionPool, + url: str, + verify: Union[bool, str], + cert: Optional[Union[str, Tuple[str, str]]], + ) -> None: + super().cert_verify(conn=conn, url=url, verify=False, cert=cert) + + +class InsecureCacheControlAdapter(CacheControlAdapter): + def cert_verify( + self, + conn: ConnectionPool, + url: str, + verify: Union[bool, str], + cert: Optional[Union[str, Tuple[str, str]]], + ) -> None: + super().cert_verify(conn=conn, url=url, verify=False, cert=cert) + + +class PipSession(requests.Session): + timeout: Optional[int] = None + + def __init__( + self, + *args: Any, + retries: int = 0, + cache: Optional[str] = None, + trusted_hosts: Sequence[str] = (), + index_urls: Optional[List[str]] = None, + ssl_context: Optional["SSLContext"] = None, + **kwargs: Any, + ) -> None: + """ + :param trusted_hosts: Domains not to emit warnings for when not using + HTTPS. + """ + super().__init__(*args, **kwargs) + + # Namespace the attribute with "pip_" just in case to prevent + # possible conflicts with the base class. + self.pip_trusted_origins: List[Tuple[str, Optional[int]]] = [] + + # Attach our User Agent to the request + self.headers["User-Agent"] = user_agent() + + # Attach our Authentication handler to the session + self.auth = MultiDomainBasicAuth(index_urls=index_urls) + + # Create our urllib3.Retry instance which will allow us to customize + # how we handle retries. + retries = urllib3.Retry( + # Set the total number of retries that a particular request can + # have. + total=retries, + # A 503 error from PyPI typically means that the Fastly -> Origin + # connection got interrupted in some way. A 503 error in general + # is typically considered a transient error so we'll go ahead and + # retry it. + # A 500 may indicate transient error in Amazon S3 + # A 502 may be a transient error from a CDN like CloudFlare or CloudFront + # A 520 or 527 - may indicate transient error in CloudFlare + status_forcelist=[500, 502, 503, 520, 527], + # Add a small amount of back off between failed requests in + # order to prevent hammering the service. + backoff_factor=0.25, + ) # type: ignore + + # Our Insecure HTTPAdapter disables HTTPS validation. It does not + # support caching so we'll use it for all http:// URLs. + # If caching is disabled, we will also use it for + # https:// hosts that we've marked as ignoring + # TLS errors for (trusted-hosts). + insecure_adapter = InsecureHTTPAdapter(max_retries=retries) + + # We want to _only_ cache responses on securely fetched origins or when + # the host is specified as trusted. We do this because + # we can't validate the response of an insecurely/untrusted fetched + # origin, and we don't want someone to be able to poison the cache and + # require manual eviction from the cache to fix it. + if cache: + secure_adapter = CacheControlAdapter( + cache=SafeFileCache(cache), + max_retries=retries, + ssl_context=ssl_context, + ) + self._trusted_host_adapter = InsecureCacheControlAdapter( + cache=SafeFileCache(cache), + max_retries=retries, + ) + else: + secure_adapter = HTTPAdapter(max_retries=retries, ssl_context=ssl_context) + self._trusted_host_adapter = insecure_adapter + + self.mount("https://", secure_adapter) + self.mount("http://", insecure_adapter) + + # Enable file:// urls + self.mount("file://", LocalFSAdapter()) + + for host in trusted_hosts: + self.add_trusted_host(host, suppress_logging=True) + + def update_index_urls(self, new_index_urls: List[str]) -> None: + """ + :param new_index_urls: New index urls to update the authentication + handler with. + """ + self.auth.index_urls = new_index_urls + + def add_trusted_host( + self, host: str, source: Optional[str] = None, suppress_logging: bool = False + ) -> None: + """ + :param host: It is okay to provide a host that has previously been + added. + :param source: An optional source string, for logging where the host + string came from. + """ + if not suppress_logging: + msg = f"adding trusted host: {host!r}" + if source is not None: + msg += f" (from {source})" + logger.info(msg) + + parsed_host, parsed_port = parse_netloc(host) + if parsed_host is None: + raise ValueError(f"Trusted host URL must include a host part: {host!r}") + if (parsed_host, parsed_port) not in self.pip_trusted_origins: + self.pip_trusted_origins.append((parsed_host, parsed_port)) + + self.mount( + build_url_from_netloc(host, scheme="http") + "/", self._trusted_host_adapter + ) + self.mount(build_url_from_netloc(host) + "/", self._trusted_host_adapter) + if not parsed_port: + self.mount( + build_url_from_netloc(host, scheme="http") + ":", + self._trusted_host_adapter, + ) + # Mount wildcard ports for the same host. + self.mount(build_url_from_netloc(host) + ":", self._trusted_host_adapter) + + def iter_secure_origins(self) -> Generator[SecureOrigin, None, None]: + yield from SECURE_ORIGINS + for host, port in self.pip_trusted_origins: + yield ("*", host, "*" if port is None else port) + + def is_secure_origin(self, location: Link) -> bool: + # Determine if this url used a secure transport mechanism + parsed = urllib.parse.urlparse(str(location)) + origin_protocol, origin_host, origin_port = ( + parsed.scheme, + parsed.hostname, + parsed.port, + ) + + # The protocol to use to see if the protocol matches. + # Don't count the repository type as part of the protocol: in + # cases such as "git+ssh", only use "ssh". (I.e., Only verify against + # the last scheme.) + origin_protocol = origin_protocol.rsplit("+", 1)[-1] + + # Determine if our origin is a secure origin by looking through our + # hardcoded list of secure origins, as well as any additional ones + # configured on this PackageFinder instance. + for secure_origin in self.iter_secure_origins(): + secure_protocol, secure_host, secure_port = secure_origin + if origin_protocol != secure_protocol and secure_protocol != "*": + continue + + try: + addr = ipaddress.ip_address(origin_host or "") + network = ipaddress.ip_network(secure_host) + except ValueError: + # We don't have both a valid address or a valid network, so + # we'll check this origin against hostnames. + if ( + origin_host + and origin_host.lower() != secure_host.lower() + and secure_host != "*" + ): + continue + else: + # We have a valid address and network, so see if the address + # is contained within the network. + if addr not in network: + continue + + # Check to see if the port matches. + if ( + origin_port != secure_port + and secure_port != "*" + and secure_port is not None + ): + continue + + # If we've gotten here, then this origin matches the current + # secure origin and we should return True + return True + + # If we've gotten to this point, then the origin isn't secure and we + # will not accept it as a valid location to search. We will however + # log a warning that we are ignoring it. + logger.warning( + "The repository located at %s is not a trusted or secure host and " + "is being ignored. If this repository is available via HTTPS we " + "recommend you use HTTPS instead, otherwise you may silence " + "this warning and allow it anyway with '--trusted-host %s'.", + origin_host, + origin_host, + ) + + return False + + def request(self, method: str, url: str, *args: Any, **kwargs: Any) -> Response: + # Allow setting a default timeout on a session + kwargs.setdefault("timeout", self.timeout) + # Allow setting a default proxies on a session + kwargs.setdefault("proxies", self.proxies) + + # Dispatch the actual request + return super().request(method, url, *args, **kwargs) diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/__pycache__/base.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/__pycache__/base.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e3a02236b5dfebc9e9592f5dc17c5075d5cabd5e Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/__pycache__/base.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__init__.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2474b9d7a261fb230a91cacb9d0cdf3c84899d1f Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/base.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/base.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7093a59b30d52f097f05a12df932373006df23e0 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/base.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f571a24f360c5df98407572eb0d012d12a7d8045 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4b28d24f024eb3bc20c2e79088bf01577f0179cd Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b7a5be41c22275cd2f410d66f3961555c684356b Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..881f8f8b05747e4a135f90d13a8f24370d6cc2ea Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..92bd0f3a417a3dca67e538428c2cc073e6cbb207 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6c10282bc9fff84af568078d1b741ce620dca09a Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/base.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/base.py new file mode 100644 index 0000000000000000000000000000000000000000..0f31dc9b3073ecf2a9ae234b752e33c8caf5798a --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/base.py @@ -0,0 +1,139 @@ +from dataclasses import dataclass +from typing import FrozenSet, Iterable, Optional, Tuple + +from pip._vendor.packaging.specifiers import SpecifierSet +from pip._vendor.packaging.utils import NormalizedName +from pip._vendor.packaging.version import Version + +from pip._internal.models.link import Link, links_equivalent +from pip._internal.req.req_install import InstallRequirement +from pip._internal.utils.hashes import Hashes + +CandidateLookup = Tuple[Optional["Candidate"], Optional[InstallRequirement]] + + +def format_name(project: NormalizedName, extras: FrozenSet[NormalizedName]) -> str: + if not extras: + return project + extras_expr = ",".join(sorted(extras)) + return f"{project}[{extras_expr}]" + + +@dataclass(frozen=True) +class Constraint: + specifier: SpecifierSet + hashes: Hashes + links: FrozenSet[Link] + + @classmethod + def empty(cls) -> "Constraint": + return Constraint(SpecifierSet(), Hashes(), frozenset()) + + @classmethod + def from_ireq(cls, ireq: InstallRequirement) -> "Constraint": + links = frozenset([ireq.link]) if ireq.link else frozenset() + return Constraint(ireq.specifier, ireq.hashes(trust_internet=False), links) + + def __bool__(self) -> bool: + return bool(self.specifier) or bool(self.hashes) or bool(self.links) + + def __and__(self, other: InstallRequirement) -> "Constraint": + if not isinstance(other, InstallRequirement): + return NotImplemented + specifier = self.specifier & other.specifier + hashes = self.hashes & other.hashes(trust_internet=False) + links = self.links + if other.link: + links = links.union([other.link]) + return Constraint(specifier, hashes, links) + + def is_satisfied_by(self, candidate: "Candidate") -> bool: + # Reject if there are any mismatched URL constraints on this package. + if self.links and not all(_match_link(link, candidate) for link in self.links): + return False + # We can safely always allow prereleases here since PackageFinder + # already implements the prerelease logic, and would have filtered out + # prerelease candidates if the user does not expect them. + return self.specifier.contains(candidate.version, prereleases=True) + + +class Requirement: + @property + def project_name(self) -> NormalizedName: + """The "project name" of a requirement. + + This is different from ``name`` if this requirement contains extras, + in which case ``name`` would contain the ``[...]`` part, while this + refers to the name of the project. + """ + raise NotImplementedError("Subclass should override") + + @property + def name(self) -> str: + """The name identifying this requirement in the resolver. + + This is different from ``project_name`` if this requirement contains + extras, where ``project_name`` would not contain the ``[...]`` part. + """ + raise NotImplementedError("Subclass should override") + + def is_satisfied_by(self, candidate: "Candidate") -> bool: + return False + + def get_candidate_lookup(self) -> CandidateLookup: + raise NotImplementedError("Subclass should override") + + def format_for_error(self) -> str: + raise NotImplementedError("Subclass should override") + + +def _match_link(link: Link, candidate: "Candidate") -> bool: + if candidate.source_link: + return links_equivalent(link, candidate.source_link) + return False + + +class Candidate: + @property + def project_name(self) -> NormalizedName: + """The "project name" of the candidate. + + This is different from ``name`` if this candidate contains extras, + in which case ``name`` would contain the ``[...]`` part, while this + refers to the name of the project. + """ + raise NotImplementedError("Override in subclass") + + @property + def name(self) -> str: + """The name identifying this candidate in the resolver. + + This is different from ``project_name`` if this candidate contains + extras, where ``project_name`` would not contain the ``[...]`` part. + """ + raise NotImplementedError("Override in subclass") + + @property + def version(self) -> Version: + raise NotImplementedError("Override in subclass") + + @property + def is_installed(self) -> bool: + raise NotImplementedError("Override in subclass") + + @property + def is_editable(self) -> bool: + raise NotImplementedError("Override in subclass") + + @property + def source_link(self) -> Optional[Link]: + raise NotImplementedError("Override in subclass") + + def iter_dependencies(self, with_requires: bool) -> Iterable[Optional[Requirement]]: + raise NotImplementedError("Override in subclass") + + def get_install_requirement(self) -> Optional[InstallRequirement]: + raise NotImplementedError("Override in subclass") + + def format_for_error(self) -> str: + raise NotImplementedError("Subclass should override") diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/factory.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/factory.py new file mode 100644 index 0000000000000000000000000000000000000000..dc6e2e12e1f9c633e272e674e50c6f48aaded4a4 --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/factory.py @@ -0,0 +1,823 @@ +import contextlib +import functools +import logging +from typing import ( + TYPE_CHECKING, + Callable, + Dict, + FrozenSet, + Iterable, + Iterator, + List, + Mapping, + NamedTuple, + Optional, + Protocol, + Sequence, + Set, + Tuple, + TypeVar, + cast, +) + +from pip._vendor.packaging.requirements import InvalidRequirement +from pip._vendor.packaging.specifiers import SpecifierSet +from pip._vendor.packaging.utils import NormalizedName, canonicalize_name +from pip._vendor.packaging.version import InvalidVersion, Version +from pip._vendor.resolvelib import ResolutionImpossible + +from pip._internal.cache import CacheEntry, WheelCache +from pip._internal.exceptions import ( + DistributionNotFound, + InstallationError, + InvalidInstalledPackage, + MetadataInconsistent, + MetadataInvalid, + UnsupportedPythonVersion, + UnsupportedWheel, +) +from pip._internal.index.package_finder import PackageFinder +from pip._internal.metadata import BaseDistribution, get_default_environment +from pip._internal.models.link import Link +from pip._internal.models.wheel import Wheel +from pip._internal.operations.prepare import RequirementPreparer +from pip._internal.req.constructors import ( + install_req_drop_extras, + install_req_from_link_and_ireq, +) +from pip._internal.req.req_install import ( + InstallRequirement, + check_invalid_constraint_type, +) +from pip._internal.resolution.base import InstallRequirementProvider +from pip._internal.utils.compatibility_tags import get_supported +from pip._internal.utils.hashes import Hashes +from pip._internal.utils.packaging import get_requirement +from pip._internal.utils.virtualenv import running_under_virtualenv + +from .base import Candidate, Constraint, Requirement +from .candidates import ( + AlreadyInstalledCandidate, + BaseCandidate, + EditableCandidate, + ExtrasCandidate, + LinkCandidate, + RequiresPythonCandidate, + as_base_candidate, +) +from .found_candidates import FoundCandidates, IndexCandidateInfo +from .requirements import ( + ExplicitRequirement, + RequiresPythonRequirement, + SpecifierRequirement, + SpecifierWithoutExtrasRequirement, + UnsatisfiableRequirement, +) + +if TYPE_CHECKING: + + class ConflictCause(Protocol): + requirement: RequiresPythonRequirement + parent: Candidate + + +logger = logging.getLogger(__name__) + +C = TypeVar("C") +Cache = Dict[Link, C] + + +class CollectedRootRequirements(NamedTuple): + requirements: List[Requirement] + constraints: Dict[str, Constraint] + user_requested: Dict[str, int] + + +class Factory: + def __init__( + self, + finder: PackageFinder, + preparer: RequirementPreparer, + make_install_req: InstallRequirementProvider, + wheel_cache: Optional[WheelCache], + use_user_site: bool, + force_reinstall: bool, + ignore_installed: bool, + ignore_requires_python: bool, + py_version_info: Optional[Tuple[int, ...]] = None, + ) -> None: + self._finder = finder + self.preparer = preparer + self._wheel_cache = wheel_cache + self._python_candidate = RequiresPythonCandidate(py_version_info) + self._make_install_req_from_spec = make_install_req + self._use_user_site = use_user_site + self._force_reinstall = force_reinstall + self._ignore_requires_python = ignore_requires_python + + self._build_failures: Cache[InstallationError] = {} + self._link_candidate_cache: Cache[LinkCandidate] = {} + self._editable_candidate_cache: Cache[EditableCandidate] = {} + self._installed_candidate_cache: Dict[str, AlreadyInstalledCandidate] = {} + self._extras_candidate_cache: Dict[ + Tuple[int, FrozenSet[NormalizedName]], ExtrasCandidate + ] = {} + self._supported_tags_cache = get_supported() + + if not ignore_installed: + env = get_default_environment() + self._installed_dists = { + dist.canonical_name: dist + for dist in env.iter_installed_distributions(local_only=False) + } + else: + self._installed_dists = {} + + @property + def force_reinstall(self) -> bool: + return self._force_reinstall + + def _fail_if_link_is_unsupported_wheel(self, link: Link) -> None: + if not link.is_wheel: + return + wheel = Wheel(link.filename) + if wheel.supported(self._finder.target_python.get_unsorted_tags()): + return + msg = f"{link.filename} is not a supported wheel on this platform." + raise UnsupportedWheel(msg) + + def _make_extras_candidate( + self, + base: BaseCandidate, + extras: FrozenSet[str], + *, + comes_from: Optional[InstallRequirement] = None, + ) -> ExtrasCandidate: + cache_key = (id(base), frozenset(canonicalize_name(e) for e in extras)) + try: + candidate = self._extras_candidate_cache[cache_key] + except KeyError: + candidate = ExtrasCandidate(base, extras, comes_from=comes_from) + self._extras_candidate_cache[cache_key] = candidate + return candidate + + def _make_candidate_from_dist( + self, + dist: BaseDistribution, + extras: FrozenSet[str], + template: InstallRequirement, + ) -> Candidate: + try: + base = self._installed_candidate_cache[dist.canonical_name] + except KeyError: + base = AlreadyInstalledCandidate(dist, template, factory=self) + self._installed_candidate_cache[dist.canonical_name] = base + if not extras: + return base + return self._make_extras_candidate(base, extras, comes_from=template) + + def _make_candidate_from_link( + self, + link: Link, + extras: FrozenSet[str], + template: InstallRequirement, + name: Optional[NormalizedName], + version: Optional[Version], + ) -> Optional[Candidate]: + base: Optional[BaseCandidate] = self._make_base_candidate_from_link( + link, template, name, version + ) + if not extras or base is None: + return base + return self._make_extras_candidate(base, extras, comes_from=template) + + def _make_base_candidate_from_link( + self, + link: Link, + template: InstallRequirement, + name: Optional[NormalizedName], + version: Optional[Version], + ) -> Optional[BaseCandidate]: + # TODO: Check already installed candidate, and use it if the link and + # editable flag match. + + if link in self._build_failures: + # We already tried this candidate before, and it does not build. + # Don't bother trying again. + return None + + if template.editable: + if link not in self._editable_candidate_cache: + try: + self._editable_candidate_cache[link] = EditableCandidate( + link, + template, + factory=self, + name=name, + version=version, + ) + except (MetadataInconsistent, MetadataInvalid) as e: + logger.info( + "Discarding [blue underline]%s[/]: [yellow]%s[reset]", + link, + e, + extra={"markup": True}, + ) + self._build_failures[link] = e + return None + + return self._editable_candidate_cache[link] + else: + if link not in self._link_candidate_cache: + try: + self._link_candidate_cache[link] = LinkCandidate( + link, + template, + factory=self, + name=name, + version=version, + ) + except MetadataInconsistent as e: + logger.info( + "Discarding [blue underline]%s[/]: [yellow]%s[reset]", + link, + e, + extra={"markup": True}, + ) + self._build_failures[link] = e + return None + return self._link_candidate_cache[link] + + def _iter_found_candidates( + self, + ireqs: Sequence[InstallRequirement], + specifier: SpecifierSet, + hashes: Hashes, + prefers_installed: bool, + incompatible_ids: Set[int], + ) -> Iterable[Candidate]: + if not ireqs: + return () + + # The InstallRequirement implementation requires us to give it a + # "template". Here we just choose the first requirement to represent + # all of them. + # Hopefully the Project model can correct this mismatch in the future. + template = ireqs[0] + assert template.req, "Candidates found on index must be PEP 508" + name = canonicalize_name(template.req.name) + + extras: FrozenSet[str] = frozenset() + for ireq in ireqs: + assert ireq.req, "Candidates found on index must be PEP 508" + specifier &= ireq.req.specifier + hashes &= ireq.hashes(trust_internet=False) + extras |= frozenset(ireq.extras) + + def _get_installed_candidate() -> Optional[Candidate]: + """Get the candidate for the currently-installed version.""" + # If --force-reinstall is set, we want the version from the index + # instead, so we "pretend" there is nothing installed. + if self._force_reinstall: + return None + try: + installed_dist = self._installed_dists[name] + except KeyError: + return None + + try: + # Don't use the installed distribution if its version + # does not fit the current dependency graph. + if not specifier.contains(installed_dist.version, prereleases=True): + return None + except InvalidVersion as e: + raise InvalidInstalledPackage(dist=installed_dist, invalid_exc=e) + + candidate = self._make_candidate_from_dist( + dist=installed_dist, + extras=extras, + template=template, + ) + # The candidate is a known incompatibility. Don't use it. + if id(candidate) in incompatible_ids: + return None + return candidate + + def iter_index_candidate_infos() -> Iterator[IndexCandidateInfo]: + result = self._finder.find_best_candidate( + project_name=name, + specifier=specifier, + hashes=hashes, + ) + icans = list(result.iter_applicable()) + + # PEP 592: Yanked releases are ignored unless the specifier + # explicitly pins a version (via '==' or '===') that can be + # solely satisfied by a yanked release. + all_yanked = all(ican.link.is_yanked for ican in icans) + + def is_pinned(specifier: SpecifierSet) -> bool: + for sp in specifier: + if sp.operator == "===": + return True + if sp.operator != "==": + continue + if sp.version.endswith(".*"): + continue + return True + return False + + pinned = is_pinned(specifier) + + # PackageFinder returns earlier versions first, so we reverse. + for ican in reversed(icans): + if not (all_yanked and pinned) and ican.link.is_yanked: + continue + func = functools.partial( + self._make_candidate_from_link, + link=ican.link, + extras=extras, + template=template, + name=name, + version=ican.version, + ) + yield ican.version, func + + return FoundCandidates( + iter_index_candidate_infos, + _get_installed_candidate(), + prefers_installed, + incompatible_ids, + ) + + def _iter_explicit_candidates_from_base( + self, + base_requirements: Iterable[Requirement], + extras: FrozenSet[str], + ) -> Iterator[Candidate]: + """Produce explicit candidates from the base given an extra-ed package. + + :param base_requirements: Requirements known to the resolver. The + requirements are guaranteed to not have extras. + :param extras: The extras to inject into the explicit requirements' + candidates. + """ + for req in base_requirements: + lookup_cand, _ = req.get_candidate_lookup() + if lookup_cand is None: # Not explicit. + continue + # We've stripped extras from the identifier, and should always + # get a BaseCandidate here, unless there's a bug elsewhere. + base_cand = as_base_candidate(lookup_cand) + assert base_cand is not None, "no extras here" + yield self._make_extras_candidate(base_cand, extras) + + def _iter_candidates_from_constraints( + self, + identifier: str, + constraint: Constraint, + template: InstallRequirement, + ) -> Iterator[Candidate]: + """Produce explicit candidates from constraints. + + This creates "fake" InstallRequirement objects that are basically clones + of what "should" be the template, but with original_link set to link. + """ + for link in constraint.links: + self._fail_if_link_is_unsupported_wheel(link) + candidate = self._make_base_candidate_from_link( + link, + template=install_req_from_link_and_ireq(link, template), + name=canonicalize_name(identifier), + version=None, + ) + if candidate: + yield candidate + + def find_candidates( + self, + identifier: str, + requirements: Mapping[str, Iterable[Requirement]], + incompatibilities: Mapping[str, Iterator[Candidate]], + constraint: Constraint, + prefers_installed: bool, + is_satisfied_by: Callable[[Requirement, Candidate], bool], + ) -> Iterable[Candidate]: + # Collect basic lookup information from the requirements. + explicit_candidates: Set[Candidate] = set() + ireqs: List[InstallRequirement] = [] + for req in requirements[identifier]: + cand, ireq = req.get_candidate_lookup() + if cand is not None: + explicit_candidates.add(cand) + if ireq is not None: + ireqs.append(ireq) + + # If the current identifier contains extras, add requires and explicit + # candidates from entries from extra-less identifier. + with contextlib.suppress(InvalidRequirement): + parsed_requirement = get_requirement(identifier) + if parsed_requirement.name != identifier: + explicit_candidates.update( + self._iter_explicit_candidates_from_base( + requirements.get(parsed_requirement.name, ()), + frozenset(parsed_requirement.extras), + ), + ) + for req in requirements.get(parsed_requirement.name, []): + _, ireq = req.get_candidate_lookup() + if ireq is not None: + ireqs.append(ireq) + + # Add explicit candidates from constraints. We only do this if there are + # known ireqs, which represent requirements not already explicit. If + # there are no ireqs, we're constraining already-explicit requirements, + # which is handled later when we return the explicit candidates. + if ireqs: + try: + explicit_candidates.update( + self._iter_candidates_from_constraints( + identifier, + constraint, + template=ireqs[0], + ), + ) + except UnsupportedWheel: + # If we're constrained to install a wheel incompatible with the + # target architecture, no candidates will ever be valid. + return () + + # Since we cache all the candidates, incompatibility identification + # can be made quicker by comparing only the id() values. + incompat_ids = {id(c) for c in incompatibilities.get(identifier, ())} + + # If none of the requirements want an explicit candidate, we can ask + # the finder for candidates. + if not explicit_candidates: + return self._iter_found_candidates( + ireqs, + constraint.specifier, + constraint.hashes, + prefers_installed, + incompat_ids, + ) + + return ( + c + for c in explicit_candidates + if id(c) not in incompat_ids + and constraint.is_satisfied_by(c) + and all(is_satisfied_by(req, c) for req in requirements[identifier]) + ) + + def _make_requirements_from_install_req( + self, ireq: InstallRequirement, requested_extras: Iterable[str] + ) -> Iterator[Requirement]: + """ + Returns requirement objects associated with the given InstallRequirement. In + most cases this will be a single object but the following special cases exist: + - the InstallRequirement has markers that do not apply -> result is empty + - the InstallRequirement has both a constraint (or link) and extras + -> result is split in two requirement objects: one with the constraint + (or link) and one with the extra. This allows centralized constraint + handling for the base, resulting in fewer candidate rejections. + """ + if not ireq.match_markers(requested_extras): + logger.info( + "Ignoring %s: markers '%s' don't match your environment", + ireq.name, + ireq.markers, + ) + elif not ireq.link: + if ireq.extras and ireq.req is not None and ireq.req.specifier: + yield SpecifierWithoutExtrasRequirement(ireq) + yield SpecifierRequirement(ireq) + else: + self._fail_if_link_is_unsupported_wheel(ireq.link) + # Always make the link candidate for the base requirement to make it + # available to `find_candidates` for explicit candidate lookup for any + # set of extras. + # The extras are required separately via a second requirement. + cand = self._make_base_candidate_from_link( + ireq.link, + template=install_req_drop_extras(ireq) if ireq.extras else ireq, + name=canonicalize_name(ireq.name) if ireq.name else None, + version=None, + ) + if cand is None: + # There's no way we can satisfy a URL requirement if the underlying + # candidate fails to build. An unnamed URL must be user-supplied, so + # we fail eagerly. If the URL is named, an unsatisfiable requirement + # can make the resolver do the right thing, either backtrack (and + # maybe find some other requirement that's buildable) or raise a + # ResolutionImpossible eventually. + if not ireq.name: + raise self._build_failures[ireq.link] + yield UnsatisfiableRequirement(canonicalize_name(ireq.name)) + else: + # require the base from the link + yield self.make_requirement_from_candidate(cand) + if ireq.extras: + # require the extras on top of the base candidate + yield self.make_requirement_from_candidate( + self._make_extras_candidate(cand, frozenset(ireq.extras)) + ) + + def collect_root_requirements( + self, root_ireqs: List[InstallRequirement] + ) -> CollectedRootRequirements: + collected = CollectedRootRequirements([], {}, {}) + for i, ireq in enumerate(root_ireqs): + if ireq.constraint: + # Ensure we only accept valid constraints + problem = check_invalid_constraint_type(ireq) + if problem: + raise InstallationError(problem) + if not ireq.match_markers(): + continue + assert ireq.name, "Constraint must be named" + name = canonicalize_name(ireq.name) + if name in collected.constraints: + collected.constraints[name] &= ireq + else: + collected.constraints[name] = Constraint.from_ireq(ireq) + else: + reqs = list( + self._make_requirements_from_install_req( + ireq, + requested_extras=(), + ) + ) + if not reqs: + continue + template = reqs[0] + if ireq.user_supplied and template.name not in collected.user_requested: + collected.user_requested[template.name] = i + collected.requirements.extend(reqs) + # Put requirements with extras at the end of the root requires. This does not + # affect resolvelib's picking preference but it does affect its initial criteria + # population: by putting extras at the end we enable the candidate finder to + # present resolvelib with a smaller set of candidates to resolvelib, already + # taking into account any non-transient constraints on the associated base. This + # means resolvelib will have fewer candidates to visit and reject. + # Python's list sort is stable, meaning relative order is kept for objects with + # the same key. + collected.requirements.sort(key=lambda r: r.name != r.project_name) + return collected + + def make_requirement_from_candidate( + self, candidate: Candidate + ) -> ExplicitRequirement: + return ExplicitRequirement(candidate) + + def make_requirements_from_spec( + self, + specifier: str, + comes_from: Optional[InstallRequirement], + requested_extras: Iterable[str] = (), + ) -> Iterator[Requirement]: + """ + Returns requirement objects associated with the given specifier. In most cases + this will be a single object but the following special cases exist: + - the specifier has markers that do not apply -> result is empty + - the specifier has both a constraint and extras -> result is split + in two requirement objects: one with the constraint and one with the + extra. This allows centralized constraint handling for the base, + resulting in fewer candidate rejections. + """ + ireq = self._make_install_req_from_spec(specifier, comes_from) + return self._make_requirements_from_install_req(ireq, requested_extras) + + def make_requires_python_requirement( + self, + specifier: SpecifierSet, + ) -> Optional[Requirement]: + if self._ignore_requires_python: + return None + # Don't bother creating a dependency for an empty Requires-Python. + if not str(specifier): + return None + return RequiresPythonRequirement(specifier, self._python_candidate) + + def get_wheel_cache_entry( + self, link: Link, name: Optional[str] + ) -> Optional[CacheEntry]: + """Look up the link in the wheel cache. + + If ``preparer.require_hashes`` is True, don't use the wheel cache, + because cached wheels, always built locally, have different hashes + than the files downloaded from the index server and thus throw false + hash mismatches. Furthermore, cached wheels at present have + nondeterministic contents due to file modification times. + """ + if self._wheel_cache is None: + return None + return self._wheel_cache.get_cache_entry( + link=link, + package_name=name, + supported_tags=self._supported_tags_cache, + ) + + def get_dist_to_uninstall(self, candidate: Candidate) -> Optional[BaseDistribution]: + # TODO: Are there more cases this needs to return True? Editable? + dist = self._installed_dists.get(candidate.project_name) + if dist is None: # Not installed, no uninstallation required. + return None + + # We're installing into global site. The current installation must + # be uninstalled, no matter it's in global or user site, because the + # user site installation has precedence over global. + if not self._use_user_site: + return dist + + # We're installing into user site. Remove the user site installation. + if dist.in_usersite: + return dist + + # We're installing into user site, but the installed incompatible + # package is in global site. We can't uninstall that, and would let + # the new user installation to "shadow" it. But shadowing won't work + # in virtual environments, so we error out. + if running_under_virtualenv() and dist.in_site_packages: + message = ( + f"Will not install to the user site because it will lack " + f"sys.path precedence to {dist.raw_name} in {dist.location}" + ) + raise InstallationError(message) + return None + + def _report_requires_python_error( + self, causes: Sequence["ConflictCause"] + ) -> UnsupportedPythonVersion: + assert causes, "Requires-Python error reported with no cause" + + version = self._python_candidate.version + + if len(causes) == 1: + specifier = str(causes[0].requirement.specifier) + message = ( + f"Package {causes[0].parent.name!r} requires a different " + f"Python: {version} not in {specifier!r}" + ) + return UnsupportedPythonVersion(message) + + message = f"Packages require a different Python. {version} not in:" + for cause in causes: + package = cause.parent.format_for_error() + specifier = str(cause.requirement.specifier) + message += f"\n{specifier!r} (required by {package})" + return UnsupportedPythonVersion(message) + + def _report_single_requirement_conflict( + self, req: Requirement, parent: Optional[Candidate] + ) -> DistributionNotFound: + if parent is None: + req_disp = str(req) + else: + req_disp = f"{req} (from {parent.name})" + + cands = self._finder.find_all_candidates(req.project_name) + skipped_by_requires_python = self._finder.requires_python_skipped_reasons() + + versions_set: Set[Version] = set() + yanked_versions_set: Set[Version] = set() + for c in cands: + is_yanked = c.link.is_yanked if c.link else False + if is_yanked: + yanked_versions_set.add(c.version) + else: + versions_set.add(c.version) + + versions = [str(v) for v in sorted(versions_set)] + yanked_versions = [str(v) for v in sorted(yanked_versions_set)] + + if yanked_versions: + # Saying "version X is yanked" isn't entirely accurate. + # https://github.com/pypa/pip/issues/11745#issuecomment-1402805842 + logger.critical( + "Ignored the following yanked versions: %s", + ", ".join(yanked_versions) or "none", + ) + if skipped_by_requires_python: + logger.critical( + "Ignored the following versions that require a different python " + "version: %s", + "; ".join(skipped_by_requires_python) or "none", + ) + logger.critical( + "Could not find a version that satisfies the requirement %s " + "(from versions: %s)", + req_disp, + ", ".join(versions) or "none", + ) + if str(req) == "requirements.txt": + logger.info( + "HINT: You are attempting to install a package literally " + 'named "requirements.txt" (which cannot exist). Consider ' + "using the '-r' flag to install the packages listed in " + "requirements.txt" + ) + + return DistributionNotFound(f"No matching distribution found for {req}") + + def get_installation_error( + self, + e: "ResolutionImpossible[Requirement, Candidate]", + constraints: Dict[str, Constraint], + ) -> InstallationError: + assert e.causes, "Installation error reported with no cause" + + # If one of the things we can't solve is "we need Python X.Y", + # that is what we report. + requires_python_causes = [ + cause + for cause in e.causes + if isinstance(cause.requirement, RequiresPythonRequirement) + and not cause.requirement.is_satisfied_by(self._python_candidate) + ] + if requires_python_causes: + # The comprehension above makes sure all Requirement instances are + # RequiresPythonRequirement, so let's cast for convenience. + return self._report_requires_python_error( + cast("Sequence[ConflictCause]", requires_python_causes), + ) + + # Otherwise, we have a set of causes which can't all be satisfied + # at once. + + # The simplest case is when we have *one* cause that can't be + # satisfied. We just report that case. + if len(e.causes) == 1: + req, parent = e.causes[0] + if req.name not in constraints: + return self._report_single_requirement_conflict(req, parent) + + # OK, we now have a list of requirements that can't all be + # satisfied at once. + + # A couple of formatting helpers + def text_join(parts: List[str]) -> str: + if len(parts) == 1: + return parts[0] + + return ", ".join(parts[:-1]) + " and " + parts[-1] + + def describe_trigger(parent: Candidate) -> str: + ireq = parent.get_install_requirement() + if not ireq or not ireq.comes_from: + return f"{parent.name}=={parent.version}" + if isinstance(ireq.comes_from, InstallRequirement): + return str(ireq.comes_from.name) + return str(ireq.comes_from) + + triggers = set() + for req, parent in e.causes: + if parent is None: + # This is a root requirement, so we can report it directly + trigger = req.format_for_error() + else: + trigger = describe_trigger(parent) + triggers.add(trigger) + + if triggers: + info = text_join(sorted(triggers)) + else: + info = "the requested packages" + + msg = ( + f"Cannot install {info} because these package versions " + "have conflicting dependencies." + ) + logger.critical(msg) + msg = "\nThe conflict is caused by:" + + relevant_constraints = set() + for req, parent in e.causes: + if req.name in constraints: + relevant_constraints.add(req.name) + msg = msg + "\n " + if parent: + msg = msg + f"{parent.name} {parent.version} depends on " + else: + msg = msg + "The user requested " + msg = msg + req.format_for_error() + for key in relevant_constraints: + spec = constraints[key].specifier + msg += f"\n The user requested (constraint) {key}{spec}" + + msg = ( + msg + + "\n\n" + + "To fix this you could try to:\n" + + "1. loosen the range of package versions you've specified\n" + + "2. remove package versions to allow pip to attempt to solve " + + "the dependency conflict\n" + ) + + logger.info(msg) + + return DistributionNotFound( + "ResolutionImpossible: for help visit " + "https://pip.pypa.io/en/latest/topics/dependency-resolution/" + "#dealing-with-dependency-conflicts" + ) diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py new file mode 100644 index 0000000000000000000000000000000000000000..a1d57e0f4b275cd5783c950381ddfff0184da138 --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py @@ -0,0 +1,174 @@ +"""Utilities to lazily create and visit candidates found. + +Creating and visiting a candidate is a *very* costly operation. It involves +fetching, extracting, potentially building modules from source, and verifying +distribution metadata. It is therefore crucial for performance to keep +everything here lazy all the way down, so we only touch candidates that we +absolutely need, and not "download the world" when we only need one version of +something. +""" + +import functools +import logging +from collections.abc import Sequence +from typing import TYPE_CHECKING, Any, Callable, Iterator, Optional, Set, Tuple + +from pip._vendor.packaging.version import _BaseVersion + +from pip._internal.exceptions import MetadataInvalid + +from .base import Candidate + +logger = logging.getLogger(__name__) + +IndexCandidateInfo = Tuple[_BaseVersion, Callable[[], Optional[Candidate]]] + +if TYPE_CHECKING: + SequenceCandidate = Sequence[Candidate] +else: + # For compatibility: Python before 3.9 does not support using [] on the + # Sequence class. + # + # >>> from collections.abc import Sequence + # >>> Sequence[str] + # Traceback (most recent call last): + # File "", line 1, in + # TypeError: 'ABCMeta' object is not subscriptable + # + # TODO: Remove this block after dropping Python 3.8 support. + SequenceCandidate = Sequence + + +def _iter_built(infos: Iterator[IndexCandidateInfo]) -> Iterator[Candidate]: + """Iterator for ``FoundCandidates``. + + This iterator is used when the package is not already installed. Candidates + from index come later in their normal ordering. + """ + versions_found: Set[_BaseVersion] = set() + for version, func in infos: + if version in versions_found: + continue + try: + candidate = func() + except MetadataInvalid as e: + logger.warning( + "Ignoring version %s of %s since it has invalid metadata:\n" + "%s\n" + "Please use pip<24.1 if you need to use this version.", + version, + e.ireq.name, + e, + ) + # Mark version as found to avoid trying other candidates with the same + # version, since they most likely have invalid metadata as well. + versions_found.add(version) + else: + if candidate is None: + continue + yield candidate + versions_found.add(version) + + +def _iter_built_with_prepended( + installed: Candidate, infos: Iterator[IndexCandidateInfo] +) -> Iterator[Candidate]: + """Iterator for ``FoundCandidates``. + + This iterator is used when the resolver prefers the already-installed + candidate and NOT to upgrade. The installed candidate is therefore + always yielded first, and candidates from index come later in their + normal ordering, except skipped when the version is already installed. + """ + yield installed + versions_found: Set[_BaseVersion] = {installed.version} + for version, func in infos: + if version in versions_found: + continue + candidate = func() + if candidate is None: + continue + yield candidate + versions_found.add(version) + + +def _iter_built_with_inserted( + installed: Candidate, infos: Iterator[IndexCandidateInfo] +) -> Iterator[Candidate]: + """Iterator for ``FoundCandidates``. + + This iterator is used when the resolver prefers to upgrade an + already-installed package. Candidates from index are returned in their + normal ordering, except replaced when the version is already installed. + + The implementation iterates through and yields other candidates, inserting + the installed candidate exactly once before we start yielding older or + equivalent candidates, or after all other candidates if they are all newer. + """ + versions_found: Set[_BaseVersion] = set() + for version, func in infos: + if version in versions_found: + continue + # If the installed candidate is better, yield it first. + if installed.version >= version: + yield installed + versions_found.add(installed.version) + candidate = func() + if candidate is None: + continue + yield candidate + versions_found.add(version) + + # If the installed candidate is older than all other candidates. + if installed.version not in versions_found: + yield installed + + +class FoundCandidates(SequenceCandidate): + """A lazy sequence to provide candidates to the resolver. + + The intended usage is to return this from `find_matches()` so the resolver + can iterate through the sequence multiple times, but only access the index + page when remote packages are actually needed. This improve performances + when suitable candidates are already installed on disk. + """ + + def __init__( + self, + get_infos: Callable[[], Iterator[IndexCandidateInfo]], + installed: Optional[Candidate], + prefers_installed: bool, + incompatible_ids: Set[int], + ): + self._get_infos = get_infos + self._installed = installed + self._prefers_installed = prefers_installed + self._incompatible_ids = incompatible_ids + + def __getitem__(self, index: Any) -> Any: + # Implemented to satisfy the ABC check. This is not needed by the + # resolver, and should not be used by the provider either (for + # performance reasons). + raise NotImplementedError("don't do this") + + def __iter__(self) -> Iterator[Candidate]: + infos = self._get_infos() + if not self._installed: + iterator = _iter_built(infos) + elif self._prefers_installed: + iterator = _iter_built_with_prepended(self._installed, infos) + else: + iterator = _iter_built_with_inserted(self._installed, infos) + return (c for c in iterator if id(c) not in self._incompatible_ids) + + def __len__(self) -> int: + # Implemented to satisfy the ABC check. This is not needed by the + # resolver, and should not be used by the provider either (for + # performance reasons). + raise NotImplementedError("don't do this") + + @functools.lru_cache(maxsize=1) + def __bool__(self) -> bool: + if self._prefers_installed and self._installed: + return True + return any(self) diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b2ba6f04a3abacf3f4c76083f8f9bffaf3adcdfb Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/_jaraco_text.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/_jaraco_text.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..494d855074bc54670c8f8c91ce7b84fbe16adb94 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/_jaraco_text.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/compat.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/compat.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5e9d8967238522e8c66144ae3fc0d252274e2433 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/compat.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..831445c5f3ef7b5ba19a80ef9e6884c8c1f2681a Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3e6b7f397f2eecc7adca40494a263edbf7393c4e Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f1989d5688e10a0cfdac19928dfe3ee9c3e76879 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4e7dfca8285443a3d90b4148e83273044a2590bb Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ab48b8524e5cfad61dd484fc64e92f56b96ac781 Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-311.pyc b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd9ea56a109d77350f1045886ff01afdd6403b7d Binary files /dev/null and b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-311.pyc differ diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/_log.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/_log.py new file mode 100644 index 0000000000000000000000000000000000000000..92c4c6a193873ce09629f6cfaa2dabc4f14ecb03 --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/_log.py @@ -0,0 +1,38 @@ +"""Customize logging + +Defines custom logger class for the `logger.verbose(...)` method. + +init_logging() must be called before any other modules that call logging.getLogger. +""" + +import logging +from typing import Any, cast + +# custom log level for `--verbose` output +# between DEBUG and INFO +VERBOSE = 15 + + +class VerboseLogger(logging.Logger): + """Custom Logger, defining a verbose log-level + + VERBOSE is between INFO and DEBUG. + """ + + def verbose(self, msg: str, *args: Any, **kwargs: Any) -> None: + return self.log(VERBOSE, msg, *args, **kwargs) + + +def getLogger(name: str) -> VerboseLogger: + """logging.getLogger, but ensures our VerboseLogger class is returned""" + return cast(VerboseLogger, logging.getLogger(name)) + + +def init_logging() -> None: + """Register our VerboseLogger and VERBOSE log level. + + Should be called before any calls to getLogger(), + i.e. in pip._internal.__init__ + """ + logging.setLoggerClass(VerboseLogger) + logging.addLevelName(VERBOSE, "VERBOSE") diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/filetypes.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/filetypes.py new file mode 100644 index 0000000000000000000000000000000000000000..5948570178f3e6e79d1ff574241d09d4d8ed78de --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/filetypes.py @@ -0,0 +1,27 @@ +"""Filetype information. +""" + +from typing import Tuple + +from pip._internal.utils.misc import splitext + +WHEEL_EXTENSION = ".whl" +BZ2_EXTENSIONS: Tuple[str, ...] = (".tar.bz2", ".tbz") +XZ_EXTENSIONS: Tuple[str, ...] = ( + ".tar.xz", + ".txz", + ".tlz", + ".tar.lz", + ".tar.lzma", +) +ZIP_EXTENSIONS: Tuple[str, ...] = (".zip", WHEEL_EXTENSION) +TAR_EXTENSIONS: Tuple[str, ...] = (".tar.gz", ".tgz", ".tar") +ARCHIVE_EXTENSIONS = ZIP_EXTENSIONS + BZ2_EXTENSIONS + TAR_EXTENSIONS + XZ_EXTENSIONS + + +def is_archive_file(name: str) -> bool: + """Return True if `name` is a considered as an archive file.""" + ext = splitext(name)[1].lower() + if ext in ARCHIVE_EXTENSIONS: + return True + return False diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/misc.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/misc.py new file mode 100644 index 0000000000000000000000000000000000000000..c0a3e4d3b9d221570b11ce0e2b64a3bbbf18cf7f --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/misc.py @@ -0,0 +1,772 @@ +import errno +import getpass +import hashlib +import logging +import os +import posixpath +import shutil +import stat +import sys +import sysconfig +import urllib.parse +from dataclasses import dataclass +from functools import partial +from io import StringIO +from itertools import filterfalse, tee, zip_longest +from pathlib import Path +from types import FunctionType, TracebackType +from typing import ( + Any, + BinaryIO, + Callable, + Dict, + Generator, + Iterable, + Iterator, + List, + Optional, + TextIO, + Tuple, + Type, + TypeVar, + Union, + cast, +) + +from pip._vendor.packaging.requirements import Requirement +from pip._vendor.pyproject_hooks import BuildBackendHookCaller + +from pip import __version__ +from pip._internal.exceptions import CommandError, ExternallyManagedEnvironment +from pip._internal.locations import get_major_minor_version +from pip._internal.utils.compat import WINDOWS +from pip._internal.utils.retry import retry +from pip._internal.utils.virtualenv import running_under_virtualenv + +__all__ = [ + "rmtree", + "display_path", + "backup_dir", + "ask", + "splitext", + "format_size", + "is_installable_dir", + "normalize_path", + "renames", + "get_prog", + "ensure_dir", + "remove_auth_from_url", + "check_externally_managed", + "ConfiguredBuildBackendHookCaller", +] + +logger = logging.getLogger(__name__) + +T = TypeVar("T") +ExcInfo = Tuple[Type[BaseException], BaseException, TracebackType] +VersionInfo = Tuple[int, int, int] +NetlocTuple = Tuple[str, Tuple[Optional[str], Optional[str]]] +OnExc = Callable[[FunctionType, Path, BaseException], Any] +OnErr = Callable[[FunctionType, Path, ExcInfo], Any] + +FILE_CHUNK_SIZE = 1024 * 1024 + + +def get_pip_version() -> str: + pip_pkg_dir = os.path.join(os.path.dirname(__file__), "..", "..") + pip_pkg_dir = os.path.abspath(pip_pkg_dir) + + return f"pip {__version__} from {pip_pkg_dir} (python {get_major_minor_version()})" + + +def normalize_version_info(py_version_info: Tuple[int, ...]) -> Tuple[int, int, int]: + """ + Convert a tuple of ints representing a Python version to one of length + three. + + :param py_version_info: a tuple of ints representing a Python version, + or None to specify no version. The tuple can have any length. + + :return: a tuple of length three if `py_version_info` is non-None. + Otherwise, return `py_version_info` unchanged (i.e. None). + """ + if len(py_version_info) < 3: + py_version_info += (3 - len(py_version_info)) * (0,) + elif len(py_version_info) > 3: + py_version_info = py_version_info[:3] + + return cast("VersionInfo", py_version_info) + + +def ensure_dir(path: str) -> None: + """os.path.makedirs without EEXIST.""" + try: + os.makedirs(path) + except OSError as e: + # Windows can raise spurious ENOTEMPTY errors. See #6426. + if e.errno != errno.EEXIST and e.errno != errno.ENOTEMPTY: + raise + + +def get_prog() -> str: + try: + prog = os.path.basename(sys.argv[0]) + if prog in ("__main__.py", "-c"): + return f"{sys.executable} -m pip" + else: + return prog + except (AttributeError, TypeError, IndexError): + pass + return "pip" + + +# Retry every half second for up to 3 seconds +@retry(stop_after_delay=3, wait=0.5) +def rmtree( + dir: str, ignore_errors: bool = False, onexc: Optional[OnExc] = None +) -> None: + if ignore_errors: + onexc = _onerror_ignore + if onexc is None: + onexc = _onerror_reraise + handler: OnErr = partial(rmtree_errorhandler, onexc=onexc) + if sys.version_info >= (3, 12): + # See https://docs.python.org/3.12/whatsnew/3.12.html#shutil. + shutil.rmtree(dir, onexc=handler) # type: ignore + else: + shutil.rmtree(dir, onerror=handler) # type: ignore + + +def _onerror_ignore(*_args: Any) -> None: + pass + + +def _onerror_reraise(*_args: Any) -> None: + raise # noqa: PLE0704 - Bare exception used to reraise existing exception + + +def rmtree_errorhandler( + func: FunctionType, + path: Path, + exc_info: Union[ExcInfo, BaseException], + *, + onexc: OnExc = _onerror_reraise, +) -> None: + """ + `rmtree` error handler to 'force' a file remove (i.e. like `rm -f`). + + * If a file is readonly then it's write flag is set and operation is + retried. + + * `onerror` is the original callback from `rmtree(... onerror=onerror)` + that is chained at the end if the "rm -f" still fails. + """ + try: + st_mode = os.stat(path).st_mode + except OSError: + # it's equivalent to os.path.exists + return + + if not st_mode & stat.S_IWRITE: + # convert to read/write + try: + os.chmod(path, st_mode | stat.S_IWRITE) + except OSError: + pass + else: + # use the original function to repeat the operation + try: + func(path) + return + except OSError: + pass + + if not isinstance(exc_info, BaseException): + _, exc_info, _ = exc_info + onexc(func, path, exc_info) + + +def display_path(path: str) -> str: + """Gives the display value for a given path, making it relative to cwd + if possible.""" + path = os.path.normcase(os.path.abspath(path)) + if path.startswith(os.getcwd() + os.path.sep): + path = "." + path[len(os.getcwd()) :] + return path + + +def backup_dir(dir: str, ext: str = ".bak") -> str: + """Figure out the name of a directory to back up the given dir to + (adding .bak, .bak2, etc)""" + n = 1 + extension = ext + while os.path.exists(dir + extension): + n += 1 + extension = ext + str(n) + return dir + extension + + +def ask_path_exists(message: str, options: Iterable[str]) -> str: + for action in os.environ.get("PIP_EXISTS_ACTION", "").split(): + if action in options: + return action + return ask(message, options) + + +def _check_no_input(message: str) -> None: + """Raise an error if no input is allowed.""" + if os.environ.get("PIP_NO_INPUT"): + raise Exception( + f"No input was expected ($PIP_NO_INPUT set); question: {message}" + ) + + +def ask(message: str, options: Iterable[str]) -> str: + """Ask the message interactively, with the given possible responses""" + while 1: + _check_no_input(message) + response = input(message) + response = response.strip().lower() + if response not in options: + print( + "Your response ({!r}) was not one of the expected responses: " + "{}".format(response, ", ".join(options)) + ) + else: + return response + + +def ask_input(message: str) -> str: + """Ask for input interactively.""" + _check_no_input(message) + return input(message) + + +def ask_password(message: str) -> str: + """Ask for a password interactively.""" + _check_no_input(message) + return getpass.getpass(message) + + +def strtobool(val: str) -> int: + """Convert a string representation of truth to true (1) or false (0). + + True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values + are 'n', 'no', 'f', 'false', 'off', and '0'. Raises ValueError if + 'val' is anything else. + """ + val = val.lower() + if val in ("y", "yes", "t", "true", "on", "1"): + return 1 + elif val in ("n", "no", "f", "false", "off", "0"): + return 0 + else: + raise ValueError(f"invalid truth value {val!r}") + + +def format_size(bytes: float) -> str: + if bytes > 1000 * 1000: + return f"{bytes / 1000.0 / 1000:.1f} MB" + elif bytes > 10 * 1000: + return f"{int(bytes / 1000)} kB" + elif bytes > 1000: + return f"{bytes / 1000.0:.1f} kB" + else: + return f"{int(bytes)} bytes" + + +def tabulate(rows: Iterable[Iterable[Any]]) -> Tuple[List[str], List[int]]: + """Return a list of formatted rows and a list of column sizes. + + For example:: + + >>> tabulate([['foobar', 2000], [0xdeadbeef]]) + (['foobar 2000', '3735928559'], [10, 4]) + """ + rows = [tuple(map(str, row)) for row in rows] + sizes = [max(map(len, col)) for col in zip_longest(*rows, fillvalue="")] + table = [" ".join(map(str.ljust, row, sizes)).rstrip() for row in rows] + return table, sizes + + +def is_installable_dir(path: str) -> bool: + """Is path is a directory containing pyproject.toml or setup.py? + + If pyproject.toml exists, this is a PEP 517 project. Otherwise we look for + a legacy setuptools layout by identifying setup.py. We don't check for the + setup.cfg because using it without setup.py is only available for PEP 517 + projects, which are already covered by the pyproject.toml check. + """ + if not os.path.isdir(path): + return False + if os.path.isfile(os.path.join(path, "pyproject.toml")): + return True + if os.path.isfile(os.path.join(path, "setup.py")): + return True + return False + + +def read_chunks( + file: BinaryIO, size: int = FILE_CHUNK_SIZE +) -> Generator[bytes, None, None]: + """Yield pieces of data from a file-like object until EOF.""" + while True: + chunk = file.read(size) + if not chunk: + break + yield chunk + + +def normalize_path(path: str, resolve_symlinks: bool = True) -> str: + """ + Convert a path to its canonical, case-normalized, absolute version. + + """ + path = os.path.expanduser(path) + if resolve_symlinks: + path = os.path.realpath(path) + else: + path = os.path.abspath(path) + return os.path.normcase(path) + + +def splitext(path: str) -> Tuple[str, str]: + """Like os.path.splitext, but take off .tar too""" + base, ext = posixpath.splitext(path) + if base.lower().endswith(".tar"): + ext = base[-4:] + ext + base = base[:-4] + return base, ext + + +def renames(old: str, new: str) -> None: + """Like os.renames(), but handles renaming across devices.""" + # Implementation borrowed from os.renames(). + head, tail = os.path.split(new) + if head and tail and not os.path.exists(head): + os.makedirs(head) + + shutil.move(old, new) + + head, tail = os.path.split(old) + if head and tail: + try: + os.removedirs(head) + except OSError: + pass + + +def is_local(path: str) -> bool: + """ + Return True if path is within sys.prefix, if we're running in a virtualenv. + + If we're not in a virtualenv, all paths are considered "local." + + Caution: this function assumes the head of path has been normalized + with normalize_path. + """ + if not running_under_virtualenv(): + return True + return path.startswith(normalize_path(sys.prefix)) + + +def write_output(msg: Any, *args: Any) -> None: + logger.info(msg, *args) + + +class StreamWrapper(StringIO): + orig_stream: TextIO + + @classmethod + def from_stream(cls, orig_stream: TextIO) -> "StreamWrapper": + ret = cls() + ret.orig_stream = orig_stream + return ret + + # compileall.compile_dir() needs stdout.encoding to print to stdout + # type ignore is because TextIOBase.encoding is writeable + @property + def encoding(self) -> str: # type: ignore + return self.orig_stream.encoding + + +# Simulates an enum +def enum(*sequential: Any, **named: Any) -> Type[Any]: + enums = dict(zip(sequential, range(len(sequential))), **named) + reverse = {value: key for key, value in enums.items()} + enums["reverse_mapping"] = reverse + return type("Enum", (), enums) + + +def build_netloc(host: str, port: Optional[int]) -> str: + """ + Build a netloc from a host-port pair + """ + if port is None: + return host + if ":" in host: + # Only wrap host with square brackets when it is IPv6 + host = f"[{host}]" + return f"{host}:{port}" + + +def build_url_from_netloc(netloc: str, scheme: str = "https") -> str: + """ + Build a full URL from a netloc. + """ + if netloc.count(":") >= 2 and "@" not in netloc and "[" not in netloc: + # It must be a bare IPv6 address, so wrap it with brackets. + netloc = f"[{netloc}]" + return f"{scheme}://{netloc}" + + +def parse_netloc(netloc: str) -> Tuple[Optional[str], Optional[int]]: + """ + Return the host-port pair from a netloc. + """ + url = build_url_from_netloc(netloc) + parsed = urllib.parse.urlparse(url) + return parsed.hostname, parsed.port + + +def split_auth_from_netloc(netloc: str) -> NetlocTuple: + """ + Parse out and remove the auth information from a netloc. + + Returns: (netloc, (username, password)). + """ + if "@" not in netloc: + return netloc, (None, None) + + # Split from the right because that's how urllib.parse.urlsplit() + # behaves if more than one @ is present (which can be checked using + # the password attribute of urlsplit()'s return value). + auth, netloc = netloc.rsplit("@", 1) + pw: Optional[str] = None + if ":" in auth: + # Split from the left because that's how urllib.parse.urlsplit() + # behaves if more than one : is present (which again can be checked + # using the password attribute of the return value) + user, pw = auth.split(":", 1) + else: + user, pw = auth, None + + user = urllib.parse.unquote(user) + if pw is not None: + pw = urllib.parse.unquote(pw) + + return netloc, (user, pw) + + +def redact_netloc(netloc: str) -> str: + """ + Replace the sensitive data in a netloc with "****", if it exists. + + For example: + - "user:pass@example.com" returns "user:****@example.com" + - "accesstoken@example.com" returns "****@example.com" + """ + netloc, (user, password) = split_auth_from_netloc(netloc) + if user is None: + return netloc + if password is None: + user = "****" + password = "" + else: + user = urllib.parse.quote(user) + password = ":****" + return f"{user}{password}@{netloc}" + + +def _transform_url( + url: str, transform_netloc: Callable[[str], Tuple[Any, ...]] +) -> Tuple[str, NetlocTuple]: + """Transform and replace netloc in a url. + + transform_netloc is a function taking the netloc and returning a + tuple. The first element of this tuple is the new netloc. The + entire tuple is returned. + + Returns a tuple containing the transformed url as item 0 and the + original tuple returned by transform_netloc as item 1. + """ + purl = urllib.parse.urlsplit(url) + netloc_tuple = transform_netloc(purl.netloc) + # stripped url + url_pieces = (purl.scheme, netloc_tuple[0], purl.path, purl.query, purl.fragment) + surl = urllib.parse.urlunsplit(url_pieces) + return surl, cast("NetlocTuple", netloc_tuple) + + +def _get_netloc(netloc: str) -> NetlocTuple: + return split_auth_from_netloc(netloc) + + +def _redact_netloc(netloc: str) -> Tuple[str]: + return (redact_netloc(netloc),) + + +def split_auth_netloc_from_url( + url: str, +) -> Tuple[str, str, Tuple[Optional[str], Optional[str]]]: + """ + Parse a url into separate netloc, auth, and url with no auth. + + Returns: (url_without_auth, netloc, (username, password)) + """ + url_without_auth, (netloc, auth) = _transform_url(url, _get_netloc) + return url_without_auth, netloc, auth + + +def remove_auth_from_url(url: str) -> str: + """Return a copy of url with 'username:password@' removed.""" + # username/pass params are passed to subversion through flags + # and are not recognized in the url. + return _transform_url(url, _get_netloc)[0] + + +def redact_auth_from_url(url: str) -> str: + """Replace the password in a given url with ****.""" + return _transform_url(url, _redact_netloc)[0] + + +def redact_auth_from_requirement(req: Requirement) -> str: + """Replace the password in a given requirement url with ****.""" + if not req.url: + return str(req) + return str(req).replace(req.url, redact_auth_from_url(req.url)) + + +@dataclass(frozen=True) +class HiddenText: + secret: str + redacted: str + + def __repr__(self) -> str: + return f"" + + def __str__(self) -> str: + return self.redacted + + # This is useful for testing. + def __eq__(self, other: Any) -> bool: + if type(self) is not type(other): + return False + + # The string being used for redaction doesn't also have to match, + # just the raw, original string. + return self.secret == other.secret + + +def hide_value(value: str) -> HiddenText: + return HiddenText(value, redacted="****") + + +def hide_url(url: str) -> HiddenText: + redacted = redact_auth_from_url(url) + return HiddenText(url, redacted=redacted) + + +def protect_pip_from_modification_on_windows(modifying_pip: bool) -> None: + """Protection of pip.exe from modification on Windows + + On Windows, any operation modifying pip should be run as: + python -m pip ... + """ + pip_names = [ + "pip", + f"pip{sys.version_info.major}", + f"pip{sys.version_info.major}.{sys.version_info.minor}", + ] + + # See https://github.com/pypa/pip/issues/1299 for more discussion + should_show_use_python_msg = ( + modifying_pip and WINDOWS and os.path.basename(sys.argv[0]) in pip_names + ) + + if should_show_use_python_msg: + new_command = [sys.executable, "-m", "pip"] + sys.argv[1:] + raise CommandError( + "To modify pip, please run the following command:\n{}".format( + " ".join(new_command) + ) + ) + + +def check_externally_managed() -> None: + """Check whether the current environment is externally managed. + + If the ``EXTERNALLY-MANAGED`` config file is found, the current environment + is considered externally managed, and an ExternallyManagedEnvironment is + raised. + """ + if running_under_virtualenv(): + return + marker = os.path.join(sysconfig.get_path("stdlib"), "EXTERNALLY-MANAGED") + if not os.path.isfile(marker): + return + raise ExternallyManagedEnvironment.from_config(marker) + + +def is_console_interactive() -> bool: + """Is this console interactive?""" + return sys.stdin is not None and sys.stdin.isatty() + + +def hash_file(path: str, blocksize: int = 1 << 20) -> Tuple[Any, int]: + """Return (hash, length) for path using hashlib.sha256()""" + + h = hashlib.sha256() + length = 0 + with open(path, "rb") as f: + for block in read_chunks(f, size=blocksize): + length += len(block) + h.update(block) + return h, length + + +def pairwise(iterable: Iterable[Any]) -> Iterator[Tuple[Any, Any]]: + """ + Return paired elements. + + For example: + s -> (s0, s1), (s2, s3), (s4, s5), ... + """ + iterable = iter(iterable) + return zip_longest(iterable, iterable) + + +def partition( + pred: Callable[[T], bool], iterable: Iterable[T] +) -> Tuple[Iterable[T], Iterable[T]]: + """ + Use a predicate to partition entries into false entries and true entries, + like + + partition(is_odd, range(10)) --> 0 2 4 6 8 and 1 3 5 7 9 + """ + t1, t2 = tee(iterable) + return filterfalse(pred, t1), filter(pred, t2) + + +class ConfiguredBuildBackendHookCaller(BuildBackendHookCaller): + def __init__( + self, + config_holder: Any, + source_dir: str, + build_backend: str, + backend_path: Optional[str] = None, + runner: Optional[Callable[..., None]] = None, + python_executable: Optional[str] = None, + ): + super().__init__( + source_dir, build_backend, backend_path, runner, python_executable + ) + self.config_holder = config_holder + + def build_wheel( + self, + wheel_directory: str, + config_settings: Optional[Dict[str, Union[str, List[str]]]] = None, + metadata_directory: Optional[str] = None, + ) -> str: + cs = self.config_holder.config_settings + return super().build_wheel( + wheel_directory, config_settings=cs, metadata_directory=metadata_directory + ) + + def build_sdist( + self, + sdist_directory: str, + config_settings: Optional[Dict[str, Union[str, List[str]]]] = None, + ) -> str: + cs = self.config_holder.config_settings + return super().build_sdist(sdist_directory, config_settings=cs) + + def build_editable( + self, + wheel_directory: str, + config_settings: Optional[Dict[str, Union[str, List[str]]]] = None, + metadata_directory: Optional[str] = None, + ) -> str: + cs = self.config_holder.config_settings + return super().build_editable( + wheel_directory, config_settings=cs, metadata_directory=metadata_directory + ) + + def get_requires_for_build_wheel( + self, config_settings: Optional[Dict[str, Union[str, List[str]]]] = None + ) -> List[str]: + cs = self.config_holder.config_settings + return super().get_requires_for_build_wheel(config_settings=cs) + + def get_requires_for_build_sdist( + self, config_settings: Optional[Dict[str, Union[str, List[str]]]] = None + ) -> List[str]: + cs = self.config_holder.config_settings + return super().get_requires_for_build_sdist(config_settings=cs) + + def get_requires_for_build_editable( + self, config_settings: Optional[Dict[str, Union[str, List[str]]]] = None + ) -> List[str]: + cs = self.config_holder.config_settings + return super().get_requires_for_build_editable(config_settings=cs) + + def prepare_metadata_for_build_wheel( + self, + metadata_directory: str, + config_settings: Optional[Dict[str, Union[str, List[str]]]] = None, + _allow_fallback: bool = True, + ) -> str: + cs = self.config_holder.config_settings + return super().prepare_metadata_for_build_wheel( + metadata_directory=metadata_directory, + config_settings=cs, + _allow_fallback=_allow_fallback, + ) + + def prepare_metadata_for_build_editable( + self, + metadata_directory: str, + config_settings: Optional[Dict[str, Union[str, List[str]]]] = None, + _allow_fallback: bool = True, + ) -> str: + cs = self.config_holder.config_settings + return super().prepare_metadata_for_build_editable( + metadata_directory=metadata_directory, + config_settings=cs, + _allow_fallback=_allow_fallback, + ) + + +def warn_if_run_as_root() -> None: + """Output a warning for sudo users on Unix. + + In a virtual environment, sudo pip still writes to virtualenv. + On Windows, users may run pip as Administrator without issues. + This warning only applies to Unix root users outside of virtualenv. + """ + if running_under_virtualenv(): + return + if not hasattr(os, "getuid"): + return + # On Windows, there are no "system managed" Python packages. Installing as + # Administrator via pip is the correct way of updating system environments. + # + # We choose sys.platform over utils.compat.WINDOWS here to enable Mypy platform + # checks: https://mypy.readthedocs.io/en/stable/common_issues.html + if sys.platform == "win32" or sys.platform == "cygwin": + return + + if os.getuid() != 0: + return + + logger.warning( + "Running pip as the 'root' user can result in broken permissions and " + "conflicting behaviour with the system package manager, possibly " + "rendering your system unusable." + "It is recommended to use a virtual environment instead: " + "https://pip.pypa.io/warnings/venv. " + "Use the --root-user-action option if you know what you are doing and " + "want to suppress this warning." + ) diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/wheel.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/wheel.py new file mode 100644 index 0000000000000000000000000000000000000000..f85aee8a3f925ad831431de5251c4e9daa6877ea --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_internal/utils/wheel.py @@ -0,0 +1,134 @@ +"""Support functions for working with wheel files. +""" + +import logging +from email.message import Message +from email.parser import Parser +from typing import Tuple +from zipfile import BadZipFile, ZipFile + +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.exceptions import UnsupportedWheel + +VERSION_COMPATIBLE = (1, 0) + + +logger = logging.getLogger(__name__) + + +def parse_wheel(wheel_zip: ZipFile, name: str) -> Tuple[str, Message]: + """Extract information from the provided wheel, ensuring it meets basic + standards. + + Returns the name of the .dist-info directory and the parsed WHEEL metadata. + """ + try: + info_dir = wheel_dist_info_dir(wheel_zip, name) + metadata = wheel_metadata(wheel_zip, info_dir) + version = wheel_version(metadata) + except UnsupportedWheel as e: + raise UnsupportedWheel(f"{name} has an invalid wheel, {e}") + + check_compatibility(version, name) + + return info_dir, metadata + + +def wheel_dist_info_dir(source: ZipFile, name: str) -> str: + """Returns the name of the contained .dist-info directory. + + Raises AssertionError or UnsupportedWheel if not found, >1 found, or + it doesn't match the provided name. + """ + # Zip file path separators must be / + subdirs = {p.split("/", 1)[0] for p in source.namelist()} + + info_dirs = [s for s in subdirs if s.endswith(".dist-info")] + + if not info_dirs: + raise UnsupportedWheel(".dist-info directory not found") + + if len(info_dirs) > 1: + raise UnsupportedWheel( + "multiple .dist-info directories found: {}".format(", ".join(info_dirs)) + ) + + info_dir = info_dirs[0] + + info_dir_name = canonicalize_name(info_dir) + canonical_name = canonicalize_name(name) + if not info_dir_name.startswith(canonical_name): + raise UnsupportedWheel( + f".dist-info directory {info_dir!r} does not start with {canonical_name!r}" + ) + + return info_dir + + +def read_wheel_metadata_file(source: ZipFile, path: str) -> bytes: + try: + return source.read(path) + # BadZipFile for general corruption, KeyError for missing entry, + # and RuntimeError for password-protected files + except (BadZipFile, KeyError, RuntimeError) as e: + raise UnsupportedWheel(f"could not read {path!r} file: {e!r}") + + +def wheel_metadata(source: ZipFile, dist_info_dir: str) -> Message: + """Return the WHEEL metadata of an extracted wheel, if possible. + Otherwise, raise UnsupportedWheel. + """ + path = f"{dist_info_dir}/WHEEL" + # Zip file path separators must be / + wheel_contents = read_wheel_metadata_file(source, path) + + try: + wheel_text = wheel_contents.decode() + except UnicodeDecodeError as e: + raise UnsupportedWheel(f"error decoding {path!r}: {e!r}") + + # FeedParser (used by Parser) does not raise any exceptions. The returned + # message may have .defects populated, but for backwards-compatibility we + # currently ignore them. + return Parser().parsestr(wheel_text) + + +def wheel_version(wheel_data: Message) -> Tuple[int, ...]: + """Given WHEEL metadata, return the parsed Wheel-Version. + Otherwise, raise UnsupportedWheel. + """ + version_text = wheel_data["Wheel-Version"] + if version_text is None: + raise UnsupportedWheel("WHEEL is missing Wheel-Version") + + version = version_text.strip() + + try: + return tuple(map(int, version.split("."))) + except ValueError: + raise UnsupportedWheel(f"invalid Wheel-Version: {version!r}") + + +def check_compatibility(version: Tuple[int, ...], name: str) -> None: + """Raises errors or warns if called with an incompatible Wheel-Version. + + pip should refuse to install a Wheel-Version that's a major series + ahead of what it's compatible with (e.g 2.0 > 1.1); and warn when + installing a version only minor version ahead (e.g 1.2 > 1.1). + + version: a 2-tuple representing a Wheel-Version (Major, Minor) + name: name of wheel or package to raise exception about + + :raises UnsupportedWheel: when an incompatible Wheel-Version is given + """ + if version[0] > VERSION_COMPATIBLE[0]: + raise UnsupportedWheel( + "{}'s Wheel-Version ({}) is not compatible with this version " + "of pip".format(name, ".".join(map(str, version))) + ) + elif version > VERSION_COMPATIBLE: + logger.warning( + "Installing from a newer Wheel-Version (%s)", + ".".join(map(str, version)), + ) diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/packaging/_musllinux.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/packaging/_musllinux.py new file mode 100644 index 0000000000000000000000000000000000000000..d2bf30b56319ba862c5c9a1a39a87c6d1cb68718 --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/packaging/_musllinux.py @@ -0,0 +1,85 @@ +"""PEP 656 support. + +This module implements logic to detect if the currently running Python is +linked against musl, and what musl version is used. +""" + +from __future__ import annotations + +import functools +import re +import subprocess +import sys +from typing import Iterator, NamedTuple, Sequence + +from ._elffile import ELFFile + + +class _MuslVersion(NamedTuple): + major: int + minor: int + + +def _parse_musl_version(output: str) -> _MuslVersion | None: + 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) -> _MuslVersion | None: + """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 + """ + try: + with open(executable, "rb") as f: + ld = ELFFile(f).interpreter + except (OSError, TypeError, ValueError): + return None + if ld is None or "musl" not in ld: + return None + proc = subprocess.run([ld], stderr=subprocess.PIPE, text=True) + return _parse_musl_version(proc.stderr) + + +def platform_tags(archs: Sequence[str]) -> Iterator[str]: + """Generate musllinux tags compatible to the current platform. + + :param archs: Sequence of compatible architectures. + The first one shall be the closest to the actual architecture and 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 arch in archs: + 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/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/packaging/_parser.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/packaging/_parser.py new file mode 100644 index 0000000000000000000000000000000000000000..c1238c06eab95f8c90c393383a703aa3b8c366a5 --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/packaging/_parser.py @@ -0,0 +1,354 @@ +"""Handwritten parser of dependency specifiers. + +The docstring for each __parse_* function contains EBNF-inspired grammar representing +the implementation. +""" + +from __future__ import annotations + +import ast +from typing import NamedTuple, Sequence, Tuple, Union + +from ._tokenizer import DEFAULT_RULES, Tokenizer + + +class Node: + def __init__(self, value: str) -> None: + self.value = value + + def __str__(self) -> str: + return 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) + + +MarkerVar = Union[Variable, Value] +MarkerItem = Tuple[MarkerVar, Op, MarkerVar] +MarkerAtom = Union[MarkerItem, Sequence["MarkerAtom"]] +MarkerList = Sequence[Union["MarkerList", MarkerAtom, str]] + + +class ParsedRequirement(NamedTuple): + name: str + url: str + extras: list[str] + specifier: str + marker: MarkerList | None + + +# -------------------------------------------------------------------------------------- +# Recursive descent parser for dependency specifier +# -------------------------------------------------------------------------------------- +def parse_requirement(source: str) -> ParsedRequirement: + return _parse_requirement(Tokenizer(source, rules=DEFAULT_RULES)) + + +def _parse_requirement(tokenizer: Tokenizer) -> ParsedRequirement: + """ + requirement = WS? IDENTIFIER WS? extras WS? requirement_details + """ + tokenizer.consume("WS") + + name_token = tokenizer.expect( + "IDENTIFIER", expected="package name at the start of dependency specifier" + ) + name = name_token.text + tokenizer.consume("WS") + + extras = _parse_extras(tokenizer) + tokenizer.consume("WS") + + url, specifier, marker = _parse_requirement_details(tokenizer) + tokenizer.expect("END", expected="end of dependency specifier") + + return ParsedRequirement(name, url, extras, specifier, marker) + + +def _parse_requirement_details( + tokenizer: Tokenizer, +) -> tuple[str, str, MarkerList | None]: + """ + requirement_details = AT URL (WS requirement_marker?)? + | specifier WS? (requirement_marker)? + """ + + specifier = "" + url = "" + marker = None + + if tokenizer.check("AT"): + tokenizer.read() + tokenizer.consume("WS") + + url_start = tokenizer.position + url = tokenizer.expect("URL", expected="URL after @").text + if tokenizer.check("END", peek=True): + return (url, specifier, marker) + + tokenizer.expect("WS", expected="whitespace after URL") + + # The input might end after whitespace. + if tokenizer.check("END", peek=True): + return (url, specifier, marker) + + marker = _parse_requirement_marker( + tokenizer, span_start=url_start, after="URL and whitespace" + ) + else: + specifier_start = tokenizer.position + specifier = _parse_specifier(tokenizer) + tokenizer.consume("WS") + + if tokenizer.check("END", peek=True): + return (url, specifier, marker) + + marker = _parse_requirement_marker( + tokenizer, + span_start=specifier_start, + after=( + "version specifier" + if specifier + else "name and no valid version specifier" + ), + ) + + return (url, specifier, marker) + + +def _parse_requirement_marker( + tokenizer: Tokenizer, *, span_start: int, after: str +) -> MarkerList: + """ + requirement_marker = SEMICOLON marker WS? + """ + + if not tokenizer.check("SEMICOLON"): + tokenizer.raise_syntax_error( + f"Expected end or semicolon (after {after})", + span_start=span_start, + ) + tokenizer.read() + + marker = _parse_marker(tokenizer) + tokenizer.consume("WS") + + return marker + + +def _parse_extras(tokenizer: Tokenizer) -> list[str]: + """ + extras = (LEFT_BRACKET wsp* extras_list? wsp* RIGHT_BRACKET)? + """ + if not tokenizer.check("LEFT_BRACKET", peek=True): + return [] + + with tokenizer.enclosing_tokens( + "LEFT_BRACKET", + "RIGHT_BRACKET", + around="extras", + ): + tokenizer.consume("WS") + extras = _parse_extras_list(tokenizer) + tokenizer.consume("WS") + + return extras + + +def _parse_extras_list(tokenizer: Tokenizer) -> list[str]: + """ + extras_list = identifier (wsp* ',' wsp* identifier)* + """ + extras: list[str] = [] + + if not tokenizer.check("IDENTIFIER"): + return extras + + extras.append(tokenizer.read().text) + + while True: + tokenizer.consume("WS") + if tokenizer.check("IDENTIFIER", peek=True): + tokenizer.raise_syntax_error("Expected comma between extra names") + elif not tokenizer.check("COMMA"): + break + + tokenizer.read() + tokenizer.consume("WS") + + extra_token = tokenizer.expect("IDENTIFIER", expected="extra name after comma") + extras.append(extra_token.text) + + return extras + + +def _parse_specifier(tokenizer: Tokenizer) -> str: + """ + specifier = LEFT_PARENTHESIS WS? version_many WS? RIGHT_PARENTHESIS + | WS? version_many WS? + """ + with tokenizer.enclosing_tokens( + "LEFT_PARENTHESIS", + "RIGHT_PARENTHESIS", + around="version specifier", + ): + tokenizer.consume("WS") + parsed_specifiers = _parse_version_many(tokenizer) + tokenizer.consume("WS") + + return parsed_specifiers + + +def _parse_version_many(tokenizer: Tokenizer) -> str: + """ + version_many = (SPECIFIER (WS? COMMA WS? SPECIFIER)*)? + """ + parsed_specifiers = "" + while tokenizer.check("SPECIFIER"): + span_start = tokenizer.position + parsed_specifiers += tokenizer.read().text + if tokenizer.check("VERSION_PREFIX_TRAIL", peek=True): + tokenizer.raise_syntax_error( + ".* suffix can only be used with `==` or `!=` operators", + span_start=span_start, + span_end=tokenizer.position + 1, + ) + if tokenizer.check("VERSION_LOCAL_LABEL_TRAIL", peek=True): + tokenizer.raise_syntax_error( + "Local version label can only be used with `==` or `!=` operators", + span_start=span_start, + span_end=tokenizer.position, + ) + tokenizer.consume("WS") + if not tokenizer.check("COMMA"): + break + parsed_specifiers += tokenizer.read().text + tokenizer.consume("WS") + + return parsed_specifiers + + +# -------------------------------------------------------------------------------------- +# Recursive descent parser for marker expression +# -------------------------------------------------------------------------------------- +def parse_marker(source: str) -> MarkerList: + return _parse_full_marker(Tokenizer(source, rules=DEFAULT_RULES)) + + +def _parse_full_marker(tokenizer: Tokenizer) -> MarkerList: + retval = _parse_marker(tokenizer) + tokenizer.expect("END", expected="end of marker expression") + return retval + + +def _parse_marker(tokenizer: Tokenizer) -> MarkerList: + """ + marker = marker_atom (BOOLOP marker_atom)+ + """ + expression = [_parse_marker_atom(tokenizer)] + while tokenizer.check("BOOLOP"): + token = tokenizer.read() + expr_right = _parse_marker_atom(tokenizer) + expression.extend((token.text, expr_right)) + return expression + + +def _parse_marker_atom(tokenizer: Tokenizer) -> MarkerAtom: + """ + marker_atom = WS? LEFT_PARENTHESIS WS? marker WS? RIGHT_PARENTHESIS WS? + | WS? marker_item WS? + """ + + tokenizer.consume("WS") + if tokenizer.check("LEFT_PARENTHESIS", peek=True): + with tokenizer.enclosing_tokens( + "LEFT_PARENTHESIS", + "RIGHT_PARENTHESIS", + around="marker expression", + ): + tokenizer.consume("WS") + marker: MarkerAtom = _parse_marker(tokenizer) + tokenizer.consume("WS") + else: + marker = _parse_marker_item(tokenizer) + tokenizer.consume("WS") + return marker + + +def _parse_marker_item(tokenizer: Tokenizer) -> MarkerItem: + """ + marker_item = WS? marker_var WS? marker_op WS? marker_var WS? + """ + tokenizer.consume("WS") + marker_var_left = _parse_marker_var(tokenizer) + tokenizer.consume("WS") + marker_op = _parse_marker_op(tokenizer) + tokenizer.consume("WS") + marker_var_right = _parse_marker_var(tokenizer) + tokenizer.consume("WS") + return (marker_var_left, marker_op, marker_var_right) + + +def _parse_marker_var(tokenizer: Tokenizer) -> MarkerVar: + """ + marker_var = VARIABLE | QUOTED_STRING + """ + if tokenizer.check("VARIABLE"): + return process_env_var(tokenizer.read().text.replace(".", "_")) + elif tokenizer.check("QUOTED_STRING"): + return process_python_str(tokenizer.read().text) + else: + tokenizer.raise_syntax_error( + message="Expected a marker variable or quoted string" + ) + + +def process_env_var(env_var: str) -> Variable: + if env_var in ("platform_python_implementation", "python_implementation"): + return Variable("platform_python_implementation") + else: + return Variable(env_var) + + +def process_python_str(python_str: str) -> Value: + value = ast.literal_eval(python_str) + return Value(str(value)) + + +def _parse_marker_op(tokenizer: Tokenizer) -> Op: + """ + marker_op = IN | NOT IN | OP + """ + if tokenizer.check("IN"): + tokenizer.read() + return Op("in") + elif tokenizer.check("NOT"): + tokenizer.read() + tokenizer.expect("WS", expected="whitespace after 'not'") + tokenizer.expect("IN", expected="'in' after 'not'") + return Op("not in") + elif tokenizer.check("OP"): + return Op(tokenizer.read().text) + else: + return tokenizer.raise_syntax_error( + "Expected marker operator, one of " + "<=, <, !=, ==, >=, >, ~=, ===, in, not in" + ) diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/packaging/markers.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/packaging/markers.py new file mode 100644 index 0000000000000000000000000000000000000000..7ac7bb69a5325a6d9866885f2266539e8413a3c9 --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/packaging/markers.py @@ -0,0 +1,325 @@ +# 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. + +from __future__ import annotations + +import operator +import os +import platform +import sys +from typing import Any, Callable, TypedDict, cast + +from ._parser import MarkerAtom, MarkerList, Op, Value, Variable +from ._parser import parse_marker as _parse_marker +from ._tokenizer import ParserSyntaxError +from .specifiers import InvalidSpecifier, Specifier +from .utils import canonicalize_name + +__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 Environment(TypedDict): + implementation_name: str + """The implementation's identifier, e.g. ``'cpython'``.""" + + implementation_version: str + """ + The implementation's version, e.g. ``'3.13.0a2'`` for CPython 3.13.0a2, or + ``'7.3.13'`` for PyPy3.10 v7.3.13. + """ + + os_name: str + """ + The value of :py:data:`os.name`. The name of the operating system dependent module + imported, e.g. ``'posix'``. + """ + + platform_machine: str + """ + Returns the machine type, e.g. ``'i386'``. + + An empty string if the value cannot be determined. + """ + + platform_release: str + """ + The system's release, e.g. ``'2.2.0'`` or ``'NT'``. + + An empty string if the value cannot be determined. + """ + + platform_system: str + """ + The system/OS name, e.g. ``'Linux'``, ``'Windows'`` or ``'Java'``. + + An empty string if the value cannot be determined. + """ + + platform_version: str + """ + The system's release version, e.g. ``'#3 on degas'``. + + An empty string if the value cannot be determined. + """ + + python_full_version: str + """ + The Python version as string ``'major.minor.patchlevel'``. + + Note that unlike the Python :py:data:`sys.version`, this value will always include + the patchlevel (it defaults to 0). + """ + + platform_python_implementation: str + """ + A string identifying the Python implementation, e.g. ``'CPython'``. + """ + + python_version: str + """The Python version as string ``'major.minor'``.""" + + sys_platform: str + """ + This string contains a platform identifier that can be used to append + platform-specific components to :py:data:`sys.path`, for instance. + + For Unix systems, except on Linux and AIX, this is the lowercased OS name as + returned by ``uname -s`` with the first part of the version as returned by + ``uname -r`` appended, e.g. ``'sunos5'`` or ``'freebsd8'``, at the time when Python + was built. + """ + + +def _normalize_extra_values(results: Any) -> Any: + """ + Normalize extra values. + """ + if isinstance(results[0], tuple): + lhs, op, rhs = results[0] + if isinstance(lhs, Variable) and lhs.value == "extra": + normalized_extra = canonicalize_name(rhs.value) + rhs = Value(normalized_extra) + elif isinstance(rhs, Variable) and rhs.value == "extra": + normalized_extra = canonicalize_name(lhs.value) + lhs = Value(normalized_extra) + results[0] = lhs, op, rhs + return results + + +def _format_marker( + marker: list[str] | MarkerAtom | str, first: bool | None = 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, prereleases=True) + + oper: Operator | None = _operators.get(op.serialize()) + if oper is None: + raise UndefinedComparison(f"Undefined {op!r} on {lhs!r} and {rhs!r}.") + + return oper(lhs, rhs) + + +def _normalize(*values: str, key: str) -> tuple[str, ...]: + # PEP 685 – Comparison of extra names for optional distribution dependencies + # https://peps.python.org/pep-0685/ + # > When comparing extra names, tools MUST normalize the names being + # > compared using the semantics outlined in PEP 503 for names + if key == "extra": + return tuple(canonicalize_name(v) for v in values) + + # other environment markers don't have such standards + return values + + +def _evaluate_markers(markers: MarkerList, 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): + environment_key = lhs.value + lhs_value = environment[environment_key] + rhs_value = rhs.value + else: + lhs_value = lhs.value + environment_key = rhs.value + rhs_value = environment[environment_key] + + lhs_value, rhs_value = _normalize(lhs_value, rhs_value, key=environment_key) + 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() -> Environment: + 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: + # Note: We create a Marker object without calling this constructor in + # packaging.requirements.Requirement. If any additional logic is + # added here, make sure to mirror/adapt Requirement. + try: + self._markers = _normalize_extra_values(_parse_marker(marker)) + # The attribute `_markers` can be described in terms of a recursive type: + # MarkerList = List[Union[Tuple[Node, ...], str, MarkerList]] + # + # For example, the following expression: + # python_version > "3.6" or (python_version == "3.6" and os_name == "unix") + # + # is parsed into: + # [ + # (, ')>, ), + # 'and', + # [ + # (, , ), + # 'or', + # (, , ) + # ] + # ] + except ParserSyntaxError as e: + raise InvalidMarker(str(e)) from e + + def __str__(self) -> str: + return _format_marker(self._markers) + + def __repr__(self) -> str: + return f"" + + def __hash__(self) -> int: + return hash((self.__class__.__name__, str(self))) + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, Marker): + return NotImplemented + + return str(self) == str(other) + + def evaluate(self, environment: dict[str, str] | None = 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 = cast("dict[str, str]", default_environment()) + current_environment["extra"] = "" + # Work around platform.python_version() returning something that is not PEP 440 + # compliant for non-tagged Python builds. We preserve default_environment()'s + # behavior of returning platform.python_version() verbatim, and leave it to the + # caller to provide a syntactically valid version if they want to override it. + if current_environment["python_full_version"].endswith("+"): + current_environment["python_full_version"] += "local" + if environment is not None: + current_environment.update(environment) + # The API used to allow setting extra to None. We need to handle this + # case for backwards compatibility. + if current_environment["extra"] is None: + current_environment["extra"] = "" + + return _evaluate_markers(self._markers, current_environment) diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/packaging/metadata.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/packaging/metadata.py new file mode 100644 index 0000000000000000000000000000000000000000..eb8dc844d285dadecdce8be98cffd8bc39310595 --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/packaging/metadata.py @@ -0,0 +1,804 @@ +from __future__ import annotations + +import email.feedparser +import email.header +import email.message +import email.parser +import email.policy +import typing +from typing import ( + Any, + Callable, + Generic, + Literal, + TypedDict, + cast, +) + +from . import requirements, specifiers, utils +from . import version as version_module + +T = typing.TypeVar("T") + + +try: + ExceptionGroup +except NameError: # pragma: no cover + + class ExceptionGroup(Exception): + """A minimal implementation of :external:exc:`ExceptionGroup` from Python 3.11. + + If :external:exc:`ExceptionGroup` is already defined by Python itself, + that version is used instead. + """ + + message: str + exceptions: list[Exception] + + def __init__(self, message: str, exceptions: list[Exception]) -> None: + self.message = message + self.exceptions = exceptions + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({self.message!r}, {self.exceptions!r})" + +else: # pragma: no cover + ExceptionGroup = ExceptionGroup + + +class InvalidMetadata(ValueError): + """A metadata field contains invalid data.""" + + field: str + """The name of the field that contains invalid data.""" + + def __init__(self, field: str, message: str) -> None: + self.field = field + super().__init__(message) + + +# The RawMetadata class attempts to make as few assumptions about the underlying +# serialization formats as possible. The idea is that as long as a serialization +# formats offer some very basic primitives in *some* way then we can support +# serializing to and from that format. +class RawMetadata(TypedDict, total=False): + """A dictionary of raw core metadata. + + Each field in core metadata maps to a key of this dictionary (when data is + provided). The key is lower-case and underscores are used instead of dashes + compared to the equivalent core metadata field. Any core metadata field that + can be specified multiple times or can hold multiple values in a single + field have a key with a plural name. See :class:`Metadata` whose attributes + match the keys of this dictionary. + + Core metadata fields that can be specified multiple times are stored as a + list or dict depending on which is appropriate for the field. Any fields + which hold multiple values in a single field are stored as a list. + + """ + + # Metadata 1.0 - PEP 241 + metadata_version: str + name: str + version: str + platforms: list[str] + summary: str + description: str + keywords: list[str] + home_page: str + author: str + author_email: str + license: str + + # Metadata 1.1 - PEP 314 + supported_platforms: list[str] + download_url: str + classifiers: list[str] + requires: list[str] + provides: list[str] + obsoletes: list[str] + + # Metadata 1.2 - PEP 345 + maintainer: str + maintainer_email: str + requires_dist: list[str] + provides_dist: list[str] + obsoletes_dist: list[str] + requires_python: str + requires_external: list[str] + project_urls: dict[str, str] + + # Metadata 2.0 + # PEP 426 attempted to completely revamp the metadata format + # but got stuck without ever being able to build consensus on + # it and ultimately ended up withdrawn. + # + # However, a number of tools had started emitting METADATA with + # `2.0` Metadata-Version, so for historical reasons, this version + # was skipped. + + # Metadata 2.1 - PEP 566 + description_content_type: str + provides_extra: list[str] + + # Metadata 2.2 - PEP 643 + dynamic: list[str] + + # Metadata 2.3 - PEP 685 + # No new fields were added in PEP 685, just some edge case were + # tightened up to provide better interoptability. + + +_STRING_FIELDS = { + "author", + "author_email", + "description", + "description_content_type", + "download_url", + "home_page", + "license", + "maintainer", + "maintainer_email", + "metadata_version", + "name", + "requires_python", + "summary", + "version", +} + +_LIST_FIELDS = { + "classifiers", + "dynamic", + "obsoletes", + "obsoletes_dist", + "platforms", + "provides", + "provides_dist", + "provides_extra", + "requires", + "requires_dist", + "requires_external", + "supported_platforms", +} + +_DICT_FIELDS = { + "project_urls", +} + + +def _parse_keywords(data: str) -> list[str]: + """Split a string of comma-separate keyboards into a list of keywords.""" + return [k.strip() for k in data.split(",")] + + +def _parse_project_urls(data: list[str]) -> dict[str, str]: + """Parse a list of label/URL string pairings separated by a comma.""" + urls = {} + for pair in data: + # Our logic is slightly tricky here as we want to try and do + # *something* reasonable with malformed data. + # + # The main thing that we have to worry about, is data that does + # not have a ',' at all to split the label from the Value. There + # isn't a singular right answer here, and we will fail validation + # later on (if the caller is validating) so it doesn't *really* + # matter, but since the missing value has to be an empty str + # and our return value is dict[str, str], if we let the key + # be the missing value, then they'd have multiple '' values that + # overwrite each other in a accumulating dict. + # + # The other potentional issue is that it's possible to have the + # same label multiple times in the metadata, with no solid "right" + # answer with what to do in that case. As such, we'll do the only + # thing we can, which is treat the field as unparseable and add it + # to our list of unparsed fields. + parts = [p.strip() for p in pair.split(",", 1)] + parts.extend([""] * (max(0, 2 - len(parts)))) # Ensure 2 items + + # TODO: The spec doesn't say anything about if the keys should be + # considered case sensitive or not... logically they should + # be case-preserving and case-insensitive, but doing that + # would open up more cases where we might have duplicate + # entries. + label, url = parts + if label in urls: + # The label already exists in our set of urls, so this field + # is unparseable, and we can just add the whole thing to our + # unparseable data and stop processing it. + raise KeyError("duplicate labels in project urls") + urls[label] = url + + return urls + + +def _get_payload(msg: email.message.Message, source: bytes | str) -> str: + """Get the body of the message.""" + # If our source is a str, then our caller has managed encodings for us, + # and we don't need to deal with it. + if isinstance(source, str): + payload: str = msg.get_payload() + return payload + # If our source is a bytes, then we're managing the encoding and we need + # to deal with it. + else: + bpayload: bytes = msg.get_payload(decode=True) + try: + return bpayload.decode("utf8", "strict") + except UnicodeDecodeError: + raise ValueError("payload in an invalid encoding") + + +# The various parse_FORMAT functions here are intended to be as lenient as +# possible in their parsing, while still returning a correctly typed +# RawMetadata. +# +# To aid in this, we also generally want to do as little touching of the +# data as possible, except where there are possibly some historic holdovers +# that make valid data awkward to work with. +# +# While this is a lower level, intermediate format than our ``Metadata`` +# class, some light touch ups can make a massive difference in usability. + +# Map METADATA fields to RawMetadata. +_EMAIL_TO_RAW_MAPPING = { + "author": "author", + "author-email": "author_email", + "classifier": "classifiers", + "description": "description", + "description-content-type": "description_content_type", + "download-url": "download_url", + "dynamic": "dynamic", + "home-page": "home_page", + "keywords": "keywords", + "license": "license", + "maintainer": "maintainer", + "maintainer-email": "maintainer_email", + "metadata-version": "metadata_version", + "name": "name", + "obsoletes": "obsoletes", + "obsoletes-dist": "obsoletes_dist", + "platform": "platforms", + "project-url": "project_urls", + "provides": "provides", + "provides-dist": "provides_dist", + "provides-extra": "provides_extra", + "requires": "requires", + "requires-dist": "requires_dist", + "requires-external": "requires_external", + "requires-python": "requires_python", + "summary": "summary", + "supported-platform": "supported_platforms", + "version": "version", +} +_RAW_TO_EMAIL_MAPPING = {raw: email for email, raw in _EMAIL_TO_RAW_MAPPING.items()} + + +def parse_email(data: bytes | str) -> tuple[RawMetadata, dict[str, list[str]]]: + """Parse a distribution's metadata stored as email headers (e.g. from ``METADATA``). + + This function returns a two-item tuple of dicts. The first dict is of + recognized fields from the core metadata specification. Fields that can be + parsed and translated into Python's built-in types are converted + appropriately. All other fields are left as-is. Fields that are allowed to + appear multiple times are stored as lists. + + The second dict contains all other fields from the metadata. This includes + any unrecognized fields. It also includes any fields which are expected to + be parsed into a built-in type but were not formatted appropriately. Finally, + any fields that are expected to appear only once but are repeated are + included in this dict. + + """ + raw: dict[str, str | list[str] | dict[str, str]] = {} + unparsed: dict[str, list[str]] = {} + + if isinstance(data, str): + parsed = email.parser.Parser(policy=email.policy.compat32).parsestr(data) + else: + parsed = email.parser.BytesParser(policy=email.policy.compat32).parsebytes(data) + + # We have to wrap parsed.keys() in a set, because in the case of multiple + # values for a key (a list), the key will appear multiple times in the + # list of keys, but we're avoiding that by using get_all(). + for name in frozenset(parsed.keys()): + # Header names in RFC are case insensitive, so we'll normalize to all + # lower case to make comparisons easier. + name = name.lower() + + # We use get_all() here, even for fields that aren't multiple use, + # because otherwise someone could have e.g. two Name fields, and we + # would just silently ignore it rather than doing something about it. + headers = parsed.get_all(name) or [] + + # The way the email module works when parsing bytes is that it + # unconditionally decodes the bytes as ascii using the surrogateescape + # handler. When you pull that data back out (such as with get_all() ), + # it looks to see if the str has any surrogate escapes, and if it does + # it wraps it in a Header object instead of returning the string. + # + # As such, we'll look for those Header objects, and fix up the encoding. + value = [] + # Flag if we have run into any issues processing the headers, thus + # signalling that the data belongs in 'unparsed'. + valid_encoding = True + for h in headers: + # It's unclear if this can return more types than just a Header or + # a str, so we'll just assert here to make sure. + assert isinstance(h, (email.header.Header, str)) + + # If it's a header object, we need to do our little dance to get + # the real data out of it. In cases where there is invalid data + # we're going to end up with mojibake, but there's no obvious, good + # way around that without reimplementing parts of the Header object + # ourselves. + # + # That should be fine since, if mojibacked happens, this key is + # going into the unparsed dict anyways. + if isinstance(h, email.header.Header): + # The Header object stores it's data as chunks, and each chunk + # can be independently encoded, so we'll need to check each + # of them. + chunks: list[tuple[bytes, str | None]] = [] + for bin, encoding in email.header.decode_header(h): + try: + bin.decode("utf8", "strict") + except UnicodeDecodeError: + # Enable mojibake. + encoding = "latin1" + valid_encoding = False + else: + encoding = "utf8" + chunks.append((bin, encoding)) + + # Turn our chunks back into a Header object, then let that + # Header object do the right thing to turn them into a + # string for us. + value.append(str(email.header.make_header(chunks))) + # This is already a string, so just add it. + else: + value.append(h) + + # We've processed all of our values to get them into a list of str, + # but we may have mojibake data, in which case this is an unparsed + # field. + if not valid_encoding: + unparsed[name] = value + continue + + raw_name = _EMAIL_TO_RAW_MAPPING.get(name) + if raw_name is None: + # This is a bit of a weird situation, we've encountered a key that + # we don't know what it means, so we don't know whether it's meant + # to be a list or not. + # + # Since we can't really tell one way or another, we'll just leave it + # as a list, even though it may be a single item list, because that's + # what makes the most sense for email headers. + unparsed[name] = value + continue + + # If this is one of our string fields, then we'll check to see if our + # value is a list of a single item. If it is then we'll assume that + # it was emitted as a single string, and unwrap the str from inside + # the list. + # + # If it's any other kind of data, then we haven't the faintest clue + # what we should parse it as, and we have to just add it to our list + # of unparsed stuff. + if raw_name in _STRING_FIELDS and len(value) == 1: + raw[raw_name] = value[0] + # If this is one of our list of string fields, then we can just assign + # the value, since email *only* has strings, and our get_all() call + # above ensures that this is a list. + elif raw_name in _LIST_FIELDS: + raw[raw_name] = value + # Special Case: Keywords + # The keywords field is implemented in the metadata spec as a str, + # but it conceptually is a list of strings, and is serialized using + # ", ".join(keywords), so we'll do some light data massaging to turn + # this into what it logically is. + elif raw_name == "keywords" and len(value) == 1: + raw[raw_name] = _parse_keywords(value[0]) + # Special Case: Project-URL + # The project urls is implemented in the metadata spec as a list of + # specially-formatted strings that represent a key and a value, which + # is fundamentally a mapping, however the email format doesn't support + # mappings in a sane way, so it was crammed into a list of strings + # instead. + # + # We will do a little light data massaging to turn this into a map as + # it logically should be. + elif raw_name == "project_urls": + try: + raw[raw_name] = _parse_project_urls(value) + except KeyError: + unparsed[name] = value + # Nothing that we've done has managed to parse this, so it'll just + # throw it in our unparseable data and move on. + else: + unparsed[name] = value + + # We need to support getting the Description from the message payload in + # addition to getting it from the the headers. This does mean, though, there + # is the possibility of it being set both ways, in which case we put both + # in 'unparsed' since we don't know which is right. + try: + payload = _get_payload(parsed, data) + except ValueError: + unparsed.setdefault("description", []).append( + parsed.get_payload(decode=isinstance(data, bytes)) + ) + else: + if payload: + # Check to see if we've already got a description, if so then both + # it, and this body move to unparseable. + if "description" in raw: + description_header = cast(str, raw.pop("description")) + unparsed.setdefault("description", []).extend( + [description_header, payload] + ) + elif "description" in unparsed: + unparsed["description"].append(payload) + else: + raw["description"] = payload + + # We need to cast our `raw` to a metadata, because a TypedDict only support + # literal key names, but we're computing our key names on purpose, but the + # way this function is implemented, our `TypedDict` can only have valid key + # names. + return cast(RawMetadata, raw), unparsed + + +_NOT_FOUND = object() + + +# Keep the two values in sync. +_VALID_METADATA_VERSIONS = ["1.0", "1.1", "1.2", "2.1", "2.2", "2.3"] +_MetadataVersion = Literal["1.0", "1.1", "1.2", "2.1", "2.2", "2.3"] + +_REQUIRED_ATTRS = frozenset(["metadata_version", "name", "version"]) + + +class _Validator(Generic[T]): + """Validate a metadata field. + + All _process_*() methods correspond to a core metadata field. The method is + called with the field's raw value. If the raw value is valid it is returned + in its "enriched" form (e.g. ``version.Version`` for the ``Version`` field). + If the raw value is invalid, :exc:`InvalidMetadata` is raised (with a cause + as appropriate). + """ + + name: str + raw_name: str + added: _MetadataVersion + + def __init__( + self, + *, + added: _MetadataVersion = "1.0", + ) -> None: + self.added = added + + def __set_name__(self, _owner: Metadata, name: str) -> None: + self.name = name + self.raw_name = _RAW_TO_EMAIL_MAPPING[name] + + def __get__(self, instance: Metadata, _owner: type[Metadata]) -> T: + # With Python 3.8, the caching can be replaced with functools.cached_property(). + # No need to check the cache as attribute lookup will resolve into the + # instance's __dict__ before __get__ is called. + cache = instance.__dict__ + value = instance._raw.get(self.name) + + # To make the _process_* methods easier, we'll check if the value is None + # and if this field is NOT a required attribute, and if both of those + # things are true, we'll skip the the converter. This will mean that the + # converters never have to deal with the None union. + if self.name in _REQUIRED_ATTRS or value is not None: + try: + converter: Callable[[Any], T] = getattr(self, f"_process_{self.name}") + except AttributeError: + pass + else: + value = converter(value) + + cache[self.name] = value + try: + del instance._raw[self.name] # type: ignore[misc] + except KeyError: + pass + + return cast(T, value) + + def _invalid_metadata( + self, msg: str, cause: Exception | None = None + ) -> InvalidMetadata: + exc = InvalidMetadata( + self.raw_name, msg.format_map({"field": repr(self.raw_name)}) + ) + exc.__cause__ = cause + return exc + + def _process_metadata_version(self, value: str) -> _MetadataVersion: + # Implicitly makes Metadata-Version required. + if value not in _VALID_METADATA_VERSIONS: + raise self._invalid_metadata(f"{value!r} is not a valid metadata version") + return cast(_MetadataVersion, value) + + def _process_name(self, value: str) -> str: + if not value: + raise self._invalid_metadata("{field} is a required field") + # Validate the name as a side-effect. + try: + utils.canonicalize_name(value, validate=True) + except utils.InvalidName as exc: + raise self._invalid_metadata( + f"{value!r} is invalid for {{field}}", cause=exc + ) + else: + return value + + def _process_version(self, value: str) -> version_module.Version: + if not value: + raise self._invalid_metadata("{field} is a required field") + try: + return version_module.parse(value) + except version_module.InvalidVersion as exc: + raise self._invalid_metadata( + f"{value!r} is invalid for {{field}}", cause=exc + ) + + def _process_summary(self, value: str) -> str: + """Check the field contains no newlines.""" + if "\n" in value: + raise self._invalid_metadata("{field} must be a single line") + return value + + def _process_description_content_type(self, value: str) -> str: + content_types = {"text/plain", "text/x-rst", "text/markdown"} + message = email.message.EmailMessage() + message["content-type"] = value + + content_type, parameters = ( + # Defaults to `text/plain` if parsing failed. + message.get_content_type().lower(), + message["content-type"].params, + ) + # Check if content-type is valid or defaulted to `text/plain` and thus was + # not parseable. + if content_type not in content_types or content_type not in value.lower(): + raise self._invalid_metadata( + f"{{field}} must be one of {list(content_types)}, not {value!r}" + ) + + charset = parameters.get("charset", "UTF-8") + if charset != "UTF-8": + raise self._invalid_metadata( + f"{{field}} can only specify the UTF-8 charset, not {list(charset)}" + ) + + markdown_variants = {"GFM", "CommonMark"} + variant = parameters.get("variant", "GFM") # Use an acceptable default. + if content_type == "text/markdown" and variant not in markdown_variants: + raise self._invalid_metadata( + f"valid Markdown variants for {{field}} are {list(markdown_variants)}, " + f"not {variant!r}", + ) + return value + + def _process_dynamic(self, value: list[str]) -> list[str]: + for dynamic_field in map(str.lower, value): + if dynamic_field in {"name", "version", "metadata-version"}: + raise self._invalid_metadata( + f"{value!r} is not allowed as a dynamic field" + ) + elif dynamic_field not in _EMAIL_TO_RAW_MAPPING: + raise self._invalid_metadata(f"{value!r} is not a valid dynamic field") + return list(map(str.lower, value)) + + def _process_provides_extra( + self, + value: list[str], + ) -> list[utils.NormalizedName]: + normalized_names = [] + try: + for name in value: + normalized_names.append(utils.canonicalize_name(name, validate=True)) + except utils.InvalidName as exc: + raise self._invalid_metadata( + f"{name!r} is invalid for {{field}}", cause=exc + ) + else: + return normalized_names + + def _process_requires_python(self, value: str) -> specifiers.SpecifierSet: + try: + return specifiers.SpecifierSet(value) + except specifiers.InvalidSpecifier as exc: + raise self._invalid_metadata( + f"{value!r} is invalid for {{field}}", cause=exc + ) + + def _process_requires_dist( + self, + value: list[str], + ) -> list[requirements.Requirement]: + reqs = [] + try: + for req in value: + reqs.append(requirements.Requirement(req)) + except requirements.InvalidRequirement as exc: + raise self._invalid_metadata(f"{req!r} is invalid for {{field}}", cause=exc) + else: + return reqs + + +class Metadata: + """Representation of distribution metadata. + + Compared to :class:`RawMetadata`, this class provides objects representing + metadata fields instead of only using built-in types. Any invalid metadata + will cause :exc:`InvalidMetadata` to be raised (with a + :py:attr:`~BaseException.__cause__` attribute as appropriate). + """ + + _raw: RawMetadata + + @classmethod + def from_raw(cls, data: RawMetadata, *, validate: bool = True) -> Metadata: + """Create an instance from :class:`RawMetadata`. + + If *validate* is true, all metadata will be validated. All exceptions + related to validation will be gathered and raised as an :class:`ExceptionGroup`. + """ + ins = cls() + ins._raw = data.copy() # Mutations occur due to caching enriched values. + + if validate: + exceptions: list[Exception] = [] + try: + metadata_version = ins.metadata_version + metadata_age = _VALID_METADATA_VERSIONS.index(metadata_version) + except InvalidMetadata as metadata_version_exc: + exceptions.append(metadata_version_exc) + metadata_version = None + + # Make sure to check for the fields that are present, the required + # fields (so their absence can be reported). + fields_to_check = frozenset(ins._raw) | _REQUIRED_ATTRS + # Remove fields that have already been checked. + fields_to_check -= {"metadata_version"} + + for key in fields_to_check: + try: + if metadata_version: + # Can't use getattr() as that triggers descriptor protocol which + # will fail due to no value for the instance argument. + try: + field_metadata_version = cls.__dict__[key].added + except KeyError: + exc = InvalidMetadata(key, f"unrecognized field: {key!r}") + exceptions.append(exc) + continue + field_age = _VALID_METADATA_VERSIONS.index( + field_metadata_version + ) + if field_age > metadata_age: + field = _RAW_TO_EMAIL_MAPPING[key] + exc = InvalidMetadata( + field, + "{field} introduced in metadata version " + "{field_metadata_version}, not {metadata_version}", + ) + exceptions.append(exc) + continue + getattr(ins, key) + except InvalidMetadata as exc: + exceptions.append(exc) + + if exceptions: + raise ExceptionGroup("invalid metadata", exceptions) + + return ins + + @classmethod + def from_email(cls, data: bytes | str, *, validate: bool = True) -> Metadata: + """Parse metadata from email headers. + + If *validate* is true, the metadata will be validated. All exceptions + related to validation will be gathered and raised as an :class:`ExceptionGroup`. + """ + raw, unparsed = parse_email(data) + + if validate: + exceptions: list[Exception] = [] + for unparsed_key in unparsed: + if unparsed_key in _EMAIL_TO_RAW_MAPPING: + message = f"{unparsed_key!r} has invalid data" + else: + message = f"unrecognized field: {unparsed_key!r}" + exceptions.append(InvalidMetadata(unparsed_key, message)) + + if exceptions: + raise ExceptionGroup("unparsed", exceptions) + + try: + return cls.from_raw(raw, validate=validate) + except ExceptionGroup as exc_group: + raise ExceptionGroup( + "invalid or unparsed metadata", exc_group.exceptions + ) from None + + metadata_version: _Validator[_MetadataVersion] = _Validator() + """:external:ref:`core-metadata-metadata-version` + (required; validated to be a valid metadata version)""" + name: _Validator[str] = _Validator() + """:external:ref:`core-metadata-name` + (required; validated using :func:`~packaging.utils.canonicalize_name` and its + *validate* parameter)""" + version: _Validator[version_module.Version] = _Validator() + """:external:ref:`core-metadata-version` (required)""" + dynamic: _Validator[list[str] | None] = _Validator( + added="2.2", + ) + """:external:ref:`core-metadata-dynamic` + (validated against core metadata field names and lowercased)""" + platforms: _Validator[list[str] | None] = _Validator() + """:external:ref:`core-metadata-platform`""" + supported_platforms: _Validator[list[str] | None] = _Validator(added="1.1") + """:external:ref:`core-metadata-supported-platform`""" + summary: _Validator[str | None] = _Validator() + """:external:ref:`core-metadata-summary` (validated to contain no newlines)""" + description: _Validator[str | None] = _Validator() # TODO 2.1: can be in body + """:external:ref:`core-metadata-description`""" + description_content_type: _Validator[str | None] = _Validator(added="2.1") + """:external:ref:`core-metadata-description-content-type` (validated)""" + keywords: _Validator[list[str] | None] = _Validator() + """:external:ref:`core-metadata-keywords`""" + home_page: _Validator[str | None] = _Validator() + """:external:ref:`core-metadata-home-page`""" + download_url: _Validator[str | None] = _Validator(added="1.1") + """:external:ref:`core-metadata-download-url`""" + author: _Validator[str | None] = _Validator() + """:external:ref:`core-metadata-author`""" + author_email: _Validator[str | None] = _Validator() + """:external:ref:`core-metadata-author-email`""" + maintainer: _Validator[str | None] = _Validator(added="1.2") + """:external:ref:`core-metadata-maintainer`""" + maintainer_email: _Validator[str | None] = _Validator(added="1.2") + """:external:ref:`core-metadata-maintainer-email`""" + license: _Validator[str | None] = _Validator() + """:external:ref:`core-metadata-license`""" + classifiers: _Validator[list[str] | None] = _Validator(added="1.1") + """:external:ref:`core-metadata-classifier`""" + requires_dist: _Validator[list[requirements.Requirement] | None] = _Validator( + added="1.2" + ) + """:external:ref:`core-metadata-requires-dist`""" + requires_python: _Validator[specifiers.SpecifierSet | None] = _Validator( + added="1.2" + ) + """:external:ref:`core-metadata-requires-python`""" + # Because `Requires-External` allows for non-PEP 440 version specifiers, we + # don't do any processing on the values. + requires_external: _Validator[list[str] | None] = _Validator(added="1.2") + """:external:ref:`core-metadata-requires-external`""" + project_urls: _Validator[dict[str, str] | None] = _Validator(added="1.2") + """:external:ref:`core-metadata-project-url`""" + # PEP 685 lets us raise an error if an extra doesn't pass `Name` validation + # regardless of metadata version. + provides_extra: _Validator[list[utils.NormalizedName] | None] = _Validator( + added="2.1", + ) + """:external:ref:`core-metadata-provides-extra`""" + provides_dist: _Validator[list[str] | None] = _Validator(added="1.2") + """:external:ref:`core-metadata-provides-dist`""" + obsoletes_dist: _Validator[list[str] | None] = _Validator(added="1.2") + """:external:ref:`core-metadata-obsoletes-dist`""" + requires: _Validator[list[str] | None] = _Validator(added="1.1") + """``Requires`` (deprecated)""" + provides: _Validator[list[str] | None] = _Validator(added="1.1") + """``Provides`` (deprecated)""" + obsoletes: _Validator[list[str] | None] = _Validator(added="1.1") + """``Obsoletes`` (deprecated)""" diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/packaging/py.typed b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/packaging/py.typed new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/packaging/requirements.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/packaging/requirements.py new file mode 100644 index 0000000000000000000000000000000000000000..4e068c9567def3564f238a76fe7ab46b569f33e5 --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/packaging/requirements.py @@ -0,0 +1,91 @@ +# 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. +from __future__ import annotations + +from typing import Any, Iterator + +from ._parser import parse_requirement as _parse_requirement +from ._tokenizer import ParserSyntaxError +from .markers import Marker, _normalize_extra_values +from .specifiers import SpecifierSet +from .utils import canonicalize_name + + +class InvalidRequirement(ValueError): + """ + An invalid requirement was found, users should refer to PEP 508. + """ + + +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: + parsed = _parse_requirement(requirement_string) + except ParserSyntaxError as e: + raise InvalidRequirement(str(e)) from e + + self.name: str = parsed.name + self.url: str | None = parsed.url or None + self.extras: set[str] = set(parsed.extras or []) + self.specifier: SpecifierSet = SpecifierSet(parsed.specifier) + self.marker: Marker | None = None + if parsed.marker is not None: + self.marker = Marker.__new__(Marker) + self.marker._markers = _normalize_extra_values(parsed.marker) + + def _iter_parts(self, name: str) -> Iterator[str]: + yield name + + if self.extras: + formatted_extras = ",".join(sorted(self.extras)) + yield f"[{formatted_extras}]" + + if self.specifier: + yield str(self.specifier) + + if self.url: + yield f"@ {self.url}" + if self.marker: + yield " " + + if self.marker: + yield f"; {self.marker}" + + def __str__(self) -> str: + return "".join(self._iter_parts(self.name)) + + def __repr__(self) -> str: + return f"" + + def __hash__(self) -> int: + return hash( + ( + self.__class__.__name__, + *self._iter_parts(canonicalize_name(self.name)), + ) + ) + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, Requirement): + return NotImplemented + + return ( + canonicalize_name(self.name) == canonicalize_name(other.name) + and self.extras == other.extras + and self.specifier == other.specifier + and self.url == other.url + and self.marker == other.marker + ) diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/packaging/tags.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/packaging/tags.py new file mode 100644 index 0000000000000000000000000000000000000000..703f0ed53c0f4624460c49a9619f15b5b8deab9a --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/packaging/tags.py @@ -0,0 +1,627 @@ +# 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. + +from __future__ import annotations + +import logging +import platform +import re +import struct +import subprocess +import sys +import sysconfig +from importlib.machinery import EXTENSION_SUFFIXES +from typing import ( + Iterable, + Iterator, + Sequence, + Tuple, + cast, +) + +from . import _manylinux, _musllinux + +logger = logging.getLogger(__name__) + +PythonVersion = Sequence[int] +AppleVersion = Tuple[int, int] + +INTERPRETER_SHORT_NAMES: dict[str, str] = { + "python": "py", # Generic. + "cpython": "cp", + "pypy": "pp", + "ironpython": "ip", + "jython": "jy", +} + + +_32_BIT_INTERPRETER = struct.calcsize("P") == 4 + + +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) -> int | str | None: + value: int | str | None = 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("-", "_").replace(" ", "_") + + +def _is_threaded_cpython(abis: list[str]) -> bool: + """ + Determine if the ABI corresponds to a threaded (`--disable-gil`) build. + + The threaded builds are indicated by a "t" in the abiflags. + """ + if len(abis) == 0: + return False + # expect e.g., cp313 + m = re.match(r"cp\d+(.*)", abis[0]) + if not m: + return False + abiflags = m.group(1) + return "t" in abiflags + + +def _abi3_applies(python_version: PythonVersion, threading: bool) -> bool: + """ + Determine if the Python version supports abi3. + + PEP 384 was first implemented in Python 3.2. The threaded (`--disable-gil`) + builds do not support abi3. + """ + return len(python_version) > 1 and tuple(python_version) >= (3, 2) and not threading + + +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]) + threading = 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, 13) and _get_config_var("Py_GIL_DISABLED", warn): + threading = "t" + 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}{threading}") + abis.insert(0, f"cp{version}{threading}{debug}{pymalloc}{ucs4}") + return abis + + +def cpython_tags( + python_version: PythonVersion | None = None, + abis: Iterable[str] | None = None, + platforms: Iterable[str] | None = 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_) + + threading = _is_threaded_cpython(abis) + use_abi3 = _abi3_applies(python_version, threading) + if use_abi3: + yield from (Tag(interpreter, "abi3", platform_) for platform_ in platforms) + yield from (Tag(interpreter, "none", platform_) for platform_ in platforms) + + if use_abi3: + 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() -> list[str]: + """ + Return the ABI tag based on EXT_SUFFIX. + """ + # The following are examples of `EXT_SUFFIX`. + # We want to keep the parts which are related to the ABI and remove the + # parts which are related to the platform: + # - linux: '.cpython-310-x86_64-linux-gnu.so' => cp310 + # - mac: '.cpython-310-darwin.so' => cp310 + # - win: '.cp310-win_amd64.pyd' => cp310 + # - win: '.pyd' => cp37 (uses _cpython_abis()) + # - pypy: '.pypy38-pp73-x86_64-linux-gnu.so' => pypy38_pp73 + # - graalpy: '.graalpy-38-native-x86_64-darwin.dylib' + # => graalpy_38_native + + ext_suffix = _get_config_var("EXT_SUFFIX", warn=True) + if not isinstance(ext_suffix, str) or ext_suffix[0] != ".": + raise SystemError("invalid sysconfig.get_config_var('EXT_SUFFIX')") + parts = ext_suffix.split(".") + if len(parts) < 3: + # CPython3.7 and earlier uses ".pyd" on Windows. + return _cpython_abis(sys.version_info[:2]) + soabi = parts[1] + if soabi.startswith("cpython"): + # non-windows + abi = "cp" + soabi.split("-")[1] + elif soabi.startswith("cp"): + # windows + abi = soabi.split("-")[0] + elif soabi.startswith("pypy"): + abi = "-".join(soabi.split("-")[:2]) + elif soabi.startswith("graalpy"): + abi = "-".join(soabi.split("-")[:3]) + elif soabi: + # pyston, ironpython, others? + abi = soabi + else: + return [] + return [_normalize_string(abi)] + + +def generic_tags( + interpreter: str | None = None, + abis: Iterable[str] | None = None, + platforms: Iterable[str] | None = 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() + else: + abis = list(abis) + platforms = list(platforms or platform_tags()) + 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: PythonVersion | None = None, + interpreter: str | None = None, + platforms: Iterable[str] | None = 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: AppleVersion, 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: AppleVersion | None = None, arch: str | None = 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("AppleVersion", tuple(map(int, version_str.split(".")[:2]))) + if version == (10, 16): + # When built against an older macOS SDK, Python will report macOS 10.16 + # instead of the real version. + version_str = subprocess.run( + [ + sys.executable, + "-sS", + "-c", + "import platform; print(platform.mac_ver()[0])", + ], + check=True, + env={"SYSTEM_VERSION_COMPAT": "0"}, + stdout=subprocess.PIPE, + text=True, + ).stdout + version = cast("AppleVersion", 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 ios_platforms( + version: AppleVersion | None = None, multiarch: str | None = None +) -> Iterator[str]: + """ + Yields the platform tags for an iOS system. + + :param version: A two-item tuple specifying the iOS version to generate + platform tags for. Defaults to the current iOS version. + :param multiarch: The CPU architecture+ABI to generate platform tags for - + (the value used by `sys.implementation._multiarch` e.g., + `arm64_iphoneos` or `x84_64_iphonesimulator`). Defaults to the current + multiarch value. + """ + if version is None: + # if iOS is the current platform, ios_ver *must* be defined. However, + # it won't exist for CPython versions before 3.13, which causes a mypy + # error. + _, release, _, _ = platform.ios_ver() # type: ignore[attr-defined] + version = cast("AppleVersion", tuple(map(int, release.split(".")[:2]))) + + if multiarch is None: + multiarch = sys.implementation._multiarch + multiarch = multiarch.replace("-", "_") + + ios_platform_template = "ios_{major}_{minor}_{multiarch}" + + # Consider any iOS major.minor version from the version requested, down to + # 12.0. 12.0 is the first iOS version that is known to have enough features + # to support CPython. Consider every possible minor release up to X.9. There + # highest the minor has ever gone is 8 (14.8 and 15.8) but having some extra + # candidates that won't ever match doesn't really hurt, and it saves us from + # having to keep an explicit list of known iOS versions in the code. Return + # the results descending order of version number. + + # If the requested major version is less than 12, there won't be any matches. + if version[0] < 12: + return + + # Consider the actual X.Y version that was requested. + yield ios_platform_template.format( + major=version[0], minor=version[1], multiarch=multiarch + ) + + # Consider every minor version from X.0 to the minor version prior to the + # version requested by the platform. + for minor in range(version[1] - 1, -1, -1): + yield ios_platform_template.format( + major=version[0], minor=minor, multiarch=multiarch + ) + + for major in range(version[0] - 1, 11, -1): + for minor in range(9, -1, -1): + yield ios_platform_template.format( + major=major, minor=minor, multiarch=multiarch + ) + + +def _linux_platforms(is_32bit: bool = _32_BIT_INTERPRETER) -> Iterator[str]: + linux = _normalize_string(sysconfig.get_platform()) + if not linux.startswith("linux_"): + # we should never be here, just yield the sysconfig one and return + yield linux + return + if is_32bit: + if linux == "linux_x86_64": + linux = "linux_i686" + elif linux == "linux_aarch64": + linux = "linux_armv8l" + _, arch = linux.split("_", 1) + archs = {"armv8l": ["armv8l", "armv7l"]}.get(arch, [arch]) + yield from _manylinux.platform_tags(archs) + yield from _musllinux.platform_tags(archs) + for arch in archs: + yield f"linux_{arch}" + + +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() == "iOS": + return ios_platforms() + elif platform.system() == "Linux": + return _linux_platforms() + else: + return _generic_platforms() + + +def interpreter_name() -> str: + """ + Returns the name of the running interpreter. + + Some implementations have a reserved, two-letter abbreviation which will + be returned when appropriate. + """ + 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": + interp = "pp3" + elif interp_name == "cp": + interp = "cp" + interpreter_version(warn=warn) + else: + interp = None + yield from compatible_tags(interpreter=interp) diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/packaging/version.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/packaging/version.py new file mode 100644 index 0000000000000000000000000000000000000000..8b0a040848d1253de6557fe0d9e93481c1252006 --- /dev/null +++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/packaging/version.py @@ -0,0 +1,563 @@ +# 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. +""" +.. testsetup:: + + from pip._vendor.packaging.version import parse, Version +""" + +from __future__ import annotations + +import itertools +import re +from typing import Any, Callable, NamedTuple, SupportsInt, Tuple, Union + +from ._structures import Infinity, InfinityType, NegativeInfinity, NegativeInfinityType + +__all__ = ["VERSION_PATTERN", "parse", "Version", "InvalidVersion"] + +LocalType = Tuple[Union[int, str], ...] + +CmpPrePostDevType = Union[InfinityType, NegativeInfinityType, Tuple[str, int]] +CmpLocalType = Union[ + NegativeInfinityType, + Tuple[Union[Tuple[int, str], Tuple[NegativeInfinityType, Union[int, str]]], ...], +] +CmpKey = Tuple[ + int, + Tuple[int, ...], + CmpPrePostDevType, + CmpPrePostDevType, + CmpPrePostDevType, + CmpLocalType, +] +VersionComparisonMethod = Callable[[CmpKey, CmpKey], bool] + + +class _Version(NamedTuple): + epoch: int + release: tuple[int, ...] + dev: tuple[str, int] | None + pre: tuple[str, int] | None + post: tuple[str, int] | None + local: LocalType | None + + +def parse(version: str) -> Version: + """Parse the given version string. + + >>> parse('1.0.dev1') + + + :param version: The version string to parse. + :raises InvalidVersion: When the version string is not a valid version. + """ + return Version(version) + + +class InvalidVersion(ValueError): + """Raised when a version string is not a valid version. + + >>> Version("invalid") + Traceback (most recent call last): + ... + packaging.version.InvalidVersion: Invalid version: 'invalid' + """ + + +class _BaseVersion: + _key: tuple[Any, ...] + + 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 + + +# 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
+            [-_\.]?
+            (?Palpha|a|beta|b|preview|pre|c|rc)
+            [-_\.]?
+            (?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_PATTERN = _VERSION_PATTERN
+"""
+A string containing the regular expression used to match a valid version.
+
+The pattern is not anchored at either end, and is intended for embedding in larger
+expressions (for example, matching a version number as part of a file name). The
+regular expression should be compiled with the ``re.VERBOSE`` and ``re.IGNORECASE``
+flags set.
+
+:meta hide-value:
+"""
+
+
+class Version(_BaseVersion):
+    """This class abstracts handling of a project's versions.
+
+    A :class:`Version` instance is comparison aware and can be compared and
+    sorted using the standard Python interfaces.
+
+    >>> v1 = Version("1.0a5")
+    >>> v2 = Version("1.0")
+    >>> v1
+    
+    >>> v2
+    
+    >>> v1 < v2
+    True
+    >>> v1 == v2
+    False
+    >>> v1 > v2
+    False
+    >>> v1 >= v2
+    False
+    >>> v1 <= v2
+    True
+    """
+
+    _regex = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE)
+    _key: CmpKey
+
+    def __init__(self, version: str) -> None:
+        """Initialize a Version object.
+
+        :param version:
+            The string representation of a version which will be parsed and normalized
+            before use.
+        :raises InvalidVersion:
+            If the ``version`` does not conform to PEP 440 in any way then this
+            exception will be raised.
+        """
+
+        # 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:
+        """A representation of the Version that shows all internal state.
+
+        >>> Version('1.0.0')
+        
+        """
+        return f""
+
+    def __str__(self) -> str:
+        """A string representation of the version that can be rounded-tripped.
+
+        >>> str(Version("1.0a5"))
+        '1.0a5'
+        """
+        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:
+        """The epoch of the version.
+
+        >>> Version("2.0.0").epoch
+        0
+        >>> Version("1!2.0.0").epoch
+        1
+        """
+        return self._version.epoch
+
+    @property
+    def release(self) -> tuple[int, ...]:
+        """The components of the "release" segment of the version.
+
+        >>> Version("1.2.3").release
+        (1, 2, 3)
+        >>> Version("2.0.0").release
+        (2, 0, 0)
+        >>> Version("1!2.0.0.post0").release
+        (2, 0, 0)
+
+        Includes trailing zeroes but not the epoch or any pre-release / development /
+        post-release suffixes.
+        """
+        return self._version.release
+
+    @property
+    def pre(self) -> tuple[str, int] | None:
+        """The pre-release segment of the version.
+
+        >>> print(Version("1.2.3").pre)
+        None
+        >>> Version("1.2.3a1").pre
+        ('a', 1)
+        >>> Version("1.2.3b1").pre
+        ('b', 1)
+        >>> Version("1.2.3rc1").pre
+        ('rc', 1)
+        """
+        return self._version.pre
+
+    @property
+    def post(self) -> int | None:
+        """The post-release number of the version.
+
+        >>> print(Version("1.2.3").post)
+        None
+        >>> Version("1.2.3.post1").post
+        1
+        """
+        return self._version.post[1] if self._version.post else None
+
+    @property
+    def dev(self) -> int | None:
+        """The development number of the version.
+
+        >>> print(Version("1.2.3").dev)
+        None
+        >>> Version("1.2.3.dev1").dev
+        1
+        """
+        return self._version.dev[1] if self._version.dev else None
+
+    @property
+    def local(self) -> str | None:
+        """The local version segment of the version.
+
+        >>> print(Version("1.2.3").local)
+        None
+        >>> Version("1.2.3+abc").local
+        'abc'
+        """
+        if self._version.local:
+            return ".".join(str(x) for x in self._version.local)
+        else:
+            return None
+
+    @property
+    def public(self) -> str:
+        """The public portion of the version.
+
+        >>> Version("1.2.3").public
+        '1.2.3'
+        >>> Version("1.2.3+abc").public
+        '1.2.3'
+        >>> Version("1.2.3+abc.dev1").public
+        '1.2.3'
+        """
+        return str(self).split("+", 1)[0]
+
+    @property
+    def base_version(self) -> str:
+        """The "base version" of the version.
+
+        >>> Version("1.2.3").base_version
+        '1.2.3'
+        >>> Version("1.2.3+abc").base_version
+        '1.2.3'
+        >>> Version("1!1.2.3+abc.dev1").base_version
+        '1!1.2.3'
+
+        The "base version" is the public version of the project without any pre or post
+        release markers.
+        """
+        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:
+        """Whether this version is a pre-release.
+
+        >>> Version("1.2.3").is_prerelease
+        False
+        >>> Version("1.2.3a1").is_prerelease
+        True
+        >>> Version("1.2.3b1").is_prerelease
+        True
+        >>> Version("1.2.3rc1").is_prerelease
+        True
+        >>> Version("1.2.3dev1").is_prerelease
+        True
+        """
+        return self.dev is not None or self.pre is not None
+
+    @property
+    def is_postrelease(self) -> bool:
+        """Whether this version is a post-release.
+
+        >>> Version("1.2.3").is_postrelease
+        False
+        >>> Version("1.2.3.post1").is_postrelease
+        True
+        """
+        return self.post is not None
+
+    @property
+    def is_devrelease(self) -> bool:
+        """Whether this version is a development release.
+
+        >>> Version("1.2.3").is_devrelease
+        False
+        >>> Version("1.2.3.dev1").is_devrelease
+        True
+        """
+        return self.dev is not None
+
+    @property
+    def major(self) -> int:
+        """The first item of :attr:`release` or ``0`` if unavailable.
+
+        >>> Version("1.2.3").major
+        1
+        """
+        return self.release[0] if len(self.release) >= 1 else 0
+
+    @property
+    def minor(self) -> int:
+        """The second item of :attr:`release` or ``0`` if unavailable.
+
+        >>> Version("1.2.3").minor
+        2
+        >>> Version("1").minor
+        0
+        """
+        return self.release[1] if len(self.release) >= 2 else 0
+
+    @property
+    def micro(self) -> int:
+        """The third item of :attr:`release` or ``0`` if unavailable.
+
+        >>> Version("1.2.3").micro
+        3
+        >>> Version("1").micro
+        0
+        """
+        return self.release[2] if len(self.release) >= 3 else 0
+
+
+def _parse_letter_version(
+    letter: str | None, number: str | bytes | SupportsInt | None
+) -> tuple[str, int] | None:
+    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 | None) -> LocalType | None:
+    """
+    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: tuple[str, int] | None,
+    post: tuple[str, int] | None,
+    dev: tuple[str, int] | None,
+    local: LocalType | None,
+) -> 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: CmpPrePostDevType = 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: CmpPrePostDevType = NegativeInfinity
+
+    else:
+        _post = post
+
+    # Versions without a development segment should sort after those with one.
+    if dev is None:
+        _dev: CmpPrePostDevType = Infinity
+
+    else:
+        _dev = dev
+
+    if local is None:
+        # Versions without a local segment should sort before those with one.
+        _local: CmpLocalType = 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/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/typing_extensions.py b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/typing_extensions.py
new file mode 100644
index 0000000000000000000000000000000000000000..e429384e76aa9a27c3168ffc998d187ebb84ab93
--- /dev/null
+++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/pip/_vendor/typing_extensions.py
@@ -0,0 +1,3641 @@
+import abc
+import collections
+import collections.abc
+import contextlib
+import functools
+import inspect
+import operator
+import sys
+import types as _types
+import typing
+import warnings
+
+__all__ = [
+    # Super-special typing primitives.
+    'Any',
+    'ClassVar',
+    'Concatenate',
+    'Final',
+    'LiteralString',
+    'ParamSpec',
+    'ParamSpecArgs',
+    'ParamSpecKwargs',
+    'Self',
+    'Type',
+    'TypeVar',
+    'TypeVarTuple',
+    'Unpack',
+
+    # ABCs (from collections.abc).
+    'Awaitable',
+    'AsyncIterator',
+    'AsyncIterable',
+    'Coroutine',
+    'AsyncGenerator',
+    'AsyncContextManager',
+    'Buffer',
+    'ChainMap',
+
+    # Concrete collection types.
+    'ContextManager',
+    'Counter',
+    'Deque',
+    'DefaultDict',
+    'NamedTuple',
+    'OrderedDict',
+    'TypedDict',
+
+    # Structural checks, a.k.a. protocols.
+    'SupportsAbs',
+    'SupportsBytes',
+    'SupportsComplex',
+    'SupportsFloat',
+    'SupportsIndex',
+    'SupportsInt',
+    'SupportsRound',
+
+    # One-off things.
+    'Annotated',
+    'assert_never',
+    'assert_type',
+    'clear_overloads',
+    'dataclass_transform',
+    'deprecated',
+    'Doc',
+    'get_overloads',
+    'final',
+    'get_args',
+    'get_origin',
+    'get_original_bases',
+    'get_protocol_members',
+    'get_type_hints',
+    'IntVar',
+    'is_protocol',
+    'is_typeddict',
+    'Literal',
+    'NewType',
+    'overload',
+    'override',
+    'Protocol',
+    'reveal_type',
+    'runtime',
+    'runtime_checkable',
+    'Text',
+    'TypeAlias',
+    'TypeAliasType',
+    'TypeGuard',
+    'TypeIs',
+    'TYPE_CHECKING',
+    'Never',
+    'NoReturn',
+    'ReadOnly',
+    'Required',
+    'NotRequired',
+
+    # Pure aliases, have always been in typing
+    'AbstractSet',
+    'AnyStr',
+    'BinaryIO',
+    'Callable',
+    'Collection',
+    'Container',
+    'Dict',
+    'ForwardRef',
+    'FrozenSet',
+    'Generator',
+    'Generic',
+    'Hashable',
+    'IO',
+    'ItemsView',
+    'Iterable',
+    'Iterator',
+    'KeysView',
+    'List',
+    'Mapping',
+    'MappingView',
+    'Match',
+    'MutableMapping',
+    'MutableSequence',
+    'MutableSet',
+    'NoDefault',
+    'Optional',
+    'Pattern',
+    'Reversible',
+    'Sequence',
+    'Set',
+    'Sized',
+    'TextIO',
+    'Tuple',
+    'Union',
+    'ValuesView',
+    'cast',
+    'no_type_check',
+    'no_type_check_decorator',
+]
+
+# for backward compatibility
+PEP_560 = True
+GenericMeta = type
+_PEP_696_IMPLEMENTED = sys.version_info >= (3, 13, 0, "beta")
+
+# The functions below are modified copies of typing internal helpers.
+# They are needed by _ProtocolMeta and they provide support for PEP 646.
+
+
+class _Sentinel:
+    def __repr__(self):
+        return ""
+
+
+_marker = _Sentinel()
+
+
+if sys.version_info >= (3, 10):
+    def _should_collect_from_parameters(t):
+        return isinstance(
+            t, (typing._GenericAlias, _types.GenericAlias, _types.UnionType)
+        )
+elif sys.version_info >= (3, 9):
+    def _should_collect_from_parameters(t):
+        return isinstance(t, (typing._GenericAlias, _types.GenericAlias))
+else:
+    def _should_collect_from_parameters(t):
+        return isinstance(t, typing._GenericAlias) and not t._special
+
+
+NoReturn = typing.NoReturn
+
+# 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.
+
+
+if sys.version_info >= (3, 11):
+    from typing import Any
+else:
+
+    class _AnyMeta(type):
+        def __instancecheck__(self, obj):
+            if self is Any:
+                raise TypeError("typing_extensions.Any cannot be used with isinstance()")
+            return super().__instancecheck__(obj)
+
+        def __repr__(self):
+            if self is Any:
+                return "typing_extensions.Any"
+            return super().__repr__()
+
+    class Any(metaclass=_AnyMeta):
+        """Special type indicating an unconstrained type.
+        - Any is compatible with every type.
+        - Any assumed to have all methods.
+        - All values assumed to be instances of Any.
+        Note that all the above statements are true from the point of view of
+        static type checkers. At runtime, Any should not be used with instance
+        checks.
+        """
+        def __new__(cls, *args, **kwargs):
+            if cls is Any:
+                raise TypeError("Any cannot be instantiated")
+            return super().__new__(cls, *args, **kwargs)
+
+
+ClassVar = typing.ClassVar
+
+
+class _ExtensionsSpecialForm(typing._SpecialForm, _root=True):
+    def __repr__(self):
+        return 'typing_extensions.' + self._name
+
+
+Final = typing.Final
+
+if sys.version_info >= (3, 11):
+    final = typing.final
+else:
+    # @final exists in 3.8+, but we backport it for all versions
+    # before 3.11 to keep support for the __final__ attribute.
+    # See https://bugs.python.org/issue46342
+    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. The decorator
+        sets the ``__final__`` attribute to ``True`` on the decorated object
+        to allow runtime introspection.
+        """
+        try:
+            f.__final__ = True
+        except (AttributeError, TypeError):
+            # Skip the attribute silently if it is not writable.
+            # AttributeError happens if the object has __slots__ or a
+            # read-only property, TypeError if it's a builtin class.
+            pass
+        return f
+
+
+def IntVar(name):
+    return typing.TypeVar(name)
+
+
+# A Literal bug was fixed in 3.11.0, 3.10.1 and 3.9.8
+if sys.version_info >= (3, 10, 1):
+    Literal = typing.Literal
+else:
+    def _flatten_literal_params(parameters):
+        """An internal helper for Literal creation: flatten Literals among parameters"""
+        params = []
+        for p in parameters:
+            if isinstance(p, _LiteralGenericAlias):
+                params.extend(p.__args__)
+            else:
+                params.append(p)
+        return tuple(params)
+
+    def _value_and_type_iter(params):
+        for p in params:
+            yield p, type(p)
+
+    class _LiteralGenericAlias(typing._GenericAlias, _root=True):
+        def __eq__(self, other):
+            if not isinstance(other, _LiteralGenericAlias):
+                return NotImplemented
+            these_args_deduped = set(_value_and_type_iter(self.__args__))
+            other_args_deduped = set(_value_and_type_iter(other.__args__))
+            return these_args_deduped == other_args_deduped
+
+        def __hash__(self):
+            return hash(frozenset(_value_and_type_iter(self.__args__)))
+
+    class _LiteralForm(_ExtensionsSpecialForm, _root=True):
+        def __init__(self, doc: str):
+            self._name = 'Literal'
+            self._doc = self.__doc__ = doc
+
+        def __getitem__(self, parameters):
+            if not isinstance(parameters, tuple):
+                parameters = (parameters,)
+
+            parameters = _flatten_literal_params(parameters)
+
+            val_type_pairs = list(_value_and_type_iter(parameters))
+            try:
+                deduped_pairs = set(val_type_pairs)
+            except TypeError:
+                # unhashable parameters
+                pass
+            else:
+                # similar logic to typing._deduplicate on Python 3.9+
+                if len(deduped_pairs) < len(val_type_pairs):
+                    new_parameters = []
+                    for pair in val_type_pairs:
+                        if pair in deduped_pairs:
+                            new_parameters.append(pair[0])
+                            deduped_pairs.remove(pair)
+                    assert not deduped_pairs, deduped_pairs
+                    parameters = tuple(new_parameters)
+
+            return _LiteralGenericAlias(self, parameters)
+
+    Literal = _LiteralForm(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.""")
+
+
+_overload_dummy = typing._overload_dummy
+
+
+if hasattr(typing, "get_overloads"):  # 3.11+
+    overload = typing.overload
+    get_overloads = typing.get_overloads
+    clear_overloads = typing.clear_overloads
+else:
+    # {module: {qualname: {firstlineno: func}}}
+    _overload_registry = collections.defaultdict(
+        functools.partial(collections.defaultdict, dict)
+    )
+
+    def overload(func):
+        """Decorator for overloaded functions/methods.
+
+        In a stub file, place two or more stub definitions for the same
+        function in a row, each decorated with @overload.  For example:
+
+        @overload
+        def utf8(value: None) -> None: ...
+        @overload
+        def utf8(value: bytes) -> bytes: ...
+        @overload
+        def utf8(value: str) -> bytes: ...
+
+        In a non-stub file (i.e. a regular .py file), do the same but
+        follow it with an implementation.  The implementation should *not*
+        be decorated with @overload.  For example:
+
+        @overload
+        def utf8(value: None) -> None: ...
+        @overload
+        def utf8(value: bytes) -> bytes: ...
+        @overload
+        def utf8(value: str) -> bytes: ...
+        def utf8(value):
+            # implementation goes here
+
+        The overloads for a function can be retrieved at runtime using the
+        get_overloads() function.
+        """
+        # classmethod and staticmethod
+        f = getattr(func, "__func__", func)
+        try:
+            _overload_registry[f.__module__][f.__qualname__][
+                f.__code__.co_firstlineno
+            ] = func
+        except AttributeError:
+            # Not a normal function; ignore.
+            pass
+        return _overload_dummy
+
+    def get_overloads(func):
+        """Return all defined overloads for *func* as a sequence."""
+        # classmethod and staticmethod
+        f = getattr(func, "__func__", func)
+        if f.__module__ not in _overload_registry:
+            return []
+        mod_dict = _overload_registry[f.__module__]
+        if f.__qualname__ not in mod_dict:
+            return []
+        return list(mod_dict[f.__qualname__].values())
+
+    def clear_overloads():
+        """Clear all overloads in the registry."""
+        _overload_registry.clear()
+
+
+# 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.
+Awaitable = typing.Awaitable
+Coroutine = typing.Coroutine
+AsyncIterable = typing.AsyncIterable
+AsyncIterator = typing.AsyncIterator
+Deque = typing.Deque
+DefaultDict = typing.DefaultDict
+OrderedDict = typing.OrderedDict
+Counter = typing.Counter
+ChainMap = typing.ChainMap
+Text = typing.Text
+TYPE_CHECKING = typing.TYPE_CHECKING
+
+
+if sys.version_info >= (3, 13, 0, "beta"):
+    from typing import AsyncContextManager, AsyncGenerator, ContextManager, Generator
+else:
+    def _is_dunder(attr):
+        return attr.startswith('__') and attr.endswith('__')
+
+    # Python <3.9 doesn't have typing._SpecialGenericAlias
+    _special_generic_alias_base = getattr(
+        typing, "_SpecialGenericAlias", typing._GenericAlias
+    )
+
+    class _SpecialGenericAlias(_special_generic_alias_base, _root=True):
+        def __init__(self, origin, nparams, *, inst=True, name=None, defaults=()):
+            if _special_generic_alias_base is typing._GenericAlias:
+                # Python <3.9
+                self.__origin__ = origin
+                self._nparams = nparams
+                super().__init__(origin, nparams, special=True, inst=inst, name=name)
+            else:
+                # Python >= 3.9
+                super().__init__(origin, nparams, inst=inst, name=name)
+            self._defaults = defaults
+
+        def __setattr__(self, attr, val):
+            allowed_attrs = {'_name', '_inst', '_nparams', '_defaults'}
+            if _special_generic_alias_base is typing._GenericAlias:
+                # Python <3.9
+                allowed_attrs.add("__origin__")
+            if _is_dunder(attr) or attr in allowed_attrs:
+                object.__setattr__(self, attr, val)
+            else:
+                setattr(self.__origin__, attr, val)
+
+        @typing._tp_cache
+        def __getitem__(self, params):
+            if not isinstance(params, tuple):
+                params = (params,)
+            msg = "Parameters to generic types must be types."
+            params = tuple(typing._type_check(p, msg) for p in params)
+            if (
+                self._defaults
+                and len(params) < self._nparams
+                and len(params) + len(self._defaults) >= self._nparams
+            ):
+                params = (*params, *self._defaults[len(params) - self._nparams:])
+            actual_len = len(params)
+
+            if actual_len != self._nparams:
+                if self._defaults:
+                    expected = f"at least {self._nparams - len(self._defaults)}"
+                else:
+                    expected = str(self._nparams)
+                if not self._nparams:
+                    raise TypeError(f"{self} is not a generic class")
+                raise TypeError(
+                    f"Too {'many' if actual_len > self._nparams else 'few'}"
+                    f" arguments for {self};"
+                    f" actual {actual_len}, expected {expected}"
+                )
+            return self.copy_with(params)
+
+    _NoneType = type(None)
+    Generator = _SpecialGenericAlias(
+        collections.abc.Generator, 3, defaults=(_NoneType, _NoneType)
+    )
+    AsyncGenerator = _SpecialGenericAlias(
+        collections.abc.AsyncGenerator, 2, defaults=(_NoneType,)
+    )
+    ContextManager = _SpecialGenericAlias(
+        contextlib.AbstractContextManager,
+        2,
+        name="ContextManager",
+        defaults=(typing.Optional[bool],)
+    )
+    AsyncContextManager = _SpecialGenericAlias(
+        contextlib.AbstractAsyncContextManager,
+        2,
+        name="AsyncContextManager",
+        defaults=(typing.Optional[bool],)
+    )
+
+
+_PROTO_ALLOWLIST = {
+    'collections.abc': [
+        'Callable', 'Awaitable', 'Iterable', 'Iterator', 'AsyncIterable',
+        'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', 'Buffer',
+    ],
+    'contextlib': ['AbstractContextManager', 'AbstractAsyncContextManager'],
+    'typing_extensions': ['Buffer'],
+}
+
+
+_EXCLUDED_ATTRS = frozenset(typing.EXCLUDED_ATTRIBUTES) | {
+    "__match_args__", "__protocol_attrs__", "__non_callable_proto_members__",
+    "__final__",
+}
+
+
+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 (*base.__dict__, *annotations):
+            if (not attr.startswith('_abc_') and attr not in _EXCLUDED_ATTRS):
+                attrs.add(attr)
+    return attrs
+
+
+def _caller(depth=2):
+    try:
+        return sys._getframe(depth).f_globals.get('__name__', '__main__')
+    except (AttributeError, ValueError):  # For platforms without _getframe()
+        return None
+
+
+# `__match_args__` attribute was removed from protocol members in 3.13,
+# we want to backport this change to older Python versions.
+if sys.version_info >= (3, 13):
+    Protocol = typing.Protocol
+else:
+    def _allow_reckless_class_checks(depth=3):
+        """Allow instance and class checks for special stdlib modules.
+        The abc and functools modules indiscriminately call isinstance() and
+        issubclass() on the whole MRO of a user class, which may contain protocols.
+        """
+        return _caller(depth) in {'abc', 'functools', None}
+
+    def _no_init(self, *args, **kwargs):
+        if type(self)._is_protocol:
+            raise TypeError('Protocols cannot be instantiated')
+
+    def _type_check_issubclass_arg_1(arg):
+        """Raise TypeError if `arg` is not an instance of `type`
+        in `issubclass(arg, )`.
+
+        In most cases, this is verified by type.__subclasscheck__.
+        Checking it again unnecessarily would slow down issubclass() checks,
+        so, we don't perform this check unless we absolutely have to.
+
+        For various error paths, however,
+        we want to ensure that *this* error message is shown to the user
+        where relevant, rather than a typing.py-specific error message.
+        """
+        if not isinstance(arg, type):
+            # Same error message as for issubclass(1, int).
+            raise TypeError('issubclass() arg 1 must be a class')
+
+    # Inheriting from typing._ProtocolMeta isn't actually desirable,
+    # but is necessary to allow typing.Protocol and typing_extensions.Protocol
+    # to mix without getting TypeErrors about "metaclass conflict"
+    class _ProtocolMeta(type(typing.Protocol)):
+        # This metaclass is somewhat unfortunate,
+        # but is necessary for several reasons...
+        #
+        # NOTE: DO NOT call super() in any methods in this class
+        # That would call the methods on typing._ProtocolMeta on Python 3.8-3.11
+        # and those are slow
+        def __new__(mcls, name, bases, namespace, **kwargs):
+            if name == "Protocol" and len(bases) < 2:
+                pass
+            elif {Protocol, typing.Protocol} & set(bases):
+                for base in bases:
+                    if not (
+                        base in {object, typing.Generic, Protocol, typing.Protocol}
+                        or base.__name__ in _PROTO_ALLOWLIST.get(base.__module__, [])
+                        or is_protocol(base)
+                    ):
+                        raise TypeError(
+                            f"Protocols can only inherit from other protocols, "
+                            f"got {base!r}"
+                        )
+            return abc.ABCMeta.__new__(mcls, name, bases, namespace, **kwargs)
+
+        def __init__(cls, *args, **kwargs):
+            abc.ABCMeta.__init__(cls, *args, **kwargs)
+            if getattr(cls, "_is_protocol", False):
+                cls.__protocol_attrs__ = _get_protocol_attrs(cls)
+
+        def __subclasscheck__(cls, other):
+            if cls is Protocol:
+                return type.__subclasscheck__(cls, other)
+            if (
+                getattr(cls, '_is_protocol', False)
+                and not _allow_reckless_class_checks()
+            ):
+                if not getattr(cls, '_is_runtime_protocol', False):
+                    _type_check_issubclass_arg_1(other)
+                    raise TypeError(
+                        "Instance and class checks can only be used with "
+                        "@runtime_checkable protocols"
+                    )
+                if (
+                    # this attribute is set by @runtime_checkable:
+                    cls.__non_callable_proto_members__
+                    and cls.__dict__.get("__subclasshook__") is _proto_hook
+                ):
+                    _type_check_issubclass_arg_1(other)
+                    non_method_attrs = sorted(cls.__non_callable_proto_members__)
+                    raise TypeError(
+                        "Protocols with non-method members don't support issubclass()."
+                        f" Non-method members: {str(non_method_attrs)[1:-1]}."
+                    )
+            return abc.ABCMeta.__subclasscheck__(cls, other)
+
+        def __instancecheck__(cls, instance):
+            # We need this method for situations where attributes are
+            # assigned in __init__.
+            if cls is Protocol:
+                return type.__instancecheck__(cls, instance)
+            if not getattr(cls, "_is_protocol", False):
+                # i.e., it's a concrete subclass of a protocol
+                return abc.ABCMeta.__instancecheck__(cls, instance)
+
+            if (
+                not getattr(cls, '_is_runtime_protocol', False) and
+                not _allow_reckless_class_checks()
+            ):
+                raise TypeError("Instance and class checks can only be used with"
+                                " @runtime_checkable protocols")
+
+            if abc.ABCMeta.__instancecheck__(cls, instance):
+                return True
+
+            for attr in cls.__protocol_attrs__:
+                try:
+                    val = inspect.getattr_static(instance, attr)
+                except AttributeError:
+                    break
+                # this attribute is set by @runtime_checkable:
+                if val is None and attr not in cls.__non_callable_proto_members__:
+                    break
+            else:
+                return True
+
+            return False
+
+        def __eq__(cls, other):
+            # Hack so that typing.Generic.__class_getitem__
+            # treats typing_extensions.Protocol
+            # as equivalent to typing.Protocol
+            if abc.ABCMeta.__eq__(cls, other) is True:
+                return True
+            return cls is Protocol and other is typing.Protocol
+
+        # This has to be defined, or the abc-module cache
+        # complains about classes with this metaclass being unhashable,
+        # if we define only __eq__!
+        def __hash__(cls) -> int:
+            return type.__hash__(cls)
+
+    @classmethod
+    def _proto_hook(cls, other):
+        if not cls.__dict__.get('_is_protocol', False):
+            return NotImplemented
+
+        for attr in cls.__protocol_attrs__:
+            for base in other.__mro__:
+                # Check if the members appears in the class dictionary...
+                if attr in base.__dict__:
+                    if base.__dict__[attr] is None:
+                        return NotImplemented
+                    break
+
+                # ...or in annotations, if it is a sub-protocol.
+                annotations = getattr(base, '__annotations__', {})
+                if (
+                    isinstance(annotations, collections.abc.Mapping)
+                    and attr in annotations
+                    and is_protocol(other)
+                ):
+                    break
+            else:
+                return NotImplemented
+        return True
+
+    class Protocol(typing.Generic, metaclass=_ProtocolMeta):
+        __doc__ = typing.Protocol.__doc__
+        __slots__ = ()
+        _is_protocol = True
+        _is_runtime_protocol = False
+
+        def __init_subclass__(cls, *args, **kwargs):
+            super().__init_subclass__(*args, **kwargs)
+
+            # Determine if this is a protocol or a concrete subclass.
+            if not cls.__dict__.get('_is_protocol', False):
+                cls._is_protocol = any(b is Protocol for b in cls.__bases__)
+
+            # Set (or override) the protocol subclass hook.
+            if '__subclasshook__' not in cls.__dict__:
+                cls.__subclasshook__ = _proto_hook
+
+            # Prohibit instantiation for protocol classes
+            if cls._is_protocol and cls.__init__ is Protocol.__init__:
+                cls.__init__ = _no_init
+
+
+if sys.version_info >= (3, 13):
+    runtime_checkable = typing.runtime_checkable
+else:
+    def runtime_checkable(cls):
+        """Mark a protocol class as a runtime protocol.
+
+        Such protocol 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
+        one trick ponies in collections.abc such as Iterable.
+
+        For example::
+
+            @runtime_checkable
+            class Closable(Protocol):
+                def close(self): ...
+
+            assert isinstance(open('/some/file'), Closable)
+
+        Warning: this will check only the presence of the required methods,
+        not their type signatures!
+        """
+        if not issubclass(cls, typing.Generic) or not getattr(cls, '_is_protocol', False):
+            raise TypeError(f'@runtime_checkable can be only applied to protocol classes,'
+                            f' got {cls!r}')
+        cls._is_runtime_protocol = True
+
+        # typing.Protocol classes on <=3.11 break if we execute this block,
+        # because typing.Protocol classes on <=3.11 don't have a
+        # `__protocol_attrs__` attribute, and this block relies on the
+        # `__protocol_attrs__` attribute. Meanwhile, typing.Protocol classes on 3.12.2+
+        # break if we *don't* execute this block, because *they* assume that all
+        # protocol classes have a `__non_callable_proto_members__` attribute
+        # (which this block sets)
+        if isinstance(cls, _ProtocolMeta) or sys.version_info >= (3, 12, 2):
+            # PEP 544 prohibits using issubclass()
+            # with protocols that have non-method members.
+            # See gh-113320 for why we compute this attribute here,
+            # rather than in `_ProtocolMeta.__init__`
+            cls.__non_callable_proto_members__ = set()
+            for attr in cls.__protocol_attrs__:
+                try:
+                    is_callable = callable(getattr(cls, attr, None))
+                except Exception as e:
+                    raise TypeError(
+                        f"Failed to determine whether protocol member {attr!r} "
+                        "is a method member"
+                    ) from e
+                else:
+                    if not is_callable:
+                        cls.__non_callable_proto_members__.add(attr)
+
+        return cls
+
+
+# The "runtime" alias exists for backwards compatibility.
+runtime = runtime_checkable
+
+
+# Our version of runtime-checkable protocols is faster on Python 3.8-3.11
+if sys.version_info >= (3, 12):
+    SupportsInt = typing.SupportsInt
+    SupportsFloat = typing.SupportsFloat
+    SupportsComplex = typing.SupportsComplex
+    SupportsBytes = typing.SupportsBytes
+    SupportsIndex = typing.SupportsIndex
+    SupportsAbs = typing.SupportsAbs
+    SupportsRound = typing.SupportsRound
+else:
+    @runtime_checkable
+    class SupportsInt(Protocol):
+        """An ABC with one abstract method __int__."""
+        __slots__ = ()
+
+        @abc.abstractmethod
+        def __int__(self) -> int:
+            pass
+
+    @runtime_checkable
+    class SupportsFloat(Protocol):
+        """An ABC with one abstract method __float__."""
+        __slots__ = ()
+
+        @abc.abstractmethod
+        def __float__(self) -> float:
+            pass
+
+    @runtime_checkable
+    class SupportsComplex(Protocol):
+        """An ABC with one abstract method __complex__."""
+        __slots__ = ()
+
+        @abc.abstractmethod
+        def __complex__(self) -> complex:
+            pass
+
+    @runtime_checkable
+    class SupportsBytes(Protocol):
+        """An ABC with one abstract method __bytes__."""
+        __slots__ = ()
+
+        @abc.abstractmethod
+        def __bytes__(self) -> bytes:
+            pass
+
+    @runtime_checkable
+    class SupportsIndex(Protocol):
+        __slots__ = ()
+
+        @abc.abstractmethod
+        def __index__(self) -> int:
+            pass
+
+    @runtime_checkable
+    class SupportsAbs(Protocol[T_co]):
+        """
+        An ABC with one abstract method __abs__ that is covariant in its return type.
+        """
+        __slots__ = ()
+
+        @abc.abstractmethod
+        def __abs__(self) -> T_co:
+            pass
+
+    @runtime_checkable
+    class SupportsRound(Protocol[T_co]):
+        """
+        An ABC with one abstract method __round__ that is covariant in its return type.
+        """
+        __slots__ = ()
+
+        @abc.abstractmethod
+        def __round__(self, ndigits: int = 0) -> T_co:
+            pass
+
+
+def _ensure_subclassable(mro_entries):
+    def inner(func):
+        if sys.implementation.name == "pypy" and sys.version_info < (3, 9):
+            cls_dict = {
+                "__call__": staticmethod(func),
+                "__mro_entries__": staticmethod(mro_entries)
+            }
+            t = type(func.__name__, (), cls_dict)
+            return functools.update_wrapper(t(), func)
+        else:
+            func.__mro_entries__ = mro_entries
+            return func
+    return inner
+
+
+# Update this to something like >=3.13.0b1 if and when
+# PEP 728 is implemented in CPython
+_PEP_728_IMPLEMENTED = False
+
+if _PEP_728_IMPLEMENTED:
+    # 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
+    # The standard library TypedDict below Python 3.11 does not store runtime
+    # information about optional and required keys when using Required or NotRequired.
+    # Generic TypedDicts are also impossible using typing.TypedDict on Python <3.11.
+    # Aaaand on 3.12 we add __orig_bases__ to TypedDict
+    # to enable better runtime introspection.
+    # On 3.13 we deprecate some odd ways of creating TypedDicts.
+    # Also on 3.13, PEP 705 adds the ReadOnly[] qualifier.
+    # PEP 728 (still pending) makes more changes.
+    TypedDict = typing.TypedDict
+    _TypedDictMeta = typing._TypedDictMeta
+    is_typeddict = typing.is_typeddict
+else:
+    # 3.10.0 and later
+    _TAKES_MODULE = "module" in inspect.signature(typing._type_check).parameters
+
+    def _get_typeddict_qualifiers(annotation_type):
+        while True:
+            annotation_origin = get_origin(annotation_type)
+            if annotation_origin is Annotated:
+                annotation_args = get_args(annotation_type)
+                if annotation_args:
+                    annotation_type = annotation_args[0]
+                else:
+                    break
+            elif annotation_origin is Required:
+                yield Required
+                annotation_type, = get_args(annotation_type)
+            elif annotation_origin is NotRequired:
+                yield NotRequired
+                annotation_type, = get_args(annotation_type)
+            elif annotation_origin is ReadOnly:
+                yield ReadOnly
+                annotation_type, = get_args(annotation_type)
+            else:
+                break
+
+    class _TypedDictMeta(type):
+        def __new__(cls, name, bases, ns, *, total=True, closed=False):
+            """Create new typed dict class object.
+
+            This method is called when TypedDict is subclassed,
+            or when TypedDict is instantiated. This way
+            TypedDict supports all three syntax forms described in its docstring.
+            Subclasses and instances of TypedDict return actual dictionaries.
+            """
+            for base in bases:
+                if type(base) is not _TypedDictMeta and base is not typing.Generic:
+                    raise TypeError('cannot inherit from both a TypedDict type '
+                                    'and a non-TypedDict base class')
+
+            if any(issubclass(b, typing.Generic) for b in bases):
+                generic_base = (typing.Generic,)
+            else:
+                generic_base = ()
+
+            # typing.py generally doesn't let you inherit from plain Generic, unless
+            # the name of the class happens to be "Protocol"
+            tp_dict = type.__new__(_TypedDictMeta, "Protocol", (*generic_base, dict), ns)
+            tp_dict.__name__ = name
+            if tp_dict.__qualname__ == "Protocol":
+                tp_dict.__qualname__ = name
+
+            if not hasattr(tp_dict, '__orig_bases__'):
+                tp_dict.__orig_bases__ = bases
+
+            annotations = {}
+            if "__annotations__" in ns:
+                own_annotations = ns["__annotations__"]
+            elif "__annotate__" in ns:
+                # TODO: Use inspect.VALUE here, and make the annotations lazily evaluated
+                own_annotations = ns["__annotate__"](1)
+            else:
+                own_annotations = {}
+            msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type"
+            if _TAKES_MODULE:
+                own_annotations = {
+                    n: typing._type_check(tp, msg, module=tp_dict.__module__)
+                    for n, tp in own_annotations.items()
+                }
+            else:
+                own_annotations = {
+                    n: typing._type_check(tp, msg)
+                    for n, tp in own_annotations.items()
+                }
+            required_keys = set()
+            optional_keys = set()
+            readonly_keys = set()
+            mutable_keys = set()
+            extra_items_type = None
+
+            for base in bases:
+                base_dict = base.__dict__
+
+                annotations.update(base_dict.get('__annotations__', {}))
+                required_keys.update(base_dict.get('__required_keys__', ()))
+                optional_keys.update(base_dict.get('__optional_keys__', ()))
+                readonly_keys.update(base_dict.get('__readonly_keys__', ()))
+                mutable_keys.update(base_dict.get('__mutable_keys__', ()))
+                base_extra_items_type = base_dict.get('__extra_items__', None)
+                if base_extra_items_type is not None:
+                    extra_items_type = base_extra_items_type
+
+            if closed and extra_items_type is None:
+                extra_items_type = Never
+            if closed and "__extra_items__" in own_annotations:
+                annotation_type = own_annotations.pop("__extra_items__")
+                qualifiers = set(_get_typeddict_qualifiers(annotation_type))
+                if Required in qualifiers:
+                    raise TypeError(
+                        "Special key __extra_items__ does not support "
+                        "Required"
+                    )
+                if NotRequired in qualifiers:
+                    raise TypeError(
+                        "Special key __extra_items__ does not support "
+                        "NotRequired"
+                    )
+                extra_items_type = annotation_type
+
+            annotations.update(own_annotations)
+            for annotation_key, annotation_type in own_annotations.items():
+                qualifiers = set(_get_typeddict_qualifiers(annotation_type))
+
+                if Required in qualifiers:
+                    required_keys.add(annotation_key)
+                elif NotRequired in qualifiers:
+                    optional_keys.add(annotation_key)
+                elif total:
+                    required_keys.add(annotation_key)
+                else:
+                    optional_keys.add(annotation_key)
+                if ReadOnly in qualifiers:
+                    mutable_keys.discard(annotation_key)
+                    readonly_keys.add(annotation_key)
+                else:
+                    mutable_keys.add(annotation_key)
+                    readonly_keys.discard(annotation_key)
+
+            tp_dict.__annotations__ = annotations
+            tp_dict.__required_keys__ = frozenset(required_keys)
+            tp_dict.__optional_keys__ = frozenset(optional_keys)
+            tp_dict.__readonly_keys__ = frozenset(readonly_keys)
+            tp_dict.__mutable_keys__ = frozenset(mutable_keys)
+            if not hasattr(tp_dict, '__total__'):
+                tp_dict.__total__ = total
+            tp_dict.__closed__ = closed
+            tp_dict.__extra_items__ = extra_items_type
+            return tp_dict
+
+        __call__ = dict  # static method
+
+        def __subclasscheck__(cls, other):
+            # Typed dicts are only for static structural subtyping.
+            raise TypeError('TypedDict does not support instance and class checks')
+
+        __instancecheck__ = __subclasscheck__
+
+    _TypedDict = type.__new__(_TypedDictMeta, 'TypedDict', (), {})
+
+    @_ensure_subclassable(lambda bases: (_TypedDict,))
+    def TypedDict(typename, fields=_marker, /, *, total=True, closed=False, **kwargs):
+        """A simple typed namespace. At runtime it is equivalent to a plain dict.
+
+        TypedDict creates a dictionary type such that a type checker will expect all
+        instances to have a certain set of keys, where each key is
+        associated with a value of a consistent type. This expectation
+        is not checked at runtime.
+
+        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 an additional equivalent form::
+
+            Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str})
+
+        By default, all keys must be present in a TypedDict. It is possible
+        to override this by specifying totality::
+
+            class Point2D(TypedDict, total=False):
+                x: int
+                y: int
+
+        This means that a Point2D TypedDict can have any of the keys omitted. A type
+        checker is only expected to support a literal False or True as the value of
+        the total argument. True is the default, and makes all items defined in the
+        class body be required.
+
+        The Required and NotRequired special forms can also be used to mark
+        individual keys as being required or not required::
+
+            class Point2D(TypedDict):
+                x: int  # the "x" key must always be present (Required is the default)
+                y: NotRequired[int]  # the "y" key can be omitted
+
+        See PEP 655 for more details on Required and NotRequired.
+        """
+        if fields is _marker or fields is None:
+            if fields is _marker:
+                deprecated_thing = "Failing to pass a value for the 'fields' parameter"
+            else:
+                deprecated_thing = "Passing `None` as the 'fields' parameter"
+
+            example = f"`{typename} = TypedDict({typename!r}, {{}})`"
+            deprecation_msg = (
+                f"{deprecated_thing} is deprecated and will be disallowed in "
+                "Python 3.15. To create a TypedDict class with 0 fields "
+                "using the functional syntax, pass an empty dictionary, e.g. "
+            ) + example + "."
+            warnings.warn(deprecation_msg, DeprecationWarning, stacklevel=2)
+            if closed is not False and closed is not True:
+                kwargs["closed"] = closed
+                closed = False
+            fields = kwargs
+        elif kwargs:
+            raise TypeError("TypedDict takes either a dict or keyword arguments,"
+                            " but not both")
+        if kwargs:
+            if sys.version_info >= (3, 13):
+                raise TypeError("TypedDict takes no keyword arguments")
+            warnings.warn(
+                "The kwargs-based syntax for TypedDict definitions is deprecated "
+                "in Python 3.11, will be removed in Python 3.13, and may not be "
+                "understood by third-party type checkers.",
+                DeprecationWarning,
+                stacklevel=2,
+            )
+
+        ns = {'__annotations__': dict(fields)}
+        module = _caller()
+        if module is not None:
+            # Setting correct module is necessary to make typed dict classes pickleable.
+            ns['__module__'] = module
+
+        td = _TypedDictMeta(typename, (), ns, total=total, closed=closed)
+        td.__orig_bases__ = (TypedDict,)
+        return td
+
+    if hasattr(typing, "_TypedDictMeta"):
+        _TYPEDDICT_TYPES = (typing._TypedDictMeta, _TypedDictMeta)
+    else:
+        _TYPEDDICT_TYPES = (_TypedDictMeta,)
+
+    def is_typeddict(tp):
+        """Check if an annotation is a TypedDict class
+
+        For example::
+            class Film(TypedDict):
+                title: str
+                year: int
+
+            is_typeddict(Film)  # => True
+            is_typeddict(Union[list, str])  # => False
+        """
+        # On 3.8, this would otherwise return True
+        if hasattr(typing, "TypedDict") and tp is typing.TypedDict:
+            return False
+        return isinstance(tp, _TYPEDDICT_TYPES)
+
+
+if hasattr(typing, "assert_type"):
+    assert_type = typing.assert_type
+
+else:
+    def assert_type(val, typ, /):
+        """Assert (to the type checker) that the value is of the given type.
+
+        When the type checker encounters a call to assert_type(), it
+        emits an error if the value is not of the specified type::
+
+            def greet(name: str) -> None:
+                assert_type(name, str)  # ok
+                assert_type(name, int)  # type checker error
+
+        At runtime this returns the first argument unchanged and otherwise
+        does nothing.
+        """
+        return val
+
+
+if hasattr(typing, "ReadOnly"):  # 3.13+
+    get_type_hints = typing.get_type_hints
+else:  # <=3.13
+    # replaces _strip_annotations()
+    def _strip_extras(t):
+        """Strips Annotated, Required and NotRequired from a given type."""
+        if isinstance(t, _AnnotatedAlias):
+            return _strip_extras(t.__origin__)
+        if hasattr(t, "__origin__") and t.__origin__ in (Required, NotRequired, ReadOnly):
+            return _strip_extras(t.__args__[0])
+        if isinstance(t, typing._GenericAlias):
+            stripped_args = tuple(_strip_extras(a) for a in t.__args__)
+            if stripped_args == t.__args__:
+                return t
+            return t.copy_with(stripped_args)
+        if hasattr(_types, "GenericAlias") and isinstance(t, _types.GenericAlias):
+            stripped_args = tuple(_strip_extras(a) for a in t.__args__)
+            if stripped_args == t.__args__:
+                return t
+            return _types.GenericAlias(t.__origin__, stripped_args)
+        if hasattr(_types, "UnionType") and isinstance(t, _types.UnionType):
+            stripped_args = tuple(_strip_extras(a) for a in t.__args__)
+            if stripped_args == t.__args__:
+                return t
+            return functools.reduce(operator.or_, stripped_args)
+
+        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, ...]', 'Required[T]' or 'NotRequired[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.
+        """
+        if hasattr(typing, "Annotated"):  # 3.9+
+            hint = typing.get_type_hints(
+                obj, globalns=globalns, localns=localns, include_extras=True
+            )
+        else:  # 3.8
+            hint = typing.get_type_hints(obj, globalns=globalns, localns=localns)
+        if include_extras:
+            return hint
+        return {k: _strip_extras(t) for k, t in hint.items()}
+
+
+# Python 3.9+ has PEP 593 (Annotated)
+if hasattr(typing, 'Annotated'):
+    Annotated = typing.Annotated
+    # Not exported and not a public API, but needed for get_origin() and get_args()
+    # to work.
+    _AnnotatedAlias = typing._AnnotatedAlias
+# 3.8
+else:
+    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).")
+            allowed_special_forms = (ClassVar, Final)
+            if get_origin(params[0]) in allowed_special_forms:
+                origin = params[0]
+            else:
+                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"
+            )
+
+# 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.8-3.9
+else:
+    try:
+        # 3.9+
+        from typing import _BaseGenericAlias
+    except ImportError:
+        _BaseGenericAlias = typing._GenericAlias
+    try:
+        # 3.9+
+        from typing import GenericAlias as _typing_GenericAlias
+    except ImportError:
+        _typing_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, _typing_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, _typing_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):
+    @_ExtensionsSpecialForm
+    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.8
+else:
+    TypeAlias = _ExtensionsSpecialForm(
+        '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."""
+    )
+
+
+if hasattr(typing, "NoDefault"):
+    NoDefault = typing.NoDefault
+else:
+    class NoDefaultTypeMeta(type):
+        def __setattr__(cls, attr, value):
+            # TypeError is consistent with the behavior of NoneType
+            raise TypeError(
+                f"cannot set {attr!r} attribute of immutable type {cls.__name__!r}"
+            )
+
+    class NoDefaultType(metaclass=NoDefaultTypeMeta):
+        """The type of the NoDefault singleton."""
+
+        __slots__ = ()
+
+        def __new__(cls):
+            return globals().get("NoDefault") or object.__new__(cls)
+
+        def __repr__(self):
+            return "typing_extensions.NoDefault"
+
+        def __reduce__(self):
+            return "NoDefault"
+
+    NoDefault = NoDefaultType()
+    del NoDefaultType, NoDefaultTypeMeta
+
+
+def _set_default(type_param, default):
+    type_param.has_default = lambda: default is not NoDefault
+    type_param.__default__ = default
+
+
+def _set_module(typevarlike):
+    # for pickling:
+    def_mod = _caller(depth=3)
+    if def_mod != 'typing_extensions':
+        typevarlike.__module__ = def_mod
+
+
+class _DefaultMixin:
+    """Mixin for TypeVarLike defaults."""
+
+    __slots__ = ()
+    __init__ = _set_default
+
+
+# Classes using this metaclass must provide a _backported_typevarlike ClassVar
+class _TypeVarLikeMeta(type):
+    def __instancecheck__(cls, __instance: Any) -> bool:
+        return isinstance(__instance, cls._backported_typevarlike)
+
+
+if _PEP_696_IMPLEMENTED:
+    from typing import TypeVar
+else:
+    # Add default and infer_variance parameters from PEP 696 and 695
+    class TypeVar(metaclass=_TypeVarLikeMeta):
+        """Type variable."""
+
+        _backported_typevarlike = typing.TypeVar
+
+        def __new__(cls, name, *constraints, bound=None,
+                    covariant=False, contravariant=False,
+                    default=NoDefault, infer_variance=False):
+            if hasattr(typing, "TypeAliasType"):
+                # PEP 695 implemented (3.12+), can pass infer_variance to typing.TypeVar
+                typevar = typing.TypeVar(name, *constraints, bound=bound,
+                                         covariant=covariant, contravariant=contravariant,
+                                         infer_variance=infer_variance)
+            else:
+                typevar = typing.TypeVar(name, *constraints, bound=bound,
+                                         covariant=covariant, contravariant=contravariant)
+                if infer_variance and (covariant or contravariant):
+                    raise ValueError("Variance cannot be specified with infer_variance.")
+                typevar.__infer_variance__ = infer_variance
+
+            _set_default(typevar, default)
+            _set_module(typevar)
+
+            def _tvar_prepare_subst(alias, args):
+                if (
+                    typevar.has_default()
+                    and alias.__parameters__.index(typevar) == len(args)
+                ):
+                    args += (typevar.__default__,)
+                return args
+
+            typevar.__typing_prepare_subst__ = _tvar_prepare_subst
+            return typevar
+
+        def __init_subclass__(cls) -> None:
+            raise TypeError(f"type '{__name__}.TypeVar' is not an acceptable base type")
+
+
+# Python 3.10+ has PEP 612
+if hasattr(typing, 'ParamSpecArgs'):
+    ParamSpecArgs = typing.ParamSpecArgs
+    ParamSpecKwargs = typing.ParamSpecKwargs
+# 3.8-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"
+
+        def __eq__(self, other):
+            if not isinstance(other, ParamSpecArgs):
+                return NotImplemented
+            return self.__origin__ == other.__origin__
+
+    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"
+
+        def __eq__(self, other):
+            if not isinstance(other, ParamSpecKwargs):
+                return NotImplemented
+            return self.__origin__ == other.__origin__
+
+
+if _PEP_696_IMPLEMENTED:
+    from typing import ParamSpec
+
+# 3.10+
+elif hasattr(typing, 'ParamSpec'):
+
+    # Add default parameter - PEP 696
+    class ParamSpec(metaclass=_TypeVarLikeMeta):
+        """Parameter specification."""
+
+        _backported_typevarlike = typing.ParamSpec
+
+        def __new__(cls, name, *, bound=None,
+                    covariant=False, contravariant=False,
+                    infer_variance=False, default=NoDefault):
+            if hasattr(typing, "TypeAliasType"):
+                # PEP 695 implemented, can pass infer_variance to typing.TypeVar
+                paramspec = typing.ParamSpec(name, bound=bound,
+                                             covariant=covariant,
+                                             contravariant=contravariant,
+                                             infer_variance=infer_variance)
+            else:
+                paramspec = typing.ParamSpec(name, bound=bound,
+                                             covariant=covariant,
+                                             contravariant=contravariant)
+                paramspec.__infer_variance__ = infer_variance
+
+            _set_default(paramspec, default)
+            _set_module(paramspec)
+
+            def _paramspec_prepare_subst(alias, args):
+                params = alias.__parameters__
+                i = params.index(paramspec)
+                if i == len(args) and paramspec.has_default():
+                    args = [*args, paramspec.__default__]
+                if i >= len(args):
+                    raise TypeError(f"Too few arguments for {alias}")
+                # Special case where Z[[int, str, bool]] == Z[int, str, bool] in PEP 612.
+                if len(params) == 1 and not typing._is_param_expr(args[0]):
+                    assert i == 0
+                    args = (args,)
+                # Convert lists to tuples to help other libraries cache the results.
+                elif isinstance(args[i], list):
+                    args = (*args[:i], tuple(args[i]), *args[i + 1:])
+                return args
+
+            paramspec.__typing_prepare_subst__ = _paramspec_prepare_subst
+            return paramspec
+
+        def __init_subclass__(cls) -> None:
+            raise TypeError(f"type '{__name__}.ParamSpec' is not an acceptable base type")
+
+# 3.8-3.9
+else:
+
+    # Inherits from list as a workaround for Callable checks in Python < 3.9.2.
+    class ParamSpec(list, _DefaultMixin):
+        """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,
+                     infer_variance=False, default=NoDefault):
+            list.__init__(self, [self])
+            self.__name__ = name
+            self.__covariant__ = bool(covariant)
+            self.__contravariant__ = bool(contravariant)
+            self.__infer_variance__ = bool(infer_variance)
+            if bound:
+                self.__bound__ = typing._type_check(bound, 'Bound must be a type.')
+            else:
+                self.__bound__ = None
+            _DefaultMixin.__init__(self, default)
+
+            # for pickling:
+            def_mod = _caller()
+            if def_mod != 'typing_extensions':
+                self.__module__ = def_mod
+
+        def __repr__(self):
+            if self.__infer_variance__:
+                prefix = ''
+            elif 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
+
+
+# 3.8-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__.
+        __class__ = typing._GenericAlias
+
+        # Flag in 3.8.
+        _special = False
+
+        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))
+            )
+
+
+# 3.8-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
+# 3.9
+elif sys.version_info[:2] >= (3, 9):
+    @_ExtensionsSpecialForm
+    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.8
+else:
+    class _ConcatenateForm(_ExtensionsSpecialForm, _root=True):
+        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.10+
+if hasattr(typing, 'TypeGuard'):
+    TypeGuard = typing.TypeGuard
+# 3.9
+elif sys.version_info[:2] >= (3, 9):
+    @_ExtensionsSpecialForm
+    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 a single type.')
+        return typing._GenericAlias(self, (item,))
+# 3.8
+else:
+    class _TypeGuardForm(_ExtensionsSpecialForm, _root=True):
+        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.13+
+if hasattr(typing, 'TypeIs'):
+    TypeIs = typing.TypeIs
+# 3.9
+elif sys.version_info[:2] >= (3, 9):
+    @_ExtensionsSpecialForm
+    def TypeIs(self, parameters):
+        """Special typing form used to annotate the return type of a user-defined
+        type narrower function.  ``TypeIs`` only accepts a single type argument.
+        At runtime, functions marked this way should return a boolean.
+
+        ``TypeIs`` 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 ``TypeIs[...]`` as its
+        return type to alert static type checkers to this intention.
+
+        Using  ``-> TypeIs`` 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 intersection of the type inside ``TypeGuard`` and the argument's
+        previously known type.
+
+        For example::
+
+            def is_awaitable(val: object) -> TypeIs[Awaitable[Any]]:
+                return hasattr(val, '__await__')
+
+            def f(val: Union[int, Awaitable[int]]) -> int:
+                if is_awaitable(val):
+                    assert_type(val, Awaitable[int])
+                else:
+                    assert_type(val, int)
+
+        ``TypeIs`` also works with type variables.  For more information, see
+        PEP 742 (Narrowing types with TypeIs).
+        """
+        item = typing._type_check(parameters, f'{self} accepts only a single type.')
+        return typing._GenericAlias(self, (item,))
+# 3.8
+else:
+    class _TypeIsForm(_ExtensionsSpecialForm, _root=True):
+        def __getitem__(self, parameters):
+            item = typing._type_check(parameters,
+                                      f'{self._name} accepts only a single type')
+            return typing._GenericAlias(self, (item,))
+
+    TypeIs = _TypeIsForm(
+        'TypeIs',
+        doc="""Special typing form used to annotate the return type of a user-defined
+        type narrower function.  ``TypeIs`` only accepts a single type argument.
+        At runtime, functions marked this way should return a boolean.
+
+        ``TypeIs`` 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 ``TypeIs[...]`` as its
+        return type to alert static type checkers to this intention.
+
+        Using  ``-> TypeIs`` 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 intersection of the type inside ``TypeGuard`` and the argument's
+        previously known type.
+
+        For example::
+
+            def is_awaitable(val: object) -> TypeIs[Awaitable[Any]]:
+                return hasattr(val, '__await__')
+
+            def f(val: Union[int, Awaitable[int]]) -> int:
+                if is_awaitable(val):
+                    assert_type(val, Awaitable[int])
+                else:
+                    assert_type(val, int)
+
+        ``TypeIs`` also works with type variables.  For more information, see
+        PEP 742 (Narrowing types with TypeIs).
+        """)
+
+
+# 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)
+
+
+if hasattr(typing, "LiteralString"):  # 3.11+
+    LiteralString = typing.LiteralString
+else:
+    @_SpecialForm
+    def LiteralString(self, params):
+        """Represents an arbitrary literal string.
+
+        Example::
+
+          from pip._vendor.typing_extensions import LiteralString
+
+          def query(sql: LiteralString) -> ...:
+              ...
+
+          query("SELECT * FROM table")  # ok
+          query(f"SELECT * FROM {input()}")  # not ok
+
+        See PEP 675 for details.
+
+        """
+        raise TypeError(f"{self} is not subscriptable")
+
+
+if hasattr(typing, "Self"):  # 3.11+
+    Self = typing.Self
+else:
+    @_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")
+
+
+if hasattr(typing, "Never"):  # 3.11+
+    Never = typing.Never
+else:
+    @_SpecialForm
+    def Never(self, params):
+        """The bottom type, a type that has no members.
+
+        This can be used to define a function that should never be
+        called, or a function that never returns::
+
+            from pip._vendor.typing_extensions import Never
+
+            def never_call_me(arg: Never) -> None:
+                pass
+
+            def int_or_str(arg: int | str) -> None:
+                never_call_me(arg)  # type checker error
+                match arg:
+                    case int():
+                        print("It's an int")
+                    case str():
+                        print("It's a str")
+                    case _:
+                        never_call_me(arg)  # ok, arg is of type Never
+
+        """
+
+        raise TypeError(f"{self} is not subscriptable")
+
+
+if hasattr(typing, 'Required'):  # 3.11+
+    Required = typing.Required
+    NotRequired = typing.NotRequired
+elif sys.version_info[:2] >= (3, 9):  # 3.9-3.10
+    @_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 a 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 a single type.')
+        return typing._GenericAlias(self, (item,))
+
+else:  # 3.8
+    class _RequiredForm(_ExtensionsSpecialForm, _root=True):
+        def __getitem__(self, parameters):
+            item = typing._type_check(parameters,
+                                      f'{self._name} accepts only a single type.')
+            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,
+            )
+        """)
+
+
+if hasattr(typing, 'ReadOnly'):
+    ReadOnly = typing.ReadOnly
+elif sys.version_info[:2] >= (3, 9):  # 3.9-3.12
+    @_ExtensionsSpecialForm
+    def ReadOnly(self, parameters):
+        """A special typing construct to mark an item of a TypedDict as read-only.
+
+        For example:
+
+            class Movie(TypedDict):
+                title: ReadOnly[str]
+                year: int
+
+            def mutate_movie(m: Movie) -> None:
+                m["year"] = 1992  # allowed
+                m["title"] = "The Matrix"  # typechecker error
+
+        There is no runtime checking for this property.
+        """
+        item = typing._type_check(parameters, f'{self._name} accepts only a single type.')
+        return typing._GenericAlias(self, (item,))
+
+else:  # 3.8
+    class _ReadOnlyForm(_ExtensionsSpecialForm, _root=True):
+        def __getitem__(self, parameters):
+            item = typing._type_check(parameters,
+                                      f'{self._name} accepts only a single type.')
+            return typing._GenericAlias(self, (item,))
+
+    ReadOnly = _ReadOnlyForm(
+        'ReadOnly',
+        doc="""A special typing construct to mark a key of a TypedDict as read-only.
+
+        For example:
+
+            class Movie(TypedDict):
+                title: ReadOnly[str]
+                year: int
+
+            def mutate_movie(m: Movie) -> None:
+                m["year"] = 1992  # allowed
+                m["title"] = "The Matrix"  # typechecker error
+
+        There is no runtime checking for this propery.
+        """)
+
+
+_UNPACK_DOC = """\
+Type unpack operator.
+
+The type unpack operator takes the child types from some container type,
+such as `tuple[int, str]` or a `TypeVarTuple`, and 'pulls them out'. For
+example:
+
+  # For some generic class `Foo`:
+  Foo[Unpack[tuple[int, str]]]  # Equivalent to Foo[int, str]
+
+  Ts = TypeVarTuple('Ts')
+  # Specifies that `Bar` is generic in an arbitrary number of types.
+  # (Think of `Ts` as a tuple of an arbitrary number of individual
+  #  `TypeVar`s, which the `Unpack` is 'pulling out' directly into the
+  #  `Generic[]`.)
+  class Bar(Generic[Unpack[Ts]]): ...
+  Bar[int]  # Valid
+  Bar[int, str]  # Also valid
+
+From Python 3.11, this can also be done using the `*` operator:
+
+    Foo[*tuple[int, str]]
+    class Bar(Generic[*Ts]): ...
+
+The operator can also be used along with a `TypedDict` to annotate
+`**kwargs` in a function signature. For instance:
+
+  class Movie(TypedDict):
+    name: str
+    year: int
+
+  # This function expects two keyword arguments - *name* of type `str` and
+  # *year* of type `int`.
+  def foo(**kwargs: Unpack[Movie]): ...
+
+Note that there is only some runtime checking of this operator. Not
+everything the runtime allows may be accepted by static type checkers.
+
+For more information, see PEP 646 and PEP 692.
+"""
+
+
+if sys.version_info >= (3, 12):  # PEP 692 changed the repr of Unpack[]
+    Unpack = typing.Unpack
+
+    def _is_unpack(obj):
+        return get_origin(obj) is Unpack
+
+elif sys.version_info[:2] >= (3, 9):  # 3.9+
+    class _UnpackSpecialForm(_ExtensionsSpecialForm, _root=True):
+        def __init__(self, getitem):
+            super().__init__(getitem)
+            self.__doc__ = _UNPACK_DOC
+
+    class _UnpackAlias(typing._GenericAlias, _root=True):
+        __class__ = typing.TypeVar
+
+        @property
+        def __typing_unpacked_tuple_args__(self):
+            assert self.__origin__ is Unpack
+            assert len(self.__args__) == 1
+            arg, = self.__args__
+            if isinstance(arg, (typing._GenericAlias, _types.GenericAlias)):
+                if arg.__origin__ is not tuple:
+                    raise TypeError("Unpack[...] must be used with a tuple type")
+                return arg.__args__
+            return None
+
+    @_UnpackSpecialForm
+    def Unpack(self, parameters):
+        item = typing._type_check(parameters, f'{self._name} accepts only a single type.')
+        return _UnpackAlias(self, (item,))
+
+    def _is_unpack(obj):
+        return isinstance(obj, _UnpackAlias)
+
+else:  # 3.8
+    class _UnpackAlias(typing._GenericAlias, _root=True):
+        __class__ = typing.TypeVar
+
+    class _UnpackForm(_ExtensionsSpecialForm, _root=True):
+        def __getitem__(self, parameters):
+            item = typing._type_check(parameters,
+                                      f'{self._name} accepts only a single type.')
+            return _UnpackAlias(self, (item,))
+
+    Unpack = _UnpackForm('Unpack', doc=_UNPACK_DOC)
+
+    def _is_unpack(obj):
+        return isinstance(obj, _UnpackAlias)
+
+
+if _PEP_696_IMPLEMENTED:
+    from typing import TypeVarTuple
+
+elif hasattr(typing, "TypeVarTuple"):  # 3.11+
+
+    def _unpack_args(*args):
+        newargs = []
+        for arg in args:
+            subargs = getattr(arg, '__typing_unpacked_tuple_args__', None)
+            if subargs is not None and not (subargs and subargs[-1] is ...):
+                newargs.extend(subargs)
+            else:
+                newargs.append(arg)
+        return newargs
+
+    # Add default parameter - PEP 696
+    class TypeVarTuple(metaclass=_TypeVarLikeMeta):
+        """Type variable tuple."""
+
+        _backported_typevarlike = typing.TypeVarTuple
+
+        def __new__(cls, name, *, default=NoDefault):
+            tvt = typing.TypeVarTuple(name)
+            _set_default(tvt, default)
+            _set_module(tvt)
+
+            def _typevartuple_prepare_subst(alias, args):
+                params = alias.__parameters__
+                typevartuple_index = params.index(tvt)
+                for param in params[typevartuple_index + 1:]:
+                    if isinstance(param, TypeVarTuple):
+                        raise TypeError(
+                            f"More than one TypeVarTuple parameter in {alias}"
+                        )
+
+                alen = len(args)
+                plen = len(params)
+                left = typevartuple_index
+                right = plen - typevartuple_index - 1
+                var_tuple_index = None
+                fillarg = None
+                for k, arg in enumerate(args):
+                    if not isinstance(arg, type):
+                        subargs = getattr(arg, '__typing_unpacked_tuple_args__', None)
+                        if subargs and len(subargs) == 2 and subargs[-1] is ...:
+                            if var_tuple_index is not None:
+                                raise TypeError(
+                                    "More than one unpacked "
+                                    "arbitrary-length tuple argument"
+                                )
+                            var_tuple_index = k
+                            fillarg = subargs[0]
+                if var_tuple_index is not None:
+                    left = min(left, var_tuple_index)
+                    right = min(right, alen - var_tuple_index - 1)
+                elif left + right > alen:
+                    raise TypeError(f"Too few arguments for {alias};"
+                                    f" actual {alen}, expected at least {plen - 1}")
+                if left == alen - right and tvt.has_default():
+                    replacement = _unpack_args(tvt.__default__)
+                else:
+                    replacement = args[left: alen - right]
+
+                return (
+                    *args[:left],
+                    *([fillarg] * (typevartuple_index - left)),
+                    replacement,
+                    *([fillarg] * (plen - right - left - typevartuple_index - 1)),
+                    *args[alen - right:],
+                )
+
+            tvt.__typing_prepare_subst__ = _typevartuple_prepare_subst
+            return tvt
+
+        def __init_subclass__(self, *args, **kwds):
+            raise TypeError("Cannot subclass special typing classes")
+
+else:  # <=3.10
+    class TypeVarTuple(_DefaultMixin):
+        """Type variable tuple.
+
+        Usage::
+
+            Ts = TypeVarTuple('Ts')
+
+        In the same way that a normal type variable is a stand-in for a single
+        type such as ``int``, a type variable *tuple* is a stand-in for a *tuple*
+        type such as ``Tuple[int, str]``.
+
+        Type variable tuples can be used in ``Generic`` declarations.
+        Consider the following example::
+
+            class Array(Generic[*Ts]): ...
+
+        The ``Ts`` type variable tuple here behaves like ``tuple[T1, T2]``,
+        where ``T1`` and ``T2`` are type variables. To use these type variables
+        as type parameters of ``Array``, we must *unpack* the type variable tuple using
+        the star operator: ``*Ts``. The signature of ``Array`` then behaves
+        as if we had simply written ``class Array(Generic[T1, T2]): ...``.
+        In contrast to ``Generic[T1, T2]``, however, ``Generic[*Shape]`` allows
+        us to parameterise the class with an *arbitrary* number of type parameters.
+
+        Type variable tuples can be used anywhere a normal ``TypeVar`` can.
+        This includes class definitions, as shown above, as well as function
+        signatures and variable annotations::
+
+            class Array(Generic[*Ts]):
+
+                def __init__(self, shape: Tuple[*Ts]):
+                    self._shape: Tuple[*Ts] = shape
+
+                def get_shape(self) -> Tuple[*Ts]:
+                    return self._shape
+
+            shape = (Height(480), Width(640))
+            x: Array[Height, Width] = Array(shape)
+            y = abs(x)  # Inferred type is Array[Height, Width]
+            z = x + x   #        ...    is Array[Height, Width]
+            x.get_shape()  #     ...    is tuple[Height, Width]
+
+        """
+
+        # Trick Generic __parameters__.
+        __class__ = typing.TypeVar
+
+        def __iter__(self):
+            yield self.__unpacked__
+
+        def __init__(self, name, *, default=NoDefault):
+            self.__name__ = name
+            _DefaultMixin.__init__(self, default)
+
+            # for pickling:
+            def_mod = _caller()
+            if def_mod != 'typing_extensions':
+                self.__module__ = def_mod
+
+            self.__unpacked__ = Unpack[self]
+
+        def __repr__(self):
+            return self.__name__
+
+        def __hash__(self):
+            return object.__hash__(self)
+
+        def __eq__(self, other):
+            return self is other
+
+        def __reduce__(self):
+            return self.__name__
+
+        def __init_subclass__(self, *args, **kwds):
+            if '_root' not in kwds:
+                raise TypeError("Cannot subclass special typing classes")
+
+
+if hasattr(typing, "reveal_type"):  # 3.11+
+    reveal_type = typing.reveal_type
+else:  # <=3.10
+    def reveal_type(obj: T, /) -> T:
+        """Reveal the inferred type of a variable.
+
+        When a static type checker encounters a call to ``reveal_type()``,
+        it will emit the inferred type of the argument::
+
+            x: int = 1
+            reveal_type(x)
+
+        Running a static type checker (e.g., ``mypy``) on this example
+        will produce output similar to 'Revealed type is "builtins.int"'.
+
+        At runtime, the function prints the runtime type of the
+        argument and returns it unchanged.
+
+        """
+        print(f"Runtime type is {type(obj).__name__!r}", file=sys.stderr)
+        return obj
+
+
+if hasattr(typing, "_ASSERT_NEVER_REPR_MAX_LENGTH"):  # 3.11+
+    _ASSERT_NEVER_REPR_MAX_LENGTH = typing._ASSERT_NEVER_REPR_MAX_LENGTH
+else:  # <=3.10
+    _ASSERT_NEVER_REPR_MAX_LENGTH = 100
+
+
+if hasattr(typing, "assert_never"):  # 3.11+
+    assert_never = typing.assert_never
+else:  # <=3.10
+    def assert_never(arg: Never, /) -> Never:
+        """Assert to the type checker that a line of code is unreachable.
+
+        Example::
+
+            def int_or_str(arg: int | str) -> None:
+                match arg:
+                    case int():
+                        print("It's an int")
+                    case str():
+                        print("It's a str")
+                    case _:
+                        assert_never(arg)
+
+        If a type checker finds that a call to assert_never() is
+        reachable, it will emit an error.
+
+        At runtime, this throws an exception when called.
+
+        """
+        value = repr(arg)
+        if len(value) > _ASSERT_NEVER_REPR_MAX_LENGTH:
+            value = value[:_ASSERT_NEVER_REPR_MAX_LENGTH] + '...'
+        raise AssertionError(f"Expected code to be unreachable, but got: {value}")
+
+
+if sys.version_info >= (3, 12):  # 3.12+
+    # dataclass_transform exists in 3.11 but lacks the frozen_default parameter
+    dataclass_transform = typing.dataclass_transform
+else:  # <=3.11
+    def dataclass_transform(
+        *,
+        eq_default: bool = True,
+        order_default: bool = False,
+        kw_only_default: bool = False,
+        frozen_default: bool = False,
+        field_specifiers: typing.Tuple[
+            typing.Union[typing.Type[typing.Any], typing.Callable[..., typing.Any]],
+            ...
+        ] = (),
+        **kwargs: typing.Any,
+    ) -> typing.Callable[[T], T]:
+        """Decorator that marks a function, class, or metaclass as providing
+        dataclass-like behavior.
+
+        Example:
+
+            from pip._vendor.typing_extensions import dataclass_transform
+
+            _T = TypeVar("_T")
+
+            # Used on a decorator function
+            @dataclass_transform()
+            def create_model(cls: type[_T]) -> type[_T]:
+                ...
+                return cls
+
+            @create_model
+            class CustomerModel:
+                id: int
+                name: str
+
+            # Used on a base class
+            @dataclass_transform()
+            class ModelBase: ...
+
+            class CustomerModel(ModelBase):
+                id: int
+                name: str
+
+            # Used on a metaclass
+            @dataclass_transform()
+            class ModelMeta(type): ...
+
+            class ModelBase(metaclass=ModelMeta): ...
+
+            class CustomerModel(ModelBase):
+                id: int
+                name: str
+
+        Each of the ``CustomerModel`` classes defined in this example will now
+        behave similarly to a dataclass created with the ``@dataclasses.dataclass``
+        decorator. For example, the type checker will synthesize an ``__init__``
+        method.
+
+        The arguments to this decorator can be used to customize this behavior:
+        - ``eq_default`` indicates whether the ``eq`` parameter is assumed to be
+          True or False if it is omitted by the caller.
+        - ``order_default`` indicates whether the ``order`` parameter is
+          assumed to be True or False if it is omitted by the caller.
+        - ``kw_only_default`` indicates whether the ``kw_only`` parameter is
+          assumed to be True or False if it is omitted by the caller.
+        - ``frozen_default`` indicates whether the ``frozen`` parameter is
+          assumed to be True or False if it is omitted by the caller.
+        - ``field_specifiers`` specifies a static list of supported classes
+          or functions that describe fields, similar to ``dataclasses.field()``.
+
+        At runtime, this decorator records its arguments in the
+        ``__dataclass_transform__`` attribute on the decorated object.
+
+        See PEP 681 for details.
+
+        """
+        def decorator(cls_or_fn):
+            cls_or_fn.__dataclass_transform__ = {
+                "eq_default": eq_default,
+                "order_default": order_default,
+                "kw_only_default": kw_only_default,
+                "frozen_default": frozen_default,
+                "field_specifiers": field_specifiers,
+                "kwargs": kwargs,
+            }
+            return cls_or_fn
+        return decorator
+
+
+if hasattr(typing, "override"):  # 3.12+
+    override = typing.override
+else:  # <=3.11
+    _F = typing.TypeVar("_F", bound=typing.Callable[..., typing.Any])
+
+    def override(arg: _F, /) -> _F:
+        """Indicate that a method is intended to override a method in a base class.
+
+        Usage:
+
+            class Base:
+                def method(self) -> None:
+                    pass
+
+            class Child(Base):
+                @override
+                def method(self) -> None:
+                    super().method()
+
+        When this decorator is applied to a method, the type checker will
+        validate that it overrides a method with the same name on a base class.
+        This helps prevent bugs that may occur when a base class is changed
+        without an equivalent change to a child class.
+
+        There is no runtime checking of these properties. The decorator
+        sets the ``__override__`` attribute to ``True`` on the decorated object
+        to allow runtime introspection.
+
+        See PEP 698 for details.
+
+        """
+        try:
+            arg.__override__ = True
+        except (AttributeError, TypeError):
+            # Skip the attribute silently if it is not writable.
+            # AttributeError happens if the object has __slots__ or a
+            # read-only property, TypeError if it's a builtin class.
+            pass
+        return arg
+
+
+if hasattr(warnings, "deprecated"):
+    deprecated = warnings.deprecated
+else:
+    _T = typing.TypeVar("_T")
+
+    class deprecated:
+        """Indicate that a class, function or overload is deprecated.
+
+        When this decorator is applied to an object, the type checker
+        will generate a diagnostic on usage of the deprecated object.
+
+        Usage:
+
+            @deprecated("Use B instead")
+            class A:
+                pass
+
+            @deprecated("Use g instead")
+            def f():
+                pass
+
+            @overload
+            @deprecated("int support is deprecated")
+            def g(x: int) -> int: ...
+            @overload
+            def g(x: str) -> int: ...
+
+        The warning specified by *category* will be emitted at runtime
+        on use of deprecated objects. For functions, that happens on calls;
+        for classes, on instantiation and on creation of subclasses.
+        If the *category* is ``None``, no warning is emitted at runtime.
+        The *stacklevel* determines where the
+        warning is emitted. If it is ``1`` (the default), the warning
+        is emitted at the direct caller of the deprecated object; if it
+        is higher, it is emitted further up the stack.
+        Static type checker behavior is not affected by the *category*
+        and *stacklevel* arguments.
+
+        The deprecation message passed to the decorator is saved in the
+        ``__deprecated__`` attribute on the decorated object.
+        If applied to an overload, the decorator
+        must be after the ``@overload`` decorator for the attribute to
+        exist on the overload as returned by ``get_overloads()``.
+
+        See PEP 702 for details.
+
+        """
+        def __init__(
+            self,
+            message: str,
+            /,
+            *,
+            category: typing.Optional[typing.Type[Warning]] = DeprecationWarning,
+            stacklevel: int = 1,
+        ) -> None:
+            if not isinstance(message, str):
+                raise TypeError(
+                    "Expected an object of type str for 'message', not "
+                    f"{type(message).__name__!r}"
+                )
+            self.message = message
+            self.category = category
+            self.stacklevel = stacklevel
+
+        def __call__(self, arg: _T, /) -> _T:
+            # Make sure the inner functions created below don't
+            # retain a reference to self.
+            msg = self.message
+            category = self.category
+            stacklevel = self.stacklevel
+            if category is None:
+                arg.__deprecated__ = msg
+                return arg
+            elif isinstance(arg, type):
+                import functools
+                from types import MethodType
+
+                original_new = arg.__new__
+
+                @functools.wraps(original_new)
+                def __new__(cls, *args, **kwargs):
+                    if cls is arg:
+                        warnings.warn(msg, category=category, stacklevel=stacklevel + 1)
+                    if original_new is not object.__new__:
+                        return original_new(cls, *args, **kwargs)
+                    # Mirrors a similar check in object.__new__.
+                    elif cls.__init__ is object.__init__ and (args or kwargs):
+                        raise TypeError(f"{cls.__name__}() takes no arguments")
+                    else:
+                        return original_new(cls)
+
+                arg.__new__ = staticmethod(__new__)
+
+                original_init_subclass = arg.__init_subclass__
+                # We need slightly different behavior if __init_subclass__
+                # is a bound method (likely if it was implemented in Python)
+                if isinstance(original_init_subclass, MethodType):
+                    original_init_subclass = original_init_subclass.__func__
+
+                    @functools.wraps(original_init_subclass)
+                    def __init_subclass__(*args, **kwargs):
+                        warnings.warn(msg, category=category, stacklevel=stacklevel + 1)
+                        return original_init_subclass(*args, **kwargs)
+
+                    arg.__init_subclass__ = classmethod(__init_subclass__)
+                # Or otherwise, which likely means it's a builtin such as
+                # object's implementation of __init_subclass__.
+                else:
+                    @functools.wraps(original_init_subclass)
+                    def __init_subclass__(*args, **kwargs):
+                        warnings.warn(msg, category=category, stacklevel=stacklevel + 1)
+                        return original_init_subclass(*args, **kwargs)
+
+                    arg.__init_subclass__ = __init_subclass__
+
+                arg.__deprecated__ = __new__.__deprecated__ = msg
+                __init_subclass__.__deprecated__ = msg
+                return arg
+            elif callable(arg):
+                import functools
+
+                @functools.wraps(arg)
+                def wrapper(*args, **kwargs):
+                    warnings.warn(msg, category=category, stacklevel=stacklevel + 1)
+                    return arg(*args, **kwargs)
+
+                arg.__deprecated__ = wrapper.__deprecated__ = msg
+                return wrapper
+            else:
+                raise TypeError(
+                    "@deprecated decorator with non-None category must be applied to "
+                    f"a class or callable, not {arg!r}"
+                )
+
+
+# We have to do some monkey patching to deal with the dual nature of
+# Unpack/TypeVarTuple:
+# - We want Unpack to be a kind of TypeVar so it gets accepted in
+#   Generic[Unpack[Ts]]
+# - We want it to *not* be treated as a TypeVar for the purposes of
+#   counting generic parameters, so that when we subscript a generic,
+#   the runtime doesn't try to substitute the Unpack with the subscripted type.
+if not hasattr(typing, "TypeVarTuple"):
+    def _check_generic(cls, parameters, elen=_marker):
+        """Check correct count for parameters of a generic cls (internal helper).
+
+        This gives a nice error message in case of count mismatch.
+        """
+        if not elen:
+            raise TypeError(f"{cls} is not a generic class")
+        if elen is _marker:
+            if not hasattr(cls, "__parameters__") or not cls.__parameters__:
+                raise TypeError(f"{cls} is not a generic class")
+            elen = len(cls.__parameters__)
+        alen = len(parameters)
+        if alen != elen:
+            expect_val = elen
+            if hasattr(cls, "__parameters__"):
+                parameters = [p for p in cls.__parameters__ if not _is_unpack(p)]
+                num_tv_tuples = sum(isinstance(p, TypeVarTuple) for p in parameters)
+                if (num_tv_tuples > 0) and (alen >= elen - num_tv_tuples):
+                    return
+
+                # deal with TypeVarLike defaults
+                # required TypeVarLikes cannot appear after a defaulted one.
+                if alen < elen:
+                    # since we validate TypeVarLike default in _collect_type_vars
+                    # or _collect_parameters we can safely check parameters[alen]
+                    if (
+                        getattr(parameters[alen], '__default__', NoDefault)
+                        is not NoDefault
+                    ):
+                        return
+
+                    num_default_tv = sum(getattr(p, '__default__', NoDefault)
+                                         is not NoDefault for p in parameters)
+
+                    elen -= num_default_tv
+
+                    expect_val = f"at least {elen}"
+
+            things = "arguments" if sys.version_info >= (3, 10) else "parameters"
+            raise TypeError(f"Too {'many' if alen > elen else 'few'} {things}"
+                            f" for {cls}; actual {alen}, expected {expect_val}")
+else:
+    # Python 3.11+
+
+    def _check_generic(cls, parameters, elen):
+        """Check correct count for parameters of a generic cls (internal helper).
+
+        This gives a nice error message in case of count mismatch.
+        """
+        if not elen:
+            raise TypeError(f"{cls} is not a generic class")
+        alen = len(parameters)
+        if alen != elen:
+            expect_val = elen
+            if hasattr(cls, "__parameters__"):
+                parameters = [p for p in cls.__parameters__ if not _is_unpack(p)]
+
+                # deal with TypeVarLike defaults
+                # required TypeVarLikes cannot appear after a defaulted one.
+                if alen < elen:
+                    # since we validate TypeVarLike default in _collect_type_vars
+                    # or _collect_parameters we can safely check parameters[alen]
+                    if (
+                        getattr(parameters[alen], '__default__', NoDefault)
+                        is not NoDefault
+                    ):
+                        return
+
+                    num_default_tv = sum(getattr(p, '__default__', NoDefault)
+                                         is not NoDefault for p in parameters)
+
+                    elen -= num_default_tv
+
+                    expect_val = f"at least {elen}"
+
+            raise TypeError(f"Too {'many' if alen > elen else 'few'} arguments"
+                            f" for {cls}; actual {alen}, expected {expect_val}")
+
+if not _PEP_696_IMPLEMENTED:
+    typing._check_generic = _check_generic
+
+
+def _has_generic_or_protocol_as_origin() -> bool:
+    try:
+        frame = sys._getframe(2)
+    # - Catch AttributeError: not all Python implementations have sys._getframe()
+    # - Catch ValueError: maybe we're called from an unexpected module
+    #   and the call stack isn't deep enough
+    except (AttributeError, ValueError):
+        return False  # err on the side of leniency
+    else:
+        # If we somehow get invoked from outside typing.py,
+        # also err on the side of leniency
+        if frame.f_globals.get("__name__") != "typing":
+            return False
+        origin = frame.f_locals.get("origin")
+        # Cannot use "in" because origin may be an object with a buggy __eq__ that
+        # throws an error.
+        return origin is typing.Generic or origin is Protocol or origin is typing.Protocol
+
+
+_TYPEVARTUPLE_TYPES = {TypeVarTuple, getattr(typing, "TypeVarTuple", None)}
+
+
+def _is_unpacked_typevartuple(x) -> bool:
+    if get_origin(x) is not Unpack:
+        return False
+    args = get_args(x)
+    return (
+        bool(args)
+        and len(args) == 1
+        and type(args[0]) in _TYPEVARTUPLE_TYPES
+    )
+
+
+# Python 3.11+ _collect_type_vars was renamed to _collect_parameters
+if hasattr(typing, '_collect_type_vars'):
+    def _collect_type_vars(types, typevar_types=None):
+        """Collect all type variable contained in types in order of
+        first appearance (lexicographic order). For example::
+
+            _collect_type_vars((T, List[S, T])) == (T, S)
+        """
+        if typevar_types is None:
+            typevar_types = typing.TypeVar
+        tvars = []
+
+        # A required TypeVarLike cannot appear after a TypeVarLike with a default
+        # if it was a direct call to `Generic[]` or `Protocol[]`
+        enforce_default_ordering = _has_generic_or_protocol_as_origin()
+        default_encountered = False
+
+        # Also, a TypeVarLike with a default cannot appear after a TypeVarTuple
+        type_var_tuple_encountered = False
+
+        for t in types:
+            if _is_unpacked_typevartuple(t):
+                type_var_tuple_encountered = True
+            elif isinstance(t, typevar_types) and t not in tvars:
+                if enforce_default_ordering:
+                    has_default = getattr(t, '__default__', NoDefault) is not NoDefault
+                    if has_default:
+                        if type_var_tuple_encountered:
+                            raise TypeError('Type parameter with a default'
+                                            ' follows TypeVarTuple')
+                        default_encountered = True
+                    elif default_encountered:
+                        raise TypeError(f'Type parameter {t!r} without a default'
+                                        ' follows type parameter with a default')
+
+                tvars.append(t)
+            if _should_collect_from_parameters(t):
+                tvars.extend([t for t in t.__parameters__ if t not in tvars])
+        return tuple(tvars)
+
+    typing._collect_type_vars = _collect_type_vars
+else:
+    def _collect_parameters(args):
+        """Collect all type variables and parameter specifications in args
+        in order of first appearance (lexicographic order).
+
+        For example::
+
+            assert _collect_parameters((T, Callable[P, T])) == (T, P)
+        """
+        parameters = []
+
+        # A required TypeVarLike cannot appear after a TypeVarLike with default
+        # if it was a direct call to `Generic[]` or `Protocol[]`
+        enforce_default_ordering = _has_generic_or_protocol_as_origin()
+        default_encountered = False
+
+        # Also, a TypeVarLike with a default cannot appear after a TypeVarTuple
+        type_var_tuple_encountered = False
+
+        for t in args:
+            if isinstance(t, type):
+                # We don't want __parameters__ descriptor of a bare Python class.
+                pass
+            elif isinstance(t, tuple):
+                # `t` might be a tuple, when `ParamSpec` is substituted with
+                # `[T, int]`, or `[int, *Ts]`, etc.
+                for x in t:
+                    for collected in _collect_parameters([x]):
+                        if collected not in parameters:
+                            parameters.append(collected)
+            elif hasattr(t, '__typing_subst__'):
+                if t not in parameters:
+                    if enforce_default_ordering:
+                        has_default = (
+                            getattr(t, '__default__', NoDefault) is not NoDefault
+                        )
+
+                        if type_var_tuple_encountered and has_default:
+                            raise TypeError('Type parameter with a default'
+                                            ' follows TypeVarTuple')
+
+                        if has_default:
+                            default_encountered = True
+                        elif default_encountered:
+                            raise TypeError(f'Type parameter {t!r} without a default'
+                                            ' follows type parameter with a default')
+
+                    parameters.append(t)
+            else:
+                if _is_unpacked_typevartuple(t):
+                    type_var_tuple_encountered = True
+                for x in getattr(t, '__parameters__', ()):
+                    if x not in parameters:
+                        parameters.append(x)
+
+        return tuple(parameters)
+
+    if not _PEP_696_IMPLEMENTED:
+        typing._collect_parameters = _collect_parameters
+
+# Backport typing.NamedTuple as it exists in Python 3.13.
+# In 3.11, the ability to define generic `NamedTuple`s was supported.
+# This was explicitly disallowed in 3.9-3.10, and only half-worked in <=3.8.
+# On 3.12, we added __orig_bases__ to call-based NamedTuples
+# On 3.13, we deprecated kwargs-based NamedTuples
+if sys.version_info >= (3, 13):
+    NamedTuple = typing.NamedTuple
+else:
+    def _make_nmtuple(name, types, module, defaults=()):
+        fields = [n for n, t in types]
+        annotations = {n: typing._type_check(t, f"field {n} annotation must be a type")
+                       for n, t in types}
+        nm_tpl = collections.namedtuple(name, fields,
+                                        defaults=defaults, module=module)
+        nm_tpl.__annotations__ = nm_tpl.__new__.__annotations__ = annotations
+        # The `_field_types` attribute was removed in 3.9;
+        # in earlier versions, it is the same as the `__annotations__` attribute
+        if sys.version_info < (3, 9):
+            nm_tpl._field_types = annotations
+        return nm_tpl
+
+    _prohibited_namedtuple_fields = typing._prohibited
+    _special_namedtuple_fields = frozenset({'__module__', '__name__', '__annotations__'})
+
+    class _NamedTupleMeta(type):
+        def __new__(cls, typename, bases, ns):
+            assert _NamedTuple in bases
+            for base in bases:
+                if base is not _NamedTuple and base is not typing.Generic:
+                    raise TypeError(
+                        'can only inherit from a NamedTuple type and Generic')
+            bases = tuple(tuple if base is _NamedTuple else base for base in bases)
+            if "__annotations__" in ns:
+                types = ns["__annotations__"]
+            elif "__annotate__" in ns:
+                # TODO: Use inspect.VALUE here, and make the annotations lazily evaluated
+                types = ns["__annotate__"](1)
+            else:
+                types = {}
+            default_names = []
+            for field_name in types:
+                if field_name in ns:
+                    default_names.append(field_name)
+                elif default_names:
+                    raise TypeError(f"Non-default namedtuple field {field_name} "
+                                    f"cannot follow default field"
+                                    f"{'s' if len(default_names) > 1 else ''} "
+                                    f"{', '.join(default_names)}")
+            nm_tpl = _make_nmtuple(
+                typename, types.items(),
+                defaults=[ns[n] for n in default_names],
+                module=ns['__module__']
+            )
+            nm_tpl.__bases__ = bases
+            if typing.Generic in bases:
+                if hasattr(typing, '_generic_class_getitem'):  # 3.12+
+                    nm_tpl.__class_getitem__ = classmethod(typing._generic_class_getitem)
+                else:
+                    class_getitem = typing.Generic.__class_getitem__.__func__
+                    nm_tpl.__class_getitem__ = classmethod(class_getitem)
+            # update from user namespace without overriding special namedtuple attributes
+            for key, val in ns.items():
+                if key in _prohibited_namedtuple_fields:
+                    raise AttributeError("Cannot overwrite NamedTuple attribute " + key)
+                elif key not in _special_namedtuple_fields:
+                    if key not in nm_tpl._fields:
+                        setattr(nm_tpl, key, ns[key])
+                    try:
+                        set_name = type(val).__set_name__
+                    except AttributeError:
+                        pass
+                    else:
+                        try:
+                            set_name(val, nm_tpl, key)
+                        except BaseException as e:
+                            msg = (
+                                f"Error calling __set_name__ on {type(val).__name__!r} "
+                                f"instance {key!r} in {typename!r}"
+                            )
+                            # BaseException.add_note() existed on py311,
+                            # but the __set_name__ machinery didn't start
+                            # using add_note() until py312.
+                            # Making sure exceptions are raised in the same way
+                            # as in "normal" classes seems most important here.
+                            if sys.version_info >= (3, 12):
+                                e.add_note(msg)
+                                raise
+                            else:
+                                raise RuntimeError(msg) from e
+
+            if typing.Generic in bases:
+                nm_tpl.__init_subclass__()
+            return nm_tpl
+
+    _NamedTuple = type.__new__(_NamedTupleMeta, 'NamedTuple', (), {})
+
+    def _namedtuple_mro_entries(bases):
+        assert NamedTuple in bases
+        return (_NamedTuple,)
+
+    @_ensure_subclassable(_namedtuple_mro_entries)
+    def NamedTuple(typename, fields=_marker, /, **kwargs):
+        """Typed version of namedtuple.
+
+        Usage::
+
+            class Employee(NamedTuple):
+                name: str
+                id: int
+
+        This is equivalent to::
+
+            Employee = collections.namedtuple('Employee', ['name', 'id'])
+
+        The resulting class has an extra __annotations__ attribute, giving a
+        dict that maps field names to types.  (The field names are also in
+        the _fields attribute, which is part of the namedtuple API.)
+        An alternative equivalent functional syntax is also accepted::
+
+            Employee = NamedTuple('Employee', [('name', str), ('id', int)])
+        """
+        if fields is _marker:
+            if kwargs:
+                deprecated_thing = "Creating NamedTuple classes using keyword arguments"
+                deprecation_msg = (
+                    "{name} is deprecated and will be disallowed in Python {remove}. "
+                    "Use the class-based or functional syntax instead."
+                )
+            else:
+                deprecated_thing = "Failing to pass a value for the 'fields' parameter"
+                example = f"`{typename} = NamedTuple({typename!r}, [])`"
+                deprecation_msg = (
+                    "{name} is deprecated and will be disallowed in Python {remove}. "
+                    "To create a NamedTuple class with 0 fields "
+                    "using the functional syntax, "
+                    "pass an empty list, e.g. "
+                ) + example + "."
+        elif fields is None:
+            if kwargs:
+                raise TypeError(
+                    "Cannot pass `None` as the 'fields' parameter "
+                    "and also specify fields using keyword arguments"
+                )
+            else:
+                deprecated_thing = "Passing `None` as the 'fields' parameter"
+                example = f"`{typename} = NamedTuple({typename!r}, [])`"
+                deprecation_msg = (
+                    "{name} is deprecated and will be disallowed in Python {remove}. "
+                    "To create a NamedTuple class with 0 fields "
+                    "using the functional syntax, "
+                    "pass an empty list, e.g. "
+                ) + example + "."
+        elif kwargs:
+            raise TypeError("Either list of fields or keywords"
+                            " can be provided to NamedTuple, not both")
+        if fields is _marker or fields is None:
+            warnings.warn(
+                deprecation_msg.format(name=deprecated_thing, remove="3.15"),
+                DeprecationWarning,
+                stacklevel=2,
+            )
+            fields = kwargs.items()
+        nt = _make_nmtuple(typename, fields, module=_caller())
+        nt.__orig_bases__ = (NamedTuple,)
+        return nt
+
+
+if hasattr(collections.abc, "Buffer"):
+    Buffer = collections.abc.Buffer
+else:
+    class Buffer(abc.ABC):  # noqa: B024
+        """Base class for classes that implement the buffer protocol.
+
+        The buffer protocol allows Python objects to expose a low-level
+        memory buffer interface. Before Python 3.12, it is not possible
+        to implement the buffer protocol in pure Python code, or even
+        to check whether a class implements the buffer protocol. In
+        Python 3.12 and higher, the ``__buffer__`` method allows access
+        to the buffer protocol from Python code, and the
+        ``collections.abc.Buffer`` ABC allows checking whether a class
+        implements the buffer protocol.
+
+        To indicate support for the buffer protocol in earlier versions,
+        inherit from this ABC, either in a stub file or at runtime,
+        or use ABC registration. This ABC provides no methods, because
+        there is no Python-accessible methods shared by pre-3.12 buffer
+        classes. It is useful primarily for static checks.
+
+        """
+
+    # As a courtesy, register the most common stdlib buffer classes.
+    Buffer.register(memoryview)
+    Buffer.register(bytearray)
+    Buffer.register(bytes)
+
+
+# Backport of types.get_original_bases, available on 3.12+ in CPython
+if hasattr(_types, "get_original_bases"):
+    get_original_bases = _types.get_original_bases
+else:
+    def get_original_bases(cls, /):
+        """Return the class's "original" bases prior to modification by `__mro_entries__`.
+
+        Examples::
+
+            from typing import TypeVar, Generic
+            from pip._vendor.typing_extensions import NamedTuple, TypedDict
+
+            T = TypeVar("T")
+            class Foo(Generic[T]): ...
+            class Bar(Foo[int], float): ...
+            class Baz(list[str]): ...
+            Eggs = NamedTuple("Eggs", [("a", int), ("b", str)])
+            Spam = TypedDict("Spam", {"a": int, "b": str})
+
+            assert get_original_bases(Bar) == (Foo[int], float)
+            assert get_original_bases(Baz) == (list[str],)
+            assert get_original_bases(Eggs) == (NamedTuple,)
+            assert get_original_bases(Spam) == (TypedDict,)
+            assert get_original_bases(int) == (object,)
+        """
+        try:
+            return cls.__dict__.get("__orig_bases__", cls.__bases__)
+        except AttributeError:
+            raise TypeError(
+                f'Expected an instance of type, not {type(cls).__name__!r}'
+            ) from None
+
+
+# NewType is a class on Python 3.10+, making it pickleable
+# The error message for subclassing instances of NewType was improved on 3.11+
+if sys.version_info >= (3, 11):
+    NewType = typing.NewType
+else:
+    class NewType:
+        """NewType creates simple unique types with almost zero
+        runtime overhead. NewType(name, tp) is considered a subtype of tp
+        by static type checkers. At runtime, NewType(name, tp) returns
+        a dummy callable that simply returns its argument. Usage::
+            UserId = NewType('UserId', int)
+            def name_by_id(user_id: UserId) -> str:
+                ...
+            UserId('user')          # Fails type check
+            name_by_id(42)          # Fails type check
+            name_by_id(UserId(42))  # OK
+            num = UserId(5) + 1     # type: int
+        """
+
+        def __call__(self, obj, /):
+            return obj
+
+        def __init__(self, name, tp):
+            self.__qualname__ = name
+            if '.' in name:
+                name = name.rpartition('.')[-1]
+            self.__name__ = name
+            self.__supertype__ = tp
+            def_mod = _caller()
+            if def_mod != 'typing_extensions':
+                self.__module__ = def_mod
+
+        def __mro_entries__(self, bases):
+            # We defined __mro_entries__ to get a better error message
+            # if a user attempts to subclass a NewType instance. bpo-46170
+            supercls_name = self.__name__
+
+            class Dummy:
+                def __init_subclass__(cls):
+                    subcls_name = cls.__name__
+                    raise TypeError(
+                        f"Cannot subclass an instance of NewType. "
+                        f"Perhaps you were looking for: "
+                        f"`{subcls_name} = NewType({subcls_name!r}, {supercls_name})`"
+                    )
+
+            return (Dummy,)
+
+        def __repr__(self):
+            return f'{self.__module__}.{self.__qualname__}'
+
+        def __reduce__(self):
+            return self.__qualname__
+
+        if sys.version_info >= (3, 10):
+            # PEP 604 methods
+            # It doesn't make sense to have these methods on Python <3.10
+
+            def __or__(self, other):
+                return typing.Union[self, other]
+
+            def __ror__(self, other):
+                return typing.Union[other, self]
+
+
+if hasattr(typing, "TypeAliasType"):
+    TypeAliasType = typing.TypeAliasType
+else:
+    def _is_unionable(obj):
+        """Corresponds to is_unionable() in unionobject.c in CPython."""
+        return obj is None or isinstance(obj, (
+            type,
+            _types.GenericAlias,
+            _types.UnionType,
+            TypeAliasType,
+        ))
+
+    class TypeAliasType:
+        """Create named, parameterized type aliases.
+
+        This provides a backport of the new `type` statement in Python 3.12:
+
+            type ListOrSet[T] = list[T] | set[T]
+
+        is equivalent to:
+
+            T = TypeVar("T")
+            ListOrSet = TypeAliasType("ListOrSet", list[T] | set[T], type_params=(T,))
+
+        The name ListOrSet can then be used as an alias for the type it refers to.
+
+        The type_params argument should contain all the type parameters used
+        in the value of the type alias. If the alias is not generic, this
+        argument is omitted.
+
+        Static type checkers should only support type aliases declared using
+        TypeAliasType that follow these rules:
+
+        - The first argument (the name) must be a string literal.
+        - The TypeAliasType instance must be immediately assigned to a variable
+          of the same name. (For example, 'X = TypeAliasType("Y", int)' is invalid,
+          as is 'X, Y = TypeAliasType("X", int), TypeAliasType("Y", int)').
+
+        """
+
+        def __init__(self, name: str, value, *, type_params=()):
+            if not isinstance(name, str):
+                raise TypeError("TypeAliasType name must be a string")
+            self.__value__ = value
+            self.__type_params__ = type_params
+
+            parameters = []
+            for type_param in type_params:
+                if isinstance(type_param, TypeVarTuple):
+                    parameters.extend(type_param)
+                else:
+                    parameters.append(type_param)
+            self.__parameters__ = tuple(parameters)
+            def_mod = _caller()
+            if def_mod != 'typing_extensions':
+                self.__module__ = def_mod
+            # Setting this attribute closes the TypeAliasType from further modification
+            self.__name__ = name
+
+        def __setattr__(self, name: str, value: object, /) -> None:
+            if hasattr(self, "__name__"):
+                self._raise_attribute_error(name)
+            super().__setattr__(name, value)
+
+        def __delattr__(self, name: str, /) -> Never:
+            self._raise_attribute_error(name)
+
+        def _raise_attribute_error(self, name: str) -> Never:
+            # Match the Python 3.12 error messages exactly
+            if name == "__name__":
+                raise AttributeError("readonly attribute")
+            elif name in {"__value__", "__type_params__", "__parameters__", "__module__"}:
+                raise AttributeError(
+                    f"attribute '{name}' of 'typing.TypeAliasType' objects "
+                    "is not writable"
+                )
+            else:
+                raise AttributeError(
+                    f"'typing.TypeAliasType' object has no attribute '{name}'"
+                )
+
+        def __repr__(self) -> str:
+            return self.__name__
+
+        def __getitem__(self, parameters):
+            if not isinstance(parameters, tuple):
+                parameters = (parameters,)
+            parameters = [
+                typing._type_check(
+                    item, f'Subscripting {self.__name__} requires a type.'
+                )
+                for item in parameters
+            ]
+            return typing._GenericAlias(self, tuple(parameters))
+
+        def __reduce__(self):
+            return self.__name__
+
+        def __init_subclass__(cls, *args, **kwargs):
+            raise TypeError(
+                "type 'typing_extensions.TypeAliasType' is not an acceptable base type"
+            )
+
+        # The presence of this method convinces typing._type_check
+        # that TypeAliasTypes are types.
+        def __call__(self):
+            raise TypeError("Type alias is not callable")
+
+        if sys.version_info >= (3, 10):
+            def __or__(self, right):
+                # For forward compatibility with 3.12, reject Unions
+                # that are not accepted by the built-in Union.
+                if not _is_unionable(right):
+                    return NotImplemented
+                return typing.Union[self, right]
+
+            def __ror__(self, left):
+                if not _is_unionable(left):
+                    return NotImplemented
+                return typing.Union[left, self]
+
+
+if hasattr(typing, "is_protocol"):
+    is_protocol = typing.is_protocol
+    get_protocol_members = typing.get_protocol_members
+else:
+    def is_protocol(tp: type, /) -> bool:
+        """Return True if the given type is a Protocol.
+
+        Example::
+
+            >>> from typing_extensions import Protocol, is_protocol
+            >>> class P(Protocol):
+            ...     def a(self) -> str: ...
+            ...     b: int
+            >>> is_protocol(P)
+            True
+            >>> is_protocol(int)
+            False
+        """
+        return (
+            isinstance(tp, type)
+            and getattr(tp, '_is_protocol', False)
+            and tp is not Protocol
+            and tp is not typing.Protocol
+        )
+
+    def get_protocol_members(tp: type, /) -> typing.FrozenSet[str]:
+        """Return the set of members defined in a Protocol.
+
+        Example::
+
+            >>> from typing_extensions import Protocol, get_protocol_members
+            >>> class P(Protocol):
+            ...     def a(self) -> str: ...
+            ...     b: int
+            >>> get_protocol_members(P)
+            frozenset({'a', 'b'})
+
+        Raise a TypeError for arguments that are not Protocols.
+        """
+        if not is_protocol(tp):
+            raise TypeError(f'{tp!r} is not a Protocol')
+        if hasattr(tp, '__protocol_attrs__'):
+            return frozenset(tp.__protocol_attrs__)
+        return frozenset(_get_protocol_attrs(tp))
+
+
+if hasattr(typing, "Doc"):
+    Doc = typing.Doc
+else:
+    class Doc:
+        """Define the documentation of a type annotation using ``Annotated``, to be
+         used in class attributes, function and method parameters, return values,
+         and variables.
+
+        The value should be a positional-only string literal to allow static tools
+        like editors and documentation generators to use it.
+
+        This complements docstrings.
+
+        The string value passed is available in the attribute ``documentation``.
+
+        Example::
+
+            >>> from typing_extensions import Annotated, Doc
+            >>> def hi(to: Annotated[str, Doc("Who to say hi to")]) -> None: ...
+        """
+        def __init__(self, documentation: str, /) -> None:
+            self.documentation = documentation
+
+        def __repr__(self) -> str:
+            return f"Doc({self.documentation!r})"
+
+        def __hash__(self) -> int:
+            return hash(self.documentation)
+
+        def __eq__(self, other: object) -> bool:
+            if not isinstance(other, Doc):
+                return NotImplemented
+            return self.documentation == other.documentation
+
+
+_CapsuleType = getattr(_types, "CapsuleType", None)
+
+if _CapsuleType is None:
+    try:
+        import _socket
+    except ImportError:
+        pass
+    else:
+        _CAPI = getattr(_socket, "CAPI", None)
+        if _CAPI is not None:
+            _CapsuleType = type(_CAPI)
+
+if _CapsuleType is not None:
+    CapsuleType = _CapsuleType
+    __all__.append("CapsuleType")
+
+
+# Aliases for items that have always been in typing.
+# Explicitly assign these (rather than using `from typing import *` at the top),
+# so that we get a CI error if one of these is deleted from typing.py
+# in a future version of Python
+AbstractSet = typing.AbstractSet
+AnyStr = typing.AnyStr
+BinaryIO = typing.BinaryIO
+Callable = typing.Callable
+Collection = typing.Collection
+Container = typing.Container
+Dict = typing.Dict
+ForwardRef = typing.ForwardRef
+FrozenSet = typing.FrozenSet
+Generic = typing.Generic
+Hashable = typing.Hashable
+IO = typing.IO
+ItemsView = typing.ItemsView
+Iterable = typing.Iterable
+Iterator = typing.Iterator
+KeysView = typing.KeysView
+List = typing.List
+Mapping = typing.Mapping
+MappingView = typing.MappingView
+Match = typing.Match
+MutableMapping = typing.MutableMapping
+MutableSequence = typing.MutableSequence
+MutableSet = typing.MutableSet
+Optional = typing.Optional
+Pattern = typing.Pattern
+Reversible = typing.Reversible
+Sequence = typing.Sequence
+Set = typing.Set
+Sized = typing.Sized
+TextIO = typing.TextIO
+Tuple = typing.Tuple
+Union = typing.Union
+ValuesView = typing.ValuesView
+cast = typing.cast
+no_type_check = typing.no_type_check
+no_type_check_decorator = typing.no_type_check_decorator
diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/typing_extensions-4.9.0.dist-info/LICENSE b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/typing_extensions-4.9.0.dist-info/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..f26bcf4d2de6eb136e31006ca3ab447d5e488adf
--- /dev/null
+++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/typing_extensions-4.9.0.dist-info/LICENSE
@@ -0,0 +1,279 @@
+A. HISTORY OF THE SOFTWARE
+==========================
+
+Python was created in the early 1990s by Guido van Rossum at Stichting
+Mathematisch Centrum (CWI, see https://www.cwi.nl) in the Netherlands
+as a successor of a language called ABC.  Guido remains Python's
+principal author, although it includes many contributions from others.
+
+In 1995, Guido continued his work on Python at the Corporation for
+National Research Initiatives (CNRI, see https://www.cnri.reston.va.us)
+in Reston, Virginia where he released several versions of the
+software.
+
+In May 2000, Guido and the Python core development team moved to
+BeOpen.com to form the BeOpen PythonLabs team.  In October of the same
+year, the PythonLabs team moved to Digital Creations, which became
+Zope Corporation.  In 2001, the Python Software Foundation (PSF, see
+https://www.python.org/psf/) was formed, a non-profit organization
+created specifically to own Python-related Intellectual Property.
+Zope Corporation was a sponsoring member of the PSF.
+
+All Python releases are Open Source (see https://opensource.org for
+the Open Source Definition).  Historically, most, but not all, Python
+releases have also been GPL-compatible; the table below summarizes
+the various releases.
+
+    Release         Derived     Year        Owner       GPL-
+                    from                                compatible? (1)
+
+    0.9.0 thru 1.2              1991-1995   CWI         yes
+    1.3 thru 1.5.2  1.2         1995-1999   CNRI        yes
+    1.6             1.5.2       2000        CNRI        no
+    2.0             1.6         2000        BeOpen.com  no
+    1.6.1           1.6         2001        CNRI        yes (2)
+    2.1             2.0+1.6.1   2001        PSF         no
+    2.0.1           2.0+1.6.1   2001        PSF         yes
+    2.1.1           2.1+2.0.1   2001        PSF         yes
+    2.1.2           2.1.1       2002        PSF         yes
+    2.1.3           2.1.2       2002        PSF         yes
+    2.2 and above   2.1.1       2001-now    PSF         yes
+
+Footnotes:
+
+(1) GPL-compatible doesn't mean that we're distributing Python under
+    the GPL.  All Python licenses, unlike the GPL, let you distribute
+    a modified version without making your changes open source.  The
+    GPL-compatible licenses make it possible to combine Python with
+    other software that is released under the GPL; the others don't.
+
+(2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
+    because its license has a choice of law clause.  According to
+    CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
+    is "not incompatible" with the GPL.
+
+Thanks to the many outside volunteers who have worked under Guido's
+direction to make these releases possible.
+
+
+B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
+===============================================================
+
+Python software and documentation are licensed under the
+Python Software Foundation License Version 2.
+
+Starting with Python 3.8.6, examples, recipes, and other code in
+the documentation are dual licensed under the PSF License Version 2
+and the Zero-Clause BSD license.
+
+Some software incorporated into Python is under different licenses.
+The licenses are listed with code falling under that license.
+
+
+PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
+--------------------------------------------
+
+1. This LICENSE AGREEMENT is between the Python Software Foundation
+("PSF"), and the Individual or Organization ("Licensee") accessing and
+otherwise using this software ("Python") in source or binary form and
+its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, PSF hereby
+grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
+analyze, test, perform and/or display publicly, prepare derivative works,
+distribute, and otherwise use Python alone or in any derivative version,
+provided, however, that PSF's License Agreement and PSF's notice of copyright,
+i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Python Software Foundation;
+All Rights Reserved" are retained in Python alone or in any derivative version
+prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates Python or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to Python.
+
+4. PSF is making Python available to Licensee on an "AS IS"
+basis.  PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any
+relationship of agency, partnership, or joint venture between PSF and
+Licensee.  This License Agreement does not grant permission to use PSF
+trademarks or trade name in a trademark sense to endorse or promote
+products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using Python, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+
+BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
+-------------------------------------------
+
+BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
+
+1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
+office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
+Individual or Organization ("Licensee") accessing and otherwise using
+this software in source or binary form and its associated
+documentation ("the Software").
+
+2. Subject to the terms and conditions of this BeOpen Python License
+Agreement, BeOpen hereby grants Licensee a non-exclusive,
+royalty-free, world-wide license to reproduce, analyze, test, perform
+and/or display publicly, prepare derivative works, distribute, and
+otherwise use the Software alone or in any derivative version,
+provided, however, that the BeOpen Python License is retained in the
+Software, alone or in any derivative version prepared by Licensee.
+
+3. BeOpen is making the Software available to Licensee on an "AS IS"
+basis.  BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
+SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
+AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
+DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+5. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+6. This License Agreement shall be governed by and interpreted in all
+respects by the law of the State of California, excluding conflict of
+law provisions.  Nothing in this License Agreement shall be deemed to
+create any relationship of agency, partnership, or joint venture
+between BeOpen and Licensee.  This License Agreement does not grant
+permission to use BeOpen trademarks or trade names in a trademark
+sense to endorse or promote products or services of Licensee, or any
+third party.  As an exception, the "BeOpen Python" logos available at
+http://www.pythonlabs.com/logos.html may be used according to the
+permissions granted on that web page.
+
+7. By copying, installing or otherwise using the software, Licensee
+agrees to be bound by the terms and conditions of this License
+Agreement.
+
+
+CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
+---------------------------------------
+
+1. This LICENSE AGREEMENT is between the Corporation for National
+Research Initiatives, having an office at 1895 Preston White Drive,
+Reston, VA 20191 ("CNRI"), and the Individual or Organization
+("Licensee") accessing and otherwise using Python 1.6.1 software in
+source or binary form and its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, CNRI
+hereby grants Licensee a nonexclusive, royalty-free, world-wide
+license to reproduce, analyze, test, perform and/or display publicly,
+prepare derivative works, distribute, and otherwise use Python 1.6.1
+alone or in any derivative version, provided, however, that CNRI's
+License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
+1995-2001 Corporation for National Research Initiatives; All Rights
+Reserved" are retained in Python 1.6.1 alone or in any derivative
+version prepared by Licensee.  Alternately, in lieu of CNRI's License
+Agreement, Licensee may substitute the following text (omitting the
+quotes): "Python 1.6.1 is made available subject to the terms and
+conditions in CNRI's License Agreement.  This Agreement together with
+Python 1.6.1 may be located on the internet using the following
+unique, persistent identifier (known as a handle): 1895.22/1013.  This
+Agreement may also be obtained from a proxy server on the internet
+using the following URL: http://hdl.handle.net/1895.22/1013".
+
+3. In the event Licensee prepares a derivative work that is based on
+or incorporates Python 1.6.1 or any part thereof, and wants to make
+the derivative work available to others as provided herein, then
+Licensee hereby agrees to include in any such work a brief summary of
+the changes made to Python 1.6.1.
+
+4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
+basis.  CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
+DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
+INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
+OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+breach of its terms and conditions.
+
+7. This License Agreement shall be governed by the federal
+intellectual property law of the United States, including without
+limitation the federal copyright law, and, to the extent such
+U.S. federal law does not apply, by the law of the Commonwealth of
+Virginia, excluding Virginia's conflict of law provisions.
+Notwithstanding the foregoing, with regard to derivative works based
+on Python 1.6.1 that incorporate non-separable material that was
+previously distributed under the GNU General Public License (GPL), the
+law of the Commonwealth of Virginia shall govern this License
+Agreement only as to issues arising under or with respect to
+Paragraphs 4, 5, and 7 of this License Agreement.  Nothing in this
+License Agreement shall be deemed to create any relationship of
+agency, partnership, or joint venture between CNRI and Licensee.  This
+License Agreement does not grant permission to use CNRI trademarks or
+trade name in a trademark sense to endorse or promote products or
+services of Licensee, or any third party.
+
+8. By clicking on the "ACCEPT" button where indicated, or by copying,
+installing or otherwise using Python 1.6.1, Licensee agrees to be
+bound by the terms and conditions of this License Agreement.
+
+        ACCEPT
+
+
+CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
+--------------------------------------------------
+
+Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
+The Netherlands.  All rights reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ZERO-CLAUSE BSD LICENSE FOR CODE IN THE PYTHON DOCUMENTATION
+----------------------------------------------------------------------
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/typing_extensions-4.9.0.dist-info/METADATA b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/typing_extensions-4.9.0.dist-info/METADATA
new file mode 100644
index 0000000000000000000000000000000000000000..863e977c2f7b65007b97a0bf4daba39aa19dbbf4
--- /dev/null
+++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/typing_extensions-4.9.0.dist-info/METADATA
@@ -0,0 +1,66 @@
+Metadata-Version: 2.1
+Name: typing_extensions
+Version: 4.9.0
+Summary: Backported and Experimental Type Hints for Python 3.8+
+Keywords: annotations,backport,checker,checking,function,hinting,hints,type,typechecking,typehinting,typehints,typing
+Author-email: "Guido van Rossum, Jukka Lehtosalo, Łukasz Langa, Michael Lee" 
+Requires-Python: >=3.8
+Description-Content-Type: text/markdown
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Console
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: Python Software Foundation License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3 :: Only
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
+Classifier: Topic :: Software Development
+Project-URL: Bug Tracker, https://github.com/python/typing_extensions/issues
+Project-URL: Changes, https://github.com/python/typing_extensions/blob/main/CHANGELOG.md
+Project-URL: Documentation, https://typing-extensions.readthedocs.io/
+Project-URL: Home, https://github.com/python/typing_extensions
+Project-URL: Q & A, https://github.com/python/typing/discussions
+Project-URL: Repository, https://github.com/python/typing_extensions
+
+# Typing Extensions
+
+[![Chat at https://gitter.im/python/typing](https://badges.gitter.im/python/typing.svg)](https://gitter.im/python/typing)
+
+[Documentation](https://typing-extensions.readthedocs.io/en/latest/#) –
+[PyPI](https://pypi.org/project/typing-extensions/)
+
+## Overview
+
+The `typing_extensions` module serves two related purposes:
+
+- Enable use of new type system features on older Python versions. For example,
+  `typing.TypeGuard` is new in Python 3.10, but `typing_extensions` allows
+  users on previous Python versions to use it too.
+- Enable experimentation with new type system PEPs before they are accepted and
+  added to the `typing` module.
+
+`typing_extensions` is treated specially by static type checkers such as
+mypy and pyright. Objects defined in `typing_extensions` are treated the same
+way as equivalent forms in `typing`.
+
+`typing_extensions` uses
+[Semantic Versioning](https://semver.org/). The
+major version will be incremented only for backwards-incompatible changes.
+Therefore, it's safe to depend
+on `typing_extensions` like this: `typing_extensions >=x.y, <(x+1)`,
+where `x.y` is the first version that includes all features you need.
+
+## Included items
+
+See [the documentation](https://typing-extensions.readthedocs.io/en/latest/#) for a
+complete listing of module contents.
+
+## Contributing
+
+See [CONTRIBUTING.md](https://github.com/python/typing_extensions/blob/main/CONTRIBUTING.md)
+for how to contribute to `typing_extensions`.
+
diff --git a/tuning-competition-baseline/.venv/lib/python3.11/site-packages/typing_extensions-4.9.0.dist-info/WHEEL b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/typing_extensions-4.9.0.dist-info/WHEEL
new file mode 100644
index 0000000000000000000000000000000000000000..3b5e64b5e6c4a210201d1676a891fd57b15cda99
--- /dev/null
+++ b/tuning-competition-baseline/.venv/lib/python3.11/site-packages/typing_extensions-4.9.0.dist-info/WHEEL
@@ -0,0 +1,4 @@
+Wheel-Version: 1.0
+Generator: flit 3.9.0
+Root-Is-Purelib: true
+Tag: py3-none-any