question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

brownie.reverts() transaction.py AttributeError on reverted transactions

See original GitHub issue

Environment information

  • brownie Version: 1.16.4
  • ganache-cli Version: 7.0.2 (@ganache/cli: 0.1.3, @ganache/core: 0.1.3)
  • solc Version: 0.8.0
  • Python Version: 3.10.2
  • OS: win
  • platform win32 – Python 3.10.2, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
  • plugins: eth-brownie-1.16.4, hypothesis-6.21.6, forked-1.3.0, xdist-1.34.0, web3-5.23.1

Virtual environment

Everything is running in a virtual python venv environment, extended with nodeenv to install ganache. The environment works in all other aspects flawlessly. Setup details can be found here: https://github.com/smartcontractkit/full-blockchain-solidity-course-py/discussions/971 A repository with minimal code reproducing the error is provided here: https://github.com/n4n0b1t3/brownie.reverts.example

What was wrong?

  • command ran: brownie test
  • Solidity contract code: directory /contracts/ExampleContract.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.6 <0.9.0;

contract ExampleContract {
    address public owner;

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "only owner");
        _;
    }

    function withdraw() public payable onlyOwner {
        payable(msg.sender).transfer(address(this).balance);
    }
}
  • the code that caused the failure: directory /test/test_reverts.py
import brownie
from brownie import ExampleContract, accounts, exceptions

def test_only_owner_can_withdraw():
    example_contract = ExampleContract.deploy({"from": accounts[0]})
    bad_account = accounts.add()
    with brownie.reverts():
        example_contract.withdraw({"from": bad_account})
  • Variation making use of pytest.raises(): directory /test/test_reverts.py
import brownie
import pytest
from brownie import ExampleContract, accounts, exceptions

def test_only_owner_can_withdraw():
    example_contract = ExampleContract.deploy({"from": accounts[0]})
    bad_account = accounts.add()
    with pytest.raises(exceptions.VirtualMachineError):
        example_contract.withdraw({"from": bad_account})
  • full output of the error you received
(.venv) testcode>brownie test
INFORMATION: Es konnten keine Dateien mit dem angegebenen
Muster gefunden werden.
Brownie v1.16.4 - Python development framework for Ethereum

======================================================================================================= test session starts =======================================================================================================
platform win32 -- Python 3.10.2, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: C:\Users\Zarathustra\blockchainProjects\testing.revert\testcode
plugins: eth-brownie-1.16.4, hypothesis-6.21.6, forked-1.3.0, xdist-1.34.0, web3-5.23.1
collected 1 item

Launching 'ganache-cli.cmd --accounts 10 --hardfork istanbul --gasLimit 12000000 --mnemonic brownie --port 8545'...

tests\test_reverts.py F                                                                                                                                                                                                      [100%]

============================================================================================================ FAILURES =============================================================================================================
__________________________________________________________________________________________________ test_only_owner_can_withdraw ___________________________________________________________________________________________________

    def test_only_owner_can_withdraw():
        fund_me = ExampleContract.deploy({"from": accounts[0]})
        print(f"FundMe deployed to {fund_me.address}")
        good = accounts[0]
        bad = accounts.add()
        # with pytest.raises(exceptions.VirtualMachineError):
>       with brownie.reverts():

tests\test_reverts.py:12:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
tests\test_reverts.py:13: in test_only_owner_can_withdraw
    fund_me.withdraw({"from": bad})
..\.venv\lib\site-packages\brownie\network\contract.py:1693: in __call__
    return self.transact(*args)
..\.venv\lib\site-packages\brownie\network\contract.py:1566: in transact
    return tx["from"].transfer(
..\.venv\lib\site-packages\brownie\network\account.py:680: in transfer
    receipt._raise_if_reverted(exc)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <Transaction '0x1f310675db8ad41f0eb4cd9338f35f2800174168b18c019645b5b1d82ade2826'>, exc = None

    def _raise_if_reverted(self, exc: Any) -> None:
        if self.status or CONFIG.mode == "console":
            return
        if not web3.supports_traces:
            # if traces are not available, do not attempt to determine the revert reason
            raise exc or ValueError("Execution reverted")

        if self._dev_revert_msg is None:
            # no revert message and unable to check dev string - have to get trace
            self._expand_trace()
        if self.contract_address:
            source = ""
        elif CONFIG.argv["revert"]:
            source = self._traceback_string()
        else:
            source = self._error_string(1)
            contract = state._find_contract(self.receiver)
            if contract:
                marker = "//" if contract._build["language"] == "Solidity" else "#"
                line = self._traceback_string().split("\n")[-1]
                if marker + " dev: " in line:
                    self._dev_revert_msg = line[line.index(marker) + len(marker) : -5].strip()

>       raise exc._with_attr(
            source=source, revert_msg=self._revert_msg, dev_revert_msg=self._dev_revert_msg
        )
E       AttributeError: 'NoneType' object has no attribute '_with_attr'

..\.venv\lib\site-packages\brownie\network\transaction.py:420: AttributeError
------------------------------------------------------------------------------------------------------ Captured stdout call ------------------------------------------------------------------------------------------------------- 
FundMe deployed to 0x3194cBDC3dbcd3E11a07892e7bA5c3394048Cc87
mnemonic: 'abandon wisdom slot exclude buyer raccoon desert grid inmate flag state castle'
===================================================================================================== short test summary info ===================================================================================================== 
FAILED tests/test_reverts.py::test_only_owner_can_withdraw - AttributeError: 'NoneType' object has no attribute '_with_attr'
======================================================================================================== 1 failed in 6.40s ======================================================================================================== 
Terminating local RPC client...
(.venv) testcode>

How can it be fixed?

I believe this is caused by brownie\network\transaction.py exiting with its own raise exc._with_attr instead of “bubbling up” the error to pytest.raise().

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:3
  • Comments:9

github_iconTop GitHub Comments

2reactions
DJerciccommented, Feb 18, 2022

I just updated brownie to the latest version (1.18.1) and it seems the bug is fixed there

1reaction
freddie71010commented, Feb 23, 2022

@n4n0b1t3 do you think you can close the issue now? Great job with the detailed post.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Brownie testing for reverted transactions does not work with ...
Complete projects are tested and work correctly in this setup, besides tests with brownie.reverts(). Here in short the command line overview:
Read more >
brownie testing for reverted transactions does not work with pytest ...
brownie testing for reverted transactions does not work with pytest.raises() or brownie.reverts(). pytest.raises(exceptions.VirtualMachineError) brownie.reverts ...
Read more >
Solution — Brownie testing for reverted transactions does not ...
Solution — Brownie testing for reverted transactions does not work with pytest.raises() or brownie.reverts() on Python 3.10.2. The problem
Read more >
Network API — Brownie 1.19.2 documentation - Read the Docs
Returns a Contract instance upon success. If the transaction reverts or you do not wait for a confirmation, a TransactionReceipt is returned instead....
Read more >
transaction.py - gists · GitHub
transaction.py ... avoid querying the trace to get the revert string if possible ... raise AttributeError(f"'TransactionReceipt' object has no attribute ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found