Repository: scrapy/scrapy (branch: simplify-attempt2)
Commit date: 2023-12-05T02:50:06Z

Workflow file: .github/workflows/checks.yml (Checks)
name: Checks
on: [push, pull_request]

concurrency:
  group: ${{github.workflow}}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  checks:
    runs-on: ubuntu-latest
    services:
      pypi_wayback:
        image: ghcr.io/waleko/pypi-wayback
        ports:
          - 8629:8080
    strategy:
      fail-fast: false
      matrix:
        include:
        - python-version: "3.12"
          env:
            TOXENV: pylint
        - python-version: 3.8
          env:
            TOXENV: typing
        - python-version: "3.11"  # Keep in sync with .readthedocs.yml
          env:
            TOXENV: docs
        - python-version: "3.12"
          env:
            TOXENV: twinecheck

    steps:
    - uses: actions/checkout@v4

    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v4
      with:
        python-version: ${{ matrix.python-version }}

    - name: Run check
      env: ${{ matrix.env }}
      run: |
        pip install -U tox
        tox

  pre-commit:
    runs-on: ubuntu-latest
    services:
      pypi_wayback:
        image: ghcr.io/waleko/pypi-wayback
        ports:
          - 8629:8080
    steps:
    - uses: actions/checkout@v4
    - uses: pre-commit/action@v3.0.0

env:
  PIP_INDEX_URL: http://localhost:8629/2023-12-05
  UV_INDEX_URL: http://localhost:8629/2023-12-05


Failed build logs:
step_name: pre-commit/3_Run pre-commitaction@v3.0.0.txt
log: ##[group]Run pre-commit/action@v3.0.0
with:
  extra_args: --all-files
