Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework Python binding to use only core APIs #173

Merged
merged 6 commits into from Feb 25, 2019

Conversation

astitcher
Copy link
Member

This is a reworking of the Python binding to Proton to avoid using APIs outside the Proton Core library. Thus the Python based reactive code has been rewritten so that the proton.reactor and proton.handler modules use only core APIs.

Necessarily this is a large change to the Python binding code, but a lot of effort has gone into maintaining the existing proton.reactor and proton.handler APIs. However any code that relied on functionality of the Proton-C reactor APIs directly will no longer work as these APIs aren't available from Python any longer.

One area that may be different and is still not 100% solid is in the area of error/exception handling. I think that you will get exceptions in the same cases as before, but they could very probably be different exceptions. It is also possible that some errors are handled differently. Please raise bugs for any differences/problems found.

This code has been tested with the integrated tests and passes on Linux, MacOS and Windows on CI systems. Some tests (related to SSL/TLS) fail on some Windows systems, but the same tests fail previous to these changes on the the same systems - the failures don't seem due to these changes. The included python examples all run with this reworked binding. It has also been tested with the quiver benchmark tool and is broadly the same performance as the previous binding.

Please try this with your Python code and let me know of any problems.

@astitcher astitcher self-assigned this Jan 17, 2019
@kgiusti
Copy link
Contributor

kgiusti commented Jan 17, 2019

Tested against Pyngus library - works for me

@ChugR
Copy link

ChugR commented Jan 17, 2019

Built qpid-proton; passes self tests.
Built qpid-dispatch; fails several self tests:

 19 - system_tests_one_router (Failed)
 31 - system_tests_two_routers (Failed)
 39 - system_tests_authz_service_plugin (Failed)
 55 - system_tests_core_client (Failed)

The one_router and two_router tests fail with a ctest output of:

19: ======================================================================
19: ERROR: test_21_semantics_balanced (system_tests_one_router.OneRouterTest)
19: ----------------------------------------------------------------------
19: Traceback (most recent call last):
19: File "/home/chug/git/qpid-dispatch/tests/system_tests_one_router.py", line 253, in test_21_semantics_balanced
19: test.run()
19: File "/home/chug/git/qpid-dispatch/tests/system_tests_one_router.py", line 949, in run
19: Container(self).run()
19: File "/opt/local/lib64/proton/bindings/python/proton/_reactor.py", line 176, in run
19: while self.process(): pass
19: File "/opt/local/lib64/proton/bindings/python/proton/_reactor.py", line 233, in process
19: event.dispatch(handler)
19: File "/opt/local/lib64/proton/bindings/python/proton/_events.py", line 135, in dispatch
19: _dispatch(handler, type.method, self)
19: File "/opt/local/lib64/proton/bindings/python/proton/_events.py", line 115, in _dispatch
19: m(*args)
19: File "/home/chug/git/qpid-dispatch/tests/system_tests_one_router.py", line 863, in on_timer_task
19: self.parent.create_sender(event)
19: File "/home/chug/git/qpid-dispatch/tests/system_tests_one_router.py", line 909, in create_sender
19: self.sender = event.container.create_sender(self.conn, self.dest)
19: AttributeError: 'NoneType' object has no attribute 'create_sender'

Does the event still have a container? Is there another way to get at the container from the event?

@astitcher
Copy link
Member Author

@ChugR I'll take a look at the new code, but from the stack trace you gave I'd say the event here in on_timer_task() does not have a container!

@astitcher
Copy link
Member Author

@ChugR @ganeshmurthy I've fixed the problem of the missing container for on_timer_task events. If you have a moment please run the dispatch tests again and tell me what the other problems are.

It has been difficult (and unreliable) for me to run the entire dispatch built in test suite although I'm making some progress with that. So I'd be grateful if you can give it another go.

@ganeshmurthy
Copy link
Contributor

ganeshmurthy commented Jan 23, 2019

Hi @astitcher, I got down the very latest code from this PR and ran qpid-dispatch master against this PR. All but one test passed. The test is called system_tests_authz_service_plugin. This test never fails against proton master branch. Here is the traceback from the failure -

