Skip to content

Commit

Permalink
Deprecate itemadapter.utils.is_pydantic_instance
Browse files Browse the repository at this point in the history
  • Loading branch information
elacuesta committed Aug 18, 2021
1 parent 2746ae7 commit f9ea9b5
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 58 deletions.
5 changes: 0 additions & 5 deletions itemadapter/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
_is_attrs_class,
_is_dataclass,
_is_pydantic_model,
is_pydantic_instance,
is_scrapy_item,
)

Expand Down Expand Up @@ -155,10 +154,6 @@ class PydanticAdapter(AdapterInterface):

item: Any

@classmethod
def is_item(cls, item: Any) -> bool:
return is_pydantic_instance(item)

@classmethod
def is_item_class(cls, item_class: type) -> bool:
return _is_pydantic_model(item_class)
Expand Down
20 changes: 15 additions & 5 deletions itemadapter/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,6 @@ def _get_pydantic_model_metadata(item_model: Any, field_name: str) -> MappingPro
return MappingProxyType(metadata)


def is_pydantic_instance(obj: Any) -> bool:
"""Return True if the given object is a Pydantic model, False otherwise."""
return _is_pydantic_model(type(obj)) and not isinstance(obj, type)


def is_scrapy_item(obj: Any) -> bool:
"""Return True if the given object is a Scrapy item, False otherwise."""
try:
Expand Down Expand Up @@ -126,6 +121,9 @@ def get_field_meta_from_class(item_class: type, field_name: str) -> MappingProxy
return ItemAdapter.get_field_meta_from_class(item_class, field_name)


# deprecated


