Repository: eth-brownie/brownie
Issue: OSX error when Ganache is already running

Whenever I run a `pytest tests`, it launches `ganache-cli` from scratch, which takes around few seconds. It is not much but when I keep runing `pytests tests` over and over again takes long time.

$ pytest tests -s -x --capture=no
==================================================================== test session starts =====================================================================
platform darwin -- Python 3.7.5, pytest-5.0.1, py-1.8.0, pluggy-0.12.0
rootdir: /Users/alper/eBlocBroker
plugins: eth-brownie-1.1.0, web3-5.0.0
collected 6 items
Launching 'ganache-cli --allowUnlimitedContractSize --port 8545 --gasLimit 6721975 --accounts 10 --hardfork petersburg --mnemonic brownie'...

------

I was wondering it it possible to run `ganache-cli` on a separet window and run `pytests tests` without relauncing the `ganache-cli`, and let it use the already running `ganache-cli`.

When I try that the error I am getting:

```
Brownie v1.1.0 - Python development framework for Ethereum

Brownie project has been compiled at /Users/alper/eBlocBroker/contract/build/contracts
==================================================================== test session starts =====================================================================
platform darwin -- Python 3.7.5, pytest-5.0.1, py-1.8.0, pluggy-0.12.0
rootdir: /Users/alper/eBlocBroker
plugins: eth-brownie-1.1.0, web3-5.0.0
collected 6 items
INTERNALERROR> Traceback (most recent call last):
INTERNALERROR>   File "/Users/alper/v/lib/python3.7/site-packages/psutil-5.6.3-py3.7-macosx-10.13-x86_64.egg/psutil/_psosx.py", line 339, in wrapper
INTERNALERROR>     return fun(self, *args, **kwargs)
INTERNALERROR>   File "/Users/alper/v/lib/python3.7/site-packages/psutil-5.6.3-py3.7-macosx-10.13-x86_64.egg/psutil/_psosx.py", line 528, in connections
INTERNALERROR>     rawlist = cext.proc_connections(self.pid, families, types)
INTERNALERROR> PermissionError: [Errno 1] Operation not permitted
INTERNALERROR>
INTERNALERROR> During handling of the above exception, another exception occurred:
INTERNALERROR>
INTERNALERROR> Traceback (most recent call last):
INTERNALERROR>   File "/Users/alper/v/lib/python3.7/site-packages/pytest-5.0.1-py3.7.egg/_pytest/main.py", line 213, in wrap_session
INTERNALERROR>     session.exitstatus = doit(config, session) or 0
INTERNALERROR>   File "/Users/alper/v/lib/python3.7/site-packages/pytest-5.0.1-py3.7.egg/_pytest/main.py", line 257, in _main
INTERNALERROR>     config.hook.pytest_runtestloop(session=session)
INTERNALERROR>   File "/Users/alper/v/lib/python3.7/site-packages/pluggy-0.12.0-py3.7.egg/pluggy/hooks.py", line 289, in __call__
INTERNALERROR>     return self._hookexec(self, self.get_hookimpls(), kwargs)
INTERNALERROR>   File "/Users/alper/v/lib/python3.7/site-packages/pluggy-0.12.0-py3.7.egg/pluggy/manager.py", line 87, in _hookexec
INTERNALERROR>     return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR>   File "/Users/alper/v/lib/python3.7/site-packages/pluggy-0.12.0-py3.7.egg/pluggy/manager.py", line 81, in <lambda>
INTERNALERROR>     firstresult=hook.spec.opts.get("firstresult") if hook.spec else False,
INTERNALERROR>   File "/Users/alper/v/lib/python3.7/site-packages/pluggy-0.12.0-py3.7.egg/pluggy/callers.py", line 208, in _multicall
INTERNALERROR>     return outcome.get_result()
INTERNALERROR>   File "/Users/alper/v/lib/python3.7/site-packages/pluggy-0.12.0-py3.7.egg/pluggy/callers.py", line 80, in get_result
INTERNALERROR>     raise ex[1].with_traceback(ex[2])
INTERNALERROR>   File "/Users/alper/v/lib/python3.7/site-packages/pluggy-0.12.0-py3.7.egg/pluggy/callers.py", line 187, in _multicall
INTERNALERROR>     res = hook_impl.function(*args)
INTERNALERROR>   File "/Users/alper/v/lib/python3.7/site-packages/brownie/test/plugin.py", line 131, in pytest_runtestloop
INTERNALERROR>     brownie.network.connect(ARGV["network"])
INTERNALERROR>   File "/Users/alper/v/lib/python3.7/site-packages/brownie/network/main.py", line 41, in connect
INTERNALERROR>     rpc.attach(host)
INTERNALERROR>   File "/Users/alper/v/lib/python3.7/site-packages/brownie/network/rpc.py", line 109, in attach
INTERNALERROR>     proc = next(i for i in psutil.net_connections() if i.laddr == laddr)
INTERNALERROR>   File "/Users/alper/v/lib/python3.7/site-packages/psutil-5.6.3-py3.7-macosx-10.13-x86_64.egg/psutil/__init__.py", line 2263, in net_connections
INTERNALERROR>     return _psplatform.net_connections(kind)
INTERNALERROR>   File "/Users/alper/v/lib/python3.7/site-packages/psutil-5.6.3-py3.7-macosx-10.13-x86_64.egg/psutil/_psosx.py", line 252, in net_connections
INTERNALERROR>     cons = Process(pid).connections(kind)
INTERNALERROR>   File "/Users/alper/v/lib/python3.7/site-packages/psutil-5.6.3-py3.7-macosx-10.13-x86_64.egg/psutil/_psosx.py", line 344, in wrapper
INTERNALERROR>     raise AccessDenied(self.pid, self._name)
INTERNALERROR> psutil.AccessDenied: psutil.AccessDenied (pid=28029)

================================================================ no tests ran in 0.10 seconds ================================================================
```



Changed files:
brownie/network/rpc.py

diff --git a/brownie/network/rpc.py b/brownie/network/rpc.py
index 93500c8a..9d4b31b6 100644
--- a/brownie/network/rpc.py
+++ b/brownie/network/rpc.py
@@ -113,9 +113,10 @@ class Rpc(metaclass=_Singleton):
                 raise ValueError("No RPC port given")
             laddr = (o.hostname, o.port)
         try:
-            proc = next(i for i in psutil.net_connections() if i.laddr == laddr)
+            proc = next(i for i in psutil.process_iter() if _check_connections(i, laddr))
         except StopIteration:
             raise ProcessLookupError("Could not find RPC process.")
+        print(f"Attached to local RPC client listening at '{laddr[0]}:{laddr[1]}'...")
         self._rpc = psutil.Process(proc.pid)
         if web3.provider:
             self._reset_id = self._snap()
@@ -284,3 +285,10 @@ def _notify_registry(height: int = None) -> None:
             obj._revert(height)
         else:
             obj._reset()
+
+
+def _check_connections(proc: psutil.Process, laddr: Tuple) -> bool:
+    try:
+        return laddr in [i.laddr for i in proc.connections()]
+    except psutil.AccessDenied:
+        return False