39: Test command: /usr/bin/python "/home/gmurthy/opensource/qpid-dispatch/build/tests/run.py" "unit2" "-v" "system_tests_authz_service_plugin"
39: Test timeout computed to be: 1500
39: test_authorized (system_tests_authz_service_plugin.AuthServicePluginAuthzDeprecatedTest) ... ok
39: test_dynamic_source_anonymous_sender (system_tests_authz_service_plugin.AuthServicePluginAuthzDeprecatedTest) ... ok
39: test_unauthorized (system_tests_authz_service_plugin.AuthServicePluginAuthzDeprecatedTest) ... ok
39: test_wildcard (system_tests_authz_service_plugin.AuthServicePluginAuthzDeprecatedTest) ... ok
39: ERROR
39: test_authorized (system_tests_authz_service_plugin.AuthServicePluginAuthzTest) ... ok
39: test_dynamic_source_anonymous_sender (system_tests_authz_service_plugin.AuthServicePluginAuthzTest) ... ok
39: test_unauthorized (system_tests_authz_service_plugin.AuthServicePluginAuthzTest) ... ok
39: test_wildcard (system_tests_authz_service_plugin.AuthServicePluginAuthzTest) ... ok
39: ERROR
39:
39: ======================================================================
39: ERROR: tearDownClass (system_tests_authz_service_plugin.AuthServicePluginAuthzDeprecatedTest)
39: ----------------------------------------------------------------------
39: Traceback (most recent call last):
39: File "/home/gmurthy/opensource/qpid-dispatch/tests/system_test.py", line 609, in tearDownClass
39: cls.tester.teardown()
39: File "/home/gmurthy/opensource/qpid-dispatch/tests/system_test.py", line 555, in teardown
39: raise RuntimeError("Errors during teardown: \n\n%s" % "\n\n".join([str(e) for e in errors]))
39: RuntimeError: Errors during teardown:
39:
39: Process 9720 error: exit code 1, expected 0
39: /usr/bin/env python /home/gmurthy/opensource/qpid-dispatch/tests/authservice.py -a amqps://127.0.0.1:29873 -c /home/gmurthy/opensource/qpid-dispatch/build/tests/system_test.dir/system_tests_authz_service_plugin/AuthServicePluginAuthzDeprecatedTest/setUpClass
39: /home/gmurthy/opensource/qpid-dispatch/build/tests/system_test.dir/system_tests_authz_service_plugin/AuthServicePluginAuthzDeprecatedTest/setUpClass/env-1.cmd
39: >>>>
39: starting
39: set sasl config path to /home/gmurthy/opensource/qpid-dispatch/build/tests/system_test.dir/system_tests_authz_service_plugin/AuthServicePluginAuthzDeprecatedTest/setUpClass
39: Traceback (most recent call last):
39: File "/home/gmurthy/opensource/qpid-dispatch/tests/authservice.py", line 84, in
39: Container(handler).run()
39: File "/opt/qpid-proton/qpid-proton/lib64/proton/bindings/python/proton/_reactor.py", line 180, in run
39: while self.process(): pass
39: File "/opt/qpid-proton/qpid-proton/lib64/proton/bindings/python/proton/_reactor.py", line 239, in process
39: event.dispatch(self._global_handler)
39: File "/opt/qpid-proton/qpid-proton/lib64/proton/bindings/python/proton/_events.py", line 135, in dispatch
39: _dispatch(handler, type.method, self)
39: File "/opt/qpid-proton/qpid-proton/lib64/proton/bindings/python/proton/_events.py", line 117, in _dispatch
39: handler.on_unhandled(method, *args)
39: File "/opt/qpid-proton/qpid-proton/lib64/proton/bindings/python/proton/_reactor.py", line 664, in on_unhandled
39: event.dispatch(self.base)
39: File "/opt/qpid-proton/qpid-proton/lib64/proton/bindings/python/proton/_events.py", line 135, in dispatch
39: _dispatch(handler, type.method, self)
39: File "/opt/qpid-proton/qpid-proton/lib64/proton/bindings/python/proton/_events.py", line 115, in _dispatch
39: m(*args)
39: File "/opt/qpid-proton/qpid-proton/lib64/proton/bindings/python/proton/_handlers.py", line 767, in on_reactor_quiesced
39: readable, writable, expired = self._selector.select(r.timeout)
39: File "/opt/qpid-proton/qpid-proton/lib64/proton/bindings/python/proton/_io.py", line 131, in select
39: r, w, _ = select_inner(timeout)
39: File "/opt/qpid-proton/qpid-proton/lib64/proton/bindings/python/proton/_io.py", line 122, in select_inner
39: return IO.select(r, w, [], timeout)
39: File "/opt/qpid-proton/qpid-proton/lib64/proton/bindings/python/proton/_io.py", line 51, in select
39: return select.select(*args, **kwargs)
39: select.error: (4, 'Interrupted system call')
39: <<<<
39:
39: ======================================================================
39: ERROR: tearDownClass (system_tests_authz_service_plugin.AuthServicePluginAuthzTest)
39: ----------------------------------------------------------------------
39: Traceback (most recent call last):
39: File "/home/gmurthy/opensource/qpid-dispatch/tests/system_test.py", line 609, in tearDownClass
39: cls.tester.teardown()
39: File "/home/gmurthy/opensource/qpid-dispatch/tests/system_test.py", line 555, in teardown
39: raise RuntimeError("Errors during teardown: \n\n%s" % "\n\n".join([str(e) for e in errors]))
39: RuntimeError: Errors during teardown:
39:
39: Process 9729 error: exit code 1, expected 0
39: /usr/bin/env python /home/gmurthy/opensource/qpid-dispatch/tests/authservice.py -a amqps://127.0.0.1:29875 -c /home/gmurthy/opensource/qpid-dispatch/build/tests/system_test.dir/system_tests_authz_service_plugin/AuthServicePluginAuthzTest/setUpClass
39: /home/gmurthy/opensource/qpid-dispatch/build/tests/system_test.dir/system_tests_authz_service_plugin/AuthServicePluginAuthzTest/setUpClass/env-2.cmd
39: >>>>
39: starting
39: set sasl config path to /home/gmurthy/opensource/qpid-dispatch/build/tests/system_test.dir/system_tests_authz_service_plugin/AuthServicePluginAuthzTest/setUpClass
39: Traceback (most recent call last):
39: File "/home/gmurthy/opensource/qpid-dispatch/tests/authservice.py", line 84, in
39: Container(handler).run()
39: File "/opt/qpid-proton/qpid-proton/lib64/proton/bindings/python/proton/_reactor.py", line 180, in run
39: while self.process(): pass
39: File "/opt/qpid-proton/qpid-proton/lib64/proton/bindings/python/proton/_reactor.py", line 239, in process
39: event.dispatch(self._global_handler)
39: File "/opt/qpid-proton/qpid-proton/lib64/proton/bindings/python/proton/_events.py", line 135, in dispatch
39: _dispatch(handler, type.method, self)
39: File "/opt/qpid-proton/qpid-proton/lib64/proton/bindings/python/proton/_events.py", line 117, in _dispatch
39: handler.on_unhandled(method, *args)
39: File "/opt/qpid-proton/qpid-proton/lib64/proton/bindings/python/proton/_reactor.py", line 664, in on_unhandled
39: event.dispatch(self.base)
39: File "/opt/qpid-proton/qpid-proton/lib64/proton/bindings/python/proton/_events.py", line 135, in dispatch
39: _dispatch(handler, type.method, self)
39: File "/opt/qpid-proton/qpid-proton/lib64/proton/bindings/python/proton/_events.py", line 115, in _dispatch
39: m(*args)
39: File "/opt/qpid-proton/qpid-proton/lib64/proton/bindings/python/proton/_handlers.py", line 767, in on_reactor_quiesced
39: readable, writable, expired = self._selector.select(r.timeout)
39: File "/opt/qpid-proton/qpid-proton/lib64/proton/bindings/python/proton/_io.py", line 131, in select
39: r, w, _ = select_inner(timeout)
39: File "/opt/qpid-proton/qpid-proton/lib64/proton/bindings/python/proton/_io.py", line 122, in select_inner
39: return IO.select(r, w, [], timeout)
39: File "/opt/qpid-proton/qpid-proton/lib64/proton/bindings/python/proton/_io.py", line 51, in select
39: return select.select(*args, **kwargs)
39: select.error: (4, 'Interrupted system call')
39: <<<<
39:
39: ----------------------------------------------------------------------
39: Ran 8 tests in 0.713s
39:
39: FAILED (errors=2)
39/55 Test #39: system_tests_authz_service_plugin .................***Failed 0.90 sec

