Merge remote-tracking branch 'origin/master' into asyncio-base

This commit is contained in:
Andrey Rakhmatullin 2019-12-13 18:07:23 +05:00
commit 352ddbb336
129 changed files with 317 additions and 427 deletions

View File

@ -1,13 +1,15 @@
skips: skips:
- B101 - B101
- B105 - B105
- B301
- B303 - B303
- B306 - B306
- B307 - B307
- B311 - B311
- B320 - B320
- B321 - B321
- B402 - B402 # https://github.com/scrapy/scrapy/issues/4180
- B403
- B404 - B404
- B406 - B406
- B410 - B410

View File

@ -1,12 +1,19 @@
from pathlib import Path
import pytest import pytest
def _py_files(folder):
return (str(p) for p in Path(folder).rglob('*.py'))
collect_ignore = [ collect_ignore = [
# not a test, but looks like a test # not a test, but looks like a test
"scrapy/utils/testsite.py", "scrapy/utils/testsite.py",
# contains scripts to be run by tests/test_crawler.py::CrawlerProcessSubprocess
*_py_files("tests/CrawlerProcess")
] ]
for line in open('tests/ignores.txt'): for line in open('tests/ignores.txt'):
file_path = line.strip() file_path = line.strip()
if file_path and file_path[0] != '#': if file_path and file_path[0] != '#':

View File

@ -34,8 +34,8 @@ http://quotes.toscrape.com, following the pagination::
def parse(self, response): def parse(self, response):
for quote in response.css('div.quote'): for quote in response.css('div.quote'):
yield { yield {
'text': quote.css('span.text::text').get(),
'author': quote.xpath('span/small/text()').get(), 'author': quote.xpath('span/small/text()').get(),
'text': quote.css('span.text::text').get(),
} }
next_page = response.css('li.next a::attr("href")').get() next_page = response.css('li.next a::attr("href")').get()

View File

@ -1,5 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python
from __future__ import print_function
from time import time from time import time
from collections import deque from collections import deque
from twisted.web.server import Site, NOT_DONE_YET from twisted.web.server import Site, NOT_DONE_YET

View File

@ -2,7 +2,6 @@ parsel>=1.5.0
PyDispatcher>=2.0.5 PyDispatcher>=2.0.5
Twisted>=17.9.0 Twisted>=17.9.0
w3lib>=1.17.0 w3lib>=1.17.0
protego>=0.1.15
pyOpenSSL>=16.2.0 # Earlier versions fail with "AttributeError: module 'lib' has no attribute 'SSL_ST_INIT'" pyOpenSSL>=16.2.0 # Earlier versions fail with "AttributeError: module 'lib' has no attribute 'SSL_ST_INIT'"
queuelib>=1.4.2 # Earlier versions fail with "AttributeError: '...QueueTest' object has no attribute 'qpath'" queuelib>=1.4.2 # Earlier versions fail with "AttributeError: '...QueueTest' object has no attribute 'qpath'"
@ -14,5 +13,4 @@ cryptography>=2.0 # Earlier versions would fail to install
cssselect>=0.9.1 cssselect>=0.9.1
lxml>=3.5.0 lxml>=3.5.0
service_identity>=16.0.0 service_identity>=16.0.0
six>=1.10.0
zope.interface>=4.1.3 zope.interface>=4.1.3

View File

@ -24,7 +24,7 @@ warnings.filterwarnings('ignore', category=DeprecationWarning, module='twisted')
del warnings del warnings
# Apply monkey patches to fix issues in external libraries # Apply monkey patches to fix issues in external libraries
from . import _monkeypatches from scrapy import _monkeypatches
del _monkeypatches del _monkeypatches
from twisted import version as _txv from twisted import version as _txv

View File

@ -1,4 +1,4 @@
from six.moves import copyreg import copyreg
# Undo what Twisted's perspective broker adds to pickle register # Undo what Twisted's perspective broker adds to pickle register

View File

@ -1,4 +1,3 @@
from __future__ import print_function
import sys import sys
import os import os
import optparse import optparse

View File

@ -1,8 +1,7 @@
import sys import sys
import time import time
import subprocess import subprocess
from urllib.parse import urlencode
from six.moves.urllib.parse import urlencode
import scrapy import scrapy
from scrapy.commands import ScrapyCommand from scrapy.commands import ScrapyCommand

View File

@ -1,4 +1,3 @@
from __future__ import print_function
import sys import sys
from w3lib.url import is_url from w3lib.url import is_url

View File

@ -1,4 +1,3 @@
from __future__ import print_function
import os import os
import shutil import shutil
import string import string

View File

@ -1,4 +1,3 @@
from __future__ import print_function
from scrapy.commands import ScrapyCommand from scrapy.commands import ScrapyCommand

View File

@ -1,4 +1,3 @@
from __future__ import print_function
import json import json
import logging import logging

View File

@ -1,4 +1,3 @@
from __future__ import print_function
import json import json
from scrapy.commands import ScrapyCommand from scrapy.commands import ScrapyCommand

View File

@ -1,4 +1,3 @@
from __future__ import print_function
import re import re
import os import os
import string import string

View File

@ -1,5 +1,3 @@
from __future__ import print_function
import scrapy import scrapy
from scrapy.commands import ScrapyCommand from scrapy.commands import ScrapyCommand
from scrapy.utils.versions import scrapy_components_versions from scrapy.utils.versions import scrapy_components_versions

View File

@ -4,7 +4,7 @@ from scrapy.item import BaseItem
from scrapy.http import Request from scrapy.http import Request
from scrapy.exceptions import ContractFail from scrapy.exceptions import ContractFail
from . import Contract from scrapy.contracts import Contract
# contracts # contracts

View File

@ -3,15 +3,14 @@ from time import time
from datetime import datetime from datetime import datetime
from collections import deque from collections import deque
import six
from twisted.internet import reactor, defer, task from twisted.internet import reactor, defer, task
from scrapy.utils.defer import mustbe_deferred from scrapy.utils.defer import mustbe_deferred
from scrapy.utils.httpobj import urlparse_cached from scrapy.utils.httpobj import urlparse_cached
from scrapy.resolver import dnscache from scrapy.resolver import dnscache
from scrapy import signals from scrapy import signals
from .middleware import DownloaderMiddlewareManager from scrapy.core.downloader.middleware import DownloaderMiddlewareManager
from .handlers import DownloadHandlers from scrapy.core.downloader.handlers import DownloadHandlers
class Slot(object): class Slot(object):
@ -188,7 +187,7 @@ class Downloader(object):
def close(self): def close(self):
self._slot_gc_loop.stop() self._slot_gc_loop.stop()
for slot in six.itervalues(self.slots): for slot in self.slots.values():
slot.close() slot.close()
def _slot_gc(self, age=60): def _slot_gc(self, age=60):

View File

@ -1,8 +1,9 @@
"""Download handlers for different schemes""" """Download handlers for different schemes"""
import logging import logging
from twisted.internet import defer from twisted.internet import defer
import six
from scrapy.exceptions import NotSupported, NotConfigured from scrapy.exceptions import NotSupported, NotConfigured
from scrapy.utils.httpobj import urlparse_cached from scrapy.utils.httpobj import urlparse_cached
from scrapy.utils.misc import load_object from scrapy.utils.misc import load_object
@ -22,7 +23,7 @@ class DownloadHandlers(object):
self._notconfigured = {} # remembers failed handlers self._notconfigured = {} # remembers failed handlers
handlers = without_none_values( handlers = without_none_values(
crawler.settings.getwithbase('DOWNLOAD_HANDLERS')) crawler.settings.getwithbase('DOWNLOAD_HANDLERS'))
for scheme, clspath in six.iteritems(handlers): for scheme, clspath in handlers.items():
self._schemes[scheme] = clspath self._schemes[scheme] = clspath
self._load_handler(scheme, skip_lazy=True) self._load_handler(scheme, skip_lazy=True)

View File

@ -30,7 +30,7 @@ In case of status 200 request, response.headers will come with two keys:
import re import re
from io import BytesIO from io import BytesIO
from six.moves.urllib.parse import unquote from urllib.parse import unquote
from twisted.internet import reactor from twisted.internet import reactor
from twisted.protocols.ftp import FTPClient, CommandFailed from twisted.protocols.ftp import FTPClient, CommandFailed

View File

@ -1,2 +1,4 @@
from .http10 import HTTP10DownloadHandler from scrapy.core.downloader.handlers.http10 import HTTP10DownloadHandler
from .http11 import HTTP11DownloadHandler as HTTPDownloadHandler from scrapy.core.downloader.handlers.http11 import (
HTTP11DownloadHandler as HTTPDownloadHandler,
)

View File

@ -2,10 +2,10 @@
import re import re
import logging import logging
import warnings
from io import BytesIO from io import BytesIO
from time import time from time import time
import warnings from urllib.parse import urldefrag
from six.moves.urllib.parse import urldefrag
from zope.interface import implementer from zope.interface import implementer
from twisted.internet import defer, reactor, protocol from twisted.internet import defer, reactor, protocol

View File

@ -1,9 +1,9 @@
from six.moves.urllib.parse import unquote from urllib.parse import unquote
from scrapy.exceptions import NotConfigured from scrapy.exceptions import NotConfigured
from scrapy.utils.httpobj import urlparse_cached from scrapy.utils.httpobj import urlparse_cached
from scrapy.utils.boto import is_botocore from scrapy.utils.boto import is_botocore
from .http import HTTPDownloadHandler from scrapy.core.downloader.handlers.http import HTTPDownloadHandler
def _get_boto_connection(): def _get_boto_connection():

View File

@ -3,8 +3,6 @@ Downloader Middleware manager
See documentation in docs/topics/downloader-middleware.rst See documentation in docs/topics/downloader-middleware.rst
""" """
import six
from twisted.internet import defer from twisted.internet import defer
from scrapy.exceptions import _InvalidOutput from scrapy.exceptions import _InvalidOutput
@ -38,7 +36,7 @@ class DownloaderMiddlewareManager(MiddlewareManager):
response = yield method(request=request, spider=spider) response = yield method(request=request, spider=spider)
if response is not None and not isinstance(response, (Response, Request)): if response is not None and not isinstance(response, (Response, Request)):
raise _InvalidOutput('Middleware %s.process_request must return None, Response or Request, got %s' % \ raise _InvalidOutput('Middleware %s.process_request must return None, Response or Request, got %s' % \
(six.get_method_self(method).__class__.__name__, response.__class__.__name__)) (method.__self__.__class__.__name__, response.__class__.__name__))
if response: if response:
defer.returnValue(response) defer.returnValue(response)
defer.returnValue((yield download_func(request=request, spider=spider))) defer.returnValue((yield download_func(request=request, spider=spider)))
@ -53,7 +51,7 @@ class DownloaderMiddlewareManager(MiddlewareManager):
response = yield method(request=request, response=response, spider=spider) response = yield method(request=request, response=response, spider=spider)
if not isinstance(response, (Response, Request)): if not isinstance(response, (Response, Request)):
raise _InvalidOutput('Middleware %s.process_response must return Response or Request, got %s' % \ raise _InvalidOutput('Middleware %s.process_response must return Response or Request, got %s' % \
(six.get_method_self(method).__class__.__name__, type(response))) (method.__self__.__class__.__name__, type(response)))
if isinstance(response, Request): if isinstance(response, Request):
defer.returnValue(response) defer.returnValue(response)
defer.returnValue(response) defer.returnValue(response)
@ -65,7 +63,7 @@ class DownloaderMiddlewareManager(MiddlewareManager):
response = yield method(request=request, exception=exception, spider=spider) response = yield method(request=request, exception=exception, spider=spider)
if response is not None and not isinstance(response, (Response, Request)): if response is not None and not isinstance(response, (Response, Request)):
raise _InvalidOutput('Middleware %s.process_exception must return None, Response or Request, got %s' % \ raise _InvalidOutput('Middleware %s.process_exception must return None, Response or Request, got %s' % \
(six.get_method_self(method).__class__.__name__, type(response))) (method.__self__.__class__.__name__, type(response)))
if response: if response:
defer.returnValue(response) defer.returnValue(response)
defer.returnValue(_failure) defer.returnValue(_failure)

View File

@ -1,5 +1,5 @@
from time import time from time import time
from six.moves.urllib.parse import urlparse, urlunparse, urldefrag from urllib.parse import urlparse, urlunparse, urldefrag
from twisted.web.client import HTTPClientFactory from twisted.web.client import HTTPClientFactory
from twisted.web.http import HTTPClient from twisted.web.http import HTTPClient

View File

@ -5,7 +5,6 @@ See documentation in docs/topics/spider-middleware.rst
""" """
from itertools import chain, islice from itertools import chain, islice
import six
from twisted.python.failure import Failure from twisted.python.failure import Failure
from scrapy.exceptions import _InvalidOutput from scrapy.exceptions import _InvalidOutput
from scrapy.middleware import MiddlewareManager from scrapy.middleware import MiddlewareManager
@ -37,8 +36,8 @@ class SpiderMiddlewareManager(MiddlewareManager):
def scrape_response(self, scrape_func, response, request, spider): def scrape_response(self, scrape_func, response, request, spider):
fname = lambda f: '%s.%s' % ( fname = lambda f: '%s.%s' % (
six.get_method_self(f).__class__.__name__, f.__self__.__class__.__name__,
six.get_method_function(f).__name__) f.__func__.__name__)
def process_spider_input(response): def process_spider_input(response):
for method in self.methods['process_spider_input']: for method in self.methods['process_spider_input']:

View File

@ -1,7 +1,6 @@
import pprint
import six
import signal
import logging import logging
import pprint
import signal
import warnings import warnings
from twisted.internet import reactor, defer from twisted.internet import reactor, defer
@ -22,6 +21,7 @@ from scrapy.utils.log import (
get_scrapy_root_handler, install_scrapy_root_handler) get_scrapy_root_handler, install_scrapy_root_handler)
from scrapy import signals from scrapy import signals
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -206,7 +206,7 @@ class CrawlerRunner(object):
return self._create_crawler(crawler_or_spidercls) return self._create_crawler(crawler_or_spidercls)
def _create_crawler(self, spidercls): def _create_crawler(self, spidercls):
if isinstance(spidercls, six.string_types): if isinstance(spidercls, str):
spidercls = self.spider_loader.load(spidercls) spidercls = self.spider_loader.load(spidercls)
return Crawler(spidercls, self.settings) return Crawler(spidercls, self.settings)

View File

@ -1,9 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import absolute_import
import re import re
import logging import logging
import six
from w3lib import html from w3lib import html
from scrapy.exceptions import NotConfigured from scrapy.exceptions import NotConfigured
@ -67,7 +65,7 @@ class AjaxCrawlMiddleware(object):
# XXX: move it to w3lib? # XXX: move it to w3lib?
_ajax_crawlable_re = re.compile(six.u(r'<meta\s+name=["\']fragment["\']\s+content=["\']!["\']/?>')) _ajax_crawlable_re = re.compile(r'<meta\s+name=["\']fragment["\']\s+content=["\']!["\']/?>')
def _has_ajaxcrawlable_meta(text): def _has_ajaxcrawlable_meta(text):

View File

@ -1,13 +1,12 @@
import logging import logging
from collections import defaultdict from collections import defaultdict
import six
from scrapy.exceptions import NotConfigured from scrapy.exceptions import NotConfigured
from scrapy.http import Response from scrapy.http import Response
from scrapy.http.cookies import CookieJar from scrapy.http.cookies import CookieJar
from scrapy.utils.python import to_unicode from scrapy.utils.python import to_unicode
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -82,8 +81,10 @@ class CookiesMiddleware(object):
def _get_request_cookies(self, jar, request): def _get_request_cookies(self, jar, request):
if isinstance(request.cookies, dict): if isinstance(request.cookies, dict):
cookie_list = [{'name': k, 'value': v} for k, v in \ cookie_list = [
six.iteritems(request.cookies)] {'name': k, 'value': v}
for k, v in request.cookies.items()
]
else: else:
cookie_list = request.cookies cookie_list = request.cookies

View File