def is_dataclass_instance(obj: Any) -> bool:
warnings.warn(
"itemadapter.utils.is_dataclass_instance is deprecated"
Expand All @@ -148,3 +146,15 @@ def is_attrs_instance(obj: Any) -> bool:
from itemadapter.adapter import AttrsAdapter

return AttrsAdapter.is_item(obj)


def is_pydantic_instance(obj: Any) -> bool:
warnings.warn(
"itemadapter.utils.is_pydantic_instance is deprecated"
" and it will be removed in a future version",
category=DeprecationWarning,
stacklevel=2,
)
from itemadapter.adapter import PydanticAdapter

return PydanticAdapter.is_item(obj)
76 changes: 76 additions & 0 deletions tests/test_adapter_pydantic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import unittest
import warnings
from types import MappingProxyType
from unittest import mock

from itemadapter.adapter import PydanticAdapter
from itemadapter.utils import get_field_meta_from_class

from tests import (
AttrsItem,
DataClassItem,
PydanticModel,
PydanticSpecialCasesModel,
ScrapyItem,
ScrapySubclassedItem,
mocked_import,
)


class DataclassTestCase(unittest.TestCase):
def test_false(self):
self.assertFalse(PydanticAdapter.is_item(int))
self.assertFalse(PydanticAdapter.is_item(sum))
self.assertFalse(PydanticAdapter.is_item(1234))
self.assertFalse(PydanticAdapter.is_item(object()))
self.assertFalse(PydanticAdapter.is_item(ScrapyItem()))
self.assertFalse(PydanticAdapter.is_item(AttrsItem()))
self.assertFalse(PydanticAdapter.is_item(DataClassItem()))
self.assertFalse(PydanticAdapter.is_item(ScrapySubclassedItem()))
self.assertFalse(PydanticAdapter.is_item("a string"))
self.assertFalse(PydanticAdapter.is_item(b"some bytes"))
self.assertFalse(PydanticAdapter.is_item({"a": "dict"}))
self.assertFalse(PydanticAdapter.is_item(["a", "list"]))
self.assertFalse(PydanticAdapter.is_item(("a", "tuple")))
self.assertFalse(PydanticAdapter.is_item({"a", "set"}))
self.assertFalse(PydanticAdapter.is_item(PydanticModel))

@unittest.skipIf(not PydanticModel, "pydantic module is not available")
@mock.patch("builtins.__import__", mocked_import)
def test_module_not_available(self):
self.assertFalse(PydanticAdapter.is_item(PydanticModel(name="asdf", value=1234)))
with self.assertRaises(TypeError, msg="PydanticModel is not a valid item class"):
get_field_meta_from_class(PydanticModel, "name")

@unittest.skipIf(not PydanticModel, "pydantic module is not available")
def test_true(self):
self.assertTrue(PydanticAdapter.is_item(PydanticModel()))
self.assertTrue(PydanticAdapter.is_item(PydanticModel(name="asdf", value=1234)))
# field metadata
self.assertEqual(
get_field_meta_from_class(PydanticModel, "name"),
MappingProxyType({"serializer": str}),
)
self.assertEqual(
get_field_meta_from_class(PydanticModel, "value"),
MappingProxyType({"serializer": int}),
)
self.assertEqual(
get_field_meta_from_class(PydanticSpecialCasesModel, "special_cases"),
MappingProxyType({"alias": "special_cases", "allow_mutation": False}),
)
with self.assertRaises(KeyError, msg="PydanticModel does not support field: non_existent"):
get_field_meta_from_class(PydanticModel, "non_existent")

def test_deprecated_is_instance(self):
from itemadapter.utils import is_pydantic_instance

with warnings.catch_warnings(record=True) as caught:
is_pydantic_instance(1)
self.assertEqual(len(caught), 1)
self.assertTrue(issubclass(caught[0].category, DeprecationWarning))
self.assertEqual(
"itemadapter.utils.is_pydantic_instance is deprecated"
" and it will be removed in a future version",
str(caught[0].message),
)
48 changes: 0 additions & 48 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from itemadapter.utils import (
get_field_meta_from_class,
is_item,
is_pydantic_instance,
is_scrapy_item,
)
from itemadapter import ItemAdapter
Expand All @@ -14,7 +13,6 @@
AttrsItem,
DataClassItem,
PydanticModel,
PydanticSpecialCasesModel,
ScrapyItem,
ScrapySubclassedItem,
mocked_import,
Expand Down Expand Up @@ -84,52 +82,6 @@ def test_true_pydantic(self):
self.assertTrue(ItemAdapter.is_item_class(PydanticModel))


class PydanticTestCase(unittest.TestCase):
def test_false(self):
self.assertFalse(is_pydantic_instance(int))
self.assertFalse(is_pydantic_instance(sum))
self.assertFalse(is_pydantic_instance(1234))
self.assertFalse(is_pydantic_instance(object()))
self.assertFalse(is_pydantic_instance(ScrapyItem()))
self.assertFalse(is_pydantic_instance(AttrsItem()))
self.assertFalse(is_pydantic_instance(DataClassItem()))
self.assertFalse(is_pydantic_instance(ScrapySubclassedItem()))
self.assertFalse(is_pydantic_instance("a string"))
self.assertFalse(is_pydantic_instance(b"some bytes"))
self.assertFalse(is_pydantic_instance({"a": "dict"}))
self.assertFalse(is_pydantic_instance(["a", "list"]))
self.assertFalse(is_pydantic_instance(("a", "tuple")))
self.assertFalse(is_pydantic_instance({"a", "set"}))
self.assertFalse(is_pydantic_instance(PydanticModel))

@unittest.skipIf(not PydanticModel, "pydantic module is not available")
@mock.patch("builtins.__import__", mocked_import)
def test_module_not_available(self):
self.assertFalse(is_pydantic_instance(PydanticModel(name="asdf", value=1234)))
with self.assertRaises(TypeError, msg="PydanticModel is not a valid item class"):
get_field_meta_from_class(PydanticModel, "name")

@unittest.skipIf(not PydanticModel, "pydantic module is not available")
def test_true(self):
self.assertTrue(is_pydantic_instance(PydanticModel()))
self.assertTrue(is_pydantic_instance(PydanticModel(name="asdf", value=1234)))
# field metadata
self.assertEqual(
get_field_meta_from_class(PydanticModel, "name"),
MappingProxyType({"serializer": str}),
)
self.assertEqual(
get_field_meta_from_class(PydanticModel, "value"),
MappingProxyType({"serializer": int}),
)
self.assertEqual(
get_field_meta_from_class(PydanticSpecialCasesModel, "special_cases"),
MappingProxyType({"alias": "special_cases", "allow_mutation": False}),
)
with self.assertRaises(KeyError, msg="PydanticModel does not support field: non_existent"):
get_field_meta_from_class(PydanticModel, "non_existent")


class ScrapyItemTestCase(unittest.TestCase):
def test_false(self):
self.assertFalse(is_scrapy_item(int))
Expand Down

0 comments on commit f9ea9b5

Please sign in to comment.