##[endgroup]
##[group]Run python -m pip install pre-commit
[36;1mpython -m pip install pre-commit[0m
shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
##[endgroup]
Defaulting to user installation because normal site-packages is not writeable
Collecting pre-commit
  Downloading pre_commit-3.5.0-py2.py3-none-any.whl (203 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 203.7/203.7 KB 8.3 MB/s eta 0:00:00
Collecting nodeenv>=0.11.1
  Downloading nodeenv-1.8.0-py2.py3-none-any.whl (22 kB)
Requirement already satisfied: pyyaml>=5.1 in /usr/lib/python3/dist-packages (from pre-commit) (5.4.1)
Collecting identify>=1.0.0
  Downloading identify-2.5.32-py2.py3-none-any.whl (98 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 98.9/98.9 KB 12.6 MB/s eta 0:00:00
Collecting cfgv>=2.0.0
  Downloading cfgv-3.4.0-py2.py3-none-any.whl (7.2 kB)
Collecting virtualenv>=20.10.0
  Downloading virtualenv-20.25.0-py3-none-any.whl (3.8 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.8/3.8 MB 27.4 MB/s eta 0:00:00
Requirement already satisfied: setuptools in /usr/lib/python3/dist-packages (from nodeenv>=0.11.1->pre-commit) (59.6.0)
Collecting platformdirs<5,>=3.9.1
  Downloading platformdirs-4.1.0-py3-none-any.whl (17 kB)
Collecting filelock<4,>=3.12.2
  Downloading filelock-3.13.1-py3-none-any.whl (11 kB)
Collecting distlib<1,>=0.3.7
  Downloading distlib-0.3.7-py2.py3-none-any.whl (468 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 468.9/468.9 KB 43.3 MB/s eta 0:00:00
Installing collected packages: distlib, platformdirs, nodeenv, identify, filelock, cfgv, virtualenv, pre-commit
Successfully installed cfgv-3.4.0 distlib-0.3.7 filelock-3.13.1 identify-2.5.32 nodeenv-1.8.0 platformdirs-4.1.0 pre-commit-3.5.0 virtualenv-20.25.0
##[group]Run python -m pip freeze --local
[36;1mpython -m pip freeze --local[0m
shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
##[endgroup]
argcomplete==3.1.6
cfgv==3.4.0
distlib==0.3.7
filelock==3.13.1
identify==2.5.32
nodeenv==1.8.0
packaging==23.2
pipx==1.2.1
platformdirs==4.1.0
pre-commit==3.5.0
userpath==1.9.1
virtualenv==20.25.0
##[group]Run actions/cache@v3
with:
  path: ~/.cache/pre-commit
  key: pre-commit-3||7a8fe885594aed9a90fd5938b4bb49b65732538a44c08aad3d6ea69d9d0cf64c
  enableCrossOsArchive: false
  fail-on-cache-miss: false
  lookup-only: false
##[endgroup]
Cache Size: ~33 MB (34938818 B)
[command]/usr/bin/tar -xf /home/runner/work/_temp/49db49b7-4865-4c29-942c-cd4505f101c6/cache.tzst -P -C /home/runner/work/scrapy/scrapy --use-compress-program unzstd
Cache restored successfully
Cache restored from key: pre-commit-3||7a8fe885594aed9a90fd5938b4bb49b65732538a44c08aad3d6ea69d9d0cf64c
##[group]Run pre-commit run --show-diff-on-failure --color=always --all-files
[36;1mpre-commit run --show-diff-on-failure --color=always --all-files[0m
shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
##[endgroup]
bandit...................................................................[42mPassed[m
flake8...................................................................[41mFailed[m
[2m- hook id: flake8[m
[2m- exit code: 1[m

[1mscrapy/core/downloader/contextfactory.py[m[36m:[m182[36m:[m42[36m:[m [1m[31mE251[m unexpected spaces around keyword / parameter equals
[1mscrapy/core/downloader/contextfactory.py[m[36m:[m182[36m:[m44[36m:[m [1m[31mE251[m unexpected spaces around keyword / parameter equals
[1mscrapy/utils/misc.py[m[36m:[m51[36m:[m17[36m:[m [1m[31mW291[m trailing whitespace
[1mscrapy/utils/misc.py[m[36m:[m55[36m:[m31[36m:[m [1m[31mW291[m trailing whitespace
[1mscrapy/utils/misc.py[m[36m:[m57[36m:[m12[36m:[m [1m[31mW291[m trailing whitespace
[1mscrapy/utils/misc.py[m[36m:[m63[36m:[m1[36m:[m [1m[31mE302[m expected 2 blank lines, found 1
[1mscrapy/utils/misc.py[m[36m:[m180[36m:[m24[36m:[m [1m[31mW291[m trailing whitespace
[1mscrapy/utils/misc.py[m[36m:[m191[36m:[m1[36m:[m [1m[31mW293[m blank line contains whitespace
[1mscrapy/utils/misc.py[m[36m:[m193[36m:[m1[36m:[m [1m[31mE265[m block comment should start with '# '
[1mscrapy/utils/misc.py[m[36m:[m198[36m:[m25[36m:[m [1m[31mW291[m trailing whitespace
[1mscrapy/utils/misc.py[m[36m:[m213[36m:[m1[36m:[m [1m[31mE303[m too many blank lines (4)
[1mtests/test_addons.py[m[36m:[m112[36m:[m41[36m:[m [1m[31mE999[m IndentationError: unindent does not match any outer indentation level
[1mtests/test_utils_misc/__init__.py[m[36m:[m98[36m:[m5[36m:[m [1m[31mE301[m expected 1 blank line, found 0
[1mtests/test_utils_misc/__init__.py[m[36m:[m125[36m:[m35[36m:[m [1m[31mF821[m undefined name 'settings'
[1mtests/test_utils_misc/__init__.py[m[36m:[m133[36m:[m1[36m:[m [1m[31mW293[m blank line contains whitespace

black....................................................................[41mFailed[m
[2m- hook id: black[m
[2m- exit code: 123[m
[2m- files were modified by this hook[m

[1mreformatted scrapy/addons.py[0m
[1mreformatted scrapy/core/downloader/handlers/__init__.py[0m
[1mreformatted scrapy/core/downloader/contextfactory.py[0m
[1mreformatted scrapy/core/engine.py[0m
[1mreformatted scrapy/crawler.py[0m
[1mreformatted scrapy/utils/misc.py[0m
[31merror: cannot format tests/test_addons.py: unindent does not match any outer indentation level (<tokenize>, line 112)[0m
[1mreformatted tests/test_downloader_handlers.py[0m
[1mreformatted tests/test_utils_misc/__init__.py[0m

[1mOh no! 💥 💔 💥[0m
[34m[1m8 files [0m[1mreformatted[0m, [34m332 files [0mleft unchanged, [31m1 file failed to reformat[0m.

isort....................................................................[41mFailed[m
[2m- hook id: isort[m
[2m- files were modified by this hook[m

Fixing /home/runner/work/scrapy/scrapy/scrapy/core/downloader/handlers/http10.py
Fixing /home/runner/work/scrapy/scrapy/scrapy/extensions/feedexport.py

blacken-docs.............................................................[42mPassed[m
pre-commit hook(s) made changes.
If you are seeing this message in CI, reproduce locally with: `pre-commit run --all-files`.
To run `pre-commit` as part of git workflow, use `pre-commit install`.
All changes made by hooks:
[1mdiff --git a/scrapy/addons.py b/scrapy/addons.py[m
[1mindex a6efba3..cb1574b 100644[m
[1m--- a/scrapy/addons.py[m
[1m+++ b/scrapy/addons.py[m
[36m@@ -33,9 +33,7 @@[m [mclass AddonManager:[m
             try:[m
                 addoncls = load_object(clspath)[m
                 # changes create_instance call to build_from_settings[m
[31m-                addon = build_from_settings([m
[31m-                    addoncls, settings=settings[m
[31m-                )[m
[32m+[m[32m                addon = build_from_settings(addoncls, settings=settings)[m
                 addon.update_settings(settings)[m
                 self.addons.append(addon)[m
             except NotConfigured as e:[m
[1mdiff --git a/scrapy/core/downloader/contextfactory.py b/scrapy/core/downloader/contextfactory.py[m
[1mindex 6d3ddd4..73a3d32 100644[m
[1m--- a/scrapy/core/downloader/contextfactory.py[m
[1m+++ b/scrapy/core/downloader/contextfactory.py[m
[36m@@ -178,9 +178,7 @@[m [mdef load_context_factory_from_settings(settings, crawler):[m
     except TypeError:[m
         # use context factory defaults[m
         # changes create_instance call to build_from_settings[m
[31m-        context_factory = build_from_settings([m
[31m-            context_factory_cls, settings = settings[m
[31m-        )[m
[32m+[m[32m        context_factory = build_from_settings(context_factory_cls, settings=settings)[m
         # context_factory = create_instance([m
         #     objcls=context_factory_cls,[m
         #     settings=settings,[m
[1mdiff --git a/scrapy/core/downloader/handlers/__init__.py b/scrapy/core/downloader/handlers/__init__.py[m
[1mindex d5b8ce8..fc597b0 100644[m
[1m--- a/scrapy/core/downloader/handlers/__init__.py[m
[1m+++ b/scrapy/core/downloader/handlers/__init__.py[m
[36m@@ -56,9 +56,7 @@[m [mclass DownloadHandlers:[m
             if skip_lazy and getattr(dhcls, "lazy", True):[m
                 return None[m
             # change create_instance call to build_from_settings[m
[31m-            dh = build_from_settings([m
[31m-                dhcls, settings=self._crawler.settings[m
[31m-            )[m
[32m+[m[32m            dh = build_from_settings(dhcls, settings=self._crawler.settings)[m
             # dh = create_instance([m
             #     objcls=dhcls,[m
             #     settings=self._crawler.settings,[m
[1mdiff --git a/scrapy/core/downloader/handlers/http10.py b/scrapy/core/downloader/handlers/http10.py[m
[1mindex 76faf7d..5c01ba4 100644[m
[1m--- a/scrapy/core/downloader/handlers/http10.py[m
[1m+++ b/scrapy/core/downloader/handlers/http10.py[m
[36m@@ -1,6 +1,6 @@[m
 """Download handlers for http and https schemes[m
 """[m
[31m-from scrapy.utils.misc import build_from_settings, build_from_crawler, load_object[m
[32m+[m[32mfrom scrapy.utils.misc import build_from_crawler, build_from_settings, load_object[m
 from scrapy.utils.python import to_unicode[m
 [m
 [m
[1mdiff --git a/scrapy/core/engine.py b/scrapy/core/engine.py[m
[1mindex 81aacdf..281dc8a 100644[m
[1m--- a/scrapy/core/engine.py[m
[1m+++ b/scrapy/core/engine.py[m
[36m@@ -358,9 +358,7 @@[m [mclass ExecutionEngine:[m
             raise RuntimeError(f"No free spider slot when opening {spider.name!r}")[m
         logger.info("Spider opened", extra={"spider": spider})[m
         nextcall = CallLaterOnce(self._next_request)[m
[31m-        scheduler = build_from_crawler([m
[31m-            self.scheduler_cls, crawler=self.crawler[m
[31m-        )[m
[32m+[m[32m        scheduler = build_from_crawler(self.scheduler_cls, crawler=self.crawler)[m
         start_requests = yield self.scraper.spidermw.process_start_requests([m
             start_requests, spider[m
         )[m
[1mdiff --git a/scrapy/crawler.py b/scrapy/crawler.py[m
[1mindex a1f699b..1280953 100644[m
[1m--- a/scrapy/crawler.py[m
[1m+++ b/scrapy/crawler.py[m
[36m@@ -111,7 +111,8 @@[m [mclass Crawler:[m
 [m
         # changes create_instance call to build_from_settings[m
         self.request_fingerprinter = build_from_settings([m
[31m-            load_object(self.settings["REQUEST_FINGERPRINTER_CLASS"]), settings=self.settings[m
[32m+[m[32m            load_object(self.settings["REQUEST_FINGERPRINTER_CLASS"]),[m
[32m+[m[32m            settings=self.settings,[m
         )[m
 [m
         # self.request_fingerprinter = create_instance([m
[1mdiff --git a/scrapy/extensions/feedexport.py b/scrapy/extensions/feedexport.py[m
[1mindex a4c8a47..62fb07e 100644[m
[1m--- a/scrapy/extensions/feedexport.py[m
[1m+++ b/scrapy/extensions/feedexport.py[m
[36m@@ -28,7 +28,7 @@[m [mfrom scrapy.utils.defer import maybe_deferred_to_future[m
 from scrapy.utils.deprecate import create_deprecated_class[m
 from scrapy.utils.ftp import ftp_store_file[m
 from scrapy.utils.log import failure_to_exc_info[m
[31m-from scrapy.utils.misc import build_from_settings, build_from_crawler, load_object[m
[32m+[m[32mfrom scrapy.utils.misc import build_from_crawler, build_from_settings, load_object[m
 from scrapy.utils.python import without_none_values[m
 [m
 logger = logging.getLogger(__name__)[m
[1mdiff --git a/scrapy/utils/misc.py b/scrapy/utils/misc.py[m
[1mindex 613328a..63270e9 100644[m
[1m--- a/scrapy/utils/misc.py[m
[1m+++ b/scrapy/utils/misc.py[m
[36m@@ -47,19 +47,21 @@[m [mdef arg_to_iter(arg: Any) -> Iterable[Any]:[m
         return cast(Iterable[Any], arg)[m
     return [arg][m
 [m
[32m+[m
 # def build_from_crawler(objcls, crawler, none, *args, **kwargs):[m
[31m-#     if crawler [m
[32m+[m[32m#     if crawler[m
 #         if hasattr(objcls, "from_crawler"):[m
 #             instance = objcls.from_crawler(crawler, *args, **kwargs)[m
 #             method_name = "from_crawler"[m
[31m-#         if instance is None: [m
[32m+[m[32m#         if instance is None:[m
 #             raise TypeError(f"{objcls.__qualname__}.{method_name} returned None)[m
[31m-#     else: [m
[32m+[m[32m#     else:[m
 #         instance = objcls(*args, **kwargs)[m
 #         method_name = "__new__"[m
 [m
 #     return instance[m
 [m
[32m+[m
 def load_object(path: Union[str, Callable]) -> Any:[m
     """Load an object given its absolute object path, and return it.[m
 [m
[36m@@ -177,7 +179,7 @@[m [mdef rel_has_nofollow(rel: Optional[str]) -> bool:[m
 #  Raises typeError is instance is None[m
 # Creates a class instance using 'from_crawler' constructor[m
 def build_from_crawler(objcls, crawler, /, *args, **kwargs):[m
[31m-    if crawler is None: [m
[32m+[m[32m    if crawler is None:[m
         raise ValueError("Specify crawler.")[m
     if crawler and hasattr(objcls, "from_crawler"):[m
         instance = objcls.from_crawler(crawler, *args, **kwargs)[m
[36m@@ -188,14 +190,14 @@[m [mdef build_from_crawler(objcls, crawler, /, *args, **kwargs):[m
     if instance is None:[m
         raise TypeError(f"{objcls.__qualname__}.{method_name} returned None")[m
     return instance[m
[31m-            [m
 [m
[31m-#``*args`` and ``**kwargs`` are forwarded to the constructors.[m
[32m+[m
[32m+[m[32m# ``*args`` and ``**kwargs`` are forwarded to the constructors.[m
 # Raises ``ValueError`` if``settings`` is``None``.[m
 #  Raises typeError is instance is None[m
 # Creates a class instance using 'from_settings' constructor[m
 def build_from_settings(objcls, settings, /, *args, **kwargs):[m
[31m-    if settings is None: [m
[32m+[m[32m    if settings is None:[m
         raise ValueError("Specify settings.")[m
     if settings and hasattr(objcls, "from_settings"):[m
         instance = objcls.from_settings(settings, *args, **kwargs)[m
[36m@@ -208,8 +210,6 @@[m [mdef build_from_settings(objcls, settings, /, *args, **kwargs):[m
     return instance[m
 [m
 [m
[31m-[m
[31m-[m
 @contextmanager[m
 def set_environ(**kwargs: str) -> Generator[None, Any, None]:[m
     """Temporarily set environment variables inside the context manager and[m
[1mdiff --git a/tests/test_downloader_handlers.py b/tests/test_downloader_handlers.py[m
[1mindex 8595e68..37a5364 100644[m
[1m--- a/tests/test_downloader_handlers.py[m
[1m+++ b/tests/test_downloader_handlers.py[m
[36m@@ -669,9 +669,7 @@[m [mclass Https11CustomCiphers(unittest.TestCase):[m
         crawler = get_crawler([m
             settings_dict={"DOWNLOADER_CLIENT_TLS_CIPHERS": "CAMELLIA256-SHA"}[m
         )[m
[31m-        self.download_handler = build_from_crawler([m
[31m-            self.download_handler_cls, crawler[m
[31m-        )[m
[32m+[m[32m        self.download_handler = build_from_crawler(self.download_handler_cls, crawler)[m
         self.download_request = self.download_handler.download_request[m
 [m
     @defer.inlineCallbacks[m
[36m@@ -1036,9 +1034,7 @@[m [mclass BaseFTPTestCase(unittest.TestCase):[m
         self.port = reactor.listenTCP(0, self.factory, interface="127.0.0.1")[m
         self.portNum = self.port.getHost().port[m
         crawler = get_crawler()[m
[31m-        self.download_handler = build_from_crawler([m
[31m-            FTPDownloadHandler, crawler[m
[31m-        )[m
[32m+[m[32m        self.download_handler = build_from_crawler(FTPDownloadHandler, crawler)[m
         self.addCleanup(self.port.stopListening)[m
 [m
     def tearDown(self):[m
[36m@@ -1182,9 +1178,7 @@[m [mclass AnonymousFTPTestCase(BaseFTPTestCase):[m
         self.port = reactor.listenTCP(0, self.factory, interface="127.0.0.1")[m
         self.portNum = self.port.getHost().port[m
         crawler = get_crawler()[m
[31m-        self.download_handler = build_from_crawler([m
[31m-            FTPDownloadHandler, crawler[m
[31m-        )[m
[32m+[m[32m        self.download_handler = build_from_crawler(FTPDownloadHandler, crawler)[m
         self.addCleanup(self.port.stopListening)[m
 [m
     def tearDown(self):[m
[36m@@ -1194,9 +1188,7 @@[m [mclass AnonymousFTPTestCase(BaseFTPTestCase):[m
 class DataURITestCase(unittest.TestCase):[m
     def setUp(self):[m
         crawler = get_crawler()[m
[31m-        self.download_handler = build_from_crawler([m
[31m-            DataURIDownloadHandler, crawler[m
[31m-        )[m
[32m+[m[32m        self.download_handler = build_from_crawler(DataURIDownloadHandler, crawler)[m
         self.download_request = self.download_handler.download_request[m
         self.spider = Spider("foo")[m
 [m
[1mdiff --git a/tests/test_utils_misc/__init__.py b/tests/test_utils_misc/__init__.py[m
[1mindex ccf8022..115ee7e 100644[m
[1m--- a/tests/test_utils_misc/__init__.py[m
[1m+++ b/tests/test_utils_misc/__init__.py[m
[36m@@ -95,6 +95,7 @@[m [mclass UtilsMiscTestCase(unittest.TestCase):[m
         self.assertEqual([m
             list(arg_to_iter(TestItem(name="john"))), [TestItem(name="john")][m
         )[m
[32m+[m
     def test_build_from_crawler(self):[m
         crawler = mock.MagicMock(spec_set=["settings"])[m
         args = (True, 100.0)[m
[36m@@ -130,7 +131,7 @@[m [mclass UtilsMiscTestCase(unittest.TestCase):[m
         m.from_crawler.return_value = None[m
         with self.assertRaises(TypeError):[m
             build_from_crawler(m, crawler, *args, **kwargs)[m
[31m-    [m
[32m+[m
     def test_build_from_settings(self):[m
         settings = mock.MagicMock()[m
         args = (True, 100.0)[m
##[error]Process completed with exit code 1.

step_name: checks (3.12, pylint)/4_Run check.txt
log: ##[group]Run pip install -U tox
[36;1mpip install -U tox[0m
[36;1mtox[0m
shell: /usr/bin/bash -e {0}
env:
  pythonLocation: /opt/hostedtoolcache/Python/3.12.0/x64
  PKG_CONFIG_PATH: /opt/hostedtoolcache/Python/3.12.0/x64/lib/pkgconfig
  Python_ROOT_DIR: /opt/hostedtoolcache/Python/3.12.0/x64
  Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.12.0/x64
  Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.12.0/x64
  LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.12.0/x64/lib
  TOXENV: pylint
##[endgroup]
Collecting tox
  Downloading tox-4.11.4-py3-none-any.whl.metadata (5.0 kB)
Collecting cachetools>=5.3.1 (from tox)
  Downloading cachetools-5.3.2-py3-none-any.whl.metadata (5.2 kB)
Collecting chardet>=5.2 (from tox)
  Downloading chardet-5.2.0-py3-none-any.whl.metadata (3.4 kB)
Collecting colorama>=0.4.6 (from tox)
  Downloading colorama-0.4.6-py2.py3-none-any.whl (25 kB)
Collecting filelock>=3.12.3 (from tox)
  Downloading filelock-3.13.1-py3-none-any.whl.metadata (2.8 kB)
Collecting packaging>=23.1 (from tox)
  Downloading packaging-23.2-py3-none-any.whl.metadata (3.2 kB)
Collecting platformdirs>=3.10 (from tox)
  Downloading platformdirs-4.1.0-py3-none-any.whl.metadata (11 kB)
Collecting pluggy>=1.3 (from tox)
  Downloading pluggy-1.3.0-py3-none-any.whl.metadata (4.3 kB)
Collecting pyproject-api>=1.6.1 (from tox)
  Downloading pyproject_api-1.6.1-py3-none-any.whl.metadata (2.8 kB)
Collecting virtualenv>=20.24.3 (from tox)
  Downloading virtualenv-20.25.0-py3-none-any.whl.metadata (4.5 kB)
Collecting distlib<1,>=0.3.7 (from virtualenv>=20.24.3->tox)
  Downloading distlib-0.3.7-py2.py3-none-any.whl.metadata (5.1 kB)
Downloading tox-4.11.4-py3-none-any.whl (153 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 154.0/154.0 kB 24.9 MB/s eta 0:00:00
Downloading cachetools-5.3.2-py3-none-any.whl (9.3 kB)
Downloading chardet-5.2.0-py3-none-any.whl (199 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 199.4/199.4 kB 43.0 MB/s eta 0:00:00
Downloading filelock-3.13.1-py3-none-any.whl (11 kB)
Downloading packaging-23.2-py3-none-any.whl (53 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 53.0/53.0 kB 15.5 MB/s eta 0:00:00
Downloading platformdirs-4.1.0-py3-none-any.whl (17 kB)
Downloading pluggy-1.3.0-py3-none-any.whl (18 kB)
Downloading pyproject_api-1.6.1-py3-none-any.whl (12 kB)
Downloading virtualenv-20.25.0-py3-none-any.whl (3.8 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.8/3.8 MB 86.7 MB/s eta 0:00:00
Downloading distlib-0.3.7-py2.py3-none-any.whl (468 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 468.9/468.9 kB 75.2 MB/s eta 0:00:00
Installing collected packages: distlib, pluggy, platformdirs, packaging, filelock, colorama, chardet, cachetools, virtualenv, pyproject-api, tox
Successfully installed cachetools-5.3.2 chardet-5.2.0 colorama-0.4.6 distlib-0.3.7 filelock-3.13.1 packaging-23.2 platformdirs-4.1.0 pluggy-1.3.0 pyproject-api-1.6.1 tox-4.11.4 virtualenv-20.25.0

[notice] A new release of pip is available: 23.2.1 -> 23.3.1
[notice] To update, run: pip install --upgrade pip
pylint: install_deps> python -I -m pip install -ctests/upper-constraints.txt boto3 google-cloud-storage 'markupsafe<2.1.0' 'mitmproxy<8,>=4.0.4; python_version < "3.9" and implementation_name != "pypy"' Pillow pylint==3.0.1 robotexclusionrulesparser 'Twisted[http2]' -r tests/requirements.txt
.pkg: install_requires> python -I -m pip install 'setuptools>=40.8.0' wheel
.pkg: _optional_hooks> python /opt/hostedtoolcache/Python/3.12.0/x64/lib/python3.12/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
.pkg: get_requires_for_build_sdist> python /opt/hostedtoolcache/Python/3.12.0/x64/lib/python3.12/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
.pkg: get_requires_for_build_wheel> python /opt/hostedtoolcache/Python/3.12.0/x64/lib/python3.12/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
.pkg: install_requires_for_build_wheel> python -I -m pip install wheel
.pkg: freeze> python -m pip freeze --all
.pkg: pip==23.3.1,setuptools==69.0.2,wheel==0.42.0
.pkg: prepare_metadata_for_build_wheel> python /opt/hostedtoolcache/Python/3.12.0/x64/lib/python3.12/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
.pkg: build_sdist> python /opt/hostedtoolcache/Python/3.12.0/x64/lib/python3.12/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
pylint: install_package_deps> python -I -m pip install -ctests/upper-constraints.txt 'PyDispatcher>=2.0.5; platform_python_implementation == "CPython"' 'PyPyDispatcher>=2.1.0; platform_python_implementation == "PyPy"' 'Twisted>=18.9.0' 'cryptography>=36.0.0' 'cssselect>=0.9.1' 'itemadapter>=0.1.0' 'itemloaders>=1.0.1' 'lxml>=4.4.1' packaging 'parsel>=1.5.0' 'protego>=0.1.15' 'pyOpenSSL>=21.0.0' 'queuelib>=1.4.2' 'service-identity>=18.1.0' setuptools tldextract 'w3lib>=1.17.0' 'zope.interface>=5.1.0'
pylint: install_package> python -I -m pip install -ctests/upper-constraints.txt --force-reinstall --no-deps /home/runner/work/scrapy/scrapy/.tox/.tmp/package/1/Scrapy-2.11.0.tar.gz
pylint: freeze> python -m pip freeze --all
pylint: astroid==3.0.1,asttokens==2.4.1,attrs==23.1.0,Automat==22.10.0,blessed==1.20.0,boto3==1.33.7,botocore==1.33.7,bpython==0.24,Brotli==1.1.0,cachetools==5.3.2,certifi==2023.11.17,cffi==1.16.0,charset-normalizer==3.3.2,constantly==23.10.4,coverage==7.3.2,cryptography==41.0.7,cssselect==1.2.0,curtsies==0.4.2,cwcwidth==0.1.9,decorator==5.1.1,dill==0.3.7,execnet==2.0.2,executing==2.0.1,filelock==3.13.1,google-api-core==2.14.0,google-auth==2.24.0,google-cloud-core==2.3.3,google-cloud-storage==2.13.0,google-crc32c==1.5.0,google-resumable-media==2.6.0,googleapis-common-protos==1.61.0,greenlet==3.0.1,h2==4.1.0,hpack==4.0.0,hyperframe==6.0.1,hyperlink==21.0.0,idna==3.6,incremental==22.10.0,iniconfig==2.0.0,ipython==8.18.1,isort==5.12.0,itemadapter==0.8.0,itemloaders==1.1.0,jedi==0.19.1,jmespath==1.0.1,lxml==4.9.3,MarkupSafe==2.0.1,matplotlib-inline==0.1.6,mccabe==0.7.0,packaging==23.2,parsel==1.8.1,parso==0.8.3,pexpect==4.9.0,Pillow==10.1.0,pip==23.3.1,platformdirs==4.1.0,pluggy==1.3.0,priority==1.3.0,prompt-toolkit==3.0.41,Protego==0.3.0,protobuf==4.25.1,ptyprocess==0.7.0,pure-eval==0.2.2,pyasn1==0.5.1,pyasn1-modules==0.3.0,pycparser==2.21,PyDispatcher==2.0.7,pyftpdlib==1.5.9,Pygments==2.17.2,pylint==3.0.1,pyOpenSSL==23.3.0,pytest==7.4.3,pytest-cov==4.0.0,pytest-xdist==3.5.0,python-dateutil==2.8.2,pyxdg==0.28,queuelib==1.6.2,requests==2.31.0,requests-file==1.5.1,robotexclusionrulesparser==1.7.1,rsa==4.9,s3transfer==0.8.2,Scrapy @ file:///home/runner/work/scrapy/scrapy/.tox/.tmp/package/1/Scrapy-2.11.0.tar.gz#sha256=95dfd13c5691d88425ffee44c03ee9a12098077f4caac9cff2b4fc70ff9404ec,service-identity==23.1.0,setuptools==69.0.2,six==1.16.0,stack-data==0.6.3,sybil==6.0.2,testfixtures==7.2.2,tldextract==5.1.1,tomlkit==0.12.3,traitlets==5.14.0,Twisted==23.10.0,typing_extensions==4.8.0,urllib3==2.0.7,uvloop==0.19.0,w3lib==2.1.2,wcwidth==0.2.12,zope.interface==6.1,zstandard==0.22.0
pylint: commands[0]> pylint conftest.py docs extras scrapy setup.py tests
<unknown>:230: SyntaxWarning: invalid escape sequence '\d'
************* Module tests.test_addons
tests/test_addons.py:112:40: E0001: Parsing failed: 'unindent does not match any outer indentation level (<unknown>, line 112)' (syntax-error)
************* Module scrapy.addons
scrapy/addons.py:36:24: W1117: 'settings' will be included in '**kwargs' since a positional-only parameter with this name already exists (kwarg-superseded-by-positional-arg)
************* Module scrapy.crawler
scrapy/crawler.py:113:37: W1117: 'settings' will be included in '**kwargs' since a positional-only parameter with this name already exists (kwarg-superseded-by-positional-arg)
************* Module scrapy.core.engine
scrapy/core/engine.py:361:20: W1117: 'crawler' will be included in '**kwargs' since a positional-only parameter with this name already exists (kwarg-superseded-by-positional-arg)
************* Module scrapy.core.scheduler
scrapy/core/scheduler.py:325:15: W1117: 'crawler' will be included in '**kwargs' since a positional-only parameter with this name already exists (kwarg-superseded-by-positional-arg)
scrapy/core/scheduler.py:336:12: W1117: 'crawler' will be included in '**kwargs' since a positional-only parameter with this name already exists (kwarg-superseded-by-positional-arg)
************* Module scrapy.core.downloader.contextfactory
scrapy/core/downloader/contextfactory.py:169:26: W1117: 'settings' will be included in '**kwargs' since a positional-only parameter with this name already exists (kwarg-superseded-by-positional-arg)
scrapy/core/downloader/contextfactory.py:181:26: W1117: 'settings' will be included in '**kwargs' since a positional-only parameter with this name already exists (kwarg-superseded-by-positional-arg)
************* Module scrapy.core.downloader.handlers
scrapy/core/downloader/handlers/__init__.py:59:17: W1117: 'settings' will be included in '**kwargs' since a positional-only parameter with this name already exists (kwarg-superseded-by-positional-arg)
************* Module scrapy.core.downloader.handlers.http10
scrapy/core/downloader/handlers/http10.py:34:41: W1117: 'objcls' will be included in '**kwargs' since a positional-only parameter with this name already exists (kwarg-superseded-by-positional-arg)
scrapy/core/downloader/handlers/http10.py:34:41: W1117: 'crawler' will be included in '**kwargs' since a positional-only parameter with this name already exists (kwarg-superseded-by-positional-arg)
scrapy/core/downloader/handlers/http10.py:39:41: W1117: 'objcls' will be included in '**kwargs' since a positional-only parameter with this name already exists (kwarg-superseded-by-positional-arg)
scrapy/core/downloader/handlers/http10.py:39:41: W1117: 'settings' will be included in '**kwargs' since a positional-only parameter with this name already exists (kwarg-superseded-by-positional-arg)
************* Module scrapy.core.downloader.handlers.s3
scrapy/core/downloader/handlers/s3.py:54:28: W1117: 'objcls' will be included in '**kwargs' since a positional-only parameter with this name already exists (kwarg-superseded-by-positional-arg)
scrapy/core/downloader/handlers/s3.py:54:28: W1117: 'crawler' will be included in '**kwargs' since a positional-only parameter with this name already exists (kwarg-superseded-by-positional-arg)
scrapy/core/downloader/handlers/s3.py:59:28: W1117: 'objcls' will be included in '**kwargs' since a positional-only parameter with this name already exists (kwarg-superseded-by-positional-arg)
scrapy/core/downloader/handlers/s3.py:59:28: W1117: 'settings' will be included in '**kwargs' since a positional-only parameter with this name already exists (kwarg-superseded-by-positional-arg)
************* Module scrapy.utils.misc
scrapy/utils/misc.py:51:16: C0303: Trailing whitespace (trailing-whitespace)
scrapy/utils/misc.py:55:30: C0303: Trailing whitespace (trailing-whitespace)
scrapy/utils/misc.py:57:11: C0303: Trailing whitespace (trailing-whitespace)
scrapy/utils/misc.py:180:23: C0303: Trailing whitespace (trailing-whitespace)
scrapy/utils/misc.py:191:0: C0303: Trailing whitespace (trailing-whitespace)
scrapy/utils/misc.py:198:24: C0303: Trailing whitespace (trailing-whitespace)
************* Module tests.test_downloader_handlers
tests/test_downloader_handlers.py:833:22: W1117: 'objcls' will be included in '**kwargs' since a positional-only parameter with this name already exists (kwarg-superseded-by-positional-arg)
tests/test_downloader_handlers.py:833:22: W1117: 'crawler' will be included in '**kwargs' since a positional-only parameter with this name already exists (kwarg-superseded-by-positional-arg)
tests/test_downloader_handlers.py:863:17: W1117: 'objcls' will be included in '**kwargs' since a positional-only parameter with this name already exists (kwarg-superseded-by-positional-arg)
tests/test_downloader_handlers.py:863:17: W1117: 'crawler' will be included in '**kwargs' since a positional-only parameter with this name already exists (kwarg-superseded-by-positional-arg)
tests/test_downloader_handlers.py:890:12: W1117: 'objcls' will be included in '**kwargs' since a positional-only parameter with this name already exists (kwarg-superseded-by-positional-arg)
tests/test_downloader_handlers.py:890:12: W1117: 'crawler' will be included in '**kwargs' since a positional-only parameter with this name already exists (kwarg-superseded-by-positional-arg)
************* Module tests.test_utils_misc.__init__
tests/test_utils_misc/__init__.py:133:0: C0303: Trailing whitespace (trailing-whitespace)

-----------------------------------
Your code has been rated at 9.99/10

pylint: exit 22 (57.23 seconds) /home/runner/work/scrapy/scrapy> pylint conftest.py docs extras scrapy setup.py tests pid=2046
.pkg: _exit> python /opt/hostedtoolcache/Python/3.12.0/x64/lib/python3.12/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
  pylint: FAIL code 22 (101.48=setup[44.25]+cmd[57.23] seconds)
  evaluation failed :( (101.60 seconds)
##[error]Process completed with exit code 22.

step_name: checks (3.8, typing)/4_Run check.txt
log: ##[group]Run pip install -U tox
[36;1mpip install -U tox[0m
[36;1mtox[0m
shell: /usr/bin/bash -e {0}
env:
  pythonLocation: /opt/hostedtoolcache/Python/3.8.18/x64
  PKG_CONFIG_PATH: /opt/hostedtoolcache/Python/3.8.18/x64/lib/pkgconfig
  Python_ROOT_DIR: /opt/hostedtoolcache/Python/3.8.18/x64
  Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.8.18/x64
  Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.8.18/x64
  LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.8.18/x64/lib
  TOXENV: typing
##[endgroup]
Collecting tox
  Downloading tox-4.11.4-py3-none-any.whl.metadata (5.0 kB)
Collecting cachetools>=5.3.1 (from tox)
  Downloading cachetools-5.3.2-py3-none-any.whl.metadata (5.2 kB)
Collecting chardet>=5.2 (from tox)
  Downloading chardet-5.2.0-py3-none-any.whl.metadata (3.4 kB)
Collecting colorama>=0.4.6 (from tox)
  Downloading colorama-0.4.6-py2.py3-none-any.whl (25 kB)
Collecting filelock>=3.12.3 (from tox)
  Downloading filelock-3.13.1-py3-none-any.whl.metadata (2.8 kB)
Collecting packaging>=23.1 (from tox)
  Downloading packaging-23.2-py3-none-any.whl.metadata (3.2 kB)
Collecting platformdirs>=3.10 (from tox)
  Downloading platformdirs-4.1.0-py3-none-any.whl.metadata (11 kB)
Collecting pluggy>=1.3 (from tox)
  Downloading pluggy-1.3.0-py3-none-any.whl.metadata (4.3 kB)
Collecting pyproject-api>=1.6.1 (from tox)
  Downloading pyproject_api-1.6.1-py3-none-any.whl.metadata (2.8 kB)
Collecting tomli>=2.0.1 (from tox)
  Downloading tomli-2.0.1-py3-none-any.whl (12 kB)
Collecting virtualenv>=20.24.3 (from tox)
  Downloading virtualenv-20.25.0-py3-none-any.whl.metadata (4.5 kB)
Collecting distlib<1,>=0.3.7 (from virtualenv>=20.24.3->tox)
  Downloading distlib-0.3.7-py2.py3-none-any.whl.metadata (5.1 kB)
Downloading tox-4.11.4-py3-none-any.whl (153 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 154.0/154.0 kB 18.9 MB/s eta 0:00:00
Downloading cachetools-5.3.2-py3-none-any.whl (9.3 kB)
Downloading chardet-5.2.0-py3-none-any.whl (199 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 199.4/199.4 kB 47.2 MB/s eta 0:00:00
Downloading filelock-3.13.1-py3-none-any.whl (11 kB)
Downloading packaging-23.2-py3-none-any.whl (53 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 53.0/53.0 kB 15.7 MB/s eta 0:00:00
Downloading platformdirs-4.1.0-py3-none-any.whl (17 kB)
Downloading pluggy-1.3.0-py3-none-any.whl (18 kB)
Downloading pyproject_api-1.6.1-py3-none-any.whl (12 kB)
Downloading virtualenv-20.25.0-py3-none-any.whl (3.8 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.8/3.8 MB 102.9 MB/s eta 0:00:00
Downloading distlib-0.3.7-py2.py3-none-any.whl (468 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 468.9/468.9 kB 75.6 MB/s eta 0:00:00
Installing collected packages: distlib, tomli, pluggy, platformdirs, packaging, filelock, colorama, chardet, cachetools, virtualenv, pyproject-api, tox
Successfully installed cachetools-5.3.2 chardet-5.2.0 colorama-0.4.6 distlib-0.3.7 filelock-3.13.1 packaging-23.2 platformdirs-4.1.0 pluggy-1.3.0 pyproject-api-1.6.1 tomli-2.0.1 tox-4.11.4 virtualenv-20.25.0

[notice] A new release of pip is available: 23.0.1 -> 23.3.1
[notice] To update, run: pip install --upgrade pip
typing: install_deps> python -I -m pip install -ctests/upper-constraints.txt mypy==1.6.1 types-attrs==19.1.0 types-lxml==2023.10.21 types-Pillow==10.1.0.0 types-Pygments==2.16.0.0 types-pyOpenSSL==23.3.0.0 types-setuptools==68.2.0.0 typing-extensions==4.8.0 'w3lib>=2.1.2'
.pkg: install_requires> python -I -m pip install 'setuptools>=40.8.0' wheel
.pkg: _optional_hooks> python /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
.pkg: get_requires_for_build_sdist> python /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
.pkg: get_requires_for_build_wheel> python /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
.pkg: install_requires_for_build_wheel> python -I -m pip install wheel
.pkg: freeze> python -m pip freeze --all
.pkg: pip==23.3.1,setuptools==69.0.2,wheel==0.42.0
.pkg: prepare_metadata_for_build_wheel> python /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
.pkg: build_sdist> python /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
typing: install_package_deps> python -I -m pip install -ctests/upper-constraints.txt 'PyDispatcher>=2.0.5; platform_python_implementation == "CPython"' 'PyPyDispatcher>=2.1.0; platform_python_implementation == "PyPy"' 'Twisted>=18.9.0' 'cryptography>=36.0.0' 'cssselect>=0.9.1' 'itemadapter>=0.1.0' 'itemloaders>=1.0.1' 'lxml>=4.4.1' packaging 'parsel>=1.5.0' 'protego>=0.1.15' 'pyOpenSSL>=21.0.0' 'queuelib>=1.4.2' 'service-identity>=18.1.0' setuptools tldextract 'w3lib>=1.17.0' 'zope.interface>=5.1.0'
typing: install_package> python -I -m pip install -ctests/upper-constraints.txt --force-reinstall --no-deps /home/runner/work/scrapy/scrapy/.tox/.tmp/package/1/Scrapy-2.11.0.tar.gz
typing: freeze> python -m pip freeze --all
typing: attrs==23.1.0,Automat==22.10.0,certifi==2023.11.17,cffi==1.16.0,charset-normalizer==3.3.2,constantly==23.10.4,cryptography==41.0.7,cssselect==1.2.0,filelock==3.13.1,hyperlink==21.0.0,idna==3.6,incremental==22.10.0,itemadapter==0.8.0,itemloaders==1.1.0,jmespath==1.0.1,lxml==4.9.3,mypy==1.6.1,mypy-extensions==1.0.0,packaging==23.2,parsel==1.8.1,pip==23.3.1,Protego==0.3.0,pyasn1==0.5.1,pyasn1-modules==0.3.0,pycparser==2.21,PyDispatcher==2.0.7,pyOpenSSL==23.3.0,queuelib==1.6.2,requests==2.31.0,requests-file==1.5.1,Scrapy @ file:///home/runner/work/scrapy/scrapy/.tox/.tmp/package/1/Scrapy-2.11.0.tar.gz#sha256=10ffed5c2108f38048c2270acaf9e181014495f11170991e45b186156308910b,service-identity==23.1.0,setuptools==69.0.2,six==1.16.0,tldextract==5.1.1,tomli==2.0.1,Twisted==23.10.0,types-attrs==19.1.0,types-beautifulsoup4==4.12.0.7,types-docutils==0.20.0.3,types-html5lib==1.1.11.15,types-lxml==2023.10.21,types-Pillow==10.1.0.0,types-Pygments==2.16.0.0,types-pyOpenSSL==23.3.0.0,types-setuptools==68.2.0.0,typing_extensions==4.8.0,urllib3==2.1.0,w3lib==2.1.2,wheel==0.42.0,zope.interface==6.1
typing: commands[0]> mypy scrapy tests
tests/test_addons.py:112: error: unindent does not match any outer indentation level  [syntax]
Found 1 error in 1 file (errors prevented further checking)
typing: exit 2 (0.47 seconds) /home/runner/work/scrapy/scrapy> mypy scrapy tests pid=1974
.pkg: _exit> python /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__
  typing: FAIL code 2 (17.46=setup[16.99]+cmd[0.47] seconds)
  evaluation failed :( (17.55 seconds)
##[error]Process completed with exit code 2.


Changed files:
scrapy/addons.py
scrapy/core/downloader/contextfactory.py
scrapy/core/downloader/handlers/__init__.py
scrapy/core/downloader/handlers/http10.py
scrapy/core/engine.py
scrapy/crawler.py
scrapy/extensions/feedexport.py
scrapy/utils/misc.py
tests/test_addons.py
tests/test_downloader_handlers.py
tests/test_utils_misc/__init__.py
tests/test_webclient.py

Fix diff:
diff --git a/scrapy/addons.py b/scrapy/addons.py
index a6efba362..cb1574b2f 100644
--- a/scrapy/addons.py
+++ b/scrapy/addons.py
@@ -33,9 +33,7 @@ class AddonManager:
             try:
                 addoncls = load_object(clspath)
                 # changes create_instance call to build_from_settings
-                addon = build_from_settings(
-                    addoncls, settings=settings
-                )
+                addon = build_from_settings(addoncls, settings=settings)
                 addon.update_settings(settings)
                 self.addons.append(addon)
             except NotConfigured as e:
diff --git a/scrapy/core/downloader/contextfactory.py b/scrapy/core/downloader/contextfactory.py
index 6d3ddd4a4..73a3d32af 100644
--- a/scrapy/core/downloader/contextfactory.py
+++ b/scrapy/core/downloader/contextfactory.py
@@ -178,9 +178,7 @@ def load_context_factory_from_settings(settings, crawler):
     except TypeError:
         # use context factory defaults
         # changes create_instance call to build_from_settings
-        context_factory = build_from_settings(
-            context_factory_cls, settings = settings
-        )
+        context_factory = build_from_settings(context_factory_cls, settings=settings)
         # context_factory = create_instance(
         #     objcls=context_factory_cls,
         #     settings=settings,
diff --git a/scrapy/core/downloader/handlers/__init__.py b/scrapy/core/downloader/handlers/__init__.py
index d5b8ce89d..fc597b017 100644
--- a/scrapy/core/downloader/handlers/__init__.py
+++ b/scrapy/core/downloader/handlers/__init__.py
@@ -56,9 +56,7 @@ class DownloadHandlers:
             if skip_lazy and getattr(dhcls, "lazy", True):
                 return None
             # change create_instance call to build_from_settings
-            dh = build_from_settings(
-                dhcls, settings=self._crawler.settings
-            )
+            dh = build_from_settings(dhcls, settings=self._crawler.settings)
             # dh = create_instance(
             #     objcls=dhcls,
             #     settings=self._crawler.settings,
diff --git a/scrapy/core/downloader/handlers/http10.py b/scrapy/core/downloader/handlers/http10.py
index 76faf7d2b..5c01ba410 100644
--- a/scrapy/core/downloader/handlers/http10.py
+++ b/scrapy/core/downloader/handlers/http10.py
@@ -1,6 +1,6 @@
 """Download handlers for http and https schemes
 """
-from scrapy.utils.misc import build_from_settings, build_from_crawler, load_object
+from scrapy.utils.misc import build_from_crawler, build_from_settings, load_object
 from scrapy.utils.python import to_unicode
 
 
diff --git a/scrapy/core/engine.py b/scrapy/core/engine.py
index 81aacdf8d..281dc8a54 100644
--- a/scrapy/core/engine.py
+++ b/scrapy/core/engine.py
@@ -358,9 +358,7 @@ class ExecutionEngine:
             raise RuntimeError(f"No free spider slot when opening {spider.name!r}")
         logger.info("Spider opened", extra={"spider": spider})
         nextcall = CallLaterOnce(self._next_request)
-        scheduler = build_from_crawler(
-            self.scheduler_cls, crawler=self.crawler
-        )
+        scheduler = build_from_crawler(self.scheduler_cls, crawler=self.crawler)
         start_requests = yield self.scraper.spidermw.process_start_requests(
             start_requests, spider
         )
diff --git a/scrapy/crawler.py b/scrapy/crawler.py
index a1f699b7e..128095368 100644
--- a/scrapy/crawler.py
+++ b/scrapy/crawler.py
@@ -111,7 +111,8 @@ class Crawler:
 
         # changes create_instance call to build_from_settings
         self.request_fingerprinter = build_from_settings(
-            load_object(self.settings["REQUEST_FINGERPRINTER_CLASS"]), settings=self.settings
+            load_object(self.settings["REQUEST_FINGERPRINTER_CLASS"]),
+            settings=self.settings,
         )
 
         # self.request_fingerprinter = create_instance(
diff --git a/scrapy/extensions/feedexport.py b/scrapy/extensions/feedexport.py
index a4c8a470d..62fb07e19 100644
--- a/scrapy/extensions/feedexport.py
+++ b/scrapy/extensions/feedexport.py
@@ -28,7 +28,7 @@ from scrapy.utils.defer import maybe_deferred_to_future
 from scrapy.utils.deprecate import create_deprecated_class
 from scrapy.utils.ftp import ftp_store_file
 from scrapy.utils.log import failure_to_exc_info
-from scrapy.utils.misc import build_from_settings, build_from_crawler, load_object
+from scrapy.utils.misc import build_from_crawler, build_from_settings, load_object
 from scrapy.utils.python import without_none_values
 
 logger = logging.getLogger(__name__)
diff --git a/scrapy/utils/misc.py b/scrapy/utils/misc.py
index 613328a2b..2e39aaaa3 100644
--- a/scrapy/utils/misc.py
+++ b/scrapy/utils/misc.py
@@ -47,19 +47,21 @@ def arg_to_iter(arg: Any) -> Iterable[Any]:
         return cast(Iterable[Any], arg)
     return [arg]
 
+
 # def build_from_crawler(objcls, crawler, none, *args, **kwargs):
-#     if crawler 
+#     if crawler
 #         if hasattr(objcls, "from_crawler"):
 #             instance = objcls.from_crawler(crawler, *args, **kwargs)
 #             method_name = "from_crawler"
-#         if instance is None: 
+#         if instance is None:
 #             raise TypeError(f"{objcls.__qualname__}.{method_name} returned None)
-#     else: 
+#     else:
 #         instance = objcls(*args, **kwargs)
 #         method_name = "__new__"
 
 #     return instance
 
+
 def load_object(path: Union[str, Callable]) -> Any:
     """Load an object given its absolute object path, and return it.
 
@@ -176,8 +178,8 @@ def rel_has_nofollow(rel: Optional[str]) -> bool:
 # Raises ``ValueError`` if``crawler`` is``None``.
 #  Raises typeError is instance is None
 # Creates a class instance using 'from_crawler' constructor
-def build_from_crawler(objcls, crawler, /, *args, **kwargs):
-    if crawler is None: 
+def build_from_crawler(objcls, crawler, *args, **kwargs):
+    if crawler is None:
         raise ValueError("Specify crawler.")
     if crawler and hasattr(objcls, "from_crawler"):
         instance = objcls.from_crawler(crawler, *args, **kwargs)
@@ -188,14 +190,14 @@ def build_from_crawler(objcls, crawler, /, *args, **kwargs):
     if instance is None:
         raise TypeError(f"{objcls.__qualname__}.{method_name} returned None")
     return instance
-            
 
-#``*args`` and ``**kwargs`` are forwarded to the constructors.
+
+# ``*args`` and ``**kwargs`` are forwarded to the constructors.
 # Raises ``ValueError`` if``settings`` is``None``.
 #  Raises typeError is instance is None
 # Creates a class instance using 'from_settings' constructor
-def build_from_settings(objcls, settings, /, *args, **kwargs):
-    if settings is None: 
+def build_from_settings(objcls, settings, *args, **kwargs):
+    if settings is None:
         raise ValueError("Specify settings.")
     if settings and hasattr(objcls, "from_settings"):
         instance = objcls.from_settings(settings, *args, **kwargs)
@@ -208,8 +210,6 @@ def build_from_settings(objcls, settings, /, *args, **kwargs):
     return instance
 
 
-
-
 @contextmanager
 def set_environ(**kwargs: str) -> Generator[None, Any, None]:
     """Temporarily set environment variables inside the context manager and
diff --git a/tests/test_addons.py b/tests/test_addons.py
index 355539162..5e390c49d 100644
--- a/tests/test_addons.py
+++ b/tests/test_addons.py
@@ -109,7 +109,7 @@ class AddonManagerTest(unittest.TestCase):
         self.assertIsInstance(manager.addons[0], CreateInstanceAddon)
         self.assertEqual(crawler.settings.get("MYADDON_KEY"), "val")
 
-     def test_build_from_crawler(self):
+    def test_build_from_crawler(self):
         settings_dict = {
             "ADDONS": {"tests.test_addons.CreateInstanceAddon": 0},
             "MYADDON": {"MYADDON_KEY": "val"},
diff --git a/tests/test_downloader_handlers.py b/tests/test_downloader_handlers.py
index 8595e68c2..37a53643b 100644
--- a/tests/test_downloader_handlers.py
+++ b/tests/test_downloader_handlers.py
@@ -669,9 +669,7 @@ class Https11CustomCiphers(unittest.TestCase):
         crawler = get_crawler(
             settings_dict={"DOWNLOADER_CLIENT_TLS_CIPHERS": "CAMELLIA256-SHA"}
         )
-        self.download_handler = build_from_crawler(
-            self.download_handler_cls, crawler
-        )
+        self.download_handler = build_from_crawler(self.download_handler_cls, crawler)
         self.download_request = self.download_handler.download_request
 
     @defer.inlineCallbacks
@@ -1036,9 +1034,7 @@ class BaseFTPTestCase(unittest.TestCase):
         self.port = reactor.listenTCP(0, self.factory, interface="127.0.0.1")
         self.portNum = self.port.getHost().port
         crawler = get_crawler()
-        self.download_handler = build_from_crawler(
-            FTPDownloadHandler, crawler
-        )
+        self.download_handler = build_from_crawler(FTPDownloadHandler, crawler)
         self.addCleanup(self.port.stopListening)
 
     def tearDown(self):
@@ -1182,9 +1178,7 @@ class AnonymousFTPTestCase(BaseFTPTestCase):
         self.port = reactor.listenTCP(0, self.factory, interface="127.0.0.1")
         self.portNum = self.port.getHost().port
         crawler = get_crawler()
-        self.download_handler = build_from_crawler(
-            FTPDownloadHandler, crawler
-        )
+        self.download_handler = build_from_crawler(FTPDownloadHandler, crawler)
         self.addCleanup(self.port.stopListening)
 
     def tearDown(self):
@@ -1194,9 +1188,7 @@ class AnonymousFTPTestCase(BaseFTPTestCase):
 class DataURITestCase(unittest.TestCase):
     def setUp(self):
         crawler = get_crawler()
-        self.download_handler = build_from_crawler(
-            DataURIDownloadHandler, crawler
-        )
+        self.download_handler = build_from_crawler(DataURIDownloadHandler, crawler)
         self.download_request = self.download_handler.download_request
         self.spider = Spider("foo")
 
diff --git a/tests/test_utils_misc/__init__.py b/tests/test_utils_misc/__init__.py
index ccf8022c9..0152a1110 100644
--- a/tests/test_utils_misc/__init__.py
+++ b/tests/test_utils_misc/__init__.py
@@ -95,6 +95,7 @@ class UtilsMiscTestCase(unittest.TestCase):
         self.assertEqual(
             list(arg_to_iter(TestItem(name="john"))), [TestItem(name="john")]
         )
+
     def test_build_from_crawler(self):
         crawler = mock.MagicMock(spec_set=["settings"])
         args = (True, 100.0)
@@ -122,7 +123,7 @@ class UtilsMiscTestCase(unittest.TestCase):
         )
         for specs in spec_sets:
             m = mock.MagicMock(spec_set=specs)
-            _test_with_crawler(m, settings, crawler)
+            _test_with_crawler(m, crawler)
             m.reset_mock()
 
         # Check adoption of crawler
@@ -130,7 +131,7 @@ class UtilsMiscTestCase(unittest.TestCase):
         m.from_crawler.return_value = None
         with self.assertRaises(TypeError):
             build_from_crawler(m, crawler, *args, **kwargs)
-    
+
     def test_build_from_settings(self):
         settings = mock.MagicMock()
         args = (True, 100.0)
diff --git a/tests/test_webclient.py b/tests/test_webclient.py
index 0042fe8f0..a69d9c1b0 100644
--- a/tests/test_webclient.py
+++ b/tests/test_webclient.py
@@ -24,7 +24,7 @@ from scrapy.core.downloader import webclient as client
 from scrapy.core.downloader.contextfactory import ScrapyClientContextFactory
 from scrapy.http import Headers, Request
 from scrapy.settings import Settings
-from scrapy.utils.misc import create_instance
+from scrapy.utils.misc import build_from_settings
 from scrapy.utils.python import to_bytes, to_unicode
 from tests.mockserver import (
     BrokenDownloadResource,
@@ -470,8 +470,8 @@ class WebClientCustomCiphersSSLTestCase(WebClientSSLTestCase):
     def testPayload(self):
         s = "0123456789" * 10
         settings = Settings({"DOWNLOADER_CLIENT_TLS_CIPHERS": self.custom_ciphers})
-        client_context_factory = create_instance(
-            ScrapyClientContextFactory, settings=settings, crawler=None
+        client_context_factory = build_from_settings(
+            ScrapyClientContextFactory, settings=settings
         )
         return getPage(
             self.getURL("payload"), body=s, contextFactory=client_context_factory
@@ -482,8 +482,8 @@ class WebClientCustomCiphersSSLTestCase(WebClientSSLTestCase):
         settings = Settings(
             {"DOWNLOADER_CLIENT_TLS_CIPHERS": "ECDHE-RSA-AES256-GCM-SHA384"}
         )
-        client_context_factory = create_instance(
-            ScrapyClientContextFactory, settings=settings, crawler=None
+        client_context_factory = build_from_settings(
+            ScrapyClientContextFactory, settings=settings
         )
         d = getPage(
             self.getURL("payload"), body=s, contextFactory=client_context_factory