Repository: ethereum/web3.py

Issue:
Autocomplete doesn't work, exploring in shell is hard
* Version: 4.0.0b9
* Python: 3.6
* OS: osx

### What was wrong?

Autocomplete is useless in python shell (ipython, ipdb, dir(), etc.).
I expected that I'll get autocompletion when I, for example, type `contract_instance.[TAB]`.

```python
contract_instance = w3.eth.contract(
    contract_address,
    abi=contract_interface['abi'],
    ContractFactoryClass=ConciseContract)
```

I expected that triggering `contract_instance.` would suggest `contract_instance.myMethod()`.
Contract is just an example, I've noticed that most of the code w/ metaclasses don't have this.

### How can it be fixed?
Looking at the source code it could be possible to add `__all__` to `PropertyCheckingFactory` or something/somewhere similar.

Exploring the API from shell is something that works really well for other python library, would be great if it would work for web3.


Discussion:
I've had this same annoyance.
I'd like to contribute, could you elaborate on this issue?

Would a decorator like the final section of [this Stackoverflow post](https://stackoverflow.com/questions/44834/can-someone-explain-all-in-python/35710527#35710527) be suitable?
Alright, this is an issue specifically with `ConciseContract`.

I see two routes

1. Implement a `__dir__` method which returns a tuple of all of the contract function names.
2. Change the `__init__` of concise contract to actually populate self with all of the contract functions using the same logic currently present in the `__getattr__`.

The `__dir__` approach seems like the lowest touch, but I think the second solution of actually populating all of the functions onto `self` seems more correct.  It would also allow us to get rid of the `__getattr__` on the class which seems like a bonus.
:+1: to approach 2 above

Resolving patch:
diff --git a/web3/contract.py b/web3/contract.py
--- a/web3/contract.py
+++ b/web3/contract.py
@@ -106,6 +106,13 @@ def __init__(self, abi, web3, address=None):
                         address=address,
                         function_identifier=func['name']))
 
+    def __iter__(self):
+        if not hasattr(self, '_functions') or not self._functions:
+            return
+
+        for func in self._functions:
+            yield func['name']
+
 
 class ContractEvents:
     """Class containing contract event objects
@@ -656,14 +663,22 @@ def __init__(self, classic_contract):
         self._classic_contract = classic_contract
         self.address = self._classic_contract.address
 
+        for func_name in self._classic_contract.functions:
+            func = getattr(self._classic_contract.functions, func_name)
+
+            setattr(
+                self,
+                func_name,
+                ConciseMethod(
+                    func,
+                    self._classic_contract._return_data_normalizers
+                )
+            )
+
     @classmethod
     def factory(cls, *args, **kwargs):
         return compose(cls, Contract.factory(*args, **kwargs))
 
-    def __getattr__(self, attr):
-        contract_function = getattr(self._classic_contract.functions, attr)
-        return ConciseMethod(contract_function, self._classic_contract._return_data_normalizers)
-
     @staticmethod
     def _none_addr(datatype, data):
         if datatype == 'address' and int(data, base=16) == 0:


Test patch:
diff --git a/tests/core/contracts/test_implicit_contract.py b/tests/core/contracts/test_implicit_contract.py
--- a/tests/core/contracts/test_implicit_contract.py
+++ b/tests/core/contracts/test_implicit_contract.py
@@ -58,13 +58,13 @@ def test_implicitcontract_call_default(math_contract, get_transaction_count):
     assert get_transaction_count("pending") == (blocknum, 0)
 
 
-def test_implicitcontract_transact_default(math_contract, get_transaction_count):
+def test_implicitcontract_transact_default(web3, math_contract, get_transaction_count):
     # Use to verify correct operation later on
     start_count = math_contract.counter()
     assert is_integer(start_count)  # Verify correct type
     # When a function is called that defaults to transact
     blocknum, starting_txns = get_transaction_count("pending")
-    math_contract.increment()
+    math_contract.increment(transact={})
     # Check that a transaction was made and not a call
     assert math_contract.counter() - start_count == 1
     # (Auto-mining is enabled, so query by block number)