(qpid-proton) 03/04: PROTON-2892: [Python] Use python library IntFlag for Endpoint state

2025-04-28 Thread astitcher
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 d8ff8f7314f4a046c4033886b92edfc20cd09e72
Author: Andrew Stitcher 
AuthorDate: Tue Apr 22 12:11:21 2025 -0400

PROTON-2892: [Python] Use python library IntFlag for Endpoint state
---
 python/proton/_endpoints.py | 52 +
 1 file changed, 34 insertions(+), 18 deletions(-)

diff --git a/python/proton/_endpoints.py b/python/proton/_endpoints.py
index d83f7e72f..13b837444 100644
--- a/python/proton/_endpoints.py
+++ b/python/proton/_endpoints.py
@@ -65,6 +65,7 @@ from ._transport import Transport
 from ._wrapper import Wrapper
 
 from collections.abc import Iterator
+from enum import IntFlag
 from typing import Any, Callable, ClassVar, Optional, Union, TYPE_CHECKING, 
overload
 
 if TYPE_CHECKING:
@@ -74,25 +75,11 @@ if TYPE_CHECKING:
 from ._message import Message
 
 
-class Endpoint(Wrapper):
+class EndpointState(IntFlag):
 """
-Abstract class from which :class:`Connection`, :class:`Session`
-and :class:`Link` are derived, and which defines the state
-of these classes.
-
-The :class:`Endpoint` state is an integral value with flags that
+The state of an AMQP endpoint. This is a bit field with flags that
 encode both the local and remote state of an AMQP Endpoint
 (:class:`Connection`, :class:`Link`, or :class:`Session`).
-The individual bits may be accessed using :const:`LOCAL_UNINIT`,
-:const:`LOCAL_ACTIVE`, :const:`LOCAL_CLOSED`, and
-:const:`REMOTE_UNINIT`, :const:`REMOTE_ACTIVE`, :const:`REMOTE_CLOSED`.
-
-Every AMQP endpoint (:class:`Connection`, :class:`Link`, or
-:class:`Session`) starts out in an uninitialized state and then
-proceeds linearly to an active and then closed state. This
-lifecycle occurs at both endpoints involved, and so the state
-model for an endpoint includes not only the known local state,
-but also the last known state of the remote endpoint.
 """
 
 LOCAL_UNINIT = PN_LOCAL_UNINIT
@@ -113,9 +100,38 @@ class Endpoint(Wrapper):
 REMOTE_CLOSED = PN_REMOTE_CLOSED
 """ The remote endpoint state is closed. """
 
+
+class Endpoint(Wrapper):
+"""
+Abstract class from which :class:`Connection`, :class:`Session`
+and :class:`Link` are derived, and which defines the state
+of these classes.
+
+The :class:`Endpoint` state is an integral value with flags that
+encode both the local and remote state of an AMQP Endpoint
+(:class:`Connection`, :class:`Link`, or :class:`Session`).
+The individual bits may be accessed using :const:`LOCAL_UNINIT`,
+:const:`LOCAL_ACTIVE`, :const:`LOCAL_CLOSED`, and
+:const:`REMOTE_UNINIT`, :const:`REMOTE_ACTIVE`, :const:`REMOTE_CLOSED`.
+
+Every AMQP endpoint (:class:`Connection`, :class:`Link`, or
+:class:`Session`) starts out in an uninitialized state and then
+proceeds linearly to an active and then closed state. This
+lifecycle occurs at both endpoints involved, and so the state
+model for an endpoint includes not only the known local state,
+but also the last known state of the remote endpoint.
+"""
+
+LOCAL_UNINIT = EndpointState.LOCAL_UNINIT
+REMOTE_UNINIT = EndpointState.REMOTE_UNINIT
+LOCAL_ACTIVE = EndpointState.LOCAL_ACTIVE
+REMOTE_ACTIVE = EndpointState.REMOTE_ACTIVE
+LOCAL_CLOSED = EndpointState.LOCAL_CLOSED
+REMOTE_CLOSED = EndpointState.REMOTE_CLOSED
+
 get_condition: ClassVar[Callable[[Any], Any]]
 get_remote_condition: ClassVar[Callable[[Any], Any]]
-get_state: ClassVar[Callable[[Any], int]]
+get_state: ClassVar[Callable[[Any], EndpointState]]
 
 def __init__(self) -> None:
 self.condition: Optional['Condition'] = None
@@ -133,7 +149,7 @@ class Endpoint(Wrapper):
 return cond2obj(type(self).get_remote_condition(self._impl))
 
 @property
-def state(self) -> int:
+def state(self) -> EndpointState:
 """
 The state of the endpoint as a bit field. The state has a local
 and a remote component. Each of these can be in one of three


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



(qpid-proton) 02/04: PROTON-2868: [Python] More work simplifying wrapped classes

2025-04-28 Thread astitcher
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 1fafacd74a7e0df37c86d65316b09d2a038580eb
Author: Andrew Stitcher 
AuthorDate: Fri Apr 18 18:25:13 2025 -0400

PROTON-2868: [Python] More work simplifying wrapped classes
---
 python/proton/_endpoints.py | 102 +---
 python/proton/_wrapper.py   |   2 +-
 2 files changed, 31 insertions(+), 73 deletions(-)

diff --git a/python/proton/_endpoints.py b/python/proton/_endpoints.py
index 21171b16d..d83f7e72f 100644
--- a/python/proton/_endpoints.py
+++ b/python/proton/_endpoints.py
@@ -65,7 +65,7 @@ from ._transport import Transport
 from ._wrapper import Wrapper
 
 from collections.abc import Iterator
-from typing import Any, Optional, Union, TYPE_CHECKING, overload
+from typing import Any, Callable, ClassVar, Optional, Union, TYPE_CHECKING, 
overload
 
 if TYPE_CHECKING:
 from ._condition import Condition
@@ -74,7 +74,7 @@ if TYPE_CHECKING:
 from ._message import Message
 
 
-class Endpoint(object):
+class Endpoint(Wrapper):
 """
 Abstract class from which :class:`Connection`, :class:`Session`
 and :class:`Link` are derived, and which defines the state
@@ -113,12 +113,16 @@ class Endpoint(object):
 REMOTE_CLOSED = PN_REMOTE_CLOSED
 """ The remote endpoint state is closed. """
 
+get_condition: ClassVar[Callable[[Any], Any]]
+get_remote_condition: ClassVar[Callable[[Any], Any]]
+get_state: ClassVar[Callable[[Any], int]]
+
 def __init__(self) -> None:
 self.condition: Optional['Condition'] = None
 self._handler: Optional[Handler] = None
 
 def _update_cond(self) -> None:
-obj2cond(self.condition, self._get_cond_impl())
+obj2cond(self.condition, type(self).get_condition(self._impl))
 
 @property
 def remote_condition(self) -> Optional['Condition']:
@@ -126,14 +130,18 @@ class Endpoint(object):
 The remote condition associated with the connection endpoint.
 See :class:`Condition` for more information.
 """
-return cond2obj(self._get_remote_cond_impl())
-
-# the following must be provided by subclasses
-def _get_cond_impl(self):
-assert False, "Subclass must override this!"
+return cond2obj(type(self).get_remote_condition(self._impl))
 
-def _get_remote_cond_impl(self):
-assert False, "Subclass must override this!"
+@property
+def state(self) -> int:
+"""
+The state of the endpoint as a bit field. The state has a local
+and a remote component. Each of these can be in one of three
+states: ``UNINIT``, ``ACTIVE`` or ``CLOSED``. These can be tested by 
masking
+against :const:`LOCAL_UNINIT`, :const:`LOCAL_ACTIVE`, 
:const:`LOCAL_CLOSED`, :const:`REMOTE_UNINIT`,
+:const:`REMOTE_ACTIVE` and :const:`REMOTE_CLOSED`.
+"""
+return type(self).get_state(self._impl)
 
 @property
 def handler(self) -> Optional[Handler]:
@@ -155,13 +163,16 @@ class Endpoint(object):
 self._handler.add(handler)
 
 
-class Connection(Wrapper, Endpoint):
+class Connection(Endpoint):
 """
 A representation of an AMQP connection.
 """
 
 constructor = pn_connection
 get_context = pn_connection_attachments
+get_condition = pn_connection_condition
+get_remote_condition = pn_connection_remote_condition
+get_state = pn_connection_state
 
 def __init__(self, impl: Any = None) -> None:
 if self.Uninitialized():
@@ -172,9 +183,6 @@ class Connection(Wrapper, Endpoint):
 self.url = None
 self._acceptor = None
 
-def _get_attachments(self):
-return pn_connection_attachments(self._impl)
-
 @property
 def connection(self) -> 'Connection':
 """
@@ -197,12 +205,6 @@ class Connection(Wrapper, Endpoint):
 else:
 return err
 
-def _get_cond_impl(self):
-return pn_connection_condition(self._impl)
-
-def _get_remote_cond_impl(self):
-return pn_connection_remote_condition(self._impl)
-
 # TODO: Blacklisted API call
 def collect(self, collector: 'Collector') -> None:
 if collector is None:
@@ -403,17 +405,6 @@ class Connection(Wrapper, Endpoint):
 s.terminate()
 s.update()
 
-@property
-def state(self) -> int:
-"""
-The state of the connection as a bit field. The state has a local
-and a remote component. Each of these can be in one of three
-states: ``UNINIT``, ``ACTIVE`` or ``CLOSED``. These can be tested by 
masking
-against :const:`LOCAL_UNINIT`, :const:`LOCAL_ACTIVE`, 
:const:`LOCAL_CLOSED`, :const:`REMOTE_UNINIT`,
-:const:`REMOTE_ACTIVE` and :const:`REMOTE_CLOSED`.
-"""
-return pn_connection_state(self._impl)
-
 def session(self) -> 'Session':
  

(qpid-proton) 04/04: PROTON-2893: [Python] Add callback for all delivery updates

2025-04-28 Thread astitcher
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 3191f95d88b3dbf78ac46474b4ce89d7627fce32
Author: Andrew Stitcher 
AuthorDate: Wed May 22 18:02:36 2024 -0400

PROTON-2893: [Python] Add callback for all delivery updates

This is useful for responding to delivery updates besides the common
AMQP updates. Specifically for better transaction support.
---
 python/proton/_handlers.py | 24 
 1 file changed, 24 insertions(+)

diff --git a/python/proton/_handlers.py b/python/proton/_handlers.py
index 79a6f3df5..e2d194db2 100644
--- a/python/proton/_handlers.py
+++ b/python/proton/_handlers.py
@@ -115,6 +115,7 @@ class OutgoingMessageHandler(Handler):
 self.on_rejected(event)
 elif dlv.remote_state == Delivery.RELEASED or dlv.remote_state == 
Delivery.MODIFIED:
 self.on_released(event)
+self.on_delivery_updated(event)
 if dlv.settled:
 self.on_settled(event)
 if self.auto_settle:
@@ -163,6 +164,18 @@ class OutgoingMessageHandler(Handler):
 if self.delegate is not None:
 _dispatch(self.delegate, 'on_released', event)
 
+def on_delivery_updated(self, event: DeliveryEvent):
+"""
+Called when the remote peer updates the status of a delivery. Note that
+this will be called even if the more specific disposition update events
+are also called.
+
+:param event: The underlying event object. Use this to obtain further
+information on the event.
+"""
+if self.delegate is not None:
+_dispatch(self.delegate, 'on_delivery_updated', event)
+
 def on_settled(self, event: DeliveryEvent):
 """
 Called when the remote peer has settled the outgoing
@@ -917,6 +930,17 @@ class MessagingHandler(Handler, Acking):
 """
 pass
 
+def on_delivery_updated(self, event: DeliveryEvent) -> None:
+"""
+Called when the remote peer updates the status of a delivery. Note that
+this will be called even if the more specific disposition update events
+are also called.
+
+:param event: The underlying event object. Use this to obtain further
+information on the event.
+"""
+pass
+
 def on_settled(self, event: DeliveryEvent) -> None:
 """
 Called when the remote peer has settled the outgoing


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



(qpid-proton) 01/04: PROTON-2891: [Python] Improve typing annotations especially for Events

2025-04-28 Thread astitcher
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 5de2b8e93300b366c1952d942897d1aa92206acb
Author: Andrew Stitcher 
AuthorDate: Fri Apr 18 18:37:57 2025 -0400

PROTON-2891: [Python] Improve typing annotations especially for Events
---
 python/proton/_delivery.py  |   3 +
 python/proton/_endpoints.py |   7 +-
 python/proton/_events.py|   2 +-
 python/proton/_handlers.py  | 196 ++--
 4 files changed, 128 insertions(+), 80 deletions(-)

diff --git a/python/proton/_delivery.py b/python/proton/_delivery.py
index 90bf3689f..41c39d84a 100644
--- a/python/proton/_delivery.py
+++ b/python/proton/_delivery.py
@@ -133,6 +133,9 @@ class Disposition:
 MODIFIED = DispositionType.MODIFIED
 TRANSACTIONAL_STATE = DispositionType.TRANSACTIONAL_STATE
 
+@property
+def type(self) -> Union[int, DispositionType]: ...
+
 
 class RemoteDisposition(Disposition):
 
diff --git a/python/proton/_endpoints.py b/python/proton/_endpoints.py
index 2559a4dd5..21171b16d 100644
--- a/python/proton/_endpoints.py
+++ b/python/proton/_endpoints.py
@@ -65,7 +65,7 @@ from ._transport import Transport
 from ._wrapper import Wrapper
 
 from collections.abc import Iterator
-from typing import Any, Optional, Union, TYPE_CHECKING
+from typing import Any, Optional, Union, TYPE_CHECKING, overload
 
 if TYPE_CHECKING:
 from ._condition import Condition
@@ -1170,6 +1170,11 @@ class Sender(Link):
 """
 return self._check(pn_link_send(self._impl, data))
 
+@overload
+def send(self, obj: bytes) -> int: ...
+@overload
+def send(self, obj: 'Message', tag: Optional[str] = None) -> Delivery: ...
+
 def send(self, obj: Union[bytes, 'Message'], tag: Optional[str] = None) -> 
Union[int, Delivery]:
 """
 A convenience method to send objects as message content.
diff --git a/python/proton/_events.py b/python/proton/_events.py
index 55c5d7717..e9995b9dc 100644
--- a/python/proton/_events.py
+++ b/python/proton/_events.py
@@ -556,7 +556,7 @@ class Event(EventBase):
 return self._session
 
 @property
-def link(self) -> Optional[Union['Receiver', 'Sender']]:
+def link(self) -> Optional[Link]:
 """
 The link associated with the event, or ``None`` if none
 is associated with it.
diff --git a/python/proton/_handlers.py b/python/proton/_handlers.py
index 819f8431c..79a6f3df5 100644
--- a/python/proton/_handlers.py
+++ b/python/proton/_handlers.py
@@ -24,8 +24,8 @@ import time
 import weakref
 
 from ._condition import Condition
-from ._delivery import Delivery, ModifiedDisposition
-from ._endpoints import Endpoint
+from ._delivery import Delivery, DispositionType, ModifiedDisposition
+from ._endpoints import Connection, Endpoint, Link, Receiver, Session
 from ._events import Event, _dispatch
 from ._exceptions import ProtonException
 from ._handler import Handler
@@ -34,16 +34,56 @@ from ._message import Message
 from ._selectable import Selectable
 from ._transport import Transport
 from ._url import Url
-from typing import Any, Optional, Union, TYPE_CHECKING
+
+from typing import Any, Optional, TYPE_CHECKING
 
 if TYPE_CHECKING:
-from ._delivery import DispositionType
 from ._reactor import Container, Transaction
-from ._endpoints import Sender, Receiver
 
 log = logging.getLogger("proton")
 
 
+class ConnectionEvent(Event):
+@property
+def connection(self) -> Connection: ...
+
+
+class SessionEvent(ConnectionEvent):
+@property
+def session(self) -> Session: ...
+
+
+class LinkEvent(SessionEvent):
+@property
+def link(self) -> Link: ...
+
+
+class DeliveryEvent(LinkEvent):
+@property
+def delivery(self) -> Delivery: ...
+
+
+class MessageEvent(DeliveryEvent):
+@property
+def message(self) -> Message: ...
+
+@property
+def receiver(self) -> Receiver: ...
+
+
+class TransportEvent(Event):
+@property
+def transport(self) -> Transport: ...
+
+
+class ConnectionBoundEvent(Event):
+@property
+def connection(self) -> Connection: ...
+
+@property
+def transport(self) -> Transport: ...
+
+
 class OutgoingMessageHandler(Handler):
 """
 A utility for simpler and more intuitive handling of delivery
@@ -60,13 +100,13 @@ class OutgoingMessageHandler(Handler):
 self.auto_settle = auto_settle
 self.delegate = delegate
 
-def on_link_flow(self, event: Event):
+def on_link_flow(self, event: LinkEvent):
 if event.link.is_sender and event.link.credit \
 and event.link.state & Endpoint.LOCAL_ACTIVE \
 and event.link.state & Endpoint.REMOTE_ACTIVE:
 self.on_sendable(event)
 
-def on_delivery(self, event: Event):
+def on_delivery(self, event: DeliveryEvent):
 dlv = event.delivery
 if dlv.link.is_sender and dlv.updat

(qpid-proton) branch main updated (e1d147e22 -> 3191f95d8)

2025-04-28 Thread astitcher
This is an automated email from the ASF dual-hosted git repository.

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


from e1d147e22 PROTON-2890: [Python examples] Simple recv now deduplicates 
more accurately
 new 5de2b8e93 PROTON-2891: [Python] Improve typing annotations especially 
for Events
 new 1fafacd74 PROTON-2868: [Python] More work simplifying wrapped classes
 new d8ff8f731 PROTON-2892: [Python] Use python library IntFlag for 
Endpoint state
 new 3191f95d8 PROTON-2893: [Python] Add callback for all delivery updates

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 python/proton/_delivery.py  |   3 +
 python/proton/_endpoints.py | 153 +-
 python/proton/_events.py|   2 +-
 python/proton/_handlers.py  | 220 
 python/proton/_wrapper.py   |   2 +-
 5 files changed, 213 insertions(+), 167 deletions(-)


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