Remove various obsolete _compat helpers (#941)
* remove obsolete _compat.iteritems()
* remove obsolete _compat.TYPE
* remove obsolete _compat.isclass()
* remove obsolete _compat.new_class()
* remove obsolete _compat.metadata_proxy
diff --git a/src/attr/_cmp.py b/src/attr/_cmp.py
index 0060222..81b99e4 100644
--- a/src/attr/_cmp.py
+++ b/src/attr/_cmp.py
@@ -2,8 +2,8 @@
import functools
+import types
-from ._compat import new_class
from ._make import _make_ne
@@ -79,7 +79,9 @@
num_order_functions += 1
body["__ge__"] = _make_operator("ge", ge)
- type_ = new_class(class_name, (object,), {}, lambda ns: ns.update(body))
+ type_ = types.new_class(
+ class_name, (object,), {}, lambda ns: ns.update(body)
+ )
# Add same type requirement.
if require_same_type:
diff --git a/src/attr/_compat.py b/src/attr/_compat.py
index b0d6908..f5f695a 100644
--- a/src/attr/_compat.py
+++ b/src/attr/_compat.py
@@ -39,24 +39,6 @@
)
-def isclass(klass):
- return isinstance(klass, type)
-
-
-TYPE = "class"
-
-
-def iteritems(d):
- return d.items()
-
-
-new_class = types.new_class
-
-
-def metadata_proxy(d):
- return types.MappingProxyType(dict(d))
-
-
class _AnnotationExtractor:
"""
Extract type annotations from a callable, returning None whenever there
diff --git a/src/attr/_funcs.py b/src/attr/_funcs.py
index 69a3cf6..a982d7c 100644
--- a/src/attr/_funcs.py
+++ b/src/attr/_funcs.py
@@ -3,7 +3,6 @@
import copy
-from ._compat import iteritems
from ._make import NOTHING, _obj_setattr, fields
from .exceptions import AttrsAttributeNotFoundError
@@ -106,7 +105,7 @@
value_serializer=value_serializer,
),
)
- for kk, vv in iteritems(v)
+ for kk, vv in v.items()
)
else:
rv[a.name] = v
@@ -178,7 +177,7 @@
value_serializer=value_serializer,
),
)
- for kk, vv in iteritems(val)
+ for kk, vv in val.items()
)
else:
rv = val
@@ -277,7 +276,7 @@
if has(vv.__class__)
else vv,
)
- for kk, vv in iteritems(v)
+ for kk, vv in v.items()
)
)
else:
@@ -328,7 +327,7 @@
)
new = copy.copy(inst)
attrs = fields(inst.__class__)
- for k, v in iteritems(changes):
+ for k, v in changes.items():
a = getattr(attrs, k, NOTHING)
if a is NOTHING:
raise AttrsAttributeNotFoundError(
diff --git a/src/attr/_make.py b/src/attr/_make.py
index ab3f0be..4d1afe3 100644
--- a/src/attr/_make.py
+++ b/src/attr/_make.py
@@ -3,6 +3,7 @@
import copy
import linecache
import sys
+import types
import typing
from operator import itemgetter
@@ -15,10 +16,6 @@
PY310,
PYPY,
_AnnotationExtractor,
- isclass,
- iteritems,
- metadata_proxy,
- new_class,
ordered_dict,
set_closure_cell,
)
@@ -48,7 +45,7 @@
# (when slots=True)
_hash_cache_field = "_attrs_cached_hash"
-_empty_metadata_singleton = metadata_proxy({})
+_empty_metadata_singleton = types.MappingProxyType({})
# Unique object for unequivocal getattr() defaults.
_sentinel = object()
@@ -504,7 +501,7 @@
anns = _get_annotations(cls)
if these is not None:
- ca_list = [(name, ca) for name, ca in iteritems(these)]
+ ca_list = [(name, ca) for name, ca in these.items()]
if not isinstance(these, ordered_dict):
ca_list.sort(key=_counter_getter)
@@ -795,7 +792,7 @@
"""
cd = {
k: v
- for k, v in iteritems(self._cls_dict)
+ for k, v in self._cls_dict.items()
if k not in tuple(self._attr_names) + ("__dict__", "__weakref__")
}
@@ -850,7 +847,7 @@
# we collect them here and update the class dict
reused_slots = {
slot: slot_descriptor
- for slot, slot_descriptor in iteritems(existing_slots)
+ for slot, slot_descriptor in existing_slots.items()
if slot in slot_names
}
slot_names = [name for name in slot_names if name not in reused_slots]
@@ -1988,7 +1985,7 @@
.. versionchanged:: 16.2.0 Returned tuple allows accessing the fields
by name.
"""
- if not isclass(cls):
+ if not isinstance(cls, type):
raise TypeError("Passed object must be a class.")
attrs = getattr(cls, "__attrs_attrs__", None)
if attrs is None:
@@ -2016,7 +2013,7 @@
.. versionadded:: 18.1.0
"""
- if not isclass(cls):
+ if not isinstance(cls, type):
raise TypeError("Passed object must be a class.")
attrs = getattr(cls, "__attrs_attrs__", None)
if attrs is None:
@@ -2542,7 +2539,7 @@
bound_setattr(
"metadata",
(
- metadata_proxy(metadata)
+ types.MappingProxyType(dict(metadata)) # Shallow copy
if metadata
else _empty_metadata_singleton
),
@@ -2628,7 +2625,7 @@
else:
bound_setattr(
name,
- metadata_proxy(value)
+ types.MappingProxyType(dict(value))
if value
else _empty_metadata_singleton,
)
@@ -2904,7 +2901,7 @@
if user_init is not None:
body["__init__"] = user_init
- type_ = new_class(name, bases, {}, lambda ns: ns.update(body))
+ type_ = types.new_class(name, bases, {}, lambda ns: ns.update(body))
# For pickling to work, the __module__ variable needs to be set to the
# frame where the class is created. Bypass this step in environments where
diff --git a/src/attr/filters.py b/src/attr/filters.py
index e7432e4..baa25e9 100644
--- a/src/attr/filters.py
+++ b/src/attr/filters.py
@@ -4,8 +4,6 @@
Commonly useful filters for `attr.asdict`.
"""
-
-from ._compat import isclass
from ._make import Attribute
@@ -14,7 +12,7 @@
Returns a tuple of `frozenset`s of classes and attributes.
"""
return (
- frozenset(cls for cls in what if isclass(cls)),
+ frozenset(cls for cls in what if isinstance(cls, type)),
frozenset(cls for cls in what if isinstance(cls, Attribute)),
)
diff --git a/tests/test_compat.py b/tests/test_compat.py
index 464b492..4a156c4 100644
--- a/tests/test_compat.py
+++ b/tests/test_compat.py
@@ -1,18 +1,18 @@
# SPDX-License-Identifier: MIT
-import pytest
+import types
-from attr._compat import metadata_proxy
+import pytest
@pytest.fixture(name="mp")
def _mp():
- return metadata_proxy({"x": 42, "y": "foo"})
+ return types.MappingProxyType({"x": 42, "y": "foo"})
class TestMetadataProxy:
"""
- Ensure properties of metadata_proxy independently of hypothesis strategies.
+ Ensure properties of metadata proxy independently of hypothesis strategies.
"""
def test_repr(self, mp):
diff --git a/tests/test_funcs.py b/tests/test_funcs.py
index 40c5487..d73d94c 100644
--- a/tests/test_funcs.py
+++ b/tests/test_funcs.py
@@ -15,7 +15,7 @@
import attr
from attr import asdict, assoc, astuple, evolve, fields, has
-from attr._compat import TYPE, Mapping, Sequence, ordered_dict
+from attr._compat import Mapping, Sequence, ordered_dict
from attr.exceptions import AttrsAttributeNotFoundError
from attr.validators import instance_of
@@ -599,7 +599,7 @@
evolve(C(a=1), a="some string")
m = e.value.args[0]
- assert m.startswith("'a' must be <{type} 'int'>".format(type=TYPE))
+ assert m.startswith("'a' must be <class 'int'>")
def test_private(self):
"""
diff --git a/tests/test_functional.py b/tests/test_functional.py
index 0f3a48c..09f5048 100644
--- a/tests/test_functional.py
+++ b/tests/test_functional.py
@@ -17,7 +17,7 @@
import attr
-from attr._compat import PY36, TYPE
+from attr._compat import PY36
from attr._make import NOTHING, Attribute
from attr.exceptions import FrozenInstanceError
@@ -161,8 +161,7 @@
# Using C1 explicitly, since slotted classes don't support this.
assert (
- "'x' must be <{type} 'int'> (got '1' that is a <{type} "
- "'str'>).".format(type=TYPE),
+ "'x' must be <class 'int'> (got '1' that is a <class 'str'>).",
attr.fields(C1).x,
int,
"1",
diff --git a/tests/test_validators.py b/tests/test_validators.py
index 633f235..f3fe69c 100644
--- a/tests/test_validators.py
+++ b/tests/test_validators.py
@@ -13,7 +13,6 @@
from attr import _config, fields, has
from attr import validators as validator_module
-from attr._compat import TYPE
from attr.validators import (
and_,
deep_iterable,
@@ -143,8 +142,7 @@
with pytest.raises(TypeError) as e:
v(None, a, "42")
assert (
- "'test' must be <{type} 'int'> (got '42' that is a <{type} "
- "'str'>).".format(type=TYPE),
+ "'test' must be <class 'int'> (got '42' that is a <class 'str'>).",
a,
int,
"42",
@@ -155,9 +153,7 @@
Returned validator has a useful `__repr__`.
"""
v = instance_of(int)
- assert (
- "<instance_of validator for type <{type} 'int'>>".format(type=TYPE)
- ) == repr(v)
+ assert ("<instance_of validator for type <class 'int'>>") == repr(v)
class TestMatchesRe:
@@ -422,8 +418,7 @@
with pytest.raises(TypeError) as e:
v(None, a, "42")
assert (
- "'test' must be <{type} 'int'> (got '42' that is a <{type} "
- "'str'>).".format(type=TYPE),
+ "'test' must be <class 'int'> (got '42' that is a <class 'str'>).",
a,
int,
"42",
@@ -438,13 +433,13 @@
if isinstance(validator, list):
repr_s = (
"<optional validator for _AndValidator(_validators=[{func}, "
- "<instance_of validator for type <{type} 'int'>>]) or None>"
- ).format(func=repr(always_pass), type=TYPE)
+ "<instance_of validator for type <class 'int'>>]) or None>"
+ ).format(func=repr(always_pass))
else:
repr_s = (
"<optional validator for <instance_of validator for type "
- "<{type} 'int'>> or None>"
- ).format(type=TYPE)
+ "<class 'int'>> or None>"
+ )
assert repr_s == repr(v)
@@ -608,9 +603,7 @@
when only member validator is set.
"""
member_validator = instance_of(int)
- member_repr = "<instance_of validator for type <{type} 'int'>>".format(
- type=TYPE
- )
+ member_repr = "<instance_of validator for type <class 'int'>>"
v = deep_iterable(member_validator)
expected_repr = (
"<deep_iterable validator for iterables of {member_repr}>"
@@ -626,8 +619,8 @@
member_validator = [always_pass, instance_of(int)]
member_repr = (
"_AndValidator(_validators=({func}, "
- "<instance_of validator for type <{type} 'int'>>))"
- ).format(func=repr(always_pass), type=TYPE)
+ "<instance_of validator for type <class 'int'>>))"
+ ).format(func=repr(always_pass))
v = deep_iterable(member_validator)
expected_repr = (
"<deep_iterable validator for iterables of {member_repr}>"
@@ -640,13 +633,9 @@
and iterable validators are set.
"""
member_validator = instance_of(int)
- member_repr = "<instance_of validator for type <{type} 'int'>>".format(
- type=TYPE
- )
+ member_repr = "<instance_of validator for type <class 'int'>>"
iterable_validator = instance_of(list)
- iterable_repr = (
- "<instance_of validator for type <{type} 'list'>>"
- ).format(type=TYPE)
+ iterable_repr = "<instance_of validator for type <class 'list'>>"
v = deep_iterable(member_validator, iterable_validator)
expected_repr = (
"<deep_iterable validator for"
@@ -663,12 +652,10 @@
member_validator = [always_pass, instance_of(int)]
member_repr = (
"_AndValidator(_validators=({func}, "
- "<instance_of validator for type <{type} 'int'>>))"
- ).format(func=repr(always_pass), type=TYPE)
+ "<instance_of validator for type <class 'int'>>))"
+ ).format(func=repr(always_pass))
iterable_validator = instance_of(list)
- iterable_repr = (
- "<instance_of validator for type <{type} 'list'>>"
- ).format(type=TYPE)
+ iterable_repr = "<instance_of validator for type <class 'list'>>"
v = deep_iterable(member_validator, iterable_validator)
expected_repr = (
"<deep_iterable validator for"
@@ -767,13 +754,9 @@
Returned validator has a useful `__repr__`.
"""
key_validator = instance_of(str)
- key_repr = "<instance_of validator for type <{type} 'str'>>".format(
- type=TYPE
- )
+ key_repr = "<instance_of validator for type <class 'str'>>"
value_validator = instance_of(int)
- value_repr = "<instance_of validator for type <{type} 'int'>>".format(
- type=TYPE
- )
+ value_repr = "<instance_of validator for type <class 'int'>>"
v = deep_mapping(key_validator, value_validator)
expected_repr = (
"<deep_mapping validator for objects mapping "