diff --git a/scrapy/selector/lxmlsel.py b/scrapy/selector/lxmlsel.py
index ca56829f8..0234703cb 100644
--- a/scrapy/selector/lxmlsel.py
+++ b/scrapy/selector/lxmlsel.py
@@ -1,47 +1,50 @@
"""
XPath selectors based on lxml
"""
+from scrapy.utils.deprecate import create_deprecated_class
from .unified import Selector, SelectorList
__all__ = ['HtmlXPathSelector', 'XmlXPathSelector', 'XPathSelector',
'XPathSelectorList']
+def _xpathselector_css(self, *a, **kw):
+ raise RuntimeError('.css() method not available for %s, '
+ 'instantiate scrapy.selector.Selector '
+ 'instead' % type(self).__name__)
-class XPathSelector(Selector):
- __slots__ = ()
- _default_type = 'html'
+XPathSelector = create_deprecated_class(
+ 'XPathSelector',
+ Selector,
+ {
+ '__slots__': (),
+ '_default_type': 'html',
+ 'css': _xpathselector_css,
+ },
+ new_class_path='scrapy.selector.Selector',
+ old_class_path='scrapy.selector.XPathSelector',
+)
- def __init__(self, *a, **kw):
- import warnings
- from scrapy.exceptions import ScrapyDeprecationWarning
- warnings.warn('%s is deprecated, instantiate scrapy.selector.Selector '
- 'instead' % type(self).__name__,
- category=ScrapyDeprecationWarning, stacklevel=1)
- super(XPathSelector, self).__init__(*a, **kw)
+XmlXPathSelector = create_deprecated_class(
+ 'XmlXPathSelector',
+ XPathSelector,
+ clsdict={
+ '__slots__': (),
+ '_default_type': 'xml',
+ },
+ new_class_path='scrapy.selector.Selector',
+ old_class_path='scrapy.selector.XmlXPathSelector',
+)
- def css(self, *a, **kw):
- raise RuntimeError('.css() method not available for %s, '
- 'instantiate scrapy.selector.Selector '
- 'instead' % type(self).__name__)
+HtmlXPathSelector = create_deprecated_class(
+ 'HtmlXPathSelector',
+ XPathSelector,
+ clsdict={
+ '__slots__': (),
+ '_default_type': 'html',
+ },
+ new_class_path='scrapy.selector.Selector',
+ old_class_path='scrapy.selector.HtmlXPathSelector',
+)
-
-class XmlXPathSelector(XPathSelector):
- __slots__ = ()
- _default_type = 'xml'
-
-
-class HtmlXPathSelector(XPathSelector):
- __slots__ = ()
- _default_type = 'html'
-
-
-class XPathSelectorList(SelectorList):
-
- def __init__(self, *a, **kw):
- import warnings
- from scrapy.exceptions import ScrapyDeprecationWarning
- warnings.warn('XPathSelectorList is deprecated, instantiate '
- 'scrapy.selector.SelectorList instead',
- category=ScrapyDeprecationWarning, stacklevel=1)
- super(XPathSelectorList, self).__init__(*a, **kw)
+XPathSelectorList = create_deprecated_class('XPathSelectorList', SelectorList)
diff --git a/scrapy/tests/test_selector.py b/scrapy/tests/test_selector.py
index 5a14031fe..72f5ebdd5 100644
--- a/scrapy/tests/test_selector.py
+++ b/scrapy/tests/test_selector.py
@@ -1,4 +1,5 @@
import re
+import inspect
import warnings
import weakref
from twisted.trial import unittest
@@ -301,17 +302,83 @@ class DeprecatedXpathSelectorTest(unittest.TestCase):
text = '

Hello
'
- def test_warnings(self):
- for cls in XPathSelector, HtmlXPathSelector, XPathSelector:
- with warnings.catch_warnings(record=True) as w:
- warnings.simplefilter('always')
- hs = cls(text=self.text)
- assert len(w) == 1, w
- assert issubclass(w[0].category, ScrapyDeprecationWarning)
- assert 'deprecated' in str(w[-1].message)
- hs.select("//div").extract()
- assert issubclass(w[1].category, ScrapyDeprecationWarning)
- assert 'deprecated' in str(w[-1].message)
+ def test_warnings_xpathselector(self):
+ cls = XPathSelector
+ with warnings.catch_warnings(record=True) as w:
+ class UserClass(cls):
+ pass
+
+ # subclassing must issue a warning
+ self.assertEqual(len(w), 1, str(cls))
+ self.assertIn('scrapy.selector.Selector', str(w[0].message))
+
+ # subclass instance doesn't issue a warning
+ usel = UserClass(text=self.text)
+ self.assertEqual(len(w), 1)
+
+ # class instance must issue a warning
+ sel = cls(text=self.text)
+ self.assertEqual(len(w), 2, str((cls, [x.message for x in w])))
+ self.assertIn('scrapy.selector.Selector', str(w[1].message))
+
+ # subclass and instance checks
+ self.assertTrue(issubclass(cls, Selector))
+ self.assertTrue(isinstance(sel, Selector))
+ self.assertTrue(isinstance(usel, Selector))
+
+ def test_warnings_xmlxpathselector(self):
+ cls = XmlXPathSelector
+ with warnings.catch_warnings(record=True) as w:
+ class UserClass(cls):
+ pass
+
+ # subclassing must issue a warning
+ self.assertEqual(len(w), 1, str(cls))
+ self.assertIn('scrapy.selector.Selector', str(w[0].message))
+
+ # subclass instance doesn't issue a warning
+ usel = UserClass(text=self.text)
+ self.assertEqual(len(w), 1)
+
+ # class instance must issue a warning
+ sel = cls(text=self.text)
+ self.assertEqual(len(w), 2, str((cls, [x.message for x in w])))
+ self.assertIn('scrapy.selector.Selector', str(w[1].message))
+
+ # subclass and instance checks
+ self.assertTrue(issubclass(cls, Selector))
+ self.assertTrue(issubclass(cls, XPathSelector))
+ self.assertTrue(isinstance(sel, Selector))
+ self.assertTrue(isinstance(usel, Selector))
+ self.assertTrue(isinstance(sel, XPathSelector))
+ self.assertTrue(isinstance(usel, XPathSelector))
+
+ def test_warnings_htmlxpathselector(self):
+ cls = HtmlXPathSelector
+ with warnings.catch_warnings(record=True) as w:
+ class UserClass(cls):
+ pass
+
+ # subclassing must issue a warning
+ self.assertEqual(len(w), 1, str(cls))
+ self.assertIn('scrapy.selector.Selector', str(w[0].message))
+
+ # subclass instance doesn't issue a warning
+ usel = UserClass(text=self.text)
+ self.assertEqual(len(w), 1)
+
+ # class instance must issue a warning
+ sel = cls(text=self.text)
+ self.assertEqual(len(w), 2, str((cls, [x.message for x in w])))
+ self.assertIn('scrapy.selector.Selector', str(w[1].message))
+
+ # subclass and instance checks
+ self.assertTrue(issubclass(cls, Selector))
+ self.assertTrue(issubclass(cls, XPathSelector))
+ self.assertTrue(isinstance(sel, Selector))
+ self.assertTrue(isinstance(usel, Selector))
+ self.assertTrue(isinstance(sel, XPathSelector))
+ self.assertTrue(isinstance(usel, XPathSelector))
def test_xpathselector(self):
with warnings.catch_warnings(record=True):