Repository: bitcoin/bitcoin
File: test/functional/test_framework/test_framework.py (Python)

Code before:
            versions = [None] * num_nodes
        bin_dirs = []
        for v in versions:
            bin_dir = bin_dir_from_version(v)

            # Fail test if any of the needed release binaries is missing
            for bin_path in (argv[0] for binaries in (self.get_binaries(bin_dir),)
                                     for argv in (binaries.node_argv(), binaries.rpc_argv())):

                if shutil.which(bin_path) is None:
                    self.log.error(f"Binary not found: {bin_path}")
                    if v is None:
                        raise AssertionError("At least one binary is missing, did you compile?")
                    raise AssertionError("At least one release binary is missing. "
                                         "Previous releases binaries can be downloaded via `test/get_previous_releases.py`.")

            bin_dirs.append(bin_dir)

        assert_equal(len(extra_confs), num_nodes)
        assert_equal(len(extra_args), num_nodes)
        assert_equal(len(versions), num_nodes)
        assert_equal(len(bin_dirs), num_nodes)
        for i in range(num_nodes):
            args = list(extra_args[i])
            test_node_i = TestNode(
                i,
                get_datadir_path(self.options.tmpdir, i),
                chain=self.chain,
                rpchost=rpchost,
                timewait=self.rpc_timeout,
                timeout_factor=self.options.timeout_factor,
                binaries=self.get_binaries(bin_dirs[i]),
                version=versions[i],
                coverage_dir=self.options.coveragedir,
                cwd=self.options.tmpdir,
                extra_conf=extra_confs[i],
                extra_args=args,
                use_cli=self.options.usecli,
                start_perf=self.options.perf,
                use_valgrind=self.options.valgrind,
                v2transport=self.options.v2transport,
                uses_wallet=self.uses_wallet,
            )
            self.nodes.append(test_node_i)
            if not test_node_i.version_is_at_least(170000):
                # adjust conf for pre 17
                test_node_i.replace_in_config([('[regtest]', '')])

    def start_node(self, i, *args, **kwargs):
        """Start a bitcoind"""


Review comment (bug):
Not sure why the lint task complains here: 

```
[21:49:19.712] test/functional/test_framework/test_framework.py:560: error: Need type annotation for "extra_init"  [var-annotated]
[21:49:21.445] Found 1 error in 1 file (checked 301 source files)
[21:49:21.473] ^---- ⚠️ Failure generated from lint-python.py
```

No other variable in this function is required to be annotated and the lint should probably be fixed to not require it here either.

Code after:
        if extra_args is None:
            extra_args = [[]] * num_nodes
        # Whitelist peers to speed up tx relay / mempool sync. Don't use it if testing tx relay or timing.
        if self.noban_tx_relay:
            for i in range(len(extra_args)):
                extra_args[i] = extra_args[i] + ["-whitelist=noban,in,out@127.0.0.1"]
        if versions is None:
            versions = [None] * num_nodes
        bin_dirs = []
        for v in versions:
            bin_dir = bin_dir_from_version(v)

            # Fail test if any of the needed release binaries is missing
            for bin_path in (argv[0] for binaries in (self.get_binaries(bin_dir),)
                                     for argv in (binaries.node_argv(), binaries.rpc_argv())):

                if shutil.which(bin_path) is None:
                    self.log.error(f"Binary not found: {bin_path}")
                    if v is None:
                        raise AssertionError("At least one binary is missing, did you compile?")
                    raise AssertionError("At least one release binary is missing. "
                                         "Previous releases binaries can be downloaded via `test/get_previous_releases.py`.")

            bin_dirs.append(bin_dir)

        extra_init = [{}] * num_nodes if self.extra_init is None else self.extra_init # type: ignore[var-annotated]
        assert_equal(len(extra_init), num_nodes)
        assert_equal(len(extra_confs), num_nodes)
        assert_equal(len(extra_args), num_nodes)
        assert_equal(len(versions), num_nodes)
        assert_equal(len(bin_dirs), num_nodes)
        for i in range(num_nodes):
            args = list(extra_args[i])
            init = dict(
                chain=self.chain,
                rpchost=rpchost,
                timewait=self.rpc_timeout,
                timeout_factor=self.options.timeout_factor,
                binaries=self.get_binaries(bin_dirs[i]),
                version=versions[i],
                coverage_dir=self.options.coveragedir,
                cwd=self.options.tmpdir,
                extra_conf=extra_confs[i],
                extra_args=args,
                use_cli=self.options.usecli,
                start_perf=self.options.perf,
                use_valgrind=self.options.valgrind,
                v2transport=self.options.v2transport,
                uses_wallet=self.uses_wallet,
            )
            init.update(extra_init[i])