Repository: ethereum/web3.py

Issue:
TypeError: Could not format invalid type of None for field 'withdrawals' on 6.2.0
* Version: 6.2.0
* Python: 3.11
* OS: linux
* `pip freeze` output

```
aiobotocore==2.5.0
aiohttp==3.8.4
aioitertools==0.11.0
aiosignal==1.3.1
anyio==3.6.2
async-timeout==4.0.2
attrs==23.1.0
base58==2.1.1
bitarray==2.7.3
botocore==1.29.76
Brotli==1.0.9
brotli-asgi==1.3.0
certifi==2022.12.7
charset-normalizer==3.1.0
click==8.1.3
cytoolz==0.12.1
dependency-injector==4.41.0
eth-abi==4.0.0
eth-account==0.8.0
eth-hash==0.5.1
eth-keyfile==0.6.1
eth-keys==0.4.0
eth-rlp==0.3.0
eth-typing==3.3.0
eth-utils==2.1.0
fastapi==0.95.1
frozenlist==1.3.3
h11==0.14.0
hexbytes==0.3.0
httpcore==0.16.3
httptools==0.5.0
httpx==0.23.3
idna==3.4
jmespath==1.0.1
jsonschema==4.17.3
lru-dict==1.1.8
multidict==6.0.4
neo4j==5.7.0
parsimonious==0.9.0
prometheus-client==0.16.0
protobuf==4.22.3
pycryptodome==3.17
pydantic==1.10.7
pyrsistent==0.19.3
python-dateutil==2.8.2
python-dotenv==1.0.0
pytz==2023.3
PyYAML==6.0
regex==2023.3.23
requests==2.28.2
rfc3986==1.5.0
rlp==3.0.0
sentry-sdk==1.19.1
six==1.16.0
sniffio==1.3.0
starlette==0.26.1
starlette-exporter==0.15.1
toolz==0.12.0
typer==0.7.0
typing_extensions==4.5.0
urllib3==1.26.15
uvicorn==0.21.1
uvloop==0.17.0
watchfiles==0.19.0
web3==6.2.0
websockets==11.0.1
wrapt==1.15.0
yarl==1.8.2

```


### What was wrong?