@ -4,16 +4,15 @@ and extract the potentially compressed responses that may arrive.
import bz2 import bz2
import gzip import gzip
from io import BytesIO
import zipfile
import tarfile
import logging import logging
import tarfile
import zipfile
from io import BytesIO
from tempfile import mktemp from tempfile import mktemp
import six
from scrapy.responsetypes import responsetypes from scrapy.responsetypes import responsetypes
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -75,7 +74,7 @@ class DecompressionMiddleware(object):
if not response.body: if not response.body:
return response return response
for fmt, func in six.iteritems(self._formats): for fmt, func in self._formats.items():
new_response = func(response) new_response = func(response)
if new_response: if new_response:
logger.debug('Decompressed response with format: %(responsefmt)s', logger.debug('Decompressed response with format: %(responsefmt)s',

View File

@ -1,8 +1,6 @@
import base64 import base64
from urllib.request import _parse_proxy from urllib.parse import unquote, urlunparse
from urllib.request import getproxies, proxy_bypass, _parse_proxy
from six.moves.urllib.parse import unquote, urlunparse
from six.moves.urllib.request import getproxies, proxy_bypass
from scrapy.exceptions import NotConfigured from scrapy.exceptions import NotConfigured
from scrapy.utils.httpobj import urlparse_cached from scrapy.utils.httpobj import urlparse_cached

View File

@ -1,5 +1,5 @@
import logging import logging
from six.moves.urllib.parse import urljoin, urlparse from urllib.parse import urljoin, urlparse
from w3lib.url import safe_url_string from w3lib.url import safe_url_string
@ -7,6 +7,7 @@ from scrapy.http import HtmlResponse
from scrapy.utils.response import get_meta_refresh from scrapy.utils.response import get_meta_refresh
from scrapy.exceptions import IgnoreRequest, NotConfigured from scrapy.exceptions import IgnoreRequest, NotConfigured
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View File

@ -1,4 +1,3 @@
from __future__ import print_function
import os import os
import logging import logging

View File

@ -6,15 +6,14 @@ import csv
import io import io
import pprint import pprint
import marshal import marshal
import six import warnings
from six.moves import cPickle as pickle import pickle
from xml.sax.saxutils import XMLGenerator from xml.sax.saxutils import XMLGenerator
from scrapy.utils.serialize import ScrapyJSONEncoder from scrapy.utils.serialize import ScrapyJSONEncoder
from scrapy.utils.python import to_bytes, to_unicode, is_listlike from scrapy.utils.python import to_bytes, to_unicode, is_listlike
from scrapy.item import BaseItem from scrapy.item import BaseItem
from scrapy.exceptions import ScrapyDeprecationWarning from scrapy.exceptions import ScrapyDeprecationWarning
import warnings
__all__ = ['BaseItemExporter', 'PprintItemExporter', 'PickleItemExporter', __all__ = ['BaseItemExporter', 'PprintItemExporter', 'PickleItemExporter',
@ -60,9 +59,9 @@ class BaseItemExporter(object):
include_empty = self.export_empty_fields include_empty = self.export_empty_fields
if self.fields_to_export is None: if self.fields_to_export is None:
if include_empty and not isinstance(item, dict): if include_empty and not isinstance(item, dict):
field_iter = six.iterkeys(item.fields) field_iter = item.fields.keys()
else: else:
field_iter = six.iterkeys(item) field_iter = item.keys()
else: else:
if include_empty: if include_empty:
field_iter = self.fields_to_export field_iter = self.fields_to_export
@ -180,7 +179,7 @@ class XmlItemExporter(BaseItemExporter):
for value in serialized_value: for value in serialized_value:
self._export_xml_field('value', value, depth=depth+1) self._export_xml_field('value', value, depth=depth+1)
self._beautify_indent(depth=depth) self._beautify_indent(depth=depth)
elif isinstance(serialized_value, six.text_type): elif isinstance(serialized_value, str):
self.xg.characters(serialized_value) self.xg.characters(serialized_value)
else: else:
self.xg.characters(str(serialized_value)) self.xg.characters(str(serialized_value))
@ -319,12 +318,12 @@ class PythonItemExporter(BaseItemExporter):
if is_listlike(value): if is_listlike(value):
return [self._serialize_value(v) for v in value] return [self._serialize_value(v) for v in value]
encode_func = to_bytes if self.binary else to_unicode encode_func = to_bytes if self.binary else to_unicode
if isinstance(value, (six.text_type, bytes)): if isinstance(value, (str, bytes)):
return encode_func(value, encoding=self.encoding) return encode_func(value, encoding=self.encoding)
return value return value
def _serialize_dict(self, value): def _serialize_dict(self, value):
for key, val in six.iteritems(value): for key, val in value.items():
key = to_bytes(key) if self.binary else key key = to_bytes(key) if self.binary else key
yield key, self._serialize_value(val) yield key, self._serialize_value(val)

View File

@ -10,7 +10,7 @@ import logging
import posixpath import posixpath
from tempfile import NamedTemporaryFile from tempfile import NamedTemporaryFile
from datetime import datetime from datetime import datetime
from six.moves.urllib.parse import urlparse, unquote from urllib.parse import urlparse, unquote
from ftplib import FTP from ftplib import FTP
from zope.interface import Interface, implementer from zope.interface import Interface, implementer

View File

@ -1,14 +1,12 @@
from __future__ import print_function
import gzip import gzip
import logging import logging
import os import os
import pickle
from email.utils import mktime_tz, parsedate_tz from email.utils import mktime_tz, parsedate_tz
from importlib import import_module from importlib import import_module
from time import time from time import time
from weakref import WeakKeyDictionary from weakref import WeakKeyDictionary
from six.moves import cPickle as pickle
from w3lib.http import headers_raw_to_dict, headers_dict_to_raw from w3lib.http import headers_raw_to_dict, headers_dict_to_raw
from scrapy.http import Headers, Response from scrapy.http import Headers, Response

View File

@ -5,7 +5,6 @@ See documentation in docs/topics/extensions.rst
""" """
import gc import gc
import six
from scrapy import signals from scrapy import signals
from scrapy.exceptions import NotConfigured from scrapy.exceptions import NotConfigured
@ -28,7 +27,7 @@ class MemoryDebugger(object):
def spider_closed(self, spider, reason): def spider_closed(self, spider, reason):
gc.collect() gc.collect()
self.stats.set_value('memdebug/gc_garbage_count', len(gc.garbage), spider=spider) self.stats.set_value('memdebug/gc_garbage_count', len(gc.garbage), spider=spider)
for cls, wdict in six.iteritems(live_refs): for cls, wdict in live_refs.items():
if not wdict: if not wdict:
continue continue
self.stats.set_value('memdebug/live_refs/%s' % cls.__name__, len(wdict), spider=spider) self.stats.set_value('memdebug/live_refs/%s' % cls.__name__, len(wdict), spider=spider)

View File

@ -1,5 +1,5 @@
import os import os
from six.moves import cPickle as pickle import pickle
from scrapy import signals from scrapy import signals
from scrapy.exceptions import NotConfigured from scrapy.exceptions import NotConfigured

View File

@ -1,7 +1,6 @@
import time import time
from six.moves.http_cookiejar import ( from http.cookiejar import CookieJar as _CookieJar, DefaultCookiePolicy, IPV4_RE
CookieJar as _CookieJar, DefaultCookiePolicy, IPV4_RE
)
from scrapy.utils.httpobj import urlparse_cached from scrapy.utils.httpobj import urlparse_cached
from scrapy.utils.python import to_unicode from scrapy.utils.python import to_unicode

View File

@ -1,4 +1,3 @@
import six
from w3lib.http import headers_dict_to_raw from w3lib.http import headers_dict_to_raw
from scrapy.utils.datatypes import CaselessDict from scrapy.utils.datatypes import CaselessDict
from scrapy.utils.python import to_unicode from scrapy.utils.python import to_unicode
@ -19,7 +18,7 @@ class Headers(CaselessDict):
"""Normalize values to bytes""" """Normalize values to bytes"""
if value is None: if value is None:
value = [] value = []
elif isinstance(value, (six.text_type, bytes)): elif isinstance(value, (str, bytes)):
value = [value] value = [value]
elif not hasattr(value, '__iter__'): elif not hasattr(value, '__iter__'):
value = [value] value = [value]
@ -29,10 +28,10 @@ class Headers(CaselessDict):
def _tobytes(self, x): def _tobytes(self, x):
if isinstance(x, bytes): if isinstance(x, bytes):
return x return x
elif isinstance(x, six.text_type): elif isinstance(x, str):
return x.encode(self.encoding) return x.encode(self.encoding)
elif isinstance(x, int): elif isinstance(x, int):
return six.text_type(x).encode(self.encoding) return str(x).encode(self.encoding)
else: else:
raise TypeError('Unsupported value type: {}'.format(type(x))) raise TypeError('Unsupported value type: {}'.format(type(x)))
@ -68,9 +67,6 @@ class Headers(CaselessDict):
self[key] = lst self[key] = lst
def items(self): def items(self):
return list(self.iteritems())
def iteritems(self):
return ((k, self.getlist(k)) for k in self.keys()) return ((k, self.getlist(k)) for k in self.keys())
def values(self): def values(self):

View File

@ -4,7 +4,6 @@ requests in Scrapy.
See documentation in docs/topics/request-response.rst See documentation in docs/topics/request-response.rst
""" """
import six
from w3lib.url import safe_url_string from w3lib.url import safe_url_string
from scrapy.http.headers import Headers from scrapy.http.headers import Headers
@ -60,7 +59,7 @@ class Request(object_ref):
return self._url return self._url
def _set_url(self, url): def _set_url(self, url):
if not isinstance(url, six.string_types): if not isinstance(url, str):
raise TypeError('Request url must be str or unicode, got %s:' % type(url).__name__) raise TypeError('Request url must be str or unicode, got %s:' % type(url).__name__)
s = safe_url_string(url, self.encoding) s = safe_url_string(url, self.encoding)

View File

@ -5,8 +5,7 @@ This module implements the FormRequest class which is a more convenient class
See documentation in docs/topics/request-response.rst See documentation in docs/topics/request-response.rst
""" """
import six from urllib.parse import urljoin, urlencode
from six.moves.urllib.parse import urljoin, urlencode
import lxml.html import lxml.html
from parsel.selector import create_root_node from parsel.selector import create_root_node
@ -208,7 +207,7 @@ def _get_clickable(clickdata, form):
# We didn't find it, so now we build an XPath expression out of the other # We didn't find it, so now we build an XPath expression out of the other
# arguments, because they can be used as such # arguments, because they can be used as such
xpath = u'.//*' + \ xpath = u'.//*' + \
u''.join(u'[@%s="%s"]' % c for c in six.iteritems(clickdata)) u''.join(u'[@%s="%s"]' % c for c in clickdata.items())
el = form.xpath(xpath) el = form.xpath(xpath)
if len(el) == 1: if len(el) == 1:
return (el[0].get('name'), el[0].get('value') or '') return (el[0].get('name'), el[0].get('value') or '')

View File

@ -4,7 +4,7 @@ This module implements the XmlRpcRequest class which is a more convenient class
See documentation in docs/topics/request-response.rst See documentation in docs/topics/request-response.rst
""" """
from six.moves import xmlrpc_client as xmlrpclib import xmlrpc.client as xmlrpclib
from scrapy.http.request import Request from scrapy.http.request import Request
from scrapy.utils.python import get_func_args from scrapy.utils.python import get_func_args

View File

@ -4,7 +4,7 @@ responses in Scrapy.
See documentation in docs/topics/request-response.rst See documentation in docs/topics/request-response.rst
""" """
from six.moves.urllib.parse import urljoin from urllib.parse import urljoin
from scrapy.http.request import Request from scrapy.http.request import Request
from scrapy.http.headers import Headers from scrapy.http.headers import Headers

View File

@ -5,8 +5,7 @@ discovering (through HTTP headers) to base Response class.
See documentation in docs/topics/request-response.rst See documentation in docs/topics/request-response.rst
""" """
import six from urllib.parse import urljoin
from six.moves.urllib.parse import urljoin
import parsel import parsel
from w3lib.encoding import html_to_unicode, resolve_encoding, \ from w3lib.encoding import html_to_unicode, resolve_encoding, \
@ -31,14 +30,14 @@ class TextResponse(Response):
super(TextResponse, self).__init__(*args, **kwargs) super(TextResponse, self).__init__(*args, **kwargs)
def _set_url(self, url): def _set_url(self, url):
if isinstance(url, six.text_type): if isinstance(url, str):
self._url = to_unicode(url, self.encoding) self._url = to_unicode(url, self.encoding)
else: else:
super(TextResponse, self)._set_url(url) super(TextResponse, self)._set_url(url)
def _set_body(self, body): def _set_body(self, body):
self._body = b'' # used by encoding detection self._body = b'' # used by encoding detection
if isinstance(body, six.text_type): if isinstance(body, str):
if self._encoding is None: if self._encoding is None:
raise TypeError('Cannot convert unicode body - %s has no encoding' % raise TypeError('Cannot convert unicode body - %s has no encoding' %
type(self).__name__) type(self).__name__)
@ -158,7 +157,7 @@ class TextResponse(Response):
def _url_from_selector(sel): def _url_from_selector(sel):
# type: (parsel.Selector) -> str # type: (parsel.Selector) -> str
if isinstance(sel.root, six.string_types): if isinstance(sel.root, str):
# e.g. ::attr(href) result # e.g. ::attr(href) result
return strip_html5_whitespace(sel.root) return strip_html5_whitespace(sel.root)
if not hasattr(sel.root, 'tag'): if not hasattr(sel.root, 'tag'):

View File

@ -10,8 +10,6 @@ from copy import deepcopy
from pprint import pformat from pprint import pformat
from warnings import warn from warnings import warn
import six
from scrapy.utils.deprecate import ScrapyDeprecationWarning from scrapy.utils.deprecate import ScrapyDeprecationWarning
from scrapy.utils.trackref import object_ref from scrapy.utils.trackref import object_ref
@ -78,7 +76,7 @@ class DictItem(MutableMapping, BaseItem):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self._values = {} self._values = {}
if args or kwargs: # avoid creating dict for most common case if args or kwargs: # avoid creating dict for most common case
for k, v in six.iteritems(dict(*args, **kwargs)): for k, v in dict(*args, **kwargs).items():
self[k] = v self[k] = v
def __getitem__(self, key): def __getitem__(self, key):
@ -130,6 +128,5 @@ class DictItem(MutableMapping, BaseItem):
return deepcopy(self) return deepcopy(self)
@six.add_metaclass(ItemMeta) class Item(DictItem, metaclass=ItemMeta):
class Item(DictItem):
pass pass

View File

@ -6,8 +6,8 @@ This package contains a collection of Link Extractors.
For more info see docs/topics/link-extractors.rst For more info see docs/topics/link-extractors.rst
""" """
import re import re
from urllib.parse import urlparse
from six.moves.urllib.parse import urlparse
from parsel.csstranslator import HTMLTranslator from parsel.csstranslator import HTMLTranslator
from w3lib.url import canonicalize_url from w3lib.url import canonicalize_url
@ -118,4 +118,4 @@ class FilteringLinkExtractor(object):
# Top-level imports # Top-level imports
from .lxmlhtml import LxmlLinkExtractor as LinkExtractor # noqa: F401 from scrapy.linkextractors.lxmlhtml import LxmlLinkExtractor as LinkExtractor # noqa: F401

View File

@ -2,9 +2,8 @@
HTMLParser-based link extractor HTMLParser-based link extractor
""" """
import warnings import warnings
import six from html.parser import HTMLParser
from six.moves.html_parser import HTMLParser from urllib.parse import urljoin
from six.moves.urllib.parse import urljoin
from w3lib.url import safe_url_string from w3lib.url import safe_url_string
from w3lib.html import strip_html5_whitespace from w3lib.html import strip_html5_whitespace
@ -42,7 +41,7 @@ class HtmlParserLinkExtractor(HTMLParser):
ret = [] ret = []
base_url = urljoin(response_url, self.base_url) if self.base_url else response_url base_url = urljoin(response_url, self.base_url) if self.base_url else response_url
for link in links: for link in links:
if isinstance(link.url, six.text_type): if isinstance(link.url, str):
link.url = link.url.encode(response_encoding) link.url = link.url.encode(response_encoding)
try: try:
link.url = urljoin(base_url, link.url) link.url = urljoin(base_url, link.url)

View File

@ -1,8 +1,7 @@
""" """
Link extractor based on lxml.html Link extractor based on lxml.html
""" """
import six from urllib.parse import urljoin
from six.moves.urllib.parse import urljoin
import lxml.etree as etree import lxml.etree as etree
from w3lib.html import strip_html5_whitespace from w3lib.html import strip_html5_whitespace
@ -22,7 +21,7 @@ _collect_string_content = etree.XPath("string()")
def _nons(tag): def _nons(tag):
if isinstance(tag, six.string_types): if isinstance(tag, str):
if tag[0] == '{' and tag[1:len(XHTML_NAMESPACE)+1] == XHTML_NAMESPACE: if tag[0] == '{' and tag[1:len(XHTML_NAMESPACE)+1] == XHTML_NAMESPACE:
return tag.split('}')[-1] return tag.split('}')[-1]
return tag return tag

View File

@ -1,10 +1,11 @@
import re import re
from six.moves.urllib.parse import urljoin from urllib.parse import urljoin
from w3lib.html import remove_tags, replace_entities, replace_escape_chars, get_base_url from w3lib.html import remove_tags, replace_entities, replace_escape_chars, get_base_url
from scrapy.link import Link from scrapy.link import Link
from .sgml import SgmlLinkExtractor from scrapy.linkextractors.sgml import SgmlLinkExtractor
linkre = re.compile( linkre = re.compile(
"<a\s.*?href=(\"[.#]+?\"|\'[.#]+?\'|[^\s]+?)(>|\s.*?>)(.*?)<[/ ]?a>", "<a\s.*?href=(\"[.#]+?\"|\'[.#]+?\'|[^\s]+?)(>|\s.*?>)(.*?)<[/ ]?a>",

View File

@ -1,9 +1,8 @@
""" """
SGMLParser-based Link extractors SGMLParser-based Link extractors
""" """
import six
from six.moves.urllib.parse import urljoin
import warnings import warnings
from urllib.parse import urljoin
from sgmllib import SGMLParser from sgmllib import SGMLParser
from w3lib.url import safe_url_string, canonicalize_url from w3lib.url import safe_url_string, canonicalize_url
@ -49,7 +48,7 @@ class BaseSgmlLinkExtractor(SGMLParser):
if base_url is None: if base_url is None:
base_url = urljoin(response_url, self.base_url) if self.base_url else response_url base_url = urljoin(response_url, self.base_url) if self.base_url else response_url
for link in self.links: for link in self.links:
if isinstance(link.url, six.text_type): if isinstance(link.url, str):
link.url = link.url.encode(response_encoding) link.url = link.url.encode(response_encoding)
try: try:
link.url = urljoin(base_url, link.url) link.url = urljoin(base_url, link.url)

View File

@ -3,21 +3,21 @@ Mail sending helpers
See documentation in docs/topics/email.rst See documentation in docs/topics/email.rst
""" """
from io import BytesIO
import logging import logging
from email.utils import COMMASPACE, formatdate
from six.moves.email_mime_multipart import MIMEMultipart
from six.moves.email_mime_text import MIMEText
from six.moves.email_mime_base import MIMEBase
from email.mime.nonmultipart import MIMENonMultipart
from email import encoders as Encoders from email import encoders as Encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.nonmultipart import MIMENonMultipart
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
from io import BytesIO
from twisted.internet import defer, reactor, ssl from twisted.internet import defer, reactor, ssl
from scrapy.utils.misc import arg_to_iter from scrapy.utils.misc import arg_to_iter
from scrapy.utils.python import to_bytes from scrapy.utils.python import to_bytes
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View File

@ -5,16 +5,14 @@ See documentation in topics/media-pipeline.rst
""" """
import functools import functools
import hashlib import hashlib
from io import BytesIO import logging
import mimetypes import mimetypes
import os import os
import os.path
import time import time
import logging
from email.utils import parsedate_tz, mktime_tz
from six.moves.urllib.parse import urlparse
from collections import defaultdict from collections import defaultdict
import six from email.utils import parsedate_tz, mktime_tz
from io import BytesIO
from urllib.parse import urlparse
from twisted.internet import defer, threads from twisted.internet import defer, threads
@ -29,6 +27,7 @@ from scrapy.utils.request import referer_str
from scrapy.utils.boto import is_botocore from scrapy.utils.boto import is_botocore
from scrapy.utils.datatypes import CaselessDict from scrapy.utils.datatypes import CaselessDict
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -153,14 +152,14 @@ class S3FilesStore(object):
Bucket=self.bucket, Bucket=self.bucket,
Key=key_name, Key=key_name,
Body=buf, Body=buf,
Metadata={k: str(v) for k, v in six.iteritems(meta or {})}, Metadata={k: str(v) for k, v in (meta or {}).items()},
ACL=self.POLICY, ACL=self.POLICY,
**extra) **extra)
else: else:
b = self._get_boto_bucket() b = self._get_boto_bucket()
k = b.new_key(key_name) k = b.new_key(key_name)
if meta: if meta:
for metakey, metavalue in six.iteritems(meta): for metakey, metavalue in meta.items():
k.set_metadata(metakey, str(metavalue)) k.set_metadata(metakey, str(metavalue))
h = self.HEADERS.copy() h = self.HEADERS.copy()
if headers: if headers:
@ -201,7 +200,7 @@ class S3FilesStore(object):
'X-Amz-Website-Redirect-Location': 'WebsiteRedirectLocation', 'X-Amz-Website-Redirect-Location': 'WebsiteRedirectLocation',
}) })
extra = {} extra = {}
for key, value in six.iteritems(headers): for key, value in headers.items():
try: try:
kwarg = mapping[key] kwarg = mapping[key]
except KeyError: except KeyError:
@ -249,7 +248,7 @@ class GCSFilesStore(object):
def persist_file(self, path, buf, info, meta=None, headers=None): def persist_file(self, path, buf, info, meta=None, headers=None):
blob = self.bucket.blob(self.prefix + path) blob = self.bucket.blob(self.prefix + path)
blob.cache_control = self.CACHE_CONTROL blob.cache_control = self.CACHE_CONTROL
blob.metadata = {k: str(v) for k, v in six.iteritems(meta or {})} blob.metadata = {k: str(v) for k, v in (meta or {}).items()}
return threads.deferToThread( return threads.deferToThread(
blob.upload_from_string, blob.upload_from_string,
data=buf.getvalue(), data=buf.getvalue(),

View File

@ -6,7 +6,6 @@ See documentation in topics/media-pipeline.rst
import functools import functools
import hashlib import hashlib
from io import BytesIO from io import BytesIO
import six
from PIL import Image from PIL import Image
@ -126,7 +125,7 @@ class ImagesPipeline(FilesPipeline):
image, buf = self.convert_image(orig_image) image, buf = self.convert_image(orig_image)
yield path, image, buf yield path, image, buf
for thumb_id, size in six.iteritems(self.thumbs): for thumb_id, size in self.thumbs.items():
thumb_path = self.thumb_path(request, thumb_id, response=response, info=info) thumb_path = self.thumb_path(request, thumb_id, response=response, info=info)
thumb_image, thumb_buf = self.convert_image(image, size) thumb_image, thumb_buf = self.convert_image(image, size)
yield thumb_path, thumb_image, thumb_buf yield thumb_path, thumb_image, thumb_buf

View File

@ -1,5 +1,3 @@
from __future__ import print_function
import functools import functools
import logging import logging
from collections import defaultdict from collections import defaultdict

View File

@ -2,11 +2,9 @@
This module implements a class which returns the appropriate Response class This module implements a class which returns the appropriate Response class
based on different criteria. based on different criteria.
""" """
from __future__ import absolute_import
from mimetypes import MimeTypes from mimetypes import MimeTypes
from pkgutil import get_data from pkgutil import get_data
from io import StringIO from io import StringIO
import six
from scrapy.http import Response from scrapy.http import Response
from scrapy.utils.misc import load_object from scrapy.utils.misc import load_object
@ -37,7 +35,7 @@ class ResponseTypes(object):
self.mimetypes = MimeTypes() self.mimetypes = MimeTypes()
mimedata = get_data('scrapy', 'mime.types').decode('utf8') mimedata = get_data('scrapy', 'mime.types').decode('utf8')
self.mimetypes.readfp(StringIO(mimedata)) self.mimetypes.readfp(StringIO(mimedata))
for mimetype, cls in six.iteritems(self.CLASSES): for mimetype, cls in self.CLASSES.items():
self.classes[mimetype] = load_object(cls) self.classes[mimetype] = load_object(cls)
def from_mimetype(self, mimetype): def from_mimetype(self, mimetype):

View File

@ -1,7 +1,6 @@
import sys import sys
import logging import logging
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
from six import with_metaclass
from scrapy.utils.python import to_unicode from scrapy.utils.python import to_unicode
@ -26,7 +25,7 @@ def decode_robotstxt(robotstxt_body, spider, to_native_str_type=False):
return robotstxt_body return robotstxt_body
class RobotParser(with_metaclass(ABCMeta)): class RobotParser(metaclass=ABCMeta):
@classmethod @classmethod
@abstractmethod @abstractmethod
def from_crawler(cls, crawler, robotstxt_body): def from_crawler(cls, crawler, robotstxt_body):
@ -56,7 +55,7 @@ class RobotParser(with_metaclass(ABCMeta)):
class PythonRobotParser(RobotParser): class PythonRobotParser(RobotParser):
def __init__(self, robotstxt_body, spider): def __init__(self, robotstxt_body, spider):
from six.moves.urllib_robotparser import RobotFileParser from urllib.robotparser import RobotFileParser
self.spider = spider self.spider = spider
robotstxt_body = decode_robotstxt(robotstxt_body, spider, to_native_str_type=True) robotstxt_body = decode_robotstxt(robotstxt_body, spider, to_native_str_type=True)
self.rp = RobotFileParser() self.rp = RobotFileParser()

View File

@ -1,4 +1,3 @@
import six
import json import json
import copy import copy
from collections.abc import MutableMapping from collections.abc import MutableMapping
@ -23,7 +22,7 @@ def get_settings_priority(priority):
:attr:`~scrapy.settings.SETTINGS_PRIORITIES` dictionary and returns its :attr:`~scrapy.settings.SETTINGS_PRIORITIES` dictionary and returns its
numerical value, or directly returns a given numerical priority. numerical value, or directly returns a given numerical priority.
""" """
if isinstance(priority, six.string_types): if isinstance(priority, str):
return SETTINGS_PRIORITIES[priority] return SETTINGS_PRIORITIES[priority]
else: else:
return priority return priority
@ -173,7 +172,7 @@ class BaseSettings(MutableMapping):
:type default: any :type default: any
""" """
value = self.get(name, default or []) value = self.get(name, default or [])
if isinstance(value, six.string_types): if isinstance(value, str):
value = value.split(',') value = value.split(',')
return list(value) return list(value)
@ -194,7 +193,7 @@ class BaseSettings(MutableMapping):
:type default: any :type default: any
""" """
value = self.get(name, default or {}) value = self.get(name, default or {})
if isinstance(value, six.string_types): if isinstance(value, str):
value = json.loads(value) value = json.loads(value)
return dict(value) return dict(value)
@ -284,7 +283,7 @@ class BaseSettings(MutableMapping):
:type priority: string or int :type priority: string or int
""" """
self._assert_mutability() self._assert_mutability()
if isinstance(module, six.string_types): if isinstance(module, str):
module = import_module(module) module = import_module(module)
for key in dir(module): for key in dir(module):
if key.isupper(): if key.isupper():
@ -313,14 +312,14 @@ class BaseSettings(MutableMapping):
:type priority: string or int :type priority: string or int
""" """
self._assert_mutability() self._assert_mutability()
if isinstance(values, six.string_types): if isinstance(values, str):
values = json.loads(values) values = json.loads(values)
if values is not None: if values is not None:
if isinstance(values, BaseSettings): if isinstance(values, BaseSettings):
for name, value in six.iteritems(values): for name, value in values.items():
self.set(name, value, values.getpriority(name)) self.set(name, value, values.getpriority(name))
else: else:
for name, value in six.iteritems(values): for name, value in values.items():
self.set(name, value, priority) self.set(name, value, priority)
def delete(self, name, priority='project'): def delete(self, name, priority='project'):
@ -377,7 +376,7 @@ class BaseSettings(MutableMapping):
def _to_dict(self): def _to_dict(self):
return {k: (v._to_dict() if isinstance(v, BaseSettings) else v) return {k: (v._to_dict() if isinstance(v, BaseSettings) else v)
for k, v in six.iteritems(self)} for k, v in self.items()}
def copy_to_dict(self): def copy_to_dict(self):
""" """
@ -445,7 +444,7 @@ class Settings(BaseSettings):
self.setmodule(default_settings, 'default') self.setmodule(default_settings, 'default')
# Promote default dictionaries to BaseSettings instances for per-key # Promote default dictionaries to BaseSettings instances for per-key
# priorities # priorities
for name, val in six.iteritems(self): for name, val in self.items():
if isinstance(val, dict): if isinstance(val, dict):
self.set(name, BaseSettings(val, 'default'), 'default') self.set(name, BaseSettings(val, 'default'), 'default')
self.update(values, priority) self.update(values, priority)

View File

@ -3,8 +3,6 @@
See documentation in docs/topics/shell.rst See documentation in docs/topics/shell.rst
""" """
from __future__ import print_function
import os import os
import signal import signal
import warnings import warnings

View File

@ -1,4 +1,3 @@
from __future__ import absolute_import
from pydispatch import dispatcher from pydispatch import dispatcher
from scrapy.utils import signal as _signal from scrapy.utils import signal as _signal

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import absolute_import
from collections import defaultdict from collections import defaultdict
import traceback import traceback
import warnings import warnings

View File

@ -2,8 +2,8 @@
RefererMiddleware: populates Request referer field, based on the Response which RefererMiddleware: populates Request referer field, based on the Response which
originated it. originated it.
""" """
from six.moves.urllib.parse import urlparse
import warnings import warnings
from urllib.parse import urlparse
from w3lib.url import safe_url_string from w3lib.url import safe_url_string

View File

@ -57,6 +57,11 @@ class Spider(object_ref):
def start_requests(self): def start_requests(self):
cls = self.__class__ cls = self.__class__
if not self.start_urls and hasattr(self, 'start_url'):
raise AttributeError(
"Crawling could not start: 'start_urls' not found "
"or empty (but found 'start_url' attribute instead, "
"did you miss an 's'?)")
if method_is_overridden(cls, Spider, 'make_requests_from_url'): if method_is_overridden(cls, Spider, 'make_requests_from_url'):
warnings.warn( warnings.warn(
"Spider.make_requests_from_url method is deprecated; it " "Spider.make_requests_from_url method is deprecated; it "

View File

@ -8,8 +8,6 @@ See documentation in docs/topics/spiders.rst
import copy import copy
import warnings import warnings
import six
from scrapy.exceptions import ScrapyDeprecationWarning from scrapy.exceptions import ScrapyDeprecationWarning
from scrapy.http import Request, HtmlResponse from scrapy.http import Request, HtmlResponse
from scrapy.linkextractors import LinkExtractor from scrapy.linkextractors import LinkExtractor
@ -25,7 +23,7 @@ def _identity(request, response):
def _get_method(method, spider): def _get_method(method, spider):
if callable(method): if callable(method):
return method return method
elif isinstance(method, six.string_types): elif isinstance(method, str):
return getattr(spider, method, None) return getattr(spider, method, None)

View File

@ -1,6 +1,5 @@
import re import re
import logging import logging
import six
from scrapy.spiders import Spider from scrapy.spiders import Spider
from scrapy.http import Request, XmlResponse from scrapy.http import Request, XmlResponse
@ -22,7 +21,7 @@ class SitemapSpider(Spider):
super(SitemapSpider, self).__init__(*a, **kw) super(SitemapSpider, self).__init__(*a, **kw)
self._cbs = [] self._cbs = []
for r, c in self.sitemap_rules: for r, c in self.sitemap_rules:
if isinstance(c, six.string_types): if isinstance(c, str):
c = getattr(self, c) c = getattr(self, c)
self._cbs.append((regex(r), c)) self._cbs.append((regex(r), c))
self._follow = [regex(x) for x in self.sitemap_follow] self._follow = [regex(x) for x in self.sitemap_follow]
@ -86,7 +85,7 @@ class SitemapSpider(Spider):
def regex(x): def regex(x):
if isinstance(x, six.string_types): if isinstance(x, str):
return re.compile(x) return re.compile(x)
return x return x

View File

@ -3,7 +3,7 @@ Scheduler queues
""" """
import marshal import marshal
from six.moves import cPickle as pickle import pickle
from queuelib import queue from queuelib import queue

View File

@ -1,5 +1,6 @@
import random import random
from six.moves.urllib.parse import urlencode from urllib.parse import urlencode
from twisted.web.server import Site from twisted.web.server import Site
from twisted.web.resource import Resource from twisted.web.resource import Resource
from twisted.internet import reactor from twisted.internet import reactor

View File

@ -1,7 +1,5 @@
"""Boto/botocore helpers""" """Boto/botocore helpers"""
from __future__ import absolute_import
from scrapy.exceptions import NotConfigured from scrapy.exceptions import NotConfigured

View File

@ -1,11 +1,9 @@
from configparser import ConfigParser
import os import os
import sys import sys
import numbers import numbers
from configparser import ConfigParser
from operator import itemgetter from operator import itemgetter
import six
from scrapy.settings import BaseSettings from scrapy.settings import BaseSettings
from scrapy.utils.deprecate import update_classpath from scrapy.utils.deprecate import update_classpath
from scrapy.utils.python import without_none_values from scrapy.utils.python import without_none_values
@ -22,7 +20,7 @@ def build_component_list(compdict, custom=None, convert=update_classpath):
def _map_keys(compdict): def _map_keys(compdict):
if isinstance(compdict, BaseSettings): if isinstance(compdict, BaseSettings):
compbs = BaseSettings() compbs = BaseSettings()
for k, v in six.iteritems(compdict): for k, v in compdict.items():
prio = compdict.getpriority(k) prio = compdict.getpriority(k)
if compbs.getpriority(convert(k)) == prio: if compbs.getpriority(convert(k)) == prio:
raise ValueError('Some paths in {!r} convert to the same ' raise ValueError('Some paths in {!r} convert to the same '
@ -33,11 +31,11 @@ def build_component_list(compdict, custom=None, convert=update_classpath):
return compbs return compbs
else: else:
_check_components(compdict) _check_components(compdict)
return {convert(k): v for k, v in six.iteritems(compdict)} return {convert(k): v for k, v in compdict.items()}
def _validate_values(compdict): def _validate_values(compdict):
"""Fail if a value in the components dict is not a real number or None.""" """Fail if a value in the components dict is not a real number or None."""
for name, value in six.iteritems(compdict): for name, value in compdict.items():
if value is not None and not isinstance(value, numbers.Real): if value is not None and not isinstance(value, numbers.Real):
raise ValueError('Invalid value {} for component {}, please provide ' \ raise ValueError('Invalid value {} for component {}, please provide ' \
'a real number or None instead'.format(value, name)) 'a real number or None instead'.format(value, name))
@ -53,7 +51,7 @@ def build_component_list(compdict, custom=None, convert=update_classpath):
_validate_values(compdict) _validate_values(compdict)
compdict = without_none_values(_map_keys(compdict)) compdict = without_none_values(_map_keys(compdict))
return [k for k, v in sorted(six.iteritems(compdict), key=itemgetter(1))] return [k for k, v in sorted(compdict.items(), key=itemgetter(1))]
def arglist_to_dict(arglist): def arglist_to_dict(arglist):

View File

@ -1,10 +1,9 @@
import argparse import argparse
import warnings import warnings
from shlex import split from shlex import split
from http.cookies import SimpleCookie
from urllib.parse import urlparse
from six.moves.http_cookies import SimpleCookie
from six.moves.urllib.parse import urlparse
from six import iteritems
from w3lib.http import basic_auth_header from w3lib.http import basic_auth_header
@ -76,7 +75,7 @@ def curl_to_request_kwargs(curl_command, ignore_unknown_options=True):
name = name.strip() name = name.strip()
val = val.strip() val = val.strip()
if name.title() == 'Cookie': if name.title() == 'Cookie':
for name, morsel in iteritems(SimpleCookie(val)): for name, morsel in SimpleCookie(val).items():
cookies[name] = morsel.value cookies[name] = morsel.value
else: else:
headers.append((name, val)) headers.append((name, val))

View File

@ -5,12 +5,10 @@ Python Standard Library.
This module must not depend on any module outside the Standard Library. This module must not depend on any module outside the Standard Library.
""" """
import copy
import collections import collections
from collections.abc import Mapping import copy
import warnings import warnings
from collections.abc import Mapping
import six
from scrapy.exceptions import ScrapyDeprecationWarning from scrapy.exceptions import ScrapyDeprecationWarning
@ -151,7 +149,7 @@ class MultiValueDict(dict):
self.setlistdefault(key, []).append(value) self.setlistdefault(key, []).append(value)
except TypeError: except TypeError:
raise ValueError("MultiValueDict.update() takes either a MultiValueDict or dictionary") raise ValueError("MultiValueDict.update() takes either a MultiValueDict or dictionary")
for key, value in six.iteritems(kwargs): for key, value in kwargs.items():
self.setlistdefault(key, []).append(value) self.setlistdefault(key, []).append(value)
@ -238,65 +236,6 @@ class CaselessDict(dict):
return dict.pop(self, self.normkey(key), *args) return dict.pop(self, self.normkey(key), *args)
class MergeDict(object):
"""
A simple class for creating new "virtual" dictionaries that actually look
up values in more than one dictionary, passed in the ``__init__`` method.
If a key appears in more than one of the given dictionaries, only the
first occurrence will be used.
"""
def __init__(self, *dicts):
warnings.warn(
"scrapy.utils.datatypes.MergeDict is deprecated in favor "
"of collections.ChainMap (introduced in Python 3.3)",
category=ScrapyDeprecationWarning,
stacklevel=2,
)
self.dicts = dicts
def __getitem__(self, key):
for dict_ in self.dicts:
try:
return dict_[key]
except KeyError:
pass
raise KeyError
def __copy__(self):
return self.__class__(*self.dicts)
def get(self, key, default=None):
try:
return self[key]
except KeyError:
return default
def getlist(self, key):
for dict_ in self.dicts:
if key in dict_.keys():
return dict_.getlist(key)
return []
def items(self):
item_list = []
for dict_ in self.dicts:
item_list.extend(dict_.items())
return item_list
def has_key(self, key):
for dict_ in self.dicts:
if key in dict_:
return True
return False
__contains__ = has_key
def copy(self):
"""Returns a copy of this object."""
return self.__copy__()
class LocalCache(collections.OrderedDict): class LocalCache(collections.OrderedDict):
"""Dictionary with a finite number of keys. """Dictionary with a finite number of keys.

View File

@ -2,7 +2,6 @@
pprint and pformat wrappers with colorization support pprint and pformat wrappers with colorization support
""" """
from __future__ import print_function
import sys import sys
from pprint import pformat as pformat_ from pprint import pformat as pformat_

View File

@ -1,8 +1,7 @@
"""Helper functions for scrapy.http objects (Request, Response)""" """Helper functions for scrapy.http objects (Request, Response)"""
import weakref import weakref
from urllib.parse import urlparse
from six.moves.urllib.parse import urlparse
_urlparse_cache = weakref.WeakKeyDictionary() _urlparse_cache = weakref.WeakKeyDictionary()

View File

@ -1,13 +1,13 @@
import re
import csv import csv
from io import StringIO
import logging import logging
import six import re
from io import StringIO
from scrapy.http import TextResponse, Response from scrapy.http import TextResponse, Response
from scrapy.selector import Selector from scrapy.selector import Selector
from scrapy.utils.python import re_rsearch, to_unicode from scrapy.utils.python import re_rsearch, to_unicode
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -60,7 +60,7 @@ class _StreamReader(object):
self._text, self.encoding = obj.body, obj.encoding self._text, self.encoding = obj.body, obj.encoding
else: else:
self._text, self.encoding = obj, 'utf-8' self._text, self.encoding = obj, 'utf-8'
self._is_unicode = isinstance(self._text, six.text_type) self._is_unicode = isinstance(self._text, str)
def read(self, n=65535): def read(self, n=65535):
self.read = self._read_unicode if self._is_unicode else self._read_string self.read = self._read_unicode if self._is_unicode else self._read_string
@ -125,7 +125,7 @@ def csviter(obj, delimiter=None, headers=None, encoding=None, quotechar=None):
def _body_or_str(obj, unicode=True): def _body_or_str(obj, unicode=True):
expected_types = (Response, six.text_type, six.binary_type) expected_types = (Response, str, bytes)
assert isinstance(obj, expected_types), \ assert isinstance(obj, expected_types), \
"obj must be %s, not %s" % ( "obj must be %s, not %s" % (
" or ".join(t.__name__ for t in expected_types), " or ".join(t.__name__ for t in expected_types),
@ -137,7 +137,7 @@ def _body_or_str(obj, unicode=True):
return obj.text return obj.text
else: else:
return obj.body.decode('utf-8') return obj.body.decode('utf-8')
elif isinstance(obj, six.text_type): elif isinstance(obj, str):
return obj if unicode else obj.encode('utf-8') return obj if unicode else obj.encode('utf-8')
else: else:
return obj.decode('utf-8') if unicode else obj return obj.decode('utf-8') if unicode else obj

View File

@ -6,14 +6,13 @@ from contextlib import contextmanager
from importlib import import_module from importlib import import_module
from pkgutil import iter_modules from pkgutil import iter_modules
import six
from w3lib.html import replace_entities from w3lib.html import replace_entities
from scrapy.utils.python import flatten, to_unicode from scrapy.utils.python import flatten, to_unicode
from scrapy.item import BaseItem from scrapy.item import BaseItem
_ITERABLE_SINGLE_VALUES = dict, BaseItem, six.text_type, bytes _ITERABLE_SINGLE_VALUES = dict, BaseItem, str, bytes
def arg_to_iter(arg): def arg_to_iter(arg):
@ -83,7 +82,7 @@ def extract_regex(regex, text, encoding='utf-8'):
* if the regex doesn't contain any group the entire regex matching is returned * if the regex doesn't contain any group the entire regex matching is returned
""" """
if isinstance(regex, six.string_types): if isinstance(regex, str):
regex = re.compile(regex, re.UNICODE) regex = re.compile(regex, re.UNICODE)
try: try:
@ -92,7 +91,7 @@ def extract_regex(regex, text, encoding='utf-8'):
strings = regex.findall(text) # full regex or numbered groups strings = regex.findall(text) # full regex or numbered groups
strings = flatten(strings) strings = flatten(strings)
if isinstance(text, six.text_type): if isinstance(text, str):
return [replace_entities(s, keep=['lt', 'amp']) for s in strings] return [replace_entities(s, keep=['lt', 'amp']) for s in strings]
else: else:
return [replace_entities(to_unicode(s, encoding), keep=['lt', 'amp']) return [replace_entities(to_unicode(s, encoding), keep=['lt', 'amp'])

View File

@ -1,5 +1,3 @@
from __future__ import absolute_import
import signal import signal
from twisted.internet import reactor from twisted.internet import reactor

View File

@ -1,5 +1,5 @@
import os import os
from six.moves import cPickle as pickle import pickle
import warnings import warnings
from importlib import import_module from importlib import import_module
@ -7,8 +7,8 @@ from os.path import join, dirname, abspath, isabs, exists
from scrapy.utils.conf import closest_scrapy_cfg, get_config, init_env from scrapy.utils.conf import closest_scrapy_cfg, get_config, init_env
from scrapy.settings import Settings from scrapy.settings import Settings
from scrapy.exceptions import NotConfigured from scrapy.exceptions import NotConfigured, ScrapyDeprecationWarning
from scrapy.exceptions import ScrapyDeprecationWarning
ENVVAR = 'SCRAPY_SETTINGS_MODULE' ENVVAR = 'SCRAPY_SETTINGS_MODULE'
DATADIR_CFG_SECTION = 'datadir' DATADIR_CFG_SECTION = 'datadir'

View File

@ -7,7 +7,6 @@ import re
import inspect import inspect
import weakref import weakref
import errno import errno
import six
from functools import partial, wraps from functools import partial, wraps
from itertools import chain from itertools import chain
import sys import sys
@ -65,10 +64,10 @@ def is_listlike(x):
True True
>>> is_listlike((x for x in range(3))) >>> is_listlike((x for x in range(3)))
True True
>>> is_listlike(six.moves.xrange(5)) >>> is_listlike(range(5))
True True
""" """
return hasattr(x, "__iter__") and not isinstance(x, (six.text_type, bytes)) return hasattr(x, "__iter__") and not isinstance(x, (str, bytes))
def unique(list_, key=lambda x: x): def unique(list_, key=lambda x: x):
@ -87,9 +86,9 @@ def unique(list_, key=lambda x: x):
def to_unicode(text, encoding=None, errors='strict'): def to_unicode(text, encoding=None, errors='strict'):
"""Return the unicode representation of a bytes object ``text``. If """Return the unicode representation of a bytes object ``text``. If
``text`` is already an unicode object, return it as-is.""" ``text`` is already an unicode object, return it as-is."""
if isinstance(text, six.text_type): if isinstance(text, str):
return text return text
if not isinstance(text, (bytes, six.text_type)): if not isinstance(text, (bytes, str)):
raise TypeError('to_unicode must receive a bytes or str ' raise TypeError('to_unicode must receive a bytes or str '
'object, got %s' % type(text).__name__) 'object, got %s' % type(text).__name__)
if encoding is None: if encoding is None:
@ -102,7 +101,7 @@ def to_bytes(text, encoding=None, errors='strict'):
is already a bytes object, return it as-is.""" is already a bytes object, return it as-is."""
if isinstance(text, bytes): if isinstance(text, bytes):
return text return text
if not isinstance(text, six.string_types): if not isinstance(text, str):
raise TypeError('to_bytes must receive a str or bytes ' raise TypeError('to_bytes must receive a str or bytes '
'object, got %s' % type(text).__name__) 'object, got %s' % type(text).__name__)
if encoding is None: if encoding is None:
@ -138,7 +137,7 @@ def re_rsearch(pattern, text, chunk_size=1024):
yield (text[offset:], offset) yield (text[offset:], offset)
yield (text, 0) yield (text, 0)
if isinstance(pattern, six.string_types): if isinstance(pattern, str):
pattern = re.compile(pattern) pattern = re.compile(pattern)
for chunk, offset in _chunk_iter(): for chunk, offset in _chunk_iter():
@ -162,7 +161,7 @@ def memoizemethod_noargs(method):
return new_method return new_method
_BINARYCHARS = {six.b(chr(i)) for i in range(32)} - {b"\0", b"\t", b"\n", b"\r"} _BINARYCHARS = {to_bytes(chr(i)) for i in range(32)} - {b"\0", b"\t", b"\n", b"\r"}
_BINARYCHARS |= {ord(ch) for ch in _BINARYCHARS} _BINARYCHARS |= {ord(ch) for ch in _BINARYCHARS}
@ -301,10 +300,10 @@ def stringify_dict(dct_or_tuples, encoding='utf-8', keys_only=True):
dict or a list of tuples, like any dict ``__init__`` method supports. dict or a list of tuples, like any dict ``__init__`` method supports.
""" """
d = {} d = {}
for k, v in six.iteritems(dict(dct_or_tuples)): for k, v in dict(dct_or_tuples).items():
k = k.encode(encoding) if isinstance(k, six.text_type) else k k = k.encode(encoding) if isinstance(k, str) else k
if not keys_only: if not keys_only:
v = v.encode(encoding) if isinstance(v, six.text_type) else v v = v.encode(encoding) if isinstance(v, str) else v
d[k] = v d[k] = v
return d return d
@ -346,7 +345,7 @@ def without_none_values(iterable):
value ``None`` have been removed. value ``None`` have been removed.
""" """
try: try:
return {k: v for k, v in six.iteritems(iterable) if v is not None} return {k: v for k, v in iterable.items() if v is not None}
except AttributeError: except AttributeError:
return type(iterable)((v for v in iterable if v is not None)) return type(iterable)((v for v in iterable if v is not None))

View File

@ -1,8 +1,6 @@
""" """
Helper functions for serializing (and deserializing) requests. Helper functions for serializing (and deserializing) requests.
""" """
import six
from scrapy.http import Request from scrapy.http import Request
from scrapy.utils.python import to_unicode from scrapy.utils.python import to_unicode
from scrapy.utils.misc import load_object from scrapy.utils.misc import load_object
@ -87,12 +85,12 @@ def _mangle_private_name(obj, func, name):
def _find_method(obj, func): def _find_method(obj, func):
if obj: if obj:
try: try:
func_self = six.get_method_self(func) func_self = func.__self__
except AttributeError: # func has no __self__ except AttributeError: # func has no __self__
pass pass
else: else:
if func_self is obj: if func_self is obj:
name = six.get_method_function(func).__name__ name = func.__func__.__name__
if _is_private_method(name): if _is_private_method(name):
return _mangle_private_name(obj, func, name) return _mangle_private_name(obj, func, name)
return name return name

View File

@ -3,16 +3,15 @@ This module provides some useful functions for working with
scrapy.http.Request objects scrapy.http.Request objects
""" """
from __future__ import print_function
import hashlib import hashlib
import weakref import weakref
from six.moves.urllib.parse import urlunparse from urllib.parse import urlunparse
from w3lib.http import basic_auth_header from w3lib.http import basic_auth_header
from scrapy.utils.python import to_bytes, to_unicode
from w3lib.url import canonicalize_url from w3lib.url import canonicalize_url
from scrapy.utils.httpobj import urlparse_cached from scrapy.utils.httpobj import urlparse_cached
from scrapy.utils.python import to_bytes, to_unicode
_fingerprint_cache = weakref.WeakKeyDictionary() _fingerprint_cache = weakref.WeakKeyDictionary()

View File

@ -5,8 +5,9 @@ Note: The main purpose of this module is to provide support for the
SitemapSpider, its API is subject to change without notice. SitemapSpider, its API is subject to change without notice.
""" """
from urllib.parse import urljoin
import lxml.etree import lxml.etree
from six.moves.urllib.parse import urljoin
class Sitemap(object): class Sitemap(object):

View File

@ -1,11 +1,10 @@
import logging import logging
import inspect import inspect
import six
from scrapy.spiders import Spider from scrapy.spiders import Spider
from scrapy.utils.misc import arg_to_iter from scrapy.utils.misc import arg_to_iter
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -21,7 +20,7 @@ def iter_spider_classes(module):
# singleton in scrapy.spider.spiders # singleton in scrapy.spider.spiders
from scrapy.spiders import Spider from scrapy.spiders import Spider
for obj in six.itervalues(vars(module)): for obj in vars(module).values():
if inspect.isclass(obj) and \ if inspect.isclass(obj) and \
issubclass(obj, Spider) and \ issubclass(obj, Spider) and \
obj.__module__ == module.__name__ and \ obj.__module__ == module.__name__ and \

View File

@ -2,7 +2,6 @@
This module contains some assorted functions used in tests This module contains some assorted functions used in tests
""" """
from __future__ import absolute_import
import os import os
from importlib import import_module from importlib import import_module

View File

@ -1,4 +1,3 @@
from __future__ import absolute_import
import sys import sys
import os import os

View File

@ -1,5 +1,4 @@
from __future__ import print_function from urllib.parse import urljoin
from six.moves.urllib.parse import urljoin
from twisted.internet import reactor from twisted.internet import reactor
from twisted.web import server, resource, static, util from twisted.web import server, resource, static, util

View File

@ -9,12 +9,10 @@ and no performance penalty at all when disabled (as object_ref becomes just an
alias to object in that case). alias to object in that case).
""" """
from __future__ import print_function
import weakref import weakref
from time import time from time import time
from operator import itemgetter from operator import itemgetter
from collections import defaultdict from collections import defaultdict
import six
NoneType = type(None) NoneType = type(None)
@ -37,13 +35,13 @@ def format_live_refs(ignore=NoneType):
"""Return a tabular representation of tracked objects""" """Return a tabular representation of tracked objects"""
s = "Live References\n\n" s = "Live References\n\n"
now = time() now = time()
for cls, wdict in sorted(six.iteritems(live_refs), for cls, wdict in sorted(live_refs.items(),
key=lambda x: x[0].__name__): key=lambda x: x[0].__name__):
if not wdict: if not wdict:
continue continue
if issubclass(cls, ignore): if issubclass(cls, ignore):
continue continue
oldest = min(six.itervalues(wdict)) oldest = min(wdict.values())
s += "%-30s %6d oldest: %ds ago\n" % ( s += "%-30s %6d oldest: %ds ago\n" % (
cls.__name__, len(wdict), now - oldest cls.__name__, len(wdict), now - oldest
) )
@ -57,15 +55,15 @@ def print_live_refs(*a, **kw):
def get_oldest(class_name): def get_oldest(class_name):
"""Get the oldest object for a specific class name""" """Get the oldest object for a specific class name"""
for cls, wdict in six.iteritems(live_refs): for cls, wdict in live_refs.items():
if cls.__name__ == class_name: if cls.__name__ == class_name:
if not wdict: if not wdict:
break break
return min(six.iteritems(wdict), key=itemgetter(1))[0] return min(wdict.items(), key=itemgetter(1))[0]
def iter_all(class_name): def iter_all(class_name):
"""Iterate over all objects of the same class by its class name""" """Iterate over all objects of the same class by its class name"""
for cls, wdict in six.iteritems(live_refs): for cls, wdict in live_refs.items():
if cls.__name__ == class_name: if cls.__name__ == class_name:
return six.iterkeys(wdict) return wdict.keys()

View File

@ -7,7 +7,7 @@ to the w3lib.url module. Always import those from there instead.
""" """
import posixpath import posixpath
import re import re
from six.moves.urllib.parse import (ParseResult, urldefrag, urlparse, urlunparse) from urllib.parse import ParseResult, urldefrag, urlparse, urlunparse
# scrapy.utils.url was moved to w3lib.url and import * ensures this # scrapy.utils.url was moved to w3lib.url and import * ensures this
# move doesn't break old code # move doesn't break old code

View File

@ -72,7 +72,6 @@ setup(
'pyOpenSSL>=16.2.0', 'pyOpenSSL>=16.2.0',
'queuelib>=1.4.2', 'queuelib>=1.4.2',
'service_identity>=16.0.0', 'service_identity>=16.0.0',
'six>=1.10.0',
'w3lib>=1.17.0', 'w3lib>=1.17.0',
'zope.interface>=4.1.3', 'zope.interface>=4.1.3',
'protego>=0.1.15', 'protego>=0.1.15',

View File

@ -0,0 +1,15 @@
import scrapy
from scrapy.crawler import CrawlerProcess
class NoRequestsSpider(scrapy.Spider):
name = 'no_request'
def start_requests(self):
return []
process = CrawlerProcess(settings={})
process.crawl(NoRequestsSpider)
process.start()

View File

@ -3,9 +3,9 @@ import os
import random import random
import sys import sys
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
from urllib.parse import urlencode
from OpenSSL import SSL from OpenSSL import SSL
from six.moves.urllib.parse import urlencode
from twisted.web.server import Site, NOT_DONE_YET from twisted.web.server import Site, NOT_DONE_YET
from twisted.web.resource import Resource from twisted.web.resource import Resource

View File

@ -1,7 +1,7 @@
# Tests requirements # Tests requirements
jmespath jmespath
mitmproxy; python_version >= '3.6' mitmproxy; python_version >= '3.6'
mitmproxy==3.0.4; python_version < '3.6' mitmproxy<4.0.0; python_version < '3.6'
pytest pytest
pytest-cov pytest-cov
pytest-twisted >= 1.11 pytest-twisted >= 1.11

View File

@ -3,7 +3,7 @@ Some spiders used for testing and benchmarking
""" """
import time import time
from six.moves.urllib.parse import urlencode from urllib.parse import urlencode
from scrapy.spiders import Spider from scrapy.spiders import Spider
from scrapy.http import Request from scrapy.http import Request

View File

@ -1,13 +1,12 @@
from io import StringIO
import json import json
import os import os
import pstats import pstats
import shutil import shutil
import six
from subprocess import Popen, PIPE
import sys import sys
import tempfile import tempfile
import unittest import unittest
from io import StringIO
from subprocess import Popen, PIPE
from scrapy.utils.test import get_testenv from scrapy.utils.test import get_testenv
@ -65,5 +64,5 @@ class CmdlineTest(unittest.TestCase):
for char in ("'", "<", ">", 'u"'): for char in ("'", "<", ">", 'u"'):
settingsstr = settingsstr.replace(char, '"') settingsstr = settingsstr.replace(char, '"')
settingsdict = json.loads(settingsstr) settingsdict = json.loads(settingsstr)
six.assertCountEqual(self, settingsdict.keys(), EXTENSIONS.keys()) self.assertCountEqual(settingsdict.keys(), EXTENSIONS.keys())
self.assertEqual(200, settingsdict[EXT_PATH]) self.assertEqual(200, settingsdict[EXT_PATH])

View File

@ -1,6 +1,5 @@
from unittest import TextTestResult from unittest import TextTestResult
from six import get_unbound_function
from twisted.internet import defer from twisted.internet import defer
from twisted.python import failure from twisted.python import failure
from twisted.trial import unittest from twisted.trial import unittest
@ -395,8 +394,8 @@ class ContractsManagerTest(unittest.TestCase):
with MockServer() as mockserver: with MockServer() as mockserver:
contract_doc = '@url {}'.format(mockserver.url('/status?n=200')) contract_doc = '@url {}'.format(mockserver.url('/status?n=200'))
get_unbound_function(TestSameUrlSpider.parse_first).__doc__ = contract_doc TestSameUrlSpider.parse_first.__doc__ = contract_doc
get_unbound_function(TestSameUrlSpider.parse_second).__doc__ = contract_doc TestSameUrlSpider.parse_second.__doc__ = contract_doc
crawler = CrawlerRunner().create_crawler(TestSameUrlSpider) crawler = CrawlerRunner().create_crawler(TestSameUrlSpider)
yield crawler.crawl() yield crawler.crawl()

View File

@ -140,7 +140,7 @@ class CrawlTestCase(TestCase):
def test_unbounded_response(self): def test_unbounded_response(self):
# Completeness of responses without Content-Length or Transfer-Encoding # Completeness of responses without Content-Length or Transfer-Encoding
# can not be determined, we treat them as valid but flagged as "partial" # can not be determined, we treat them as valid but flagged as "partial"
from six.moves.urllib.parse import urlencode from urllib.parse import urlencode
query = urlencode({'raw': '''\ query = urlencode({'raw': '''\
HTTP/1.1 200 OK HTTP/1.1 200 OK
Server: Apache-Coyote/1.1 Server: Apache-Coyote/1.1

View File

@ -1,4 +1,7 @@
import logging import logging
import os
import subprocess
import sys
import warnings import warnings
from pytest import raises, mark from pytest import raises, mark
@ -16,6 +19,7 @@ from scrapy.utils.spider import DefaultSpider
from scrapy.utils.misc import load_object from scrapy.utils.misc import load_object
from scrapy.extensions.throttle import AutoThrottle from scrapy.extensions.throttle import AutoThrottle
from scrapy.extensions import telnet from scrapy.extensions import telnet
from scrapy.utils.test import get_testenv
class BaseCrawlerTest(unittest.TestCase): class BaseCrawlerTest(unittest.TestCase):
@ -281,3 +285,19 @@ class CrawlerRunnerHasSpider(unittest.TestCase):
with LogCapture() as log: with LogCapture() as log:
yield runner.crawl(AsyncioSpider) yield runner.crawl(AsyncioSpider)
log.check_present(('asyncio', 'INFO', 'Asyncio support: %s' % (self.reactor_pytest == 'asyncio'))) log.check_present(('asyncio', 'INFO', 'Asyncio support: %s' % (self.reactor_pytest == 'asyncio')))
class CrawlerProcessSubprocess(unittest.TestCase):
script_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'CrawlerProcess')
def run_script(self, script_name):
script_path = os.path.join(self.script_dir, script_name)
args = (sys.executable, script_path)
p = subprocess.Popen(args, env=get_testenv(),
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
return stderr.decode('utf-8')
def test_simple(self):
log = self.run_script('simple.py')
self.assertIn('Spider closed (finished)', log)

View File

@ -1,6 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import absolute_import
from unittest import mock from unittest import mock
from twisted.internet import reactor, error from twisted.internet import reactor, error

View File

@ -10,9 +10,10 @@ module with the ``runserver`` argument::
python test_engine.py runserver python test_engine.py runserver
""" """
from __future__ import print_function import os
import sys, os, re import re
from six.moves.urllib.parse import urlparse import sys
from urllib.parse import urlparse
from twisted.internet import reactor, defer from twisted.internet import reactor, defer
from twisted.web import server, static, util from twisted.web import server, static, util

View File

@ -1,15 +1,13 @@
from __future__ import absolute_import
import re import re
import json import json
import marshal import marshal
import pickle
import tempfile import tempfile
import unittest import unittest
from io import BytesIO from io import BytesIO
from datetime import datetime from datetime import datetime
from six.moves import cPickle as pickle
import lxml.etree import lxml.etree
import six
from scrapy.item import Item, Field from scrapy.item import Item, Field
from scrapy.utils.python import to_unicode from scrapy.utils.python import to_unicode
@ -80,7 +78,7 @@ class BaseItemExporterTest(unittest.TestCase):
ie = self._get_exporter(fields_to_export=['name'], encoding='latin-1') ie = self._get_exporter(fields_to_export=['name'], encoding='latin-1')
_, name = list(ie._get_serialized_fields(self.i))[0] _, name = list(ie._get_serialized_fields(self.i))[0]
assert isinstance(name, six.text_type) assert isinstance(name, str)
self.assertEqual(name, u'John\xa3') self.assertEqual(name, u'John\xa3')
def test_field_custom_serializer(self): def test_field_custom_serializer(self):

View File

@ -1,15 +1,15 @@
from __future__ import absolute_import
import os import os
import csv import csv
import json import json
import warnings import warnings
from io import BytesIO
import tempfile import tempfile
import shutil import shutil
import string import string
from io import BytesIO
from pathlib import Path
from unittest import mock from unittest import mock
from six.moves.urllib.parse import urljoin, urlparse, quote from urllib.parse import urljoin, urlparse, quote
from six.moves.urllib.request import pathname2url from urllib.request import pathname2url
from zope.interface.verify import verifyObject from zope.interface.verify import verifyObject
from twisted.trial import unittest from twisted.trial import unittest
@ -28,8 +28,6 @@ from scrapy.extensions.feedexport import (
from scrapy.utils.test import assert_aws_environ, get_s3_content_and_delete, get_crawler from scrapy.utils.test import assert_aws_environ, get_s3_content_and_delete, get_crawler
from scrapy.utils.python import to_unicode from scrapy.utils.python import to_unicode
from pathlib import Path
class FileFeedStorageTest(unittest.TestCase): class FileFeedStorageTest(unittest.TestCase):

Some files were not shown because too many files have changed in this diff Show More