From b3be6e210de837c54fc50cf62fc9e34a504c705e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gra=C3=B1a?= Date: Fri, 3 Jan 2014 17:32:40 -0200 Subject: [PATCH] warn XPathSelector deprecation on subclassing and direct instance --- scrapy/selector/lxmlsel.py | 71 +++++++++++++++------------- scrapy/tests/test_selector.py | 89 ++++++++++++++++++++++++++++++----- 2 files changed, 115 insertions(+), 45 deletions(-) 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):