This is an automated email from the ASF dual-hosted git repository.

astitcher pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-proton.git

commit 6b29f6d848828f5d0cd5706333c6570e71cbc666
Author: Andrew Stitcher <astitc...@apache.org>
AuthorDate: Tue Apr 4 15:52:06 2023 -0400

    PROTON-2704: Reorganise python code to avoid runtime import of _events
    
    This runtime import was causing an exception at shutdown with the new
    cffi based code as it can happen in a delete operation in the middle of
    shutting down python.
    
    This was causing the test to hang.
---
 python/CMakeLists.txt       |  1 +
 python/proton/__init__.py   |  3 ++-
 python/proton/_endpoints.py | 14 +++++-----
 python/proton/_events.py    | 55 +++++----------------------------------
 python/proton/_handler.py   | 63 +++++++++++++++++++++++++++++++++++++++++++++
 python/proton/_handlers.py  |  5 ++--
 python/proton/_reactor.py   |  3 ++-
 7 files changed, 84 insertions(+), 60 deletions(-)

diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index 2f6da5ad5..a2480b795 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -28,6 +28,7 @@ set (pysrc
     proton/_endpoints.py
     proton/_events.py
     proton/_exceptions.py
+    proton/_handler.py
     proton/_io.py
     proton/_message.py
     proton/_tracing.py
diff --git a/python/proton/__init__.py b/python/proton/__init__.py
index 5f82a4bfe..302b0ae96 100644
--- a/python/proton/__init__.py
+++ b/python/proton/__init__.py
@@ -38,9 +38,10 @@ from ._data import UNDESCRIBED, Array, Data, Described, 
char, symbol, timestamp,
     byte, short, int32, float32, decimal32, decimal64, decimal128, 
AnnotationDict, PropertyDict, SymbolList
 from ._delivery import Delivery, Disposition
 from ._endpoints import Endpoint, Connection, Session, Link, Receiver, Sender, 
Terminus
-from ._events import Collector, Event, EventType, Handler
+from ._events import Collector, Event, EventType
 from ._exceptions import ProtonException, MessageException, DataException, 
TransportException, \
     SSLException, SSLUnavailable, ConnectionException, SessionException, 
LinkException, Timeout, Interrupt
+from ._handler import Handler
 from ._message import Message
 from ._transport import Transport, SASL, SSL, SSLDomain, SSLSessionDetails
 from ._url import Url
diff --git a/python/proton/_endpoints.py b/python/proton/_endpoints.py
index ee4defe42..ae7ab81d6 100644
--- a/python/proton/_endpoints.py
+++ b/python/proton/_endpoints.py
@@ -61,14 +61,15 @@ from ._condition import cond2obj, obj2cond
 from ._data import Data, dat2obj, obj2dat, PropertyDict, SymbolList
 from ._delivery import Delivery
 from ._exceptions import ConnectionException, EXCEPTIONS, LinkException, 
SessionException
+from ._handler import Handler
 from ._transport import Transport
 from ._wrapper import Wrapper
-from typing import Callable, Dict, List, Optional, Union, TYPE_CHECKING, Any
+from typing import Dict, List, Optional, Union, TYPE_CHECKING, Any
 
 if TYPE_CHECKING:
     from ._condition import Condition
     from ._data import Array, PythonAMQPData, symbol
-    from ._events import Collector, Handler
+    from ._events import Collector
     from ._message import Message
 
 
@@ -113,7 +114,7 @@ class Endpoint(object):
 
     def _init(self) -> None:
         self.condition: Optional['Condition'] = None
-        self._handler: Optional['Handler'] = None
+        self._handler: Optional[Handler] = None
 
     def _update_cond(self) -> None:
         obj2cond(self.condition, self._get_cond_impl())
@@ -134,7 +135,7 @@ class Endpoint(object):
         assert False, "Subclass must override this!"
 
     @property
-    def handler(self) -> Optional['Handler']:
+    def handler(self) -> Optional[Handler]:
         """Handler for events.
 
         :getter: Get the event handler, or return ``None`` if no handler has 
been set.
@@ -142,12 +143,11 @@ class Endpoint(object):
         return self._handler
 
     @handler.setter
-    def handler(self, handler: Optional['Handler']) -> None:
+    def handler(self, handler: Optional[Handler]) -> None:
         # TODO Hack This is here for some very odd (IMO) backwards compat 
behaviour
-        from ._events import Handler
         if handler is None:
             self._handler = None
-        elif issubclass(type(handler), Handler):
+        elif isinstance(handler, Handler):
             self._handler = handler
         else:
             self._handler = Handler()
diff --git a/python/proton/_events.py b/python/proton/_events.py
index 9cc721ad9..76d14f021 100644
--- a/python/proton/_events.py
+++ b/python/proton/_events.py
@@ -33,15 +33,13 @@ from cproton import PN_CONNECTION_BOUND, 
PN_CONNECTION_FINAL, PN_CONNECTION_INIT
 
 from ._delivery import Delivery
 from ._endpoints import Connection, Link, Session
+from ._handler import Handler
 from ._transport import Transport
-from typing import Any, List, Optional, Union, TYPE_CHECKING, Callable, Tuple, 
Type
+from typing import Any, Optional, Union, TYPE_CHECKING
 
 if TYPE_CHECKING:
-    from ._reactor import Container
     from ._endpoints import Receiver, Sender
-    from ._handlers import ConnectSelectable
-    from ._selectable import Selectable
-    from types import TracebackType
+    from ._reactor import Container
 
 
 class Collector:
@@ -143,11 +141,11 @@ class EventBase(object):
         return self._type
 
     @property
-    def handler(self) -> Optional['Handler']:
+    def handler(self) -> Optional[Handler]:
         """The handler for this event type. Not implemented, always returns 
``None``."""
         return None
 
-    def dispatch(self, handler: 'Handler', type: Optional[EventType] = None) 
-> None:
+    def dispatch(self, handler: Handler, type: Optional[EventType] = None) -> 
None:
         """
         Process this event by sending it to all known handlers that
         are valid for this event type.
@@ -474,7 +472,7 @@ class Event(EventBase):
         return self._context
 
     @property
-    def handler(self) -> Optional['Handler']:
+    def handler(self) -> Optional[Handler]:
         """
         The handler for this event. The handler is determined by looking
         at the following in order:
@@ -600,44 +598,3 @@ class Event(EventBase):
         is associated with it.
         """
         return self._delivery
-
-
-class LazyHandlers(object):
-    def __get__(self, obj: 'Handler', clazz: Any) -> Union['LazyHandlers', 
List[Any]]:
-        if obj is None:
-            return self
-        ret = []
-        obj.__dict__['handlers'] = ret
-        return ret
-
-
-class Handler(object):
-    """
-    An abstract handler for events which supports child handlers.
-    """
-    handlers = LazyHandlers()
-
-    # TODO What to do with on_error?
-    def add(
-            self,
-            handler: Any,
-            on_error: Optional[Callable[[Tuple[Type[BaseException], 
BaseException, 'TracebackType']], None]] = None,
-    ) -> None:
-        """
-        Add a child handler
-
-        :param handler: A child handler
-        :type handler: :class:`Handler` or one of its derivatives.
-        :param on_error: Not used
-        """
-        self.handlers.append(handler)
-
-    def on_unhandled(self, method: str, *args) -> None:
-        """
-        The callback for handling events which are not handled by
-        any other handler.
-
-        :param method: The name of the intended handler method.
-        :param args: Arguments for the intended handler method.
-        """
-        pass
diff --git a/python/proton/_handler.py b/python/proton/_handler.py
new file mode 100644
index 000000000..e6d911855
--- /dev/null
+++ b/python/proton/_handler.py
@@ -0,0 +1,63 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+
+from typing import Any, Callable, List, Optional, Tuple, Type, Union
+from types import TracebackType
+
+
+class LazyHandlers(object):
+    def __get__(self, obj: 'Handler', clazz: Any) -> Union['LazyHandlers', 
List[Any]]:
+        if obj is None:
+            return self
+        ret = []
+        obj.__dict__['handlers'] = ret
+        return ret
+
+
+class Handler(object):
+    """
+    An abstract handler for events which supports child handlers.
+    """
+    handlers = LazyHandlers()
+
+    # TODO What to do with on_error?
+    def add(
+            self,
+            handler: Any,
+            on_error: Optional[Callable[[Tuple[Type[BaseException], 
BaseException, 'TracebackType']], None]] = None,
+    ) -> None:
+        """
+        Add a child handler
+
+        :param handler: A child handler
+        :type handler: :class:`Handler` or one of its derivatives.
+        :param on_error: Not used
+        """
+        self.handlers.append(handler)
+
+    def on_unhandled(self, method: str, *args) -> None:
+        """
+        The callback for handling events which are not handled by
+        any other handler.
+
+        :param method: The name of the intended handler method.
+        :param args: Arguments for the intended handler method.
+        """
+        pass
diff --git a/python/proton/_handlers.py b/python/proton/_handlers.py
index c9d1ec21f..1d390886c 100644
--- a/python/proton/_handlers.py
+++ b/python/proton/_handlers.py
@@ -26,14 +26,15 @@ import weakref
 from ._condition import Condition
 from ._delivery import Delivery
 from ._endpoints import Endpoint
-from ._events import Event, Handler, _dispatch
+from ._events import Event, _dispatch
 from ._exceptions import ProtonException
+from ._handler import Handler
 from ._io import IO
 from ._message import Message
 from ._selectable import Selectable
 from ._transport import Transport
 from ._url import Url
-from typing import Any, List, Optional, Tuple, Union, TYPE_CHECKING, TypeVar
+from typing import Any, List, Optional, Union, TYPE_CHECKING
 
 if TYPE_CHECKING:
     from ._delivery import DispositionType
diff --git a/python/proton/_reactor.py b/python/proton/_reactor.py
index 40939863e..6b86968b1 100644
--- a/python/proton/_reactor.py
+++ b/python/proton/_reactor.py
@@ -46,8 +46,9 @@ from cproton import PN_ACCEPTED, PN_EVENT_NONE
 from ._data import Described, symbol, ulong
 from ._delivery import Delivery
 from ._endpoints import Connection, Endpoint, Link, Session, Terminus
-from ._events import Collector, EventType, EventBase, Handler, Event
+from ._events import Collector, EventType, EventBase, Event
 from ._exceptions import SSLUnavailable
+from ._handler import Handler
 from ._handlers import OutgoingMessageHandler, IOHandler
 from ._io import IO
 from ._message import Message


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@qpid.apache.org
For additional commands, e-mail: commits-h...@qpid.apache.org

Reply via email to