mirror of https://github.com/scrapy/scrapy.git
Assorted docstring fixes (#7698)
* Smaller fixes. * Add more code blocks in docstrings. * Queue stuff. * Response stuff. * Round 2. * Address feedback.
This commit is contained in:
parent
deb7e2861e
commit
00098cb596
|
|
@ -64,7 +64,7 @@ class AddonManager:
|
||||||
|
|
||||||
:param settings: The :class:`~scrapy.settings.BaseSettings` object from \
|
:param settings: The :class:`~scrapy.settings.BaseSettings` object from \
|
||||||
which to read the early add-on configuration
|
which to read the early add-on configuration
|
||||||
:type settings: :class:`~scrapy.settings.Settings`
|
:type settings: :class:`~scrapy.settings.BaseSettings`
|
||||||
"""
|
"""
|
||||||
for clspath in build_component_list(settings["ADDONS"]):
|
for clspath in build_component_list(settings["ADDONS"]):
|
||||||
addoncls = load_object(clspath)
|
addoncls = load_object(clspath)
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ class ScrapyCommand(ABC):
|
||||||
def long_desc(self) -> str:
|
def long_desc(self) -> str:
|
||||||
"""A long description of the command. Return short description when not
|
"""A long description of the command. Return short description when not
|
||||||
available. It cannot contain newlines since contents will be formatted
|
available. It cannot contain newlines since contents will be formatted
|
||||||
by optparser which removes newlines and wraps text.
|
by argparse which removes newlines and wraps text.
|
||||||
"""
|
"""
|
||||||
return self.short_desc()
|
return self.short_desc()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,13 @@ class _ScrapyClientContextFactory(BrowserLikePolicyForHTTPS):
|
||||||
instance.
|
instance.
|
||||||
|
|
||||||
The purpose of this custom class is to provide a ``creatorForNetloc()``
|
The purpose of this custom class is to provide a ``creatorForNetloc()``
|
||||||
method that returns a ``_ScrapyClientTLSOptions`` instance configured based
|
method that returns:
|
||||||
on TLS settings provided to the factory.
|
|
||||||
|
- a ``_ScrapyClientTLSOptions26`` or ``_ScrapyClientTLSOptions`` instance
|
||||||
|
configured based on TLS settings provided to the factory (when the
|
||||||
|
certificate verification is disabled);
|
||||||
|
- a result of ``optionsForClientTLS()`` called with those TLS settings
|
||||||
|
(when the certificate verification is enabled).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@
|
||||||
An asynchronous FTP file download handler for scrapy which somehow emulates an http response.
|
An asynchronous FTP file download handler for scrapy which somehow emulates an http response.
|
||||||
|
|
||||||
FTP connection parameters are passed using the request meta field:
|
FTP connection parameters are passed using the request meta field:
|
||||||
- ftp_user (required)
|
- ftp_user (optional, falls back to FTP_USER)
|
||||||
- ftp_password (required)
|
- ftp_password (optional, falls back to FTP_PASSWORD)
|
||||||
- ftp_passive (by default, enabled) sets FTP connection passive mode
|
- ftp_passive (optional, falls back to FTP_PASSIVE_MODE) sets FTP connection passive mode
|
||||||
- ftp_local_filename
|
- ftp_local_filename
|
||||||
- If not given, file data will come in the response.body, as a normal scrapy Response,
|
- If not given, file data will come in the response.body, as a normal scrapy Response,
|
||||||
which will imply that the entire file will be on memory.
|
which will imply that the entire file will be on memory.
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,6 @@ class HTTP11DownloadHandler(BaseHttpDownloadHandler):
|
||||||
self._disconnect_timeout: int = 1
|
self._disconnect_timeout: int = 1
|
||||||
|
|
||||||
async def download_request(self, request: Request) -> Response:
|
async def download_request(self, request: Request) -> Response:
|
||||||
"""Return a deferred for the HTTP download"""
|
|
||||||
if hasattr(self._crawler.spider, "download_maxsize"): # pragma: no cover
|
if hasattr(self._crawler.spider, "download_maxsize"): # pragma: no cover
|
||||||
warn_on_deprecated_spider_attribute("download_maxsize", "DOWNLOAD_MAXSIZE")
|
warn_on_deprecated_spider_attribute("download_maxsize", "DOWNLOAD_MAXSIZE")
|
||||||
if hasattr(self._crawler.spider, "download_warnsize"): # pragma: no cover
|
if hasattr(self._crawler.spider, "download_warnsize"): # pragma: no cover
|
||||||
|
|
@ -283,7 +282,7 @@ def _tunnel_request_data(
|
||||||
|
|
||||||
|
|
||||||
class _TunnelingAgent(Agent):
|
class _TunnelingAgent(Agent):
|
||||||
"""An agent that uses a L{TunnelingTCP4ClientEndpoint} to make HTTPS
|
"""An agent that uses a ``_TunnelingTCP4ClientEndpoint`` to make HTTPS
|
||||||
downloads. It may look strange that we have chosen to subclass Agent and not
|
downloads. It may look strange that we have chosen to subclass Agent and not
|
||||||
ProxyAgent but consider that after the tunnel is opened the proxy is
|
ProxyAgent but consider that after the tunnel is opened the proxy is
|
||||||
transparent to the client; thus the agent should behave like there is no
|
transparent to the client; thus the agent should behave like there is no
|
||||||
|
|
|
||||||
|
|
@ -114,11 +114,7 @@ class H2ConnectionPool:
|
||||||
d.errback(ResponseFailed(errors))
|
d.errback(ResponseFailed(errors))
|
||||||
|
|
||||||
def close_connections(self) -> None:
|
def close_connections(self) -> None:
|
||||||
"""Close all the HTTP/2 connections and remove them from pool
|
"""Close all the HTTP/2 connections and remove them from pool."""
|
||||||
|
|
||||||
Returns:
|
|
||||||
Deferred that fires when all connections have been closed
|
|
||||||
"""
|
|
||||||
for conn in self._connections.values():
|
for conn in self._connections.values():
|
||||||
assert conn.transport is not None # typing
|
assert conn.transport is not None # typing
|
||||||
conn.transport.abortConnection()
|
conn.transport.abortConnection()
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ class H2ClientProtocol(Protocol, TimeoutMixin):
|
||||||
uri is used to verify that incoming client requests have correct
|
uri is used to verify that incoming client requests have correct
|
||||||
base URL.
|
base URL.
|
||||||
settings -- Scrapy project settings
|
settings -- Scrapy project settings
|
||||||
conn_lost_deferred -- Deferred fires with the reason: Failure to notify
|
conn_lost_deferred -- Deferred that fires with the list of underlying exceptions to notify
|
||||||
that connection was lost
|
that connection was lost
|
||||||
tls_verbose_logging -- Whether to log TLS details
|
tls_verbose_logging -- Whether to log TLS details
|
||||||
"""
|
"""
|
||||||
|
|
@ -375,7 +375,7 @@ class H2ClientProtocol(Protocol, TimeoutMixin):
|
||||||
|
|
||||||
def _handle_events(self, events: list[Event]) -> None:
|
def _handle_events(self, events: list[Event]) -> None:
|
||||||
"""Private method which acts as a bridge between the events
|
"""Private method which acts as a bridge between the events
|
||||||
received from the HTTP/2 data and IH2EventsHandler
|
received from the HTTP/2 data and the handlers in this class.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
events -- A list of events that the remote peer triggered by sending data
|
events -- A list of events that the remote peer triggered by sending data
|
||||||
|
|
|
||||||
|
|
@ -131,10 +131,10 @@ class Scheduler(BaseScheduler):
|
||||||
(:setting:`SCHEDULER_PRIORITY_QUEUE`) that sort requests by
|
(:setting:`SCHEDULER_PRIORITY_QUEUE`) that sort requests by
|
||||||
:attr:`~scrapy.http.Request.priority`.
|
:attr:`~scrapy.http.Request.priority`.
|
||||||
|
|
||||||
By default, a single, memory-based priority queue is used for all requests.
|
By default, memory-based priority queues are used for all requests.
|
||||||
When using :setting:`JOBDIR`, a disk-based priority queue is also created,
|
When using :setting:`JOBDIR`, disk-based priority queues are also created,
|
||||||
and only unserializable requests are stored in the memory-based priority
|
and only unserializable requests are stored in the memory-based priority
|
||||||
queue. For a given priority value, requests in memory take precedence over
|
queues. For a given priority value, requests in memory take precedence over
|
||||||
requests in disk.
|
requests in disk.
|
||||||
|
|
||||||
Each priority queue stores requests in separate internal queues, one per
|
Each priority queue stores requests in separate internal queues, one per
|
||||||
|
|
@ -209,8 +209,8 @@ class Scheduler(BaseScheduler):
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
While pending requests are below the configured values of
|
While pending requests are below the configured values of
|
||||||
:setting:`CONCURRENT_REQUESTS`, :setting:`CONCURRENT_REQUESTS_PER_DOMAIN`
|
:setting:`CONCURRENT_REQUESTS` or
|
||||||
or :setting:`CONCURRENT_REQUESTS_PER_IP`, those requests are sent
|
:setting:`CONCURRENT_REQUESTS_PER_DOMAIN`, those requests are sent
|
||||||
concurrently.
|
concurrently.
|
||||||
|
|
||||||
As a result, the first few requests of a crawl may not follow the desired
|
As a result, the first few requests of a crawl may not follow the desired
|
||||||
|
|
@ -342,7 +342,7 @@ class Scheduler(BaseScheduler):
|
||||||
def open(self, spider: Spider) -> Deferred[None] | None:
|
def open(self, spider: Spider) -> Deferred[None] | None:
|
||||||
"""
|
"""
|
||||||
(1) initialize the memory queue
|
(1) initialize the memory queue
|
||||||
(2) initialize the disk queue if the ``jobdir`` attribute is a valid directory
|
(2) initialize the disk queue if the ``jobdir`` argument wasn't empty
|
||||||
(3) return the result of the dupefilter's ``open`` method
|
(3) return the result of the dupefilter's ``open`` method
|
||||||
"""
|
"""
|
||||||
self.spider: Spider = spider
|
self.spider: Spider = spider
|
||||||
|
|
|
||||||
|
|
@ -441,7 +441,7 @@ class Scraper:
|
||||||
self, output: Any, response: Response | Failure
|
self, output: Any, response: Response | Failure
|
||||||
) -> Deferred[None]:
|
) -> Deferred[None]:
|
||||||
"""Process each Request/Item (given in the output parameter) returned
|
"""Process each Request/Item (given in the output parameter) returned
|
||||||
from the given spider.
|
from the spider.
|
||||||
|
|
||||||
Items are sent to the item pipelines, requests are scheduled.
|
Items are sent to the item pipelines, requests are scheduled.
|
||||||
"""
|
"""
|
||||||
|
|
@ -451,7 +451,7 @@ class Scraper:
|
||||||
self, output: Any, response: Response | Failure
|
self, output: Any, response: Response | Failure
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Process each Request/Item (given in the output parameter) returned
|
"""Process each Request/Item (given in the output parameter) returned
|
||||||
from the given spider.
|
from the spider.
|
||||||
|
|
||||||
Items are sent to the item pipelines, requests are scheduled.
|
Items are sent to the item pipelines, requests are scheduled.
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -531,8 +531,8 @@ class AsyncCrawlerRunner(CrawlerRunnerBase):
|
||||||
"""
|
"""
|
||||||
Run a crawler with the provided arguments.
|
Run a crawler with the provided arguments.
|
||||||
|
|
||||||
It will call the given Crawler's :meth:`~Crawler.crawl` method, while
|
It will call the given Crawler's :meth:`~Crawler.crawl_async` method,
|
||||||
keeping track of it so it can be stopped later.
|
while keeping track of it so it can be stopped later.
|
||||||
|
|
||||||
If ``crawler_or_spidercls`` isn't a :class:`~scrapy.crawler.Crawler`
|
If ``crawler_or_spidercls`` isn't a :class:`~scrapy.crawler.Crawler`
|
||||||
instance, this method will try to create one using this parameter as
|
instance, this method will try to create one using this parameter as
|
||||||
|
|
@ -773,7 +773,7 @@ class CrawlerProcess(CrawlerProcessBase, CrawlerRunner):
|
||||||
"""
|
"""
|
||||||
This method starts a :mod:`~twisted.internet.reactor`, adjusts its pool
|
This method starts a :mod:`~twisted.internet.reactor`, adjusts its pool
|
||||||
size to :setting:`REACTOR_THREADPOOL_MAXSIZE`, and installs a DNS
|
size to :setting:`REACTOR_THREADPOOL_MAXSIZE`, and installs a DNS
|
||||||
resolver based on :setting:`DNSCACHE_ENABLED`.
|
resolver based on :setting:`TWISTED_DNS_RESOLVER`.
|
||||||
|
|
||||||
If ``stop_after_crawl`` is True, the reactor will be stopped after all
|
If ``stop_after_crawl`` is True, the reactor will be stopped after all
|
||||||
crawlers have finished, using :meth:`join`.
|
crawlers have finished, using :meth:`join`.
|
||||||
|
|
@ -875,10 +875,10 @@ class AsyncCrawlerProcess(CrawlerProcessBase, AsyncCrawlerRunner):
|
||||||
|
|
||||||
When using a reactor it adjusts its pool size to
|
When using a reactor it adjusts its pool size to
|
||||||
:setting:`REACTOR_THREADPOOL_MAXSIZE` and installs a DNS resolver based
|
:setting:`REACTOR_THREADPOOL_MAXSIZE` and installs a DNS resolver based
|
||||||
on :setting:`DNSCACHE_ENABLED`.
|
on :setting:`TWISTED_DNS_RESOLVER`.
|
||||||
|
|
||||||
If ``stop_after_crawl`` is True, the reactor will be stopped after all
|
If ``stop_after_crawl`` is True, the reactor/event loop will be stopped
|
||||||
crawlers have finished, using :meth:`join`.
|
after all crawlers have finished, using :meth:`join`.
|
||||||
|
|
||||||
:param bool stop_after_crawl: stop or not the reactor when all
|
:param bool stop_after_crawl: stop or not the reactor when all
|
||||||
crawlers have finished
|
crawlers have finished
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ else:
|
||||||
|
|
||||||
|
|
||||||
class HttpCompressionMiddleware:
|
class HttpCompressionMiddleware:
|
||||||
"""This middleware allows compressed (gzip, deflate) traffic to be
|
"""This middleware allows compressed (gzip, deflate etc.) traffic to be
|
||||||
sent/received from websites"""
|
sent/received from websites"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
|
|
||||||
|
|
@ -196,10 +196,7 @@ class BaseRedirectMiddleware:
|
||||||
|
|
||||||
|
|
||||||
class RedirectMiddleware(BaseRedirectMiddleware):
|
class RedirectMiddleware(BaseRedirectMiddleware):
|
||||||
"""
|
"""Handle redirection of requests based on response status."""
|
||||||
Handle redirection of requests based on response status
|
|
||||||
and meta-refresh html tag.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@_warn_spider_arg
|
@_warn_spider_arg
|
||||||
def process_response(
|
def process_response(
|
||||||
|
|
@ -251,6 +248,8 @@ class RedirectMiddleware(BaseRedirectMiddleware):
|
||||||
|
|
||||||
|
|
||||||
class MetaRefreshMiddleware(BaseRedirectMiddleware):
|
class MetaRefreshMiddleware(BaseRedirectMiddleware):
|
||||||
|
"""Handle redirection of requests based on meta-refresh html tag."""
|
||||||
|
|
||||||
enabled_setting = "METAREFRESH_ENABLED"
|
enabled_setting = "METAREFRESH_ENABLED"
|
||||||
|
|
||||||
def __init__(self, settings: BaseSettings):
|
def __init__(self, settings: BaseSettings):
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,6 @@ problems such as a connection timeout or HTTP 500 error.
|
||||||
You can change the behaviour of this middleware by modifying the scraping settings:
|
You can change the behaviour of this middleware by modifying the scraping settings:
|
||||||
RETRY_TIMES - how many times to retry a failed page
|
RETRY_TIMES - how many times to retry a failed page
|
||||||
RETRY_HTTP_CODES - which HTTP response codes to retry
|
RETRY_HTTP_CODES - which HTTP response codes to retry
|
||||||
|
|
||||||
Failed pages are collected on the scraping process and rescheduled at the end,
|
|
||||||
once the spider has finished crawling all regular (non-failed) pages.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
@ -70,8 +67,9 @@ def get_retry_request(
|
||||||
and :ref:`stats <topics-stats>`, and to provide extra logging context (see
|
and :ref:`stats <topics-stats>`, and to provide extra logging context (see
|
||||||
:func:`logging.debug`).
|
:func:`logging.debug`).
|
||||||
|
|
||||||
*reason* is a string or an :class:`Exception` object that indicates the
|
*reason* is a string, an :class:`Exception` subclass or an
|
||||||
reason why the request needs to be retried. It is used to name retry stats.
|
:class:`Exception` object that indicates the reason why the request needs
|
||||||
|
to be retried. It is used to name retry stats.
|
||||||
|
|
||||||
*max_retry_times* is a number that determines the maximum number of times
|
*max_retry_times* is a number that determines the maximum number of times
|
||||||
that *request* can be retried. If not specified or ``None``, the number is
|
that *request* can be retried. If not specified or ``None``, the number is
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ class UsageError(Exception):
|
||||||
|
|
||||||
class ScrapyDeprecationWarning(Warning):
|
class ScrapyDeprecationWarning(Warning):
|
||||||
"""Warning category for deprecated features, since the default
|
"""Warning category for deprecated features, since the default
|
||||||
DeprecationWarning is silenced on Python 2.7+
|
:exc:`DeprecationWarning` is silenced.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class LogStats:
|
class LogStats:
|
||||||
"""Log basic scraping stats periodically like:
|
"""Log basic scraping stats periodically like:
|
||||||
* RPM - Requests per Minute
|
* RPM - Responses per Minute
|
||||||
* IPM - Items per Minute
|
* IPM - Items per Minute
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ class AutoThrottle:
|
||||||
# It works better with problematic sites.
|
# It works better with problematic sites.
|
||||||
new_delay = max(target_delay, new_delay)
|
new_delay = max(target_delay, new_delay)
|
||||||
|
|
||||||
# Make sure self.mindelay <= new_delay <= self.max_delay
|
# Make sure self.mindelay <= new_delay <= self.maxdelay
|
||||||
new_delay = min(max(self.mindelay, new_delay), self.maxdelay)
|
new_delay = min(max(self.mindelay, new_delay), self.maxdelay)
|
||||||
|
|
||||||
# Dont adjust delay if response status != 200 and new delay is smaller
|
# Dont adjust delay if response status != 200 and new delay is smaller
|
||||||
|
|
|
||||||
|
|
@ -136,9 +136,9 @@ class _DummyLock:
|
||||||
|
|
||||||
|
|
||||||
class WrappedRequest:
|
class WrappedRequest:
|
||||||
"""Wraps a scrapy Request class with methods defined by urllib2.Request class to interact with CookieJar class
|
"""Wraps a :class:`scrapy.Request` class with methods defined by
|
||||||
|
the :class:`urllib.request.Request` class to interact with
|
||||||
see http://docs.python.org/library/urllib2.html#urllib2.Request
|
the :class:`http.cookiejar.CookieJar` class.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, request: Request):
|
def __init__(self, request: Request):
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"""
|
"""
|
||||||
This module implements the HtmlResponse class which adds encoding
|
This module implements the :class:`HtmlResponse` class which is used as a
|
||||||
discovering through HTML encoding declarations to the TextResponse class.
|
content type marker by :class:`~scrapy.selector.Selector` and can be used in
|
||||||
|
``isinstance()`` checks.
|
||||||
|
|
||||||
See documentation in docs/topics/request-response.rst
|
See documentation in docs/topics/request-response.rst
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"""
|
"""
|
||||||
This module implements the XmlResponse class which adds encoding
|
This module implements the :class:`XmlResponse` class which is used as a
|
||||||
discovering through XML encoding declarations to the TextResponse class.
|
content type marker by :class:`~scrapy.selector.Selector` and can be used in
|
||||||
|
``isinstance()`` checks.
|
||||||
|
|
||||||
See documentation in docs/topics/request-response.rst
|
See documentation in docs/topics/request-response.rst
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
"""
|
"""
|
||||||
Scrapy Item
|
Scrapy Item
|
||||||
|
|
||||||
See documentation in docs/topics/item.rst
|
See documentation in docs/topics/items.rst
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,9 @@ its documentation in: docs/topics/link-extractors.rst
|
||||||
class Link:
|
class Link:
|
||||||
"""Link objects represent an extracted link by the LinkExtractor.
|
"""Link objects represent an extracted link by the LinkExtractor.
|
||||||
|
|
||||||
Using the anchor tag sample below to illustrate the parameters::
|
Using the anchor tag sample below to illustrate the parameters:
|
||||||
|
|
||||||
|
.. code-block:: html
|
||||||
|
|
||||||
<a href="https://example.com/nofollow.html#foo" rel="nofollow">Dont follow this one</a>
|
<a href="https://example.com/nofollow.html#foo" rel="nofollow">Dont follow this one</a>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,18 +58,20 @@ class LogFormatter:
|
||||||
logging an action the method must return ``None``.
|
logging an action the method must return ``None``.
|
||||||
|
|
||||||
Here is an example on how to create a custom log formatter to lower the severity level of
|
Here is an example on how to create a custom log formatter to lower the severity level of
|
||||||
the log message when an item is dropped from the pipeline::
|
the log message when an item is dropped from the pipeline:
|
||||||
|
|
||||||
class PoliteLogFormatter(logformatter.LogFormatter):
|
.. code-block:: python
|
||||||
def dropped(self, item, exception, response, spider):
|
|
||||||
return {
|
class PoliteLogFormatter(logformatter.LogFormatter):
|
||||||
'level': logging.INFO, # lowering the level from logging.WARNING
|
def dropped(self, item, exception, response, spider):
|
||||||
'msg': "Dropped: %(exception)s" + os.linesep + "%(item)s",
|
return {
|
||||||
'args': {
|
"level": logging.INFO, # lowering the level from logging.WARNING
|
||||||
'exception': exception,
|
"msg": "Dropped: %(exception)s" + os.linesep + "%(item)s",
|
||||||
'item': item,
|
"args": {
|
||||||
}
|
"exception": exception,
|
||||||
}
|
"item": item,
|
||||||
|
},
|
||||||
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def crawled(
|
def crawled(
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
"""
|
"""
|
||||||
Mail sending helpers
|
Mail sending helpers
|
||||||
|
|
||||||
See documentation in docs/topics/email.rst
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
"""
|
"""
|
||||||
Item pipeline
|
Item pipeline
|
||||||
|
|
||||||
See documentation in docs/item-pipeline.rst
|
See documentation in docs/topics/item-pipeline.rst
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
|
||||||
|
|
@ -423,7 +423,7 @@ class FTPFilesStore:
|
||||||
|
|
||||||
|
|
||||||
class FilesPipeline(MediaPipeline):
|
class FilesPipeline(MediaPipeline):
|
||||||
"""Abstract pipeline that implement the file downloading
|
"""Pipeline that implements file downloading.
|
||||||
|
|
||||||
This pipeline tries to minimize network transfers and file processing,
|
This pipeline tries to minimize network transfers and file processing,
|
||||||
doing stat of the files and determining if file is new, up-to-date or
|
doing stat of the files and determining if file is new, up-to-date or
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ class ImageException(FileException):
|
||||||
|
|
||||||
|
|
||||||
class ImagesPipeline(FilesPipeline):
|
class ImagesPipeline(FilesPipeline):
|
||||||
"""Abstract pipeline that implement the image thumbnail generation logic"""
|
"""Pipeline that implements the handling logic specific to images."""
|
||||||
|
|
||||||
MEDIA_NAME: str = "image"
|
MEDIA_NAME: str = "image"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -92,9 +92,10 @@ class ScrapyPriorityQueue:
|
||||||
- The :data:`~scrapy.Request.priority` of the request.
|
- The :data:`~scrapy.Request.priority` of the request.
|
||||||
|
|
||||||
For each combination of the above seen, this class creates an instance of
|
For each combination of the above seen, this class creates an instance of
|
||||||
*downstream_queue_cls* with *key* set to a subdirectory of the persistence
|
*downstream_queue_cls* (or *start_queue_cls* for start requests if it was
|
||||||
directory, named as the request priority (e.g. ``1``), with an ``s`` suffix
|
passed) with *key* set to a subdirectory of the persistence directory,
|
||||||
in case of a start request (e.g. ``1s``).
|
named as the negated request priority (e.g. ``-1``), with an ``s`` suffix
|
||||||
|
in case of a start request (e.g. ``-1s``).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
||||||
|
|
@ -454,9 +454,10 @@ class BaseSettings(MutableMapping[str, Any]):
|
||||||
"""
|
"""
|
||||||
Store a key/value attribute with a given priority.
|
Store a key/value attribute with a given priority.
|
||||||
|
|
||||||
Settings should be populated *before* configuring the Crawler object
|
Settings should be populated *before* the Crawler object applies them
|
||||||
(through the :meth:`~scrapy.crawler.Crawler.configure` method),
|
(in the :meth:`~scrapy.crawler.Crawler.crawl_async` or
|
||||||
otherwise they won't have any effect.
|
:meth:`~scrapy.crawler.Crawler.crawl` method), otherwise they won't
|
||||||
|
have any effect.
|
||||||
|
|
||||||
:param name: the setting name
|
:param name: the setting name
|
||||||
:type name: str
|
:type name: str
|
||||||
|
|
@ -613,7 +614,7 @@ class BaseSettings(MutableMapping[str, Any]):
|
||||||
"""
|
"""
|
||||||
Make a deep copy of current settings.
|
Make a deep copy of current settings.
|
||||||
|
|
||||||
This method returns a new instance of the :class:`Settings` class,
|
This method returns a new instance of this class,
|
||||||
populated with the same values and their priorities.
|
populated with the same values and their priorities.
|
||||||
|
|
||||||
Modifications to the new object won't be reflected on the original
|
Modifications to the new object won't be reflected on the original
|
||||||
|
|
@ -658,7 +659,7 @@ class BaseSettings(MutableMapping[str, Any]):
|
||||||
Make a copy of current settings and convert to a dict.
|
Make a copy of current settings and convert to a dict.
|
||||||
|
|
||||||
This method returns a new dict populated with the same values
|
This method returns a new dict populated with the same values
|
||||||
and their priorities as the current settings.
|
as the current settings.
|
||||||
|
|
||||||
Modifications to the returned dict won't be reflected on the original
|
Modifications to the returned dict won't be reflected on the original
|
||||||
settings.
|
settings.
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ if TYPE_CHECKING:
|
||||||
# running event loop.
|
# running event loop.
|
||||||
#
|
#
|
||||||
# Side note: it should be possible to remove _request_deferred() by using
|
# Side note: it should be possible to remove _request_deferred() by using
|
||||||
# engine.download_async() instead of engine.schedule(), losing the usual stuff
|
# engine.download_async() instead of engine.crawl(), losing the usual stuff
|
||||||
# like spider middlewares (none of which should be important).
|
# like spider middlewares (none of which should be important).
|
||||||
#
|
#
|
||||||
# Other architecture problems:
|
# Other architecture problems:
|
||||||
|
|
@ -188,7 +188,8 @@ class Shell:
|
||||||
async def _schedule(self, request: Request, spider: Spider | None) -> Response:
|
async def _schedule(self, request: Request, spider: Spider | None) -> Response:
|
||||||
"""Send the request to the engine, wait for the result.
|
"""Send the request to the engine, wait for the result.
|
||||||
|
|
||||||
Runs in the reactor thread.
|
Runs in the reactor thread when using the reactor, or in the asyncio
|
||||||
|
event loop thread otherwise.
|
||||||
"""
|
"""
|
||||||
if not self.spider:
|
if not self.spider:
|
||||||
await self._open_spider(spider)
|
await self._open_spider(spider)
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ class BaseSpiderMiddleware:
|
||||||
) -> Request | None:
|
) -> Request | None:
|
||||||
"""Return a processed request from the spider output.
|
"""Return a processed request from the spider output.
|
||||||
|
|
||||||
This method is called with a single request from the start seeds or the
|
This method is called with a single request from ``start()`` or the
|
||||||
spider output. It should return the same or a different request, or
|
spider output. It should return the same or a different request, or
|
||||||
``None`` to ignore it.
|
``None`` to ignore it.
|
||||||
|
|
||||||
|
|
@ -84,7 +84,7 @@ class BaseSpiderMiddleware:
|
||||||
|
|
||||||
:param response: the response being processed
|
:param response: the response being processed
|
||||||
:type response: :class:`~scrapy.http.Response` object or ``None`` for
|
:type response: :class:`~scrapy.http.Response` object or ``None`` for
|
||||||
start seeds
|
start requests
|
||||||
|
|
||||||
:return: the processed request or ``None``
|
:return: the processed request or ``None``
|
||||||
"""
|
"""
|
||||||
|
|
@ -93,7 +93,7 @@ class BaseSpiderMiddleware:
|
||||||
def get_processed_item(self, item: Any, response: Response | None) -> Any:
|
def get_processed_item(self, item: Any, response: Response | None) -> Any:
|
||||||
"""Return a processed item from the spider output.
|
"""Return a processed item from the spider output.
|
||||||
|
|
||||||
This method is called with a single item from the start seeds or the
|
This method is called with a single item from ``start()`` or the
|
||||||
spider output. It should return the same or a different item, or
|
spider output. It should return the same or a different item, or
|
||||||
``None`` to ignore it.
|
``None`` to ignore it.
|
||||||
|
|
||||||
|
|
@ -102,7 +102,7 @@ class BaseSpiderMiddleware:
|
||||||
|
|
||||||
:param response: the response being processed
|
:param response: the response being processed
|
||||||
:type response: :class:`~scrapy.http.Response` object or ``None`` for
|
:type response: :class:`~scrapy.http.Response` object or ``None`` for
|
||||||
start seeds
|
start items
|
||||||
|
|
||||||
:return: the processed item or ``None``
|
:return: the processed item or ``None``
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class HttpError(IgnoreRequest):
|
class HttpError(IgnoreRequest):
|
||||||
"""A non-200 response was filtered"""
|
"""A non-2xx response was filtered"""
|
||||||
|
|
||||||
def __init__(self, response: Response, *args: Any, **kwargs: Any):
|
def __init__(self, response: Response, *args: Any, **kwargs: Any):
|
||||||
self.response = response
|
self.response = response
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ class ReferrerPolicy(ABC):
|
||||||
)
|
)
|
||||||
|
|
||||||
def origin(self, url: str) -> str | None:
|
def origin(self, url: str) -> str | None:
|
||||||
"""Return serialized origin (scheme, host, path) for a request or response URL."""
|
"""Return serialized origin (scheme, host, port) for a request or response URL."""
|
||||||
return self.strip_url(url, origin_only=True)
|
return self.strip_url(url, origin_only=True)
|
||||||
|
|
||||||
def potentially_trustworthy(self, url: str) -> bool:
|
def potentially_trustworthy(self, url: str) -> bool:
|
||||||
|
|
|
||||||
|
|
@ -54,17 +54,21 @@ class XMLFeedSpider(Spider):
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def parse_node(self, response: Response, selector: Selector) -> Any:
|
def parse_node(self, response: Response, selector: Selector) -> Any:
|
||||||
"""This method must be overridden with your custom spider functionality"""
|
"""This method is called for the nodes matching the provided tag name
|
||||||
|
(itertag). Receives the response and an Selector for each node.
|
||||||
|
|
||||||
|
This method must return either an item, a request, or a list
|
||||||
|
containing any of them.
|
||||||
|
|
||||||
|
This method must be overridden with your custom spider functionality.
|
||||||
|
"""
|
||||||
if hasattr(self, "parse_item"): # backward compatibility
|
if hasattr(self, "parse_item"): # backward compatibility
|
||||||
return self.parse_item(response, selector)
|
return self.parse_item(response, selector)
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def parse_nodes(self, response: Response, nodes: Iterable[Selector]) -> Any:
|
def parse_nodes(self, response: Response, nodes: Iterable[Selector]) -> Any:
|
||||||
"""This method is called for the nodes matching the provided tag name
|
"""This method is called for the nodes matching the provided tag name
|
||||||
(itertag). Receives the response and an Selector for each node.
|
(itertag). Receives the response and an iterable of Selectors.
|
||||||
Overriding this method is mandatory. Otherwise, you spider won't work.
|
|
||||||
This method must return either an item, a request, or a list
|
|
||||||
containing any of them.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for selector in nodes:
|
for selector in nodes:
|
||||||
|
|
@ -113,6 +117,9 @@ class CSVFeedSpider(Spider):
|
||||||
It receives a CSV file in a response; iterates through each of its rows,
|
It receives a CSV file in a response; iterates through each of its rows,
|
||||||
and calls parse_row with a dict containing each field's data.
|
and calls parse_row with a dict containing each field's data.
|
||||||
|
|
||||||
|
This spider also gives the opportunity to override adapt_response and
|
||||||
|
process_results methods for pre and post-processing purposes.
|
||||||
|
|
||||||
You can set some options regarding the CSV file, such as the delimiter, quotechar
|
You can set some options regarding the CSV file, such as the delimiter, quotechar
|
||||||
and the file's headers.
|
and the file's headers.
|
||||||
"""
|
"""
|
||||||
|
|
@ -136,16 +143,14 @@ class CSVFeedSpider(Spider):
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def parse_row(self, response: Response, row: dict[str, str]) -> Any:
|
def parse_row(self, response: Response, row: dict[str, str]) -> Any:
|
||||||
"""This method must be overridden with your custom spider functionality"""
|
"""Receives a response and a dict (representing each row) with a key for
|
||||||
|
each provided (or detected) header of the CSV file.
|
||||||
|
|
||||||
|
This method must be overridden with your custom spider functionality.
|
||||||
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def parse_rows(self, response: Response) -> Any:
|
def parse_rows(self, response: Response) -> Any:
|
||||||
"""Receives a response and a dict (representing each row) with a key for
|
|
||||||
each provided (or detected) header of the CSV file. This spider also
|
|
||||||
gives the opportunity to override adapt_response and
|
|
||||||
process_results methods for pre and post-processing purposes.
|
|
||||||
"""
|
|
||||||
|
|
||||||
for row in csviter(
|
for row in csviter(
|
||||||
response, self.delimiter, self.headers, quotechar=self.quotechar
|
response, self.delimiter, self.headers, quotechar=self.quotechar
|
||||||
):
|
):
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
"""
|
"""
|
||||||
This module contains data types used by Scrapy which are not included in the
|
This module contains data types used by Scrapy which are not included in the
|
||||||
Python Standard Library.
|
Python Standard Library.
|
||||||
|
|
||||||
This module must not depend on any module outside the Standard Library.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ async def _defer_sleep_async() -> None:
|
||||||
def defer_result(result: Any) -> Deferred[Any]: # pragma: no cover
|
def defer_result(result: Any) -> Deferred[Any]: # pragma: no cover
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"scrapy.utils.defer.defer_result() is deprecated, use"
|
"scrapy.utils.defer.defer_result() is deprecated, use"
|
||||||
" twisted.internet.defer.success() and twisted.internet.defer.fail(),"
|
" twisted.internet.defer.succeed() and twisted.internet.defer.fail(),"
|
||||||
" plus an explicit sleep if needed, or explicit reactor.callLater().",
|
" plus an explicit sleep if needed, or explicit reactor.callLater().",
|
||||||
category=ScrapyDeprecationWarning,
|
category=ScrapyDeprecationWarning,
|
||||||
stacklevel=2,
|
stacklevel=2,
|
||||||
|
|
@ -469,22 +469,22 @@ def _maybeDeferred_coro(
|
||||||
def deferred_to_future(d: Deferred[_T]) -> Future[_T]:
|
def deferred_to_future(d: Deferred[_T]) -> Future[_T]:
|
||||||
"""Return an :class:`asyncio.Future` object that wraps *d*.
|
"""Return an :class:`asyncio.Future` object that wraps *d*.
|
||||||
|
|
||||||
This function requires
|
This function requires an installed asyncio reactor or a running asyncio
|
||||||
:class:`~twisted.internet.asyncioreactor.AsyncioSelectorReactor` to be
|
event loop, see :ref:`using-asyncio`.
|
||||||
installed.
|
|
||||||
|
|
||||||
When :ref:`using the asyncio reactor <install-asyncio>`, you cannot await
|
In this state you cannot await on :class:`~twisted.internet.defer.Deferred`
|
||||||
on :class:`~twisted.internet.defer.Deferred` objects from :ref:`Scrapy
|
objects from :ref:`Scrapy callables defined as coroutines
|
||||||
callables defined as coroutines <coroutine-support>`, you can only await on
|
<coroutine-support>`, you can only await on ``Future`` objects. Wrapping
|
||||||
``Future`` objects. Wrapping ``Deferred`` objects into ``Future`` objects
|
``Deferred`` objects into ``Future`` objects allows you to wait on them:
|
||||||
allows you to wait on them::
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
class MySpider(Spider):
|
class MySpider(Spider):
|
||||||
...
|
...
|
||||||
|
|
||||||
async def parse(self, response):
|
async def parse(self, response):
|
||||||
additional_request = scrapy.Request('https://example.org/price')
|
deferred = some_dfd_helper()
|
||||||
deferred = self.crawler.engine.download(additional_request)
|
result = await deferred_to_future(deferred)
|
||||||
additional_response = await deferred_to_future(deferred)
|
|
||||||
|
|
||||||
.. versionchanged:: 2.14
|
.. versionchanged:: 2.14
|
||||||
This function no longer installs an asyncio loop if called before the
|
This function no longer installs an asyncio loop if called before the
|
||||||
|
|
@ -492,7 +492,10 @@ def deferred_to_future(d: Deferred[_T]) -> Future[_T]:
|
||||||
in this case.
|
in this case.
|
||||||
"""
|
"""
|
||||||
if not is_asyncio_available():
|
if not is_asyncio_available():
|
||||||
raise RuntimeError("deferred_to_future() requires AsyncioSelectorReactor.")
|
raise RuntimeError(
|
||||||
|
"deferred_to_future() requires an installed asyncio reactor"
|
||||||
|
" or a running asyncio event loop."
|
||||||
|
)
|
||||||
return d.asFuture(asyncio.get_event_loop())
|
return d.asFuture(asyncio.get_event_loop())
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -501,23 +504,26 @@ def maybe_deferred_to_future(d: Deferred[_T]) -> Deferred[_T] | Future[_T]:
|
||||||
defined as a coroutine <coroutine-support>`.
|
defined as a coroutine <coroutine-support>`.
|
||||||
|
|
||||||
What you can await in Scrapy callables defined as coroutines depends on the
|
What you can await in Scrapy callables defined as coroutines depends on the
|
||||||
value of :setting:`TWISTED_REACTOR`:
|
value of :setting:`TWISTED_REACTOR` and :setting:`TWISTED_REACTOR_ENABLED`:
|
||||||
|
|
||||||
- When :ref:`using the asyncio reactor <install-asyncio>`, you can only
|
- When :ref:`using the asyncio reactor <install-asyncio>`, or :ref:`not
|
||||||
await on :class:`asyncio.Future` objects.
|
using a reactor at all <asyncio-without-reactor>`, you can only await
|
||||||
|
on :class:`asyncio.Future` objects.
|
||||||
|
|
||||||
- When not using the asyncio reactor, you can only await on
|
- When :ref:`using a non-asyncio reactor <disable-asyncio>`, you can only
|
||||||
:class:`~twisted.internet.defer.Deferred` objects.
|
await on :class:`~twisted.internet.defer.Deferred` objects.
|
||||||
|
|
||||||
If you want to write code that uses ``Deferred`` objects but works with any
|
If you want to write code that uses ``Deferred`` objects but works in both
|
||||||
reactor, use this function on all ``Deferred`` objects::
|
of these states, use this function on all ``Deferred`` objects:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
class MySpider(Spider):
|
class MySpider(Spider):
|
||||||
...
|
...
|
||||||
|
|
||||||
async def parse(self, response):
|
async def parse(self, response):
|
||||||
additional_request = scrapy.Request('https://example.org/price')
|
deferred = some_dfd_helper()
|
||||||
deferred = self.crawler.engine.download(additional_request)
|
result = await maybe_deferred_to_future(deferred)
|
||||||
additional_response = await maybe_deferred_to_future(deferred)
|
|
||||||
"""
|
"""
|
||||||
if not is_asyncio_available():
|
if not is_asyncio_available():
|
||||||
return d
|
return d
|
||||||
|
|
|
||||||
|
|
@ -43,15 +43,18 @@ def create_deprecated_class(
|
||||||
It can be used to rename a base class in a library. For example, if we
|
It can be used to rename a base class in a library. For example, if we
|
||||||
have
|
have
|
||||||
|
|
||||||
class OldName(SomeClass):
|
.. code-block:: python
|
||||||
# ...
|
|
||||||
|
|
||||||
and we want to rename it to NewName, we can do the following::
|
class OldName(SomeClass): ...
|
||||||
|
|
||||||
class NewName(SomeClass):
|
and we want to rename it to NewName, we can do the following:
|
||||||
# ...
|
|
||||||
|
|
||||||
OldName = create_deprecated_class('OldName', NewName)
|
.. code-block:: python
|
||||||
|
|
||||||
|
class NewName(SomeClass): ...
|
||||||
|
|
||||||
|
|
||||||
|
OldName = create_deprecated_class("OldName", NewName)
|
||||||
|
|
||||||
Then, if user class inherits from OldName, warning is issued. Also, if
|
Then, if user class inherits from OldName, warning is issued. Also, if
|
||||||
some code uses ``issubclass(sub, OldName)`` or ``isinstance(sub(), OldName)``
|
some code uses ``issubclass(sub, OldName)`` or ``isinstance(sub(), OldName)``
|
||||||
|
|
|
||||||
|
|
@ -248,8 +248,7 @@ def logformatter_adapter(
|
||||||
) -> tuple[int, str, dict[str, Any] | tuple[Any, ...]]:
|
) -> tuple[int, str, dict[str, Any] | tuple[Any, ...]]:
|
||||||
"""
|
"""
|
||||||
Helper that takes the dictionary output from the methods in LogFormatter
|
Helper that takes the dictionary output from the methods in LogFormatter
|
||||||
and adapts it into a tuple of positional arguments for logger.log calls,
|
and adapts it into a tuple of positional arguments for logger.log calls.
|
||||||
handling backward compatibility as well.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
level = logkws.get("level", logging.INFO)
|
level = logkws.get("level", logging.INFO)
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ def open_in_browser(
|
||||||
|
|
||||||
|
|
||||||
def parse_details(self, response):
|
def parse_details(self, response):
|
||||||
if "item name" not in response.body:
|
if "item name" not in response.text:
|
||||||
open_in_browser(response)
|
open_in_browser(response)
|
||||||
"""
|
"""
|
||||||
# circular imports
|
# circular imports
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ def send_catch_log(
|
||||||
*arguments: TypingAny,
|
*arguments: TypingAny,
|
||||||
**named: TypingAny,
|
**named: TypingAny,
|
||||||
) -> list[tuple[TypingAny, TypingAny]]:
|
) -> list[tuple[TypingAny, TypingAny]]:
|
||||||
"""Like ``pydispatcher.robust.sendRobust()`` but it also logs errors and returns
|
"""Like ``pydispatch.robust.sendRobust()`` but it also logs errors and returns
|
||||||
Failures instead of exceptions.
|
Failures instead of exceptions.
|
||||||
"""
|
"""
|
||||||
dont_log = named.pop("dont_log", ())
|
dont_log = named.pop("dont_log", ())
|
||||||
|
|
@ -172,9 +172,8 @@ async def _send_catch_log_asyncio(
|
||||||
|
|
||||||
Returns a coroutine that completes once all signal handlers have finished.
|
Returns a coroutine that completes once all signal handlers have finished.
|
||||||
|
|
||||||
This function requires
|
This function requires an installed asyncio reactor or a running asyncio
|
||||||
:class:`~twisted.internet.asyncioreactor.AsyncioSelectorReactor` to be
|
event loop.
|
||||||
installed.
|
|
||||||
|
|
||||||
.. versionadded:: 2.14
|
.. versionadded:: 2.14
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,7 @@ references to live object instances.
|
||||||
If you want live objects for a particular class to be tracked, you only have to
|
If you want live objects for a particular class to be tracked, you only have to
|
||||||
subclass from object_ref (instead of object).
|
subclass from object_ref (instead of object).
|
||||||
|
|
||||||
About performance: This library has a minimal performance impact when enabled,
|
This library has a minimal performance impact.
|
||||||
and no performance penalty at all when disabled (as object_ref becomes just an
|
|
||||||
alias to object in that case).
|
|
||||||
|
|
||||||
.. note:: PyPy uses a tracing garbage collector, so objects may
|
.. note:: PyPy uses a tracing garbage collector, so objects may
|
||||||
remain in the ``live_refs`` longer than expected, even after they
|
remain in the ``live_refs`` longer than expected, even after they
|
||||||
|
|
|
||||||
|
|
@ -117,8 +117,8 @@ def strip_url(
|
||||||
- ``strip_credentials`` removes "user:password@"
|
- ``strip_credentials`` removes "user:password@"
|
||||||
- ``strip_default_port`` removes ":80" (resp. ":443", ":21")
|
- ``strip_default_port`` removes ":80" (resp. ":443", ":21")
|
||||||
from http:// (resp. https://, ftp://) URLs
|
from http:// (resp. https://, ftp://) URLs
|
||||||
- ``origin_only`` replaces path component with "/", also dropping
|
- ``origin_only`` replaces the path component with "/", also dropping
|
||||||
query and fragment components ; it also strips credentials
|
the query component; it also strips credentials
|
||||||
- ``strip_fragment`` drops any #fragment component
|
- ``strip_fragment`` drops any #fragment component
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue