Skip to content

Conversation

decorator-factory
Copy link

@decorator-factory decorator-factory commented Oct 1, 2025

The current stub for copy.replace accepts arbitrary keyword arguments. We can use ParamSpec to link the signature of obj.__replace__ to the supplied keyword arguments.

This allows passing positional arguments to copy.replace, but I think it's fine, given that __replace__ isn't supposed to contain positional arguments in the signature anyway (docs for object.__replace__)

Demo of the proposed stub for copy.replace in the pyright playground:

from dataclasses import dataclass
from typing import Protocol

import copy

@dataclass(frozen=True)
class Fruit:
  name: str
  long: bool

banana = Fruit("Banana", True)
reveal_type(banana.__replace__)  # (*, name: str = ..., long: bool = ...) -> Fruit

class _SupportsReplace[**P, T](Protocol):
    def __replace__(self, /, *args: P.args, **kwargs: P.kwargs) -> T:
        ...

def replace_v2[**P, T](obj: _SupportsReplace[P, T], *args: P.args, **kwargs: P.kwargs) -> T:
  return obj.__replace__(*args, **kwargs)

# using the current copy.replace stub
x = copy.replace(banana, name="Apple")              # no error, as expected
y = copy.replace(banana, name="Apple", long=False)  # no error, as expected
z = copy.replace(banana, missing=42)                # no error, but should be
w = copy.replace(banana, name="Apple", long=42)     # no error, but should be

# using suggested change
x = replace_v2(banana, name="Apple")              # no error, as expected
y = replace_v2(banana, name="Apple", long=False)  # no error, as expected
z = replace_v2(banana, missing=42)                # error: no parameter named missing, as expected
w = replace_v2(banana, name="Apple", long=42)     # error: wrong type, as expected

This comment has been minimized.

This comment has been minimized.

1 similar comment
Copy link
Contributor

github-actions bot commented Oct 2, 2025

According to mypy_primer, this change has no effect on the checked open source code. 🤖🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant