Repository: tomerfiliba-org/rpyc

Issue #278: Cannot load dumped exception with @property and no setter
Created: 2018-06-21T11:26:05Z
I'm using python 3.6.5 (3.4.8 as well) and rpyc 4.0.1
On the classic server side, when we're throwing an exception that has some @property, but no setter for it, it cannot be properly loaded on client side, because vinegar.py:load tries to assign dumped property value into the property, thus raising AttributeError because of missing setter.
The issue inflicts only exceptions that are defined in site-packages (the original exception is mapped to client's version of it).
Attached you'll find reproduction files:
The custom_class.py file:
from custom_method import worker
class MyObj:
    def start(self):
        worker()

The custom_method.py file:
from custom_module.custom_exception import ExceptionWithProperty

def worker():
    print("Worker called")
    exc = ExceptionWithProperty()
    raise exc

The reproduction.py file:
import rpyc
conn = rpyc.classic.connect('localhost')
conn.modules.sys.path.append(".")  # so the RPyC server sees the "custom_class" module
obj = conn.modules.custom_class.MyObj()
obj.start()

And the custom_module-0.1-py3-none-any.whl package file, which contains only custom_exception.py file:
class ExceptionWithProperty(Exception):

    def __init__(self, msg="default msg"):
        print("Creating ExceptionWithProperty: {}".format(msg))
        self.msg = msg
        self._custom_msg = "Yep, this is custom message"

    # No setter!
    @property
    def custom_msg(self):
        return self._custom_msg

The most important thing is that the ExceptionWithProperty has to be installed in python's site-packages (when the custom_exception.py file is simply in the current directory instead of being installed as a package, everything works fine)
To reproduce, please download rpyc_reproduction.zip, extract it to /tmp/rpyc_repro and:
cd /tmp/rpyc_repro
python3 -m virtualenv venv
source venv/bin/activate
pip install rpyc custom_module-0.1-py3-none-any.whl
./venv/bin/rpyc_classic.py &
python reproduction.py

The result is as follows:
(venv) shalak@home:/tmp/rpyc_repro$ python reproduction.py 
INFO:SLAVE/18812:accepted ('127.0.0.1', 55520) with fd 4
INFO:SLAVE/18812:welcome ('127.0.0.1', 55520)
Worker called
Creating ExceptionWithProperty: default msg
DEBUG:SLAVE/18812:Exception caught
Traceback (most recent call last):
  File "/tmp/rpyc_repro/venv/lib/python3.6/site-packages/rpyc/core/protocol.py", line 329, in _dispatch_request
    res = self._HANDLERS[handler](self, *args)
  File "/tmp/rpyc_repro/venv/lib/python3.6/site-packages/rpyc/core/protocol.py", line 590, in _handle_call
    return obj(*args, **dict(kwargs))
  File "./custom_class.py", line 7, in start
    worker()
  File "./custom_method.py", line 6, in worker
    raise exc
custom_module.custom_exception.ExceptionWithProperty
Traceback (most recent call last):
  File "reproduction.py", line 5, in <module>
    obj.start()
  File "/tmp/rpyc_repro/venv/lib/python3.6/site-packages/rpyc/core/netref.py", line 199, in __call__
    return syncreq(_self, consts.HANDLE_CALL, args, kwargs)
  File "/tmp/rpyc_repro/venv/lib/python3.6/site-packages/rpyc/core/netref.py", line 75, in syncreq
    return conn.sync_request(handler, proxy, *args)
  File "/tmp/rpyc_repro/venv/lib/python3.6/site-packages/rpyc/core/protocol.py", line 471, in sync_request
    return self.async_request(handler, *args, timeout=timeout).value
  File "/tmp/rpyc_repro/venv/lib/python3.6/site-packages/rpyc/core/async_.py", line 95, in value
    self.wait()
  File "/tmp/rpyc_repro/venv/lib/python3.6/site-packages/rpyc/core/async_.py", line 45, in wait
    self._conn.serve(self._ttl)
  File "/tmp/rpyc_repro/venv/lib/python3.6/site-packages/rpyc/core/protocol.py", line 397, in serve
    self._dispatch(data)
  File "/tmp/rpyc_repro/venv/lib/python3.6/site-packages/rpyc/core/protocol.py", line 367, in _dispatch
    obj = self._unbox_exc(args)
  File "/tmp/rpyc_repro/venv/lib/python3.6/site-packages/rpyc/core/protocol.py", line 353, in _unbox_exc
    instantiate_oldstyle_exceptions = self._config["instantiate_oldstyle_exceptions"])
  File "/tmp/rpyc_repro/venv/lib/python3.6/site-packages/rpyc/core/vinegar.py", line 158, in load
    setattr(exc, name, attrval)
AttributeError: can't set attribute
INFO:SLAVE/18812:goodbye ('127.0.0.1', 55520)

Duplicate issue #308: Issues about accessing class members in another file without import
Created: 2018-11-02T06:09:03Z
I have posted my doubt herehttps://stackoverflow.com/questions/53111529/access-to-class-members-in-another-file-using-rpyc-without-import?noredirect=1#comment93118595_53111529. I still cannot get what I want. Ideally, the self-defined exception should be raised and I can get its member variables. How am I supposed to implement it?

Closing comment (2018-11-02T14:10:49Z): Related to #278. The comment explains it correctly: on the client you don't see the real exception object with the correct type on the client, but a netref proxy instead. For the reason stated in the TypeError you can't really raise a remote exception locally.
How to implement? -> easy enough, replace the return e line with raise e