Skip to content
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

Remove code and tests related to deprecated 'convert' kwarg #504

Merged
merged 5 commits into from
Mar 7, 2019
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: 2 additions & 0 deletions changelog.d/504.breaking.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Removed deprecated ``Attribute`` attribute ``convert`` per scheduled removal on 2019/1.
This planned deprecation is tracked in issue `#307 <https:/python-attrs/attrs/issues/307>`_.
2 changes: 1 addition & 1 deletion docs/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ If you don't set ``kw_only=True``, then there's is no valid attribute ordering a
... b = attr.ib()
Traceback (most recent call last):
...
ValueError: No mandatory attributes allowed after an attribute with a default value or factory. Attribute in question: Attribute(name='b', default=NOTHING, validator=None, repr=True, cmp=True, hash=None, init=True, convert=None, metadata=mappingproxy({}), type=None, kw_only=False)
ValueError: No mandatory attributes allowed after an attribute with a default value or factory. Attribute in question: Attribute(name='b', default=NOTHING, validator=None, repr=True, cmp=True, hash=None, init=True, converter=None, metadata=mappingproxy({}), type=None, kw_only=False)

.. _asdict:

Expand Down
4 changes: 2 additions & 2 deletions docs/extending.rst
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,10 @@ Here are some tips for effective use of metadata:

>>> MY_TYPE_METADATA = '__my_type_metadata'
>>>
>>> def typed(cls, default=attr.NOTHING, validator=None, repr=True, cmp=True, hash=None, init=True, convert=None, metadata={}):
>>> def typed(cls, default=attr.NOTHING, validator=None, repr=True, cmp=True, hash=None, init=True, metadata={}, type=None, converter=None):
... metadata = dict() if not metadata else metadata
... metadata[MY_TYPE_METADATA] = cls
... return attr.ib(default, validator, repr, cmp, hash, init, convert, metadata)
... return attr.ib(default, validator, repr, cmp, hash, init, metadata, type, converter)
>>>
>>> @attr.s
... class C(object):
Expand Down
4 changes: 0 additions & 4 deletions src/attr/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ def attrib(
cmp: bool = ...,
hash: Optional[bool] = ...,
init: bool = ...,
convert: None = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
type: None = ...,
converter: None = ...,
Expand All @@ -110,7 +109,6 @@ def attrib(
cmp: bool = ...,
hash: Optional[bool] = ...,
init: bool = ...,
convert: Optional[_ConverterType[_T]] = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
type: Optional[Type[_T]] = ...,
converter: Optional[_ConverterType[_T]] = ...,
Expand All @@ -127,7 +125,6 @@ def attrib(
cmp: bool = ...,
hash: Optional[bool] = ...,
init: bool = ...,
convert: Optional[_ConverterType[_T]] = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
type: Optional[Type[_T]] = ...,
converter: Optional[_ConverterType[_T]] = ...,
Expand All @@ -144,7 +141,6 @@ def attrib(
cmp: bool = ...,
hash: Optional[bool] = ...,
init: bool = ...,
convert: Optional[_ConverterType[_T]] = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
type: object = ...,
converter: Optional[_ConverterType[_T]] = ...,
Expand Down
43 changes: 1 addition & 42 deletions src/attr/_make.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ def attrib(
cmp=True,
hash=None,
init=True,
convert=None,
metadata=None,
type=None,
converter=None,
Expand Down Expand Up @@ -172,26 +171,13 @@ def attrib(
.. versionadded:: 18.1.0
``factory=f`` is syntactic sugar for ``default=attr.Factory(f)``.
.. versionadded:: 18.2.0 *kw_only*
.. versionchanged:: 19.2.0 *convert* keyword argument removed
"""
if hash is not None and hash is not True and hash is not False:
raise TypeError(
"Invalid value for hash. Must be True, False, or None."
)

if convert is not None:
if converter is not None:
raise RuntimeError(
"Can't pass both `convert` and `converter`. "
"Please use `converter` only."
)
warnings.warn(
"The `convert` argument is deprecated in favor of `converter`. "
"It will be removed after 2019/01.",
DeprecationWarning,
stacklevel=2,
)
converter = convert

if factory is not None:
if default is not NOTHING:
raise ValueError(
Expand Down Expand Up @@ -1706,7 +1692,6 @@ def __init__(
cmp,
hash,
init,
convert=None,
metadata=None,
type=None,
converter=None,
Expand All @@ -1717,20 +1702,6 @@ def __init__(

# Despite the big red warning, people *do* instantiate `Attribute`
# themselves.
if convert is not None:
if converter is not None:
raise RuntimeError(
"Can't pass both `convert` and `converter`. "
"Please use `converter` only."
)
warnings.warn(
"The `convert` argument is deprecated in favor of `converter`."
" It will be removed after 2019/01.",
DeprecationWarning,
stacklevel=2,
)
converter = convert

bound_setattr("name", name)
bound_setattr("default", default)
bound_setattr("validator", validator)
Expand All @@ -1753,16 +1724,6 @@ def __init__(
def __setattr__(self, name, value):
raise FrozenInstanceError()

@property
def convert(self):
warnings.warn(
"The `convert` attribute is deprecated in favor of `converter`. "
"It will be removed after 2019/01.",
DeprecationWarning,
stacklevel=2,
)
return self.converter

@classmethod
def from_counting_attr(cls, name, ca, type=None):
# type holds the annotated value. deal with conflicts:
Expand All @@ -1781,7 +1742,6 @@ def from_counting_attr(cls, name, ca, type=None):
"validator",
"default",
"type",
"convert",
) # exclude methods and deprecated alias
}
return cls(
Expand Down Expand Up @@ -1844,7 +1804,6 @@ def _setattrs(self, name_values_pairs):
init=True,
)
for name in Attribute.__slots__
if name != "convert" # XXX: remove once `convert` is gone
]

Attribute = _add_hash(
Expand Down
118 changes: 3 additions & 115 deletions tests/test_make.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,76 +143,6 @@ def f(self):
assert Factory(f, True) == a._default


class TestAttribute(object):
"""
Tests for `attr.Attribute`.
"""

def test_deprecated_convert_argument(self):
"""
Using *convert* raises a DeprecationWarning and sets the converter
field.
"""

def conv(v):
return v

with pytest.warns(DeprecationWarning) as wi:
a = Attribute(
"a", True, True, True, True, True, True, convert=conv
)
w = wi.pop()

assert conv == a.converter
assert (
"The `convert` argument is deprecated in favor of `converter`. "
"It will be removed after 2019/01.",
) == w.message.args
assert __file__ == w.filename

def test_deprecated_convert_attribute(self):
"""
If Attribute.convert is accessed, a DeprecationWarning is raised.
"""

def conv(v):
return v

a = simple_attr("a", converter=conv)
with pytest.warns(DeprecationWarning) as wi:
convert = a.convert
w = wi.pop()

assert conv is convert is a.converter
assert (
"The `convert` attribute is deprecated in favor of `converter`. "
"It will be removed after 2019/01.",
) == w.message.args
assert __file__ == w.filename

def test_convert_converter(self):
"""
A TypeError is raised if both *convert* and *converter* are passed.
"""
with pytest.raises(RuntimeError) as ei:
Attribute(
"a",
True,
True,
True,
True,
True,
True,
convert=lambda v: v,
converter=lambda v: v,
)

assert (
"Can't pass both `convert` and `converter`. "
"Please use `converter` only.",
) == ei.value.args


def make_tc():
class TransformC(object):
z = attr.ib()
Expand Down Expand Up @@ -1072,7 +1002,7 @@ def test_convert(self):
@given(integers(), booleans())
def test_convert_property(self, val, init):
"""
Property tests for attributes with convert.
Property tests for attributes using converter.
"""
C = make_class(
"C",
Expand All @@ -1089,9 +1019,9 @@ def test_convert_property(self, val, init):
assert c.y == 2

@given(integers(), booleans())
def test_convert_factory_property(self, val, init):
def test_converter_factory_property(self, val, init):
"""
Property tests for attributes with convert, and a factory default.
Property tests for attributes with converter, and a factory default.
"""
C = make_class(
"C",
Expand Down Expand Up @@ -1164,48 +1094,6 @@ def test_frozen(self):
)
C("1")

def test_deprecated_convert(self):
"""
Using *convert* raises a DeprecationWarning and sets the converter
field.
"""

def conv(v):
return v

with pytest.warns(DeprecationWarning) as wi:

@attr.s
class C(object):
x = attr.ib(convert=conv)

convert = fields(C).x.convert

assert 2 == len(wi.list)
w = wi.pop()

assert conv == fields(C).x.converter == convert
assert (
"The `convert` argument is deprecated in favor of `converter`. "
"It will be removed after 2019/01.",
) == w.message.args
assert __file__ == w.filename

def test_convert_converter(self):
"""
A TypeError is raised if both *convert* and *converter* are passed.
"""
with pytest.raises(RuntimeError) as ei:

@attr.s
class C(object):
x = attr.ib(convert=lambda v: v, converter=lambda v: v)

assert (
"Can't pass both `convert` and `converter`. "
"Please use `converter` only.",
) == ei.value.args


class TestValidate(object):
"""
Expand Down