query of this block by it's number: 17034890 gives an error.
The command: `await w3.eth.get_block(block_id, full_transactions=True)`
The exception I get:
```
  + Exception Group Traceback (most recent call last):

  |   File "<frozen runpy>", line 198, in _run_module_as_main

  |   File "<frozen runpy>", line 88, in _run_code

  |   File "/src/app/cli/__main__.py", line 15, in <module>
  |     app()

  |   File "/src/app/utils/time_decorator.py", line 30, in wrapped
  |     result = fn(*args, **kwargs)
  |              ^^^^^^^^^^^^^^^^^^^

  |   File "/src/app/cli/data/commands.py", line 85, in bulk_import_bare_blocks
  |     asyncio.run(_do())

  |   File "/usr/local/lib/python3.11/asyncio/runners.py", line 190, in run
  |     return runner.run(main)
  |            ^^^^^^^^^^^^^^^^

  |   File "/usr/local/lib/python3.11/asyncio/runners.py", line 118, in run
  |     return self._loop.run_until_complete(task)
  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  |   File "/usr/local/lib/python3.11/asyncio/base_events.py", line 653, in run_until_complete
  |     return future.result()
  |            ^^^^^^^^^^^^^^^

  |   File "/src/app/cli/data/commands.py", line 68, in _do
  |     async with asyncio.TaskGroup() as tg:

  |   File "/usr/local/lib/python3.11/asyncio/taskgroups.py", line 147, in __aexit__
  |     raise me from None

  | ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception)

  +-+---------------- 1 ----------------

    | Traceback (most recent call last):

    |   File "/env/lib/python3.11/site-packages/eth_utils/applicators.py", line 84, in apply_formatters_to_dict
    |     yield key, formatters[key](item)
    |                ^^^^^^^^^^^^^^^^^^^^^

    |   File "cytoolz/functoolz.pyx", line 253, in cytoolz.functoolz.curry.__call__

    |   File "cytoolz/functoolz.pyx", line 249, in cytoolz.functoolz.curry.__call__

    |   File "/env/lib/python3.11/site-packages/eth_utils/decorators.py", line 91, in wrapper
    |     return ReturnType(result)  # type: ignore
    |            ^^^^^^^^^^^^^^^^^^

    | TypeError: NoneType takes no arguments

    | 
    | The above exception was the direct cause of the following exception:
    | 

    | Traceback (most recent call last):

    |   File "/src/app/cli/data/commands.py", line 24, in fetch_block
    |     block_data = await w3.eth.get_block(block_id, full_transactions=True)
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    |   File "/env/lib/python3.11/site-packages/web3/eth/async_eth.py", line 402, in get_block
    |     return await self._get_block(block_identifier, full_transactions)
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    |   File "/env/lib/python3.11/site-packages/web3/module.py", line 96, in caller
    |     return apply_result_formatters(result_formatters, result)
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    |   File "cytoolz/functoolz.pyx", line 253, in cytoolz.functoolz.curry.__call__

    |   File "cytoolz/functoolz.pyx", line 249, in cytoolz.functoolz.curry.__call__

    |   File "/env/lib/python3.11/site-packages/web3/module.py", line 43, in apply_result_formatters
    |     formatted_result = pipe(result, result_formatters)
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    |   File "cytoolz/functoolz.pyx", line 666, in cytoolz.functoolz.pipe

    |   File "cytoolz/functoolz.pyx", line 641, in cytoolz.functoolz.c_pipe

    |   File "cytoolz/functoolz.pyx", line 253, in cytoolz.functoolz.curry.__call__

    |   File "cytoolz/functoolz.pyx", line 249, in cytoolz.functoolz.curry.__call__

    |   File "/env/lib/python3.11/site-packages/eth_utils/applicators.py", line 72, in apply_formatter_if
    |     return formatter(value)
    |            ^^^^^^^^^^^^^^^^

    |   File "cytoolz/functoolz.pyx", line 253, in cytoolz.functoolz.curry.__call__

    |   File "cytoolz/functoolz.pyx", line 249, in cytoolz.functoolz.curry.__call__

    |   File "/env/lib/python3.11/site-packages/web3/_utils/method_formatters.py", line 163, in type_aware_apply_formatters_to_dict
    |     formatted_dict: Dict[str, Any] = apply_formatters_to_dict(formatters, dict(value))
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    |   File "cytoolz/functoolz.pyx", line 253, in cytoolz.functoolz.curry.__call__

    |   File "cytoolz/functoolz.pyx", line 249, in cytoolz.functoolz.curry.__call__

    |   File "/env/lib/python3.11/site-packages/eth_utils/functional.py", line 45, in inner
    |     return callback(fn(*args, **kwargs))
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    |   File "/env/lib/python3.11/site-packages/eth_utils/applicators.py", line 95, in apply_formatters_to_dict
    |     raise TypeError(new_error_message) from exc

    | TypeError: Could not format invalid type of None for field 'withdrawals'

    +------------------------------------

```

Receiving this block with curl shows that the `withdrawals` field is `null`:
```
...
    "transactionsRoot": "0x92601570ffa29723769c21a76bcd7037391d65ffe1d20eae230b97adfe8e7c3c",
    "uncles": [],
    "withdrawals": null,
    "withdrawalsRoot": "0x48768ac4179cce1b245fc5c18ab1f809b09bfb03e1f855fddc12f182e4ea36d7"
...

```

Checked on Infura API and private Geth node.

### How can it be fixed?
It seems that the web3 formatter for this field is not ready for the None value.




Discussion:

Resolving patch:
diff --git a/web3/_utils/method_formatters.py b/web3/_utils/method_formatters.py
--- a/web3/_utils/method_formatters.py
+++ b/web3/_utils/method_formatters.py
@@ -297,7 +297,9 @@ def apply_list_to_array_formatter(formatter: Any) -> Callable[..., Any]:
         )
     ),
     "transactionsRoot": apply_formatter_if(is_not_null, to_hexbytes(32)),
-    "withdrawals": apply_formatter_to_array(withdrawal_result_formatter),
+    "withdrawals": apply_formatter_if(
+        is_not_null, apply_list_to_array_formatter(withdrawal_result_formatter)
+    ),
     "withdrawalsRoot": apply_formatter_if(is_not_null, to_hexbytes(32)),
 }
 


Test patch: