Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

5245 f-strings #5246

Merged
merged 32 commits into from Oct 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
82c26ab
extentions.httpcache : string format replaced by f-strings
GeorgeA92 Sep 23, 2021
5c622ae
downloadermiddlewares.httpcache : string format replaced by f-strings
GeorgeA92 Sep 23, 2021
5befc88
scrapy.utils.misc : string format replaced by f-strings
GeorgeA92 Sep 23, 2021
5372d95
scrapy.core.downloader.contextfactory : string format replaced by f-s…
GeorgeA92 Sep 23, 2021
42da1f4
scrapy.core.downloader.tls : string format replaced by f-strings
GeorgeA92 Sep 23, 2021
9b5354d
tests.test_closespider : string format replaced by f-strings
GeorgeA92 Sep 23, 2021
cb93322
tests.test_http_request : string format replaced by f-strings
GeorgeA92 Sep 23, 2021
1485f61
tests.test_commands : string format replaced by f-strings
GeorgeA92 Sep 23, 2021
abeb3c2
tests.test_downloader_handlers_http2 : string format replaced by f-st…
GeorgeA92 Sep 23, 2021
79c1713
tests.spiders : string format replaced by f-strings
GeorgeA92 Sep 23, 2021
06aaf0a
scrapy.extensions.feedexport : string format replaced by f-strings
GeorgeA92 Sep 23, 2021
8b312cb
scrapy.extensions.feedexport : _close_slot f-string usage optimized
GeorgeA92 Sep 23, 2021
9ac5b6c
scrapy.extensions.feedexport : error fixed
GeorgeA92 Sep 23, 2021
7362fc7
tests.test_http_request : regular string used
GeorgeA92 Sep 23, 2021
c30db21
extentions.httpcache : logger debug message formatting updated
GeorgeA92 Sep 23, 2021
dc19c7d
scrapy.__init__ : string format replaced by f-strings
GeorgeA92 Sep 23, 2021
ead32c1
scrapy.core.downloader.tls : logger warning message formatting updated
GeorgeA92 Sep 23, 2021
16fddcb
scrapy.extensions.feedexport: logger message formatting updated
GeorgeA92 Sep 23, 2021
7f2990e
scrapy.extensions.feedexport: logger message formatting fixed
GeorgeA92 Sep 23, 2021
5c6db3c
tests.spiders: logger message formatting fixed
GeorgeA92 Sep 24, 2021
799cd84
tests.spiders: log message fixed
GeorgeA92 Sep 24, 2021
91b776e
scrapy.extensions.feedexport: `logfmt` -> renamed to `logmsg`
GeorgeA92 Sep 24, 2021
2a1faec
scrapy.core.downloader.contextfactory : remove tuple from f-string
GeorgeA92 Sep 24, 2021
9c6b2b9
code.downloader.contextfactory: warning message formatting updated
GeorgeA92 Sep 27, 2021
3ce0fad
core.downloader.tls: logger message formatting updated
GeorgeA92 Sep 27, 2021
0f27f1b
extensions.feedexport: `logmsg` formatting updated
GeorgeA92 Sep 27, 2021
bb62afd
utils.misc: error message formatting updated
GeorgeA92 Sep 27, 2021
67ce305
tests.test_http_request: test_from_response_valid_form_methods -> upd…
GeorgeA92 Sep 27, 2021
548906e
tests.test_http_request: statement formatting updated
GeorgeA92 Oct 1, 2021
bec8b1c
tests.test_downloadermiddleware_stats: statement formatting updated
GeorgeA92 Oct 1, 2021
d3be17b
tests.test_http_request: typo fixed
GeorgeA92 Oct 1, 2021
a4cc04c
downloadermiddlewares.httpcache: `{str(request)}` -> `{request}`
GeorgeA92 Oct 2, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion scrapy/__init__.py
Expand Up @@ -29,7 +29,7 @@

# Check minimum required Python version
if sys.version_info < (3, 6):
print("Scrapy %s requires Python 3.6+" % __version__)
print(f"Scrapy {__version__} requires Python 3.6+")
sys.exit(1)


Expand Down
12 changes: 7 additions & 5 deletions scrapy/core/downloader/contextfactory.py
Expand Up @@ -135,11 +135,13 @@ def load_context_factory_from_settings(settings, crawler):
settings=settings,
crawler=crawler,
)
msg = """
'%s' does not accept `method` argument (type OpenSSL.SSL method,\
e.g. OpenSSL.SSL.SSLv23_METHOD) and/or `tls_verbose_logging` argument and/or `tls_ciphers` argument.\
Please upgrade your context factory class to handle them or ignore them.""" % (
settings['DOWNLOADER_CLIENTCONTEXTFACTORY'],)
msg = (
f"{settings['DOWNLOADER_CLIENTCONTEXTFACTORY']} does not accept "
"a `method` argument (type OpenSSL.SSL method, e.g. "
"OpenSSL.SSL.SSLv23_METHOD) and/or a `tls_verbose_logging` "
"argument and/or a `tls_ciphers` argument. Please, upgrade your "
"context factory class to handle them or ignore them."
)
warnings.warn(msg)

return context_factory
8 changes: 4 additions & 4 deletions scrapy/core/downloader/tls.py
Expand Up @@ -65,14 +65,14 @@ def _identityVerifyingInfoCallback(self, connection, where, ret):
verifyHostname(connection, self._hostnameASCII)
except (CertificateError, VerificationError) as e:
logger.warning(
'Remote certificate is not valid for hostname "{}"; {}'.format(
self._hostnameASCII, e))
'Remote certificate is not valid for hostname "%s"; %s',
self._hostnameASCII, e)

except ValueError as e:
logger.warning(
'Ignoring error while verifying certificate '
'from host "{}" (exception: {})'.format(
self._hostnameASCII, repr(e)))
'from host "%s" (exception: %r)',
self._hostnameASCII, e)


DEFAULT_CIPHERS = AcceptableCiphers.fromOpenSSLCipherString('DEFAULT')
2 changes: 1 addition & 1 deletion scrapy/downloadermiddlewares/httpcache.py
Expand Up @@ -70,7 +70,7 @@ def process_request(self, request: Request, spider: Spider) -> Optional[Response
self.stats.inc_value('httpcache/miss', spider=spider)
if self.ignore_missing:
self.stats.inc_value('httpcache/ignore', spider=spider)
raise IgnoreRequest("Ignored request not in cache: %s" % request)
raise IgnoreRequest(f"Ignored request not in cache: {request}")
return None # first time request

# Return cached response only if not expired
Expand Down
33 changes: 14 additions & 19 deletions scrapy/extensions/feedexport.py
Expand Up @@ -38,11 +38,10 @@ def build_storage(builder, uri, *args, feed_options=None, preargs=(), **kwargs):
kwargs['feed_options'] = feed_options
else:
warnings.warn(
"{} does not support the 'feed_options' keyword argument. Add a "
f"{builder.__qualname__} does not support the 'feed_options' keyword argument. Add a "
"'feed_options' parameter to its signature to remove this "
"warning. This parameter will become mandatory in a future "
"version of Scrapy."
.format(builder.__qualname__),
"version of Scrapy.",
category=ScrapyDeprecationWarning
)
return builder(*preargs, uri, *args, **kwargs)
Expand Down Expand Up @@ -356,32 +355,28 @@ def _close_slot(self, slot, spider):
# properly closed.
return defer.maybeDeferred(slot.storage.store, slot.file)
slot.finish_exporting()
logfmt = "%s %%(format)s feed (%%(itemcount)d items) in: %%(uri)s"
log_args = {'format': slot.format,
'itemcount': slot.itemcount,
'uri': slot.uri}
logmsg = f"{slot.format} feed ({slot.itemcount} items) in: {slot.uri}"
d = defer.maybeDeferred(slot.storage.store, slot.file)

# Use `largs=log_args` to copy log_args into function's scope
# instead of using `log_args` from the outer scope
d.addCallback(
self._handle_store_success, log_args, logfmt, spider, type(slot.storage).__name__
self._handle_store_success, logmsg, spider, type(slot.storage).__name__
)
d.addErrback(
self._handle_store_error, log_args, logfmt, spider, type(slot.storage).__name__
self._handle_store_error, logmsg, spider, type(slot.storage).__name__
)
return d

def _handle_store_error(self, f, largs, logfmt, spider, slot_type):
def _handle_store_error(self, f, logmsg, spider, slot_type):
logger.error(
logfmt % "Error storing", largs,
"Error storing %s", logmsg,
exc_info=failure_to_exc_info(f), extra={'spider': spider}
)
self.crawler.stats.inc_value(f"feedexport/failed_count/{slot_type}")

def _handle_store_success(self, f, largs, logfmt, spider, slot_type):
def _handle_store_success(self, f, logmsg, spider, slot_type):
logger.info(
logfmt % "Stored", largs, extra={'spider': spider}
"Stored %s", logmsg,
extra={'spider': spider}
Comment on lines +378 to +379
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Nitpick) I would suggest either putting everything in the same line (which should be ok given our current line length), or each argument in its own line.

)
self.crawler.stats.inc_value(f"feedexport/success_count/{slot_type}")

Expand Down Expand Up @@ -474,10 +469,10 @@ def _settings_are_valid(self):
for uri_template, values in self.feeds.items():
if values['batch_item_count'] and not re.search(r'%\(batch_time\)s|%\(batch_id\)', uri_template):
logger.error(
'%(batch_time)s or %(batch_id)d must be in the feed URI ({}) if FEED_EXPORT_BATCH_ITEM_COUNT '
'%%(batch_time)s or %%(batch_id)d must be in the feed URI (%s) if FEED_EXPORT_BATCH_ITEM_COUNT '
'setting or FEEDS.batch_item_count is specified and greater than 0. For more info see: '
'https://docs.scrapy.org/en/latest/topics/feed-exports.html#feed-export-batch-item-count'
''.format(uri_template)
'https://docs.scrapy.org/en/latest/topics/feed-exports.html#feed-export-batch-item-count',
uri_template
)
return False
return True
Expand Down Expand Up @@ -526,7 +521,7 @@ def build_instance(builder, *preargs):
instance = build_instance(feedcls)
method_name = '__new__'
if instance is None:
raise TypeError("%s.%s returned None" % (feedcls.__qualname__, method_name))
raise TypeError(f"{feedcls.__qualname__}.{method_name} returned None")
return instance

def _get_uri_params(self, spider, uri_params, slot=None):
Expand Down
4 changes: 2 additions & 2 deletions scrapy/extensions/httpcache.py
Expand Up @@ -226,7 +226,7 @@ def open_spider(self, spider):
dbpath = os.path.join(self.cachedir, f'{spider.name}.db')
self.db = self.dbmodule.open(dbpath, 'c')

logger.debug("Using DBM cache storage in %(cachepath)s" % {'cachepath': dbpath}, extra={'spider': spider})
logger.debug("Using DBM cache storage in %(cachepath)s", {'cachepath': dbpath}, extra={'spider': spider})

def close_spider(self, spider):
self.db.close()
Expand Down Expand Up @@ -280,7 +280,7 @@ def __init__(self, settings):
self._open = gzip.open if self.use_gzip else open

def open_spider(self, spider):
logger.debug("Using filesystem cache storage in %(cachedir)s" % {'cachedir': self.cachedir},
logger.debug("Using filesystem cache storage in %(cachedir)s", {'cachedir': self.cachedir},
extra={'spider': spider})

def close_spider(self, spider):
Expand Down
2 changes: 1 addition & 1 deletion scrapy/utils/misc.py
Expand Up @@ -50,7 +50,7 @@ def load_object(path):
return path
else:
raise TypeError("Unexpected argument type, expected string "
"or object, got: %s" % type(path))
f"or object, got: {type(path)}")

try:
dot = path.rindex('.')
Expand Down
16 changes: 8 additions & 8 deletions tests/spiders.py
Expand Up @@ -86,7 +86,7 @@ def __init__(self, url="http://localhost:8998", *args, **kwargs):
self.start_urls = [url]

def parse(self, response):
self.logger.info("Got response %d" % response.status)
self.logger.info(f"Got response {response.status}")


class AsyncDefSpider(SimpleSpider):
Expand All @@ -95,7 +95,7 @@ class AsyncDefSpider(SimpleSpider):

async def parse(self, response):
await defer.succeed(42)
self.logger.info("Got response %d" % response.status)
self.logger.info(f"Got response {response.status}")


class AsyncDefAsyncioSpider(SimpleSpider):
Expand All @@ -105,7 +105,7 @@ class AsyncDefAsyncioSpider(SimpleSpider):
async def parse(self, response):
await asyncio.sleep(0.2)
status = await get_from_asyncio_queue(response.status)
self.logger.info("Got response %d" % status)
self.logger.info(f"Got response {status}")


class AsyncDefAsyncioReturnSpider(SimpleSpider):
Expand All @@ -115,7 +115,7 @@ class AsyncDefAsyncioReturnSpider(SimpleSpider):
async def parse(self, response):
await asyncio.sleep(0.2)
status = await get_from_asyncio_queue(response.status)
self.logger.info("Got response %d" % status)
self.logger.info(f"Got response {status}")
return [{'id': 1}, {'id': 2}]


Expand All @@ -126,7 +126,7 @@ class AsyncDefAsyncioReturnSingleElementSpider(SimpleSpider):
async def parse(self, response):
await asyncio.sleep(0.1)
status = await get_from_asyncio_queue(response.status)
self.logger.info("Got response %d" % status)
self.logger.info(f"Got response {status}")
return {"foo": 42}


Expand All @@ -138,7 +138,7 @@ async def parse(self, response):
await asyncio.sleep(0.2)
req_id = response.meta.get('req_id', 0)
status = await get_from_asyncio_queue(response.status)
self.logger.info("Got response %d, req_id %d" % (status, req_id))
self.logger.info(f"Got response {status}, req_id {req_id}")
if req_id > 0:
return
reqs = []
Expand All @@ -155,7 +155,7 @@ class AsyncDefAsyncioGenSpider(SimpleSpider):
async def parse(self, response):
await asyncio.sleep(0.2)
yield {'foo': 42}
self.logger.info("Got response %d" % response.status)
self.logger.info(f"Got response {response.status}")


class AsyncDefAsyncioGenLoopSpider(SimpleSpider):
Expand All @@ -166,7 +166,7 @@ async def parse(self, response):
for i in range(10):
await asyncio.sleep(0.1)
yield {'foo': i}
self.logger.info("Got response %d" % response.status)
self.logger.info(f"Got response {response.status}")


class AsyncDefAsyncioGenComplexSpider(SimpleSpider):
Expand Down
2 changes: 1 addition & 1 deletion tests/test_closespider.py
Expand Up @@ -41,7 +41,7 @@ def test_closespider_errorcount(self):
yield crawler.crawl(total=1000000, mockserver=self.mockserver)
reason = crawler.spider.meta['close_reason']
self.assertEqual(reason, 'closespider_errorcount')
key = 'spider_exceptions/{name}'.format(name=crawler.spider.exception_cls.__name__)
key = f'spider_exceptions/{crawler.spider.exception_cls.__name__}'
errorcount = crawler.stats.get_value(key)
self.assertTrue(errorcount >= close_on)

Expand Down
4 changes: 2 additions & 2 deletions tests/test_commands.py
Expand Up @@ -498,7 +498,7 @@ def test_url(self, url='test.com', domain="test.com"):
self.find_in_file(join(self.proj_mod_path,
'spiders', 'test_name.py'),
r'allowed_domains\s*=\s*\[\'(.+)\'\]').group(1))
self.assertEqual('http://%s/' % domain,
self.assertEqual(f'http://{domain}/',
self.find_in_file(join(self.proj_mod_path,
'spiders', 'test_name.py'),
r'start_urls\s*=\s*\[\'(.+)\'\]').group(1))
Expand Down Expand Up @@ -708,7 +708,7 @@ def test_custom_asyncio_loop_enabled_false(self):
])
import asyncio
loop = asyncio.new_event_loop()
self.assertIn("Using asyncio event loop: %s.%s" % (loop.__module__, loop.__class__.__name__), log)
self.assertIn(f"Using asyncio event loop: {loop.__module__}.{loop.__class__.__name__}", log)

def test_output(self):
spider_code = """
Expand Down
2 changes: 1 addition & 1 deletion tests/test_downloader_handlers_http2.py
Expand Up @@ -248,7 +248,7 @@ def _test(response):
self.assertEqual(response.url, request.url)
self.assertEqual(response.body, b'/')

http_proxy = '%s?noconnect' % self.getURL('')
http_proxy = f"{self.getURL('')}?noconnect"
request = Request('https://example.com', meta={'proxy': http_proxy})
with self.assertWarnsRegex(
Warning,
Expand Down
21 changes: 10 additions & 11 deletions tests/test_http_request.py
Expand Up @@ -1217,18 +1217,17 @@ def test_from_response_css(self):
response, formcss="input[name='abc']")

def test_from_response_valid_form_methods(self):
body = """<form action="post.php" method="%s">
<input type="hidden" name="one" value="1">
</form>"""
Gallaecio marked this conversation as resolved.
Show resolved Hide resolved

for method in self.request_class.valid_form_methods:
response = _buildresponse(body % method)
form_methods = [[method, method] for method in self.request_class.valid_form_methods]
form_methods.append(['UNKNOWN', 'GET'])

for method, expected in form_methods:
response = _buildresponse(
f'<form action="post.php" method="{method}">'
'<input type="hidden" name="one" value="1">'
'</form>'
)
r = self.request_class.from_response(response)
self.assertEqual(r.method, method)

response = _buildresponse(body % 'UNKNOWN')
r = self.request_class.from_response(response)
self.assertEqual(r.method, 'GET')
self.assertEqual(r.method, expected)


def _buildresponse(body, **kwargs):
Expand Down