Skip to content

Remove vendored typing-extensions #13336

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 26, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -41,6 +41,7 @@ repos:
'types-setuptools==68.2.0.0',
'types-freezegun==1.1.10',
'types-pyyaml==6.0.12.12',
'typing-extensions',
]

- repo: https://github.com/pre-commit/pygrep-hooks
1 change: 1 addition & 0 deletions news/rich.vendor.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Upgrade rich to 14.1.0
2 changes: 1 addition & 1 deletion news/typing_extensions.vendor.rst
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Upgrade typing_extensions to 4.14.1
Remove vendored typing-extensions.
2 changes: 1 addition & 1 deletion src/pip/_internal/index/package_finder.py
Original file line number Diff line number Diff line change
@@ -45,7 +45,7 @@
from pip._internal.utils.unpacking import SUPPORTED_EXTENSIONS

if TYPE_CHECKING:
from pip._vendor.typing_extensions import TypeGuard
from typing_extensions import TypeGuard

__all__ = ["FormatControl", "BestCandidateResult", "PackageFinder"]

6 changes: 4 additions & 2 deletions src/pip/_internal/models/pylock.py
Original file line number Diff line number Diff line change
@@ -5,16 +5,18 @@
from collections.abc import Iterable
from dataclasses import dataclass
from pathlib import Path
from typing import Any
from typing import TYPE_CHECKING, Any

from pip._vendor import tomli_w
from pip._vendor.typing_extensions import Self

from pip._internal.models.direct_url import ArchiveInfo, DirInfo, VcsInfo
from pip._internal.models.link import Link
from pip._internal.req.req_install import InstallRequirement
from pip._internal.utils.urls import url_to_path

if TYPE_CHECKING:
from typing_extensions import Self

PYLOCK_FILE_NAME_RE = re.compile(r"^pylock\.([^.]+)\.toml$")


11 changes: 7 additions & 4 deletions src/pip/_internal/utils/retry.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
from __future__ import annotations

import functools
from time import perf_counter, sleep
from typing import Callable, TypeVar
from typing import TYPE_CHECKING, Callable, TypeVar

from pip._vendor.typing_extensions import ParamSpec
if TYPE_CHECKING:
from typing_extensions import ParamSpec

T = TypeVar("T")
P = ParamSpec("P")
T = TypeVar("T")
P = ParamSpec("P")


def retry(
2 changes: 1 addition & 1 deletion src/pip/_vendor/pkg_resources/__init__.py
Original file line number Diff line number Diff line change
@@ -100,7 +100,7 @@

if TYPE_CHECKING:
from _typeshed import BytesPath, StrPath, StrOrBytesPath
from pip._vendor.typing_extensions import Self
from typing_extensions import Self


# Patch: Remove deprecation warning from vendored pkg_resources.
52 changes: 12 additions & 40 deletions src/pip/_vendor/rich/__main__.py
Original file line number Diff line number Diff line change
@@ -207,6 +207,8 @@ def iter_last(values: Iterable[T]) -> Iterable[Tuple[bool, T]]:


if __name__ == "__main__": # pragma: no cover
from pip._vendor.rich.panel import Panel

console = Console(
file=io.StringIO(),
force_terminal=True,
@@ -227,47 +229,17 @@ def iter_last(values: Iterable[T]) -> Iterable[Tuple[bool, T]]:
c = Console(record=True)
c.print(test_card)

print(f"rendered in {pre_cache_taken}ms (cold cache)")
print(f"rendered in {taken}ms (warm cache)")

from pip._vendor.rich.panel import Panel

console = Console()

sponsor_message = Table.grid(padding=1)
sponsor_message.add_column(style="green", justify="right")
sponsor_message.add_column(no_wrap=True)

sponsor_message.add_row(
"Textualize",
"[u blue link=https://github.com/textualize]https://github.com/textualize",
)
sponsor_message.add_row(
"Twitter",
"[u blue link=https://twitter.com/willmcgugan]https://twitter.com/willmcgugan",
)

intro_message = Text.from_markup(
"""\
We hope you enjoy using Rich!

Rich is maintained with [red]:heart:[/] by [link=https://www.textualize.io]Textualize.io[/]

- Will McGugan"""
)

message = Table.grid(padding=2)
message.add_column()
message.add_column(no_wrap=True)
message.add_row(intro_message, sponsor_message)

console.print(f"[dim]rendered in [not dim]{pre_cache_taken}ms[/] (cold cache)")
console.print(f"[dim]rendered in [not dim]{taken}ms[/] (warm cache)")
console.print()
console.print(
Panel.fit(
message,
box=box.ROUNDED,
padding=(1, 2),
title="[b red]Thanks for trying out Rich!",
border_style="bright_blue",
),
justify="center",
"[b magenta]Hope you enjoy using Rich![/]\n\n"
"Please consider sponsoring me if you get value from my work.\n\n"
"Even the price of a ☕ can brighten my day!\n\n"
"https://github.com/sponsors/willmcgugan",
border_style="red",
title="Help ensure Rich is maintained",
)
)
2 changes: 1 addition & 1 deletion src/pip/_vendor/rich/_inspect.py
Original file line number Diff line number Diff line change
@@ -214,7 +214,7 @@ def safe_getattr(attr_name: str) -> Tuple[Any, Any]:
def _get_formatted_doc(self, object_: Any) -> Optional[str]:
"""
Extract the docstring of an object, process it and returns it.
The processing consists in cleaning up the doctring's indentation,
The processing consists in cleaning up the docstring's indentation,
taking only its 1st paragraph if `self.help` is not True,
and escape its control codes.

8 changes: 1 addition & 7 deletions src/pip/_vendor/rich/_ratio.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import sys
from fractions import Fraction
from math import ceil
from typing import cast, List, Optional, Sequence

if sys.version_info >= (3, 8):
from typing import Protocol
else:
from pip._vendor.typing_extensions import Protocol # pragma: no cover
from typing import cast, List, Optional, Sequence, Protocol


class Edge(Protocol):
8 changes: 1 addition & 7 deletions src/pip/_vendor/rich/align.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import sys
from itertools import chain
from typing import TYPE_CHECKING, Iterable, Optional

if sys.version_info >= (3, 8):
from typing import Literal
else:
from pip._vendor.typing_extensions import Literal # pragma: no cover
from typing import TYPE_CHECKING, Iterable, Optional, Literal

from .constrain import Constrain
from .jupyter import JupyterMixin
8 changes: 1 addition & 7 deletions src/pip/_vendor/rich/box.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
import sys
from typing import TYPE_CHECKING, Iterable, List

if sys.version_info >= (3, 8):
from typing import Literal
else:
from pip._vendor.typing_extensions import Literal # pragma: no cover
from typing import TYPE_CHECKING, Iterable, List, Literal


from ._loop import loop_last
45 changes: 25 additions & 20 deletions src/pip/_vendor/rich/console.py
Original file line number Diff line number Diff line change
@@ -22,27 +22,21 @@
Dict,
Iterable,
List,
Literal,
Mapping,
NamedTuple,
Optional,
Protocol,
TextIO,
Tuple,
Type,
Union,
cast,
runtime_checkable,
)

from pip._vendor.rich._null_file import NULL_FILE

if sys.version_info >= (3, 8):
from typing import Literal, Protocol, runtime_checkable
else:
from pip._vendor.typing_extensions import (
Literal,
Protocol,
runtime_checkable,
) # pragma: no cover

from . import errors, themes
from ._emoji_replace import _emoji_replace
from ._export_format import CONSOLE_HTML_FORMAT, CONSOLE_SVG_FORMAT
@@ -739,6 +733,14 @@ def __init__(
if no_color is not None
else self._environ.get("NO_COLOR", "") != ""
)
if force_interactive is None:
tty_interactive = self._environ.get("TTY_INTERACTIVE", None)
if tty_interactive is not None:
if tty_interactive == "0":
force_interactive = False
elif tty_interactive == "1":
force_interactive = True

self.is_interactive = (
(self.is_terminal and not self.is_dumb_terminal)
if force_interactive is None
@@ -751,7 +753,7 @@ def __init__(
)
self._record_buffer: List[Segment] = []
self._render_hooks: List[RenderHook] = []
self._live: Optional["Live"] = None
self._live_stack: List[Live] = []
self._is_alt_screen = False

def __repr__(self) -> str:
@@ -823,24 +825,26 @@ def _exit_buffer(self) -> None:
self._buffer_index -= 1
self._check_buffer()

def set_live(self, live: "Live") -> None:
"""Set Live instance. Used by Live context manager.
def set_live(self, live: "Live") -> bool:
"""Set Live instance. Used by Live context manager (no need to call directly).

Args:
live (Live): Live instance using this Console.

Returns:
Boolean that indicates if the live is the topmost of the stack.

Raises:
errors.LiveError: If this Console has a Live context currently active.
"""
with self._lock:
if self._live is not None:
raise errors.LiveError("Only one live display may be active at once")
self._live = live
self._live_stack.append(live)
return len(self._live_stack) == 1

def clear_live(self) -> None:
"""Clear the Live instance."""
"""Clear the Live instance. Used by the Live context manager (no need to call directly)."""
with self._lock:
self._live = None
self._live_stack.pop()

def push_render_hook(self, hook: RenderHook) -> None:
"""Add a new render hook to the stack.
@@ -992,12 +996,13 @@ def is_dumb_terminal(self) -> bool:
@property
def options(self) -> ConsoleOptions:
"""Get default console options."""
size = self.size
return ConsoleOptions(
max_height=self.size.height,
size=self.size,
max_height=size.height,
size=size,
legacy_windows=self.legacy_windows,
min_width=1,
max_width=self.width,
max_width=size.width,
encoding=self.encoding,
is_terminal=self.is_terminal,
)
8 changes: 1 addition & 7 deletions src/pip/_vendor/rich/control.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import sys
import time
from typing import TYPE_CHECKING, Callable, Dict, Iterable, List, Union

if sys.version_info >= (3, 8):
from typing import Final
else:
from pip._vendor.typing_extensions import Final # pragma: no cover
from typing import TYPE_CHECKING, Callable, Dict, Iterable, List, Union, Final

from .segment import ControlCode, ControlType, Segment

1 change: 1 addition & 0 deletions src/pip/_vendor/rich/diagnose.py
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@ def report() -> None: # pragma: no cover
"TERM_PROGRAM",
"TERM",
"TTY_COMPATIBLE",
"TTY_INTERACTIVE",
"VSCODE_VERBOSE_LOGGING",
)
env = {name: os.getenv(name) for name in env_names}
7 changes: 1 addition & 6 deletions src/pip/_vendor/rich/emoji.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import sys
from typing import TYPE_CHECKING, Optional, Union
from typing import TYPE_CHECKING, Optional, Union, Literal

from .jupyter import JupyterMixin
from .segment import Segment
from .style import Style
from ._emoji_codes import EMOJI
from ._emoji_replace import _emoji_replace

if sys.version_info >= (3, 8):
from typing import Literal
else:
from pip._vendor.typing_extensions import Literal # pragma: no cover


if TYPE_CHECKING:
from .console import Console, ConsoleOptions, RenderResult
Loading
Oops, something went wrong.
Loading
Oops, something went wrong.