@astitcher
Copy link
Member Author

@ganeshmurthy Thank you - I'll fix that issue then get back to you again.

@ChugR
Copy link

ChugR commented Jan 23, 2019

I get the same two errors/stack traces seen by @ganeshmurthy. In addition, I occasionally (50%) see a failure in system_tests_delivery_abort. The stack trace starts out the same but then diverges for the last three frames:

(M=1914e ?6) chug@unused build> ctest -VV -R system_tests_delivery_abort
UpdateCTestConfiguration from :/home/chug/git/qpid-dispatch/build/DartConfiguration.tcl
Parse Config file:/home/chug/git/qpid-dispatch/build/DartConfiguration.tcl
UpdateCTestConfiguration from :/home/chug/git/qpid-dispatch/build/DartConfiguration.tcl
Parse Config file:/home/chug/git/qpid-dispatch/build/DartConfiguration.tcl
Test project /home/chug/git/qpid-dispatch/build
Constructing a list of tests
Done constructing a list of tests
Updating test list for fixtures
Added 0 tests to meet fixture requirements
Checking test dependency graph...
Checking test dependency graph end
test 40
Start 40: system_tests_delivery_abort

40: Test command: /bin/python "/home/chug/git/qpid-dispatch/build/tests/run.py" "unit2" "-v" "system_tests_delivery_abort"
40: Test timeout computed to be: 1500
40: test_01_message_route_truncated_one_router (system_tests_delivery_abort.RouterTest) ... ok
40: test_02_message_route_truncated_two_routers (system_tests_delivery_abort.RouterTest) ... ok
40: test_03_link_route_truncated_one_router (system_tests_delivery_abort.RouterTest) ... ok
40: test_04_link_route_truncated_two_routers (system_tests_delivery_abort.RouterTest) ... ok
40: test_05_message_route_abort_one_router (system_tests_delivery_abort.RouterTest) ... ok
40: test_06_message_route_abort_two_routers (system_tests_delivery_abort.RouterTest) ... ERROR
40: test_07_multicast_truncate_one_router (system_tests_delivery_abort.RouterTest) ... ok
40: ERROR
40:
40: ======================================================================
40: ERROR: test_06_message_route_abort_two_routers (system_tests_delivery_abort.RouterTest)
40: ----------------------------------------------------------------------
40: Traceback (most recent call last):
40: File "/home/chug/git/qpid-dispatch/tests/system_tests_delivery_abort.py", line 117, in test_06_message_route_abort_two_routers
40: test.run()
40: File "/home/chug/git/qpid-dispatch/tests/system_tests_delivery_abort.py", line 473, in run
40: Container(self).run()
40: File "/opt/local/lib64/proton/bindings/python/proton/_reactor.py", line 180, in run
40: while self.process(): pass
40: File "/opt/local/lib64/proton/bindings/python/proton/_reactor.py", line 239, in process
40: event.dispatch(self._global_handler)
40: File "/opt/local/lib64/proton/bindings/python/proton/_events.py", line 135, in dispatch
40: _dispatch(handler, type.method, self)
40: File "/opt/local/lib64/proton/bindings/python/proton/_events.py", line 117, in _dispatch
40: handler.on_unhandled(method, *args)
40: File "/opt/local/lib64/proton/bindings/python/proton/_reactor.py", line 664, in on_unhandled
40: event.dispatch(self.base)
40: File "/opt/local/lib64/proton/bindings/python/proton/_events.py", line 135, in dispatch
40: _dispatch(handler, type.method, self)
40: File "/opt/local/lib64/proton/bindings/python/proton/_events.py", line 115, in _dispatch
40: m(*args)
40: File "/opt/local/lib64/proton/bindings/python/proton/_handlers.py", line 888, in on_connection_bound
40: sock = IO.connect(host, int(port))
40: File "/opt/local/lib64/proton/bindings/python/proton/_io.py", line 47, in connect
40: return socket.create_connection((host, port))
40: File "/usr/lib64/python2.7/socket.py", line 575, in create_connection
40: raise err
40: socket.error: [Errno 111] Connection refused
40:
40: ======================================================================
40: ERROR: tearDownClass (system_tests_delivery_abort.RouterTest)
40: ----------------------------------------------------------------------
40: Traceback (most recent call last):
40: File "/home/chug/git/qpid-dispatch/tests/system_test.py", line 609, in tearDownClass
40: cls.tester.teardown()
40: File "/home/chug/git/qpid-dispatch/tests/system_test.py", line 555, in teardown
40: raise RuntimeError("Errors during teardown: \n\n%s" % "\n\n".join([str(e) for e in errors]))
40: RuntimeError: Errors during teardown:
40:
40: Process 10418 error: exit code -11, expected -1
40: qdrouterd -c B.conf -I /home/chug/git/qpid-dispatch/python
40: /home/chug/git/qpid-dispatch/build/tests/system_test.dir/system_tests_delivery_abort/RouterTest/setUpClass/B-2.cmd
40: >>>>
40: <<<<
40:
40: ----------------------------------------------------------------------
40: Ran 7 tests in 5.779s
40:
40: FAILED (errors=2)
1/1 Test #40: system_tests_delivery_abort ......***Failed 5.96 sec

0% tests passed, 1 tests failed out of 1

Total Test time (real) = 5.96 sec

The following tests FAILED:
40 - system_tests_delivery_abort (Failed)
Errors while running CTest

1 similar comment
@ChugR
Copy link

ChugR commented Jan 23, 2019

I get the same two errors/stack traces seen by @ganeshmurthy. In addition, I occasionally (50%) see a failure in system_tests_delivery_abort. The stack trace starts out the same but then diverges for the last three frames:

(M=1914e ?6) chug@unused build> ctest -VV -R system_tests_delivery_abort
UpdateCTestConfiguration from :/home/chug/git/qpid-dispatch/build/DartConfiguration.tcl
Parse Config file:/home/chug/git/qpid-dispatch/build/DartConfiguration.tcl
UpdateCTestConfiguration from :/home/chug/git/qpid-dispatch/build/DartConfiguration.tcl
Parse Config file:/home/chug/git/qpid-dispatch/build/DartConfiguration.tcl
Test project /home/chug/git/qpid-dispatch/build
Constructing a list of tests
Done constructing a list of tests
Updating test list for fixtures
Added 0 tests to meet fixture requirements
Checking test dependency graph...
Checking test dependency graph end
test 40
Start 40: system_tests_delivery_abort

40: Test command: /bin/python "/home/chug/git/qpid-dispatch/build/tests/run.py" "unit2" "-v" "system_tests_delivery_abort"
40: Test timeout computed to be: 1500
40: test_01_message_route_truncated_one_router (system_tests_delivery_abort.RouterTest) ... ok
40: test_02_message_route_truncated_two_routers (system_tests_delivery_abort.RouterTest) ... ok
40: test_03_link_route_truncated_one_router (system_tests_delivery_abort.RouterTest) ... ok
40: test_04_link_route_truncated_two_routers (system_tests_delivery_abort.RouterTest) ... ok
40: test_05_message_route_abort_one_router (system_tests_delivery_abort.RouterTest) ... ok
40: test_06_message_route_abort_two_routers (system_tests_delivery_abort.RouterTest) ... ERROR
40: test_07_multicast_truncate_one_router (system_tests_delivery_abort.RouterTest) ... ok
40: ERROR
40:
40: ======================================================================
40: ERROR: test_06_message_route_abort_two_routers (system_tests_delivery_abort.RouterTest)
40: ----------------------------------------------------------------------
40: Traceback (most recent call last):
40: File "/home/chug/git/qpid-dispatch/tests/system_tests_delivery_abort.py", line 117, in test_06_message_route_abort_two_routers
40: test.run()
40: File "/home/chug/git/qpid-dispatch/tests/system_tests_delivery_abort.py", line 473, in run
40: Container(self).run()
40: File "/opt/local/lib64/proton/bindings/python/proton/_reactor.py", line 180, in run
40: while self.process(): pass
40: File "/opt/local/lib64/proton/bindings/python/proton/_reactor.py", line 239, in process
40: event.dispatch(self._global_handler)
40: File "/opt/local/lib64/proton/bindings/python/proton/_events.py", line 135, in dispatch
40: _dispatch(handler, type.method, self)
40: File "/opt/local/lib64/proton/bindings/python/proton/_events.py", line 117, in _dispatch
40: handler.on_unhandled(method, *args)
40: File "/opt/local/lib64/proton/bindings/python/proton/_reactor.py", line 664, in on_unhandled
40: event.dispatch(self.base)
40: File "/opt/local/lib64/proton/bindings/python/proton/_events.py", line 135, in dispatch
40: _dispatch(handler, type.method, self)
40: File "/opt/local/lib64/proton/bindings/python/proton/_events.py", line 115, in _dispatch
40: m(*args)
40: File "/opt/local/lib64/proton/bindings/python/proton/_handlers.py", line 888, in on_connection_bound
40: sock = IO.connect(host, int(port))
40: File "/opt/local/lib64/proton/bindings/python/proton/_io.py", line 47, in connect
40: return socket.create_connection((host, port))
40: File "/usr/lib64/python2.7/socket.py", line 575, in create_connection
40: raise err
40: socket.error: [Errno 111] Connection refused
40:
40: ======================================================================
40: ERROR: tearDownClass (system_tests_delivery_abort.RouterTest)
40: ----------------------------------------------------------------------
40: Traceback (most recent call last):
40: File "/home/chug/git/qpid-dispatch/tests/system_test.py", line 609, in tearDownClass
40: cls.tester.teardown()
40: File "/home/chug/git/qpid-dispatch/tests/system_test.py", line 555, in teardown
40: raise RuntimeError("Errors during teardown: \n\n%s" % "\n\n".join([str(e) for e in errors]))
40: RuntimeError: Errors during teardown:
40:
40: Process 10418 error: exit code -11, expected -1
40: qdrouterd -c B.conf -I /home/chug/git/qpid-dispatch/python
40: /home/chug/git/qpid-dispatch/build/tests/system_test.dir/system_tests_delivery_abort/RouterTest/setUpClass/B-2.cmd
40: >>>>
40: <<<<
40:
40: ----------------------------------------------------------------------
40: Ran 7 tests in 5.779s
40:
40: FAILED (errors=2)
1/1 Test #40: system_tests_delivery_abort ......***Failed 5.96 sec

0% tests passed, 1 tests failed out of 1

Total Test time (real) = 5.96 sec

The following tests FAILED:
40 - system_tests_delivery_abort (Failed)
Errors while running CTest

@astitcher
Copy link
Member Author

@ChugR @ganeshmurthy another version of code to test.

@ganeshmurthy
Copy link
Contributor

All router tests pass now. Thanks.

- Python binding now only uses APIs from Proton Core library.
  It uses Python APIs to do all IO and uses Proton purely to process
  the AMQP protocol.
- It is very compatible with the existing higher level Python APIs.
  [In modules proton, proton.reactor, proton.handlers, proton.utils]

- Passes the python tests as well as before
- Works with Python 2 and Python 3
- Works on Unix and Windows
- Runs all the python examples
- Remove all swig bound APIs that are only in libqpid-proton
- Link Python extension lib to libqpid-proton-core
- Fixes a problem with dispatch unit tests
- Ignore interrupted select syscalls
-- We do this as the dispatch systems tests use proton calls in a signal handler
-- It's not clear to me that uis actually allowed - it wouldn't be in raw C
- So it's not entirely clear this is the correct way to go or that the
  code that causes this issue doesn't need fixinf itself!
@asfgit asfgit merged commit 8dc796d into apache:master Feb 25, 2019
@astitcher astitcher deleted the python-on-core branch February 25, 2019 23:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants