Skip to content
Merged
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ jobs:
python -Im coverage html --skip-covered --skip-empty

# Report and write to summary.
python -Im coverage report | sed 's/^/ /' >> $GITHUB_STEP_SUMMARY
python -Im coverage report --format=markdown >> $GITHUB_STEP_SUMMARY

# Report again and fail if under 100%.
python -Im coverage report --fail-under=100
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ tmp*
attrs.docset
attrs.tgz
Justfile
t.py
2 changes: 2 additions & 0 deletions changelog.d/1172.change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
`attrs.AttrsInstance` is now a `typing.Protocol` in both type hints and code.
This allows you to subclass it along with another `Protocol`.
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ exclude_lines = [
"pragma: no cover",
# PyPy is unacceptably slow under coverage.
"if PYPY:",
# not meant to be executed
': \.\.\.$',
'^ +\.\.\.$',
]


Expand Down
3 changes: 2 additions & 1 deletion src/attr/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from . import converters, exceptions, filters, setters, validators
from ._cmp import cmp_using
from ._compat import Protocol
from ._config import get_run_validators, set_run_validators
from ._funcs import asdict, assoc, astuple, evolve, has, resolve_types
from ._make import (
Expand All @@ -31,7 +32,7 @@
dataclass = partial(attrs, auto_attribs=True) # happy Easter ;)


class AttrsInstance:
class AttrsInstance(Protocol):
pass


Expand Down
9 changes: 9 additions & 0 deletions src/attr/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@
PY_3_12_PLUS = sys.version_info[:2] >= (3, 12)


if sys.version_info < (3, 8):
try:
from typing_extensions import Protocol
except ImportError: # pragma: no cover
Protocol = object
else:
from typing import Protocol # noqa: F401


def just_warn(*args, **kw):
warnings.warn(
"Running interpreter doesn't sufficiently support code object "
Expand Down
12 changes: 12 additions & 0 deletions tests/test_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

import pytest

import attr


@pytest.fixture(name="mp")
def _mp():
Expand Down Expand Up @@ -50,3 +52,13 @@ def test_immutable(self, mp):

with pytest.raises(AttributeError, match="no attribute 'setdefault'"):
mp.setdefault("x")


def test_attrsinstance_subclass_protocol():
"""
It's possible to subclass AttrsInstance and Protocol at once.
"""

class Foo(attr.AttrsInstance, attr._compat.Protocol):
def attribute(self) -> int:
...