From 912c993bd3f7c41c163e38e16ea83dc90354d757 Mon Sep 17 00:00:00 2001 From: Kashif Khan Date: Mon, 18 Jul 2022 10:00:50 -0500 Subject: [PATCH 01/46] init changes to client --- .../azure/eventhub/_pyamqp/client.py | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index c0a152bba31b..159b61940530 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -18,7 +18,7 @@ from .session import Session from .sender import SenderLink from .receiver import ReceiverLink -from .sasl import SASLTransport +from .sasl import SASLAnonymousCredential, SASLTransport from .endpoints import Source, Target from .error import ( AMQPConnectionError, @@ -60,13 +60,13 @@ class AMQPClient(object): :param remote_address: The AMQP endpoint to connect to. This could be a send target or a receive source. :type remote_address: str, bytes or ~uamqp.address.Address - :param auth: Authentication for the connection. This should be one of the subclasses of - uamqp.authentication.AMQPAuth. Currently this includes: - - uamqp.authentication.SASLAnonymous - - uamqp.authentication.SASLPlain - - uamqp.authentication.SASTokenAuth + :param auth: Authentication for the connection. This should be one of the following: + - pyamqp.authentication.SASLAnonymous + - pyamqp.authentication.SASLPlain + - pyamqp.authentication.SASTokenAuth + - pyamqp.authentication.JWTTokenAuth If no authentication is supplied, SASLAnnoymous will be used by default. - :type auth: ~uamqp.authentication.common.AMQPAuth + :type auth: ~pyamqp.authentication :param client_name: The name for the client, also known as the Container ID. If no name is provided, a random GUID will be used. :type client_name: str or bytes @@ -75,7 +75,7 @@ class AMQPClient(object): :type debug: bool :param retry_policy: A policy for parsing errors on link, connection and message disposition to determine whether the error should be retryable. - :type retry_policy: ~uamqp.errors.RetryPolicy + :type retry_policy: ~pyamqp.errors.RetryPolicy :param keep_alive_interval: If set, a thread will be started to keep the connection alive during periods of user inactivity. The value will determine how long the thread will sleep (in seconds) between pinging the connection. If 0 or None, no @@ -105,7 +105,7 @@ class AMQPClient(object): :type handle_max: int :param on_attach: A callback function to be run on receipt of an ATTACH frame. The function must take 4 arguments: source, target, properties and error. - :type on_attach: func[~uamqp.address.Source, ~uamqp.address.Target, dict, ~uamqp.errors.AMQPConnectionError] + :type on_attach: func[~uamqp.address.Source, ~uamqp.address.Target, dict, ~pyamqp.error.AMQPConnectionError] :param send_settle_mode: The mode by which to settle message send operations. If set to `Unsettled`, the client will wait for a confirmation from the service that the message was successfully sent. If set to 'Settled', @@ -116,16 +116,17 @@ class AMQPClient(object): the client accepts or rejects the message. If set to `ReceiveAndDelete`, the service will assume successful receipt of the message and clear it from the queue. The default is `PeekLock`. - :type receive_settle_mode: ~uamqp.constants.ReceiverSettleMode + :type receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode :param encoding: The encoding to use for parameters supplied as strings. Default is 'UTF-8' :type encoding: str """ - def __init__(self, hostname, auth=None, **kwargs): - self._hostname = hostname - self._auth = auth - self._name = kwargs.pop("client_name", str(uuid.uuid4())) + def __init__(self, remote_address, auth=None, client_name=None, debug=False, retry_policy=None, + keep_alive_interval=None, **kwargs): + self._remote_address = remote_address + self._auth = auth if auth else SASLAnonymousCredential() + self._name = client_name if client_name else str(uuid.uuid4()) self._shutdown = False self._connection = None @@ -136,14 +137,15 @@ def __init__(self, hostname, auth=None, **kwargs): self._cbs_authenticator = None self._auth_timeout = kwargs.pop("auth_timeout", DEFAULT_AUTH_TIMEOUT) self._mgmt_links = {} - self._retry_policy = kwargs.pop("retry_policy", RetryPolicy()) + self._retry_policy = retry_policy if retry_policy else RetryPolicy() + self._keep_alive_interval = int(keep_alive_interval) if keep_alive_interval else 0 # Connection settings self._max_frame_size = kwargs.pop('max_frame_size', None) or MAX_FRAME_SIZE_BYTES self._channel_max = kwargs.pop('channel_max', None) or 65535 self._idle_timeout = kwargs.pop('idle_timeout', None) self._properties = kwargs.pop('properties', None) - self._network_trace = kwargs.pop("network_trace", False) + self._network_trace = debug # Session settings self._outgoing_window = kwargs.pop('outgoing_window', None) or OUTGOING_WIDNOW @@ -242,7 +244,7 @@ def open(self): _logger.debug("Opening client connection.") if not self._connection: self._connection = Connection( - "amqps://" + self._hostname, + "amqps://" + self._remote_address, sasl_credential=self._auth.sasl, ssl={'ca_certs':self._connection_verify or certifi.where()}, container_id=self._name, @@ -385,13 +387,13 @@ def mgmt_request(self, message, **kwargs): class SendClient(AMQPClient): - def __init__(self, hostname, target, auth=None, **kwargs): + def __init__(self, target, auth=None, **kwargs): self.target = target # Sender and Link settings self._max_message_size = kwargs.pop('max_message_size', None) or MAX_FRAME_SIZE_BYTES self._link_properties = kwargs.pop('link_properties', None) self._link_credit = kwargs.pop('link_credit', None) - super(SendClient, self).__init__(hostname, auth=auth, **kwargs) + super(SendClient, self).__init__(target, auth=auth, **kwargs) def _client_ready(self): """Determine whether the client is ready to start receiving messages. @@ -611,7 +613,7 @@ class ReceiveClient(AMQPClient): :type encoding: str """ - def __init__(self, hostname, source, auth=None, **kwargs): + def __init__(self, target, source, auth=None, **kwargs): self.source = source self._streaming_receive = kwargs.pop("streaming_receive", False) # TODO: whether public? self._received_messages = queue.Queue() @@ -621,7 +623,7 @@ def __init__(self, hostname, source, auth=None, **kwargs): self._max_message_size = kwargs.pop('max_message_size', None) or MAX_FRAME_SIZE_BYTES self._link_properties = kwargs.pop('link_properties', None) self._link_credit = kwargs.pop('link_credit', 300) - super(ReceiveClient, self).__init__(hostname, auth=auth, **kwargs) + super(ReceiveClient, self).__init__(target, auth=auth, **kwargs) def _client_ready(self): """Determine whether the client is ready to start receiving messages. From 1a5faf2c8699c2478267fda4839e065225da1fae Mon Sep 17 00:00:00 2001 From: Kashif Khan Date: Mon, 18 Jul 2022 14:53:13 -0500 Subject: [PATCH 02/46] fix doctring --- sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index 159b61940530..0f64259c3db3 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -75,7 +75,7 @@ class AMQPClient(object): :type debug: bool :param retry_policy: A policy for parsing errors on link, connection and message disposition to determine whether the error should be retryable. - :type retry_policy: ~pyamqp.errors.RetryPolicy + :type retry_policy: ~pyamqp.error.RetryPolicy :param keep_alive_interval: If set, a thread will be started to keep the connection alive during periods of user inactivity. The value will determine how long the thread will sleep (in seconds) between pinging the connection. If 0 or None, no From 20fbe030eb2e4a3e97abc3fcf0036455f89dccf5 Mon Sep 17 00:00:00 2001 From: Kashif Khan Date: Mon, 18 Jul 2022 14:54:19 -0500 Subject: [PATCH 03/46] remove error --- sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index 0f64259c3db3..8fc150dbd853 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -125,7 +125,7 @@ class AMQPClient(object): def __init__(self, remote_address, auth=None, client_name=None, debug=False, retry_policy=None, keep_alive_interval=None, **kwargs): self._remote_address = remote_address - self._auth = auth if auth else SASLAnonymousCredential() + self._auth = auth self._name = client_name if client_name else str(uuid.uuid4()) self._shutdown = False From 18599d5655262835daf983de7b8563ec44ef5ebf Mon Sep 17 00:00:00 2001 From: Kashif Khan Date: Wed, 27 Jul 2022 09:33:28 -0500 Subject: [PATCH 04/46] cleanup --- .../azure/eventhub/_pyamqp/client.py | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index 8fc150dbd853..4b6ae8bdbd33 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -110,7 +110,7 @@ class AMQPClient(object): operations. If set to `Unsettled`, the client will wait for a confirmation from the service that the message was successfully sent. If set to 'Settled', the client will not wait for confirmation and assume success. - :type send_settle_mode: ~uamqp.constants.SenderSettleMode + :type send_settle_mode: ~pyamqp.constants.SenderSettleMode :param receive_settle_mode: The mode by which to settle message receive operations. If set to `PeekLock`, the receiver will lock a message once received until the client accepts or rejects the message. If set to `ReceiveAndDelete`, the service @@ -145,12 +145,15 @@ def __init__(self, remote_address, auth=None, client_name=None, debug=False, ret self._channel_max = kwargs.pop('channel_max', None) or 65535 self._idle_timeout = kwargs.pop('idle_timeout', None) self._properties = kwargs.pop('properties', None) + self._remote_idle_timeout_empty_frame_send_ratio = kwargs.pop( + 'remote_idle_timeout_empty_frame_send_ratio', None) self._network_trace = debug # Session settings self._outgoing_window = kwargs.pop('outgoing_window', None) or OUTGOING_WIDNOW self._incoming_window = kwargs.pop('incoming_window', None) or INCOMING_WINDOW self._handle_max = kwargs.pop('handle_max', None) + self._on_attach = kwargs.pop('on_attach', None) # Link settings self._send_settle_mode = kwargs.pop('send_settle_mode', SenderSettleMode.Unsettled) @@ -236,7 +239,7 @@ def open(self): :param connection: An existing Connection that may be shared between multiple clients. - :type connetion: ~uamqp.Connection + :type connetion: ~pyamqp.Connection """ # pylint: disable=protected-access if self._session: @@ -536,10 +539,10 @@ class ReceiveClient(AMQPClient): a string or a ~uamqp.address.Source object. :type target: str, bytes or ~uamqp.address.Source :param auth: Authentication for the connection. This should be one of the subclasses of - uamqp.authentication.AMQPAuth. Currently this includes: - - uamqp.authentication.SASLAnonymous - - uamqp.authentication.SASLPlain - - uamqp.authentication.SASTokenAuth + pyamqp.authentication.AMQPAuth. Currently this includes: + - pyamqp.authentication.SASLAnonymous + - pyamqp.authentication.SASLPlain + - pyamqp.authentication.SASTokenAuth If no authentication is supplied, SASLAnnoymous will be used by default. :type auth: ~uamqp.authentication.common.AMQPAuth :param client_name: The name for the client, also known as the Container ID. @@ -556,7 +559,7 @@ class ReceiveClient(AMQPClient): :type auto_complete: bool :param retry_policy: A policy for parsing errors on link, connection and message disposition to determine whether the error should be retryable. - :type retry_policy: ~uamqp.errors.RetryPolicy + :type retry_policy: ~pyamqp.errors.RetryPolicy :param keep_alive_interval: If set, a thread will be started to keep the connection alive during periods of user inactivity. The value will determine how long the thread will sleep (in seconds) between pinging the connection. If 0 or None, no @@ -566,13 +569,13 @@ class ReceiveClient(AMQPClient): operations. If set to `Unsettled`, the client will wait for a confirmation from the service that the message was successfully sent. If set to 'Settled', the client will not wait for confirmation and assume success. - :type send_settle_mode: ~uamqp.constants.SenderSettleMode + :type send_settle_mode: ~pyamqp.constants.SenderSettleMode :param receive_settle_mode: The mode by which to settle message receive operations. If set to `PeekLock`, the receiver will lock a message once received until the client accepts or rejects the message. If set to `ReceiveAndDelete`, the service will assume successful receipt of the message and clear it from the queue. The default is `PeekLock`. - :type receive_settle_mode: ~uamqp.constants.ReceiverSettleMode + :type receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode :param desired_capabilities: The extension capabilities desired from the peer endpoint. To create an desired_capabilities object, please do as follows: - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` @@ -607,7 +610,7 @@ class ReceiveClient(AMQPClient): :type handle_max: int :param on_attach: A callback function to be run on receipt of an ATTACH frame. The function must take 4 arguments: source, target, properties and error. - :type on_attach: func[~uamqp.address.Source, ~uamqp.address.Target, dict, ~uamqp.errors.AMQPConnectionError] + :type on_attach: func[~uamqp.address.Source, ~uamqp.address.Target, dict, ~pyamqp.errors.AMQPConnectionError] :param encoding: The encoding to use for parameters supplied as strings. Default is 'UTF-8' :type encoding: str From 943f0d661794f4d608ddb48eed0bf11876968790 Mon Sep 17 00:00:00 2001 From: Kashif Khan Date: Wed, 27 Jul 2022 10:07:35 -0500 Subject: [PATCH 05/46] further clean up --- .../azure/eventhub/_pyamqp/client.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index 4b6ae8bdbd33..5b82683ec2e7 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -19,7 +19,7 @@ from .sender import SenderLink from .receiver import ReceiverLink from .sasl import SASLAnonymousCredential, SASLTransport -from .endpoints import Source, Target +from .endpoints import Sopurce, Source, Target from .error import ( AMQPConnectionError, AMQPException, @@ -59,7 +59,7 @@ class AMQPClient(object): :param remote_address: The AMQP endpoint to connect to. This could be a send target or a receive source. - :type remote_address: str, bytes or ~uamqp.address.Address + :type remote_address: str, bytes or ~pyamqp.endpoint.Target or ~pyamqp.endpoint.Source :param auth: Authentication for the connection. This should be one of the following: - pyamqp.authentication.SASLAnonymous - pyamqp.authentication.SASLPlain @@ -105,7 +105,7 @@ class AMQPClient(object): :type handle_max: int :param on_attach: A callback function to be run on receipt of an ATTACH frame. The function must take 4 arguments: source, target, properties and error. - :type on_attach: func[~uamqp.address.Source, ~uamqp.address.Target, dict, ~pyamqp.error.AMQPConnectionError] + :type on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.error.AMQPConnectionError] :param send_settle_mode: The mode by which to settle message send operations. If set to `Unsettled`, the client will wait for a confirmation from the service that the message was successfully sent. If set to 'Settled', @@ -124,7 +124,7 @@ class AMQPClient(object): def __init__(self, remote_address, auth=None, client_name=None, debug=False, retry_policy=None, keep_alive_interval=None, **kwargs): - self._remote_address = remote_address + self._remote_address = remote_address.address if (isinstance(remote_address, Source) or isinstance(remote_address, Target)) else remote_address self._auth = auth self._name = client_name if client_name else str(uuid.uuid4()) @@ -535,9 +535,9 @@ def send_message(self, message, **kwargs): class ReceiveClient(AMQPClient): """An AMQP client for receiving messages. - :param target: The source AMQP service endpoint. This can either be the URI as - a string or a ~uamqp.address.Source object. - :type target: str, bytes or ~uamqp.address.Source + :param source: The source AMQP service endpoint. This can either be the URI as + a string or a ~pyamqp.endpoint.Source object. + :type source: str, bytes or ~pyamqp.endpoint.Source :param auth: Authentication for the connection. This should be one of the subclasses of pyamqp.authentication.AMQPAuth. Currently this includes: - pyamqp.authentication.SASLAnonymous @@ -616,7 +616,7 @@ class ReceiveClient(AMQPClient): :type encoding: str """ - def __init__(self, target, source, auth=None, **kwargs): + def __init__(self, source, auth=None, **kwargs): self.source = source self._streaming_receive = kwargs.pop("streaming_receive", False) # TODO: whether public? self._received_messages = queue.Queue() From 179321a6fcb64dec7231ec7937553f608e6da1a8 Mon Sep 17 00:00:00 2001 From: Kashif Khan Date: Wed, 27 Jul 2022 10:07:43 -0500 Subject: [PATCH 06/46] fix tests --- .../tests/pyamqp_tests/unittest/test_client_creation_pyamqp.py | 2 -- .../tests/pyamqp_tests/unittest/test_exceptions_pyamqp.py | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_client_creation_pyamqp.py b/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_client_creation_pyamqp.py index b0541f11a080..b49a240fd532 100644 --- a/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_client_creation_pyamqp.py +++ b/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_client_creation_pyamqp.py @@ -9,7 +9,6 @@ def test_send_client_creation(): sender = SendClient( - "fake.host.com", "fake_eh", "my_fake_auth" ) @@ -20,7 +19,6 @@ def test_send_client_creation(): def test_receive_client_creation(): receiver = ReceiveClient( - "fake.host.com", "fake_eh", "my_fake_auth" ) diff --git a/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_exceptions_pyamqp.py b/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_exceptions_pyamqp.py index d45f13147d22..0666a2b9d75d 100644 --- a/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_exceptions_pyamqp.py +++ b/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_exceptions_pyamqp.py @@ -12,7 +12,7 @@ def test_client_creation_exceptions(): sender = SendClient( "fake.host.com", ) - assert sender._hostname == "fake.host.com" + assert sender._remote_address == "fake.host.com" def test_connection_endpoint_exceptions(): with pytest.raises(AMQPConnectionError): From e880b9c2a9e4aef083e51c441cf5e3379caf3524 Mon Sep 17 00:00:00 2001 From: Kashif Khan Date: Wed, 27 Jul 2022 10:28:30 -0500 Subject: [PATCH 07/46] tweaks --- .../azure/eventhub/_pyamqp/client.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index 5b82683ec2e7..b34e376a75f9 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -337,7 +337,7 @@ def do_work(self, **kwargs): to be shut down. :rtype: bool - :raises: TimeoutError or ~uamqp.errors.ClientTimeout if CBS authentication timeout reached. + :raises: TimeoutError if CBS authentication timeout reached. """ if self._shutdown: return False @@ -348,7 +348,7 @@ def do_work(self, **kwargs): def mgmt_request(self, message, **kwargs): """ :param message: The message to send in the management request. - :type message: ~uamqp.message.Message + :type message: ~pyamqp.message.Message :keyword str operation: The type of operation to be performed. This value will be service-specific, but common values include READ, CREATE and UPDATE. This value will be added as an application property on the message. @@ -358,7 +358,7 @@ def mgmt_request(self, message, **kwargs): :keyword str node: The target node. Default node is `$management`. :keyword float timeout: Provide an optional timeout in seconds within which a response to the management request must be received. - :rtype: ~uamqp.message.Message + :rtype: ~pyamqp.message.Message """ # The method also takes "status_code_field" and "status_description_field" @@ -524,7 +524,7 @@ def _send_message_impl(self, message, **kwargs): def send_message(self, message, **kwargs): """ - :param ~uamqp.message.Message message: + :param ~pyamqp.message.Message message: :keyword float timeout: timeout in seconds. If set to 0, the client will continue to wait until the message is sent or error happens. The default is 0. @@ -544,7 +544,8 @@ class ReceiveClient(AMQPClient): - pyamqp.authentication.SASLPlain - pyamqp.authentication.SASTokenAuth If no authentication is supplied, SASLAnnoymous will be used by default. - :type auth: ~uamqp.authentication.common.AMQPAuth + :type auth: ~pyamqp.authentication.SASLAnonymous or pyamqp.authentication.SASLPlain + or pyamqp.authentication.SASTokenAuth :param client_name: The name for the client, also known as the Container ID. If no name is provided, a random GUID will be used. :type client_name: str or bytes @@ -610,7 +611,7 @@ class ReceiveClient(AMQPClient): :type handle_max: int :param on_attach: A callback function to be run on receipt of an ATTACH frame. The function must take 4 arguments: source, target, properties and error. - :type on_attach: func[~uamqp.address.Source, ~uamqp.address.Target, dict, ~pyamqp.errors.AMQPConnectionError] + :type on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.errors.AMQPConnectionError] :param encoding: The encoding to use for parameters supplied as strings. Default is 'UTF-8' :type encoding: str @@ -678,7 +679,7 @@ def _message_received(self, message): or iterator, the message will be added to an internal queue. :param message: Received message. - :type message: ~uamqp.message.Message + :type message: ~pyamqp.message.Message """ if self._message_received_callback: self._message_received_callback(message) @@ -753,8 +754,8 @@ def receive_message_batch(self, **kwargs): the prefetch value will be used. :type max_batch_size: int :param on_message_received: A callback to process messages as they arrive from the - service. It takes a single argument, a ~uamqp.message.Message object. - :type on_message_received: callable[~uamqp.message.Message] + service. It takes a single argument, a ~pyamqp.message.Message object. + :type on_message_received: callable[~pyamqp.message.Message] :param timeout: I timeout in milliseconds for which to wait to receive any messages. If no messages are received in this time, an empty list will be returned. If set to 0, the client will continue to wait until at least one message is received. The From cf66a143e80655ea712b1243f7dfd8b3540dc266 Mon Sep 17 00:00:00 2001 From: Kashif Khan Date: Wed, 27 Jul 2022 10:43:30 -0500 Subject: [PATCH 08/46] fix import --- sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index b34e376a75f9..bd2b36a3ca69 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -19,7 +19,7 @@ from .sender import SenderLink from .receiver import ReceiverLink from .sasl import SASLAnonymousCredential, SASLTransport -from .endpoints import Sopurce, Source, Target +from .endpoints import Source, Target from .error import ( AMQPConnectionError, AMQPException, From 7424d4aa83adad1fc82f54e9a7667a0becf5e8da Mon Sep 17 00:00:00 2001 From: Kashif Khan Date: Wed, 27 Jul 2022 12:33:53 -0500 Subject: [PATCH 09/46] fix unit tests --- .../tests/pyamqp_tests/unittest/test_exceptions_pyamqp.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_exceptions_pyamqp.py b/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_exceptions_pyamqp.py index 0666a2b9d75d..83244e2b23b2 100644 --- a/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_exceptions_pyamqp.py +++ b/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_exceptions_pyamqp.py @@ -34,7 +34,7 @@ def test_connection_sas_authentication_exception(): password="" ) with pytest.raises(AttributeError): - sender = SendClient("fake.host.com", target, auth=sas_auth) + sender = SendClient(target, auth=sas_auth) sender.client_ready() def test_connection_sasl_annon_authentication_exception(): @@ -45,5 +45,5 @@ def test_connection_sasl_annon_authentication_exception(): sas_auth = authentication.SASLAnonymousCredential() with pytest.raises(AttributeError): - sender = SendClient("fake.host.com", target, auth=sas_auth) + sender = SendClient(target, auth=sas_auth) sender.client_ready() From 592046d6e5be20ab9b05a11a240d87b146a446c2 Mon Sep 17 00:00:00 2001 From: Kashif Khan Date: Wed, 27 Jul 2022 13:34:14 -0500 Subject: [PATCH 10/46] fix var --- sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index bd2b36a3ca69..d301fddaa8b6 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -627,7 +627,7 @@ def __init__(self, source, auth=None, **kwargs): self._max_message_size = kwargs.pop('max_message_size', None) or MAX_FRAME_SIZE_BYTES self._link_properties = kwargs.pop('link_properties', None) self._link_credit = kwargs.pop('link_credit', 300) - super(ReceiveClient, self).__init__(target, auth=auth, **kwargs) + super(ReceiveClient, self).__init__(source, auth=auth, **kwargs) def _client_ready(self): """Determine whether the client is ready to start receiving messages. From 65c628cb0a54b0608c3793b364c58ff3941e64ce Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Thu, 28 Jul 2022 10:31:34 -0700 Subject: [PATCH 11/46] looking into removing hostname on SDK side -- new branch so not messy --- sdk/eventhub/azure-eventhub/azure/eventhub/_client_base.py | 3 ++- sdk/eventhub/azure-eventhub/azure/eventhub/_consumer.py | 2 +- sdk/eventhub/azure-eventhub/azure/eventhub/_producer.py | 2 +- sdk/eventhub/azure-eventhub/azure/eventhub/_producer_client.py | 1 + sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py | 3 ++- 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_client_base.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_client_base.py index 4fd65f126086..66b5f65c688f 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_client_base.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_client_base.py @@ -374,7 +374,8 @@ def _management_request(self, mgmt_msg, op_type): if custom_endpoint_address: custom_endpoint_address += '/$servicebus/websocket/' mgmt_client = AMQPClient( - hostname, + # Do we want this to be hostname or remote_address + # hostname, auth=mgmt_auth, network_trace=self._config.network_tracing, transport_type=self._config.transport_type, diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_consumer.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_consumer.py index ae20041b4b1e..873f26e1105d 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_consumer.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_consumer.py @@ -159,7 +159,7 @@ def _create_handler(self, auth): custom_endpoint_address += '/$servicebus/websocket/' self._handler = ReceiveClient( - hostname, + # hostname, source, auth=auth, idle_timeout=self._idle_timeout, diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_producer.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_producer.py index 0ebc1f62a548..f76a97c9023d 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_producer.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_producer.py @@ -133,7 +133,7 @@ def _create_handler(self, auth): if custom_endpoint_address: custom_endpoint_address += '/$servicebus/websocket/' self._handler = SendClient( - hostname, + # hostname, self._target, auth=auth, idle_timeout=self._idle_timeout, diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_producer_client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_producer_client.py index 6a6cfb181c1a..254126c3b461 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_producer_client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_producer_client.py @@ -121,6 +121,7 @@ def _get_partitions(self): for p_id in cast(List[str], self._partition_ids): self._producers[p_id] = None + # this is spelled wrong here -- do we change - or were the changes elsewhere def _get_max_mesage_size(self): # type: () -> None # pylint: disable=protected-access,line-too-long diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index d301fddaa8b6..c90d17e588a5 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -124,6 +124,7 @@ class AMQPClient(object): def __init__(self, remote_address, auth=None, client_name=None, debug=False, retry_policy=None, keep_alive_interval=None, **kwargs): + # I think these are just strings not instances of target or source self._remote_address = remote_address.address if (isinstance(remote_address, Source) or isinstance(remote_address, Target)) else remote_address self._auth = auth self._name = client_name if client_name else str(uuid.uuid4()) @@ -239,7 +240,7 @@ def open(self): :param connection: An existing Connection that may be shared between multiple clients. - :type connetion: ~pyamqp.Connection + :type connection: ~pyamqp.Connection """ # pylint: disable=protected-access if self._session: From a7599a4a2e27066a3956db39c13c5d6e72324cf8 Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Thu, 28 Jul 2022 12:45:25 -0700 Subject: [PATCH 12/46] test-fix --- .../tests/pyamqp_tests/unittest/test_exceptions_pyamqp.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_exceptions_pyamqp.py b/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_exceptions_pyamqp.py index 83244e2b23b2..17303720ea82 100644 --- a/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_exceptions_pyamqp.py +++ b/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_exceptions_pyamqp.py @@ -9,10 +9,9 @@ def test_client_creation_exceptions(): with pytest.raises(TypeError): - sender = SendClient( - "fake.host.com", - ) - assert sender._remote_address == "fake.host.com" + sender = SendClient() + # assert sender._remote_address == "fake.host.com" + # We can't test this now b/c the assert would have to be against source and would pass -- maybe remove this test def test_connection_endpoint_exceptions(): with pytest.raises(AMQPConnectionError): From 07dd588e789c9868139a40583f0d17e55cf139dd Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Thu, 28 Jul 2022 14:37:17 -0700 Subject: [PATCH 13/46] switch to kwargs --- .../azure/eventhub/_pyamqp/client.py | 86 +++++++++---------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index c90d17e588a5..cfe5b0010c02 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -60,74 +60,74 @@ class AMQPClient(object): :param remote_address: The AMQP endpoint to connect to. This could be a send target or a receive source. :type remote_address: str, bytes or ~pyamqp.endpoint.Target or ~pyamqp.endpoint.Source - :param auth: Authentication for the connection. This should be one of the following: + :keyword auth: Authentication for the connection. This should be one of the following: - pyamqp.authentication.SASLAnonymous - pyamqp.authentication.SASLPlain - pyamqp.authentication.SASTokenAuth - pyamqp.authentication.JWTTokenAuth If no authentication is supplied, SASLAnnoymous will be used by default. - :type auth: ~pyamqp.authentication - :param client_name: The name for the client, also known as the Container ID. + :paramtype auth: ~pyamqp.authentication + :keyword client_name: The name for the client, also known as the Container ID. If no name is provided, a random GUID will be used. - :type client_name: str or bytes - :param debug: Whether to turn on network trace logs. If `True`, trace logs + :paramtype client_name: str or bytes + :keyword debug: Whether to turn on network trace logs. If `True`, trace logs will be logged at INFO level. Default is `False`. - :type debug: bool - :param retry_policy: A policy for parsing errors on link, connection and message + :paramtype debug: bool + :keyword retry_policy: A policy for parsing errors on link, connection and message disposition to determine whether the error should be retryable. - :type retry_policy: ~pyamqp.error.RetryPolicy - :param keep_alive_interval: If set, a thread will be started to keep the connection + :paramtype retry_policy: ~pyamqp.error.RetryPolicy + :keyword keep_alive_interval: If set, a thread will be started to keep the connection alive during periods of user inactivity. The value will determine how long the thread will sleep (in seconds) between pinging the connection. If 0 or None, no thread will be started. - :type keep_alive_interval: int - :param max_frame_size: Maximum AMQP frame size. Default is 63488 bytes. - :type max_frame_size: int - :param channel_max: Maximum number of Session channels in the Connection. - :type channel_max: int - :param idle_timeout: Timeout in seconds after which the Connection will close + :paramtype keep_alive_interval: int + :keyword max_frame_size: Maximum AMQP frame size. Default is 63488 bytes. + :paramtype max_frame_size: int + :keyword channel_max: Maximum number of Session channels in the Connection. + :paramtype channel_max: int + :keyword idle_timeout: Timeout in seconds after which the Connection will close if there is no further activity. - :type idle_timeout: int - :param auth_timeout: Timeout in seconds for CBS authentication. Otherwise this value will be ignored. + :paramtype idle_timeout: int + :keyword auth_timeout: Timeout in seconds for CBS authentication. Otherwise this value will be ignored. Default value is 60s. - :type auth_timeout: int - :param properties: Connection properties. - :type properties: dict - :param remote_idle_timeout_empty_frame_send_ratio: Ratio of empty frames to + :paramtype auth_timeout: int + :keyword properties: Connection properties. + :paramtype properties: dict + :keyword remote_idle_timeout_empty_frame_send_ratio: Ratio of empty frames to idle time for Connections with no activity. Value must be between 0.0 and 1.0 inclusive. Default is 0.5. - :type remote_idle_timeout_empty_frame_send_ratio: float - :param incoming_window: The size of the allowed window for incoming messages. - :type incoming_window: int - :param outgoing_window: The size of the allowed window for outgoing messages. - :type outgoing_window: int - :param handle_max: The maximum number of concurrent link handles. - :type handle_max: int - :param on_attach: A callback function to be run on receipt of an ATTACH frame. + :paramtype remote_idle_timeout_empty_frame_send_ratio: float + :keyword incoming_window: The size of the allowed window for incoming messages. + :paramtype incoming_window: int + :keyword outgoing_window: The size of the allowed window for outgoing messages. + :paramtype outgoing_window: int + :keyword handle_max: The maximum number of concurrent link handles. + :paramtype handle_max: int + :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. The function must take 4 arguments: source, target, properties and error. - :type on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.error.AMQPConnectionError] - :param send_settle_mode: The mode by which to settle message send + :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.error.AMQPConnectionError] + :keyword send_settle_mode: The mode by which to settle message send operations. If set to `Unsettled`, the client will wait for a confirmation from the service that the message was successfully sent. If set to 'Settled', the client will not wait for confirmation and assume success. - :type send_settle_mode: ~pyamqp.constants.SenderSettleMode - :param receive_settle_mode: The mode by which to settle message receive + :paramtype send_settle_mode: ~pyamqp.constants.SenderSettleMode + :keyword receive_settle_mode: The mode by which to settle message receive operations. If set to `PeekLock`, the receiver will lock a message once received until the client accepts or rejects the message. If set to `ReceiveAndDelete`, the service will assume successful receipt of the message and clear it from the queue. The default is `PeekLock`. - :type receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode - :param encoding: The encoding to use for parameters supplied as strings. + :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode + :keyword encoding: The encoding to use for parameters supplied as strings. Default is 'UTF-8' - :type encoding: str + :paramtype encoding: str """ - def __init__(self, remote_address, auth=None, client_name=None, debug=False, retry_policy=None, - keep_alive_interval=None, **kwargs): +# auth=None, client_name=None, debug=False, retry_policy=None, keep_alive_interval=None, + def __init__(self, remote_address, **kwargs): # I think these are just strings not instances of target or source self._remote_address = remote_address.address if (isinstance(remote_address, Source) or isinstance(remote_address, Target)) else remote_address - self._auth = auth - self._name = client_name if client_name else str(uuid.uuid4()) + self._auth = kwargs.pop("auth", None) + self._name = kwargs.pop("client_name", str(uuid.uuid4())) self._shutdown = False self._connection = None @@ -138,8 +138,8 @@ def __init__(self, remote_address, auth=None, client_name=None, debug=False, ret self._cbs_authenticator = None self._auth_timeout = kwargs.pop("auth_timeout", DEFAULT_AUTH_TIMEOUT) self._mgmt_links = {} - self._retry_policy = retry_policy if retry_policy else RetryPolicy() - self._keep_alive_interval = int(keep_alive_interval) if keep_alive_interval else 0 + self._retry_policy = kwargs.pop("rety_policy", RetryPolicy()) + self._keep_alive_interval = int(kwargs.pop("keep_alive_interval") or 0) # Connection settings self._max_frame_size = kwargs.pop('max_frame_size', None) or MAX_FRAME_SIZE_BYTES @@ -148,7 +148,7 @@ def __init__(self, remote_address, auth=None, client_name=None, debug=False, ret self._properties = kwargs.pop('properties', None) self._remote_idle_timeout_empty_frame_send_ratio = kwargs.pop( 'remote_idle_timeout_empty_frame_send_ratio', None) - self._network_trace = debug + self._network_trace = kwargs.pop("network_trace", False) # Session settings self._outgoing_window = kwargs.pop('outgoing_window', None) or OUTGOING_WIDNOW From ba4b04ddf4d2b16c6d19d5d8c6b6e87dd6197c3c Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Mon, 1 Aug 2022 10:55:01 -0700 Subject: [PATCH 14/46] SendClient had no docstring --- .../azure/eventhub/_pyamqp/client.py | 106 ++++++++++++++++-- 1 file changed, 96 insertions(+), 10 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index cfe5b0010c02..51cbfd751789 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -56,10 +56,9 @@ class AMQPClient(object): """An AMQP client. - - :param remote_address: The AMQP endpoint to connect to. This could be a send target - or a receive source. - :type remote_address: str, bytes or ~pyamqp.endpoint.Target or ~pyamqp.endpoint.Source +# TODO: would it be a target or source? + :param hostname: The AMQP endpoint to connect to. + :type hostname: str, bytes or ~pyamqp.endpoint.Target or ~pyamqp.endpoint.Source :keyword auth: Authentication for the connection. This should be one of the following: - pyamqp.authentication.SASLAnonymous - pyamqp.authentication.SASLPlain @@ -122,10 +121,9 @@ class AMQPClient(object): :paramtype encoding: str """ -# auth=None, client_name=None, debug=False, retry_policy=None, keep_alive_interval=None, - def __init__(self, remote_address, **kwargs): + def __init__(self, hostname, **kwargs): # I think these are just strings not instances of target or source - self._remote_address = remote_address.address if (isinstance(remote_address, Source) or isinstance(remote_address, Target)) else remote_address + self._hostname = hostname self._auth = kwargs.pop("auth", None) self._name = kwargs.pop("client_name", str(uuid.uuid4())) @@ -248,7 +246,7 @@ def open(self): _logger.debug("Opening client connection.") if not self._connection: self._connection = Connection( - "amqps://" + self._remote_address, + "amqps://" + self._hostname, sasl_credential=self._auth.sasl, ssl={'ca_certs':self._connection_verify or certifi.where()}, container_id=self._name, @@ -391,13 +389,99 @@ def mgmt_request(self, message, **kwargs): class SendClient(AMQPClient): - def __init__(self, target, auth=None, **kwargs): + """An AMQP client for sending messages. + + :param hostname: The AMQP endpoint to connect to. + :type hostname: str, bytes or ~pyamqp.endpoint.Target or ~pyamqp.endpoint.Source + :param target: The target AMQP service endpoint. This can either be the URI as + a string or a ~pyamqp.endpoint.Target object. + :type target: str, bytes or ~pyamqp.endpoint.Target + :param auth: Authentication for the connection. This should be one of the subclasses of + pyamqp.authentication.AMQPAuth. Currently this includes: + - pyamqp.authentication.SASLAnonymous + - pyamqp.authentication.SASLPlain + - pyamqp.authentication.SASTokenAuth + If no authentication is supplied, SASLAnnoymous will be used by default. + :type auth: ~pyamqp.authentication.SASLAnonymous or pyamqp.authentication.SASLPlain + or pyamqp.authentication.SASTokenAuth + :param client_name: The name for the client, also known as the Container ID. + If no name is provided, a random GUID will be used. + :type client_name: str or bytes + :param debug: Whether to turn on network trace logs. If `True`, trace logs + will be logged at INFO level. Default is `False`. + :type debug: bool + :param auto_complete: Whether to automatically settle message received via callback + or via iterator. If the message has not been explicitly settled after processing + the message will be accepted. Alternatively, when used with batch receive, this setting + will determine whether the messages are pre-emptively settled during batching, or otherwise + let to the user to be explicitly settled. + :type auto_complete: bool + :param retry_policy: A policy for parsing errors on link, connection and message + disposition to determine whether the error should be retryable. + :type retry_policy: ~pyamqp.errors.RetryPolicy + :param keep_alive_interval: If set, a thread will be started to keep the connection + alive during periods of user inactivity. The value will determine how long the + thread will sleep (in seconds) between pinging the connection. If 0 or None, no + thread will be started. + :type keep_alive_interval: int + :param send_settle_mode: The mode by which to settle message send + operations. If set to `Unsettled`, the client will wait for a confirmation + from the service that the message was successfully sent. If set to 'Settled', + the client will not wait for confirmation and assume success. + :type send_settle_mode: ~pyamqp.constants.SenderSettleMode + :param receive_settle_mode: The mode by which to settle message receive + operations. If set to `PeekLock`, the receiver will lock a message once received until + the client accepts or rejects the message. If set to `ReceiveAndDelete`, the service + will assume successful receipt of the message and clear it from the queue. The + default is `PeekLock`. + :type receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode + :param desired_capabilities: The extension capabilities desired from the peer endpoint. + To create an desired_capabilities object, please do as follows: + - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` + - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` + :type desired_capabilities: ~uamqp.c_uamqp.AMQPValue + :param max_message_size: The maximum allowed message size negotiated for the Link. + :type max_message_size: int + :param link_properties: Metadata to be sent in the Link ATTACH frame. + :type link_properties: dict + :param prefetch: The receiver Link credit that determines how many + messages the Link will attempt to handle per connection iteration. + The default is 300. + :type prefetch: int + :param max_frame_size: Maximum AMQP frame size. Default is 63488 bytes. + :type max_frame_size: int + :param channel_max: Maximum number of Session channels in the Connection. + :type channel_max: int + :param idle_timeout: Timeout in seconds after which the Connection will close + if there is no further activity. + :type idle_timeout: int + :param properties: Connection properties. + :type properties: dict + :param remote_idle_timeout_empty_frame_send_ratio: Ratio of empty frames to + idle time for Connections with no activity. Value must be between + 0.0 and 1.0 inclusive. Default is 0.5. + :type remote_idle_timeout_empty_frame_send_ratio: float + :param incoming_window: The size of the allowed window for incoming messages. + :type incoming_window: int + :param outgoing_window: The size of the allowed window for outgoing messages. + :type outgoing_window: int + :param handle_max: The maximum number of concurrent link handles. + :type handle_max: int + :param on_attach: A callback function to be run on receipt of an ATTACH frame. + The function must take 4 arguments: source, target, properties and error. + :type on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.errors.AMQPConnectionError] + :param encoding: The encoding to use for parameters supplied as strings. + Default is 'UTF-8' + :type encoding: str + """ + + def __init__(self, hostname, target, auth=None, **kwargs): self.target = target # Sender and Link settings self._max_message_size = kwargs.pop('max_message_size', None) or MAX_FRAME_SIZE_BYTES self._link_properties = kwargs.pop('link_properties', None) self._link_credit = kwargs.pop('link_credit', None) - super(SendClient, self).__init__(target, auth=auth, **kwargs) + super(SendClient, self).__init__(hostname, auth=auth, **kwargs) def _client_ready(self): """Determine whether the client is ready to start receiving messages. @@ -536,6 +620,8 @@ def send_message(self, message, **kwargs): class ReceiveClient(AMQPClient): """An AMQP client for receiving messages. + :param hostname: The AMQP endpoint to connect to. + :type hostname: str, bytes or ~pyamqp.endpoint.Target or ~pyamqp.endpoint.Source :param source: The source AMQP service endpoint. This can either be the URI as a string or a ~pyamqp.endpoint.Source object. :type source: str, bytes or ~pyamqp.endpoint.Source From ec307a501f6efcb36f2464dd736fb3cfe6f5e07b Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Mon, 1 Aug 2022 11:24:03 -0700 Subject: [PATCH 15/46] adding back in hostname --- sdk/eventhub/azure-eventhub/azure/eventhub/_client_base.py | 3 +-- sdk/eventhub/azure-eventhub/azure/eventhub/_consumer.py | 2 +- sdk/eventhub/azure-eventhub/azure/eventhub/_producer.py | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_client_base.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_client_base.py index 66b5f65c688f..4fd65f126086 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_client_base.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_client_base.py @@ -374,8 +374,7 @@ def _management_request(self, mgmt_msg, op_type): if custom_endpoint_address: custom_endpoint_address += '/$servicebus/websocket/' mgmt_client = AMQPClient( - # Do we want this to be hostname or remote_address - # hostname, + hostname, auth=mgmt_auth, network_trace=self._config.network_tracing, transport_type=self._config.transport_type, diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_consumer.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_consumer.py index 873f26e1105d..ae20041b4b1e 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_consumer.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_consumer.py @@ -159,7 +159,7 @@ def _create_handler(self, auth): custom_endpoint_address += '/$servicebus/websocket/' self._handler = ReceiveClient( - # hostname, + hostname, source, auth=auth, idle_timeout=self._idle_timeout, diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_producer.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_producer.py index f76a97c9023d..0ebc1f62a548 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_producer.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_producer.py @@ -133,7 +133,7 @@ def _create_handler(self, auth): if custom_endpoint_address: custom_endpoint_address += '/$servicebus/websocket/' self._handler = SendClient( - # hostname, + hostname, self._target, auth=auth, idle_timeout=self._idle_timeout, From 45d958716ce109eb03076add9053058d144ebdb5 Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Mon, 1 Aug 2022 11:28:20 -0700 Subject: [PATCH 16/46] making send client param keyword instead --- .../azure/eventhub/_pyamqp/client.py | 84 +++++++++---------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index 51cbfd751789..84f6fa246414 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -404,75 +404,75 @@ class SendClient(AMQPClient): If no authentication is supplied, SASLAnnoymous will be used by default. :type auth: ~pyamqp.authentication.SASLAnonymous or pyamqp.authentication.SASLPlain or pyamqp.authentication.SASTokenAuth - :param client_name: The name for the client, also known as the Container ID. + :keyword client_name: The name for the client, also known as the Container ID. If no name is provided, a random GUID will be used. - :type client_name: str or bytes - :param debug: Whether to turn on network trace logs. If `True`, trace logs + :paramtype client_name: str or bytes + :keyword debug: Whether to turn on network trace logs. If `True`, trace logs will be logged at INFO level. Default is `False`. - :type debug: bool - :param auto_complete: Whether to automatically settle message received via callback + :paramtype debug: bool + :keyword auto_complete: Whether to automatically settle message received via callback or via iterator. If the message has not been explicitly settled after processing the message will be accepted. Alternatively, when used with batch receive, this setting will determine whether the messages are pre-emptively settled during batching, or otherwise let to the user to be explicitly settled. - :type auto_complete: bool - :param retry_policy: A policy for parsing errors on link, connection and message + :paramtype auto_complete: bool + :keyword retry_policy: A policy for parsing errors on link, connection and message disposition to determine whether the error should be retryable. - :type retry_policy: ~pyamqp.errors.RetryPolicy - :param keep_alive_interval: If set, a thread will be started to keep the connection + :paramtype retry_policy: ~pyamqp.errors.RetryPolicy + :keyword keep_alive_interval: If set, a thread will be started to keep the connection alive during periods of user inactivity. The value will determine how long the thread will sleep (in seconds) between pinging the connection. If 0 or None, no thread will be started. - :type keep_alive_interval: int - :param send_settle_mode: The mode by which to settle message send + :paramtype keep_alive_interval: int + :keyword send_settle_mode: The mode by which to settle message send operations. If set to `Unsettled`, the client will wait for a confirmation from the service that the message was successfully sent. If set to 'Settled', the client will not wait for confirmation and assume success. - :type send_settle_mode: ~pyamqp.constants.SenderSettleMode - :param receive_settle_mode: The mode by which to settle message receive + :paramtype send_settle_mode: ~pyamqp.constants.SenderSettleMode + :keyword receive_settle_mode: The mode by which to settle message receive operations. If set to `PeekLock`, the receiver will lock a message once received until the client accepts or rejects the message. If set to `ReceiveAndDelete`, the service will assume successful receipt of the message and clear it from the queue. The default is `PeekLock`. - :type receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode - :param desired_capabilities: The extension capabilities desired from the peer endpoint. + :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode + :keywprd desired_capabilities: The extension capabilities desired from the peer endpoint. To create an desired_capabilities object, please do as follows: - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` - :type desired_capabilities: ~uamqp.c_uamqp.AMQPValue - :param max_message_size: The maximum allowed message size negotiated for the Link. - :type max_message_size: int - :param link_properties: Metadata to be sent in the Link ATTACH frame. - :type link_properties: dict - :param prefetch: The receiver Link credit that determines how many + :paramtype desired_capabilities: ~uamqp.c_uamqp.AMQPValue + :keyword max_message_size: The maximum allowed message size negotiated for the Link. + :paramtype max_message_size: int + :keyword link_properties: Metadata to be sent in the Link ATTACH frame. + :paramtype link_properties: dict + :keyword prefetch: The receiver Link credit that determines how many messages the Link will attempt to handle per connection iteration. The default is 300. - :type prefetch: int - :param max_frame_size: Maximum AMQP frame size. Default is 63488 bytes. - :type max_frame_size: int - :param channel_max: Maximum number of Session channels in the Connection. - :type channel_max: int - :param idle_timeout: Timeout in seconds after which the Connection will close + :paramtype prefetch: int + :keyword max_frame_size: Maximum AMQP frame size. Default is 63488 bytes. + :paramtype max_frame_size: int + :keyword channel_max: Maximum number of Session channels in the Connection. + :paramtype channel_max: int + :keyword idle_timeout: Timeout in seconds after which the Connection will close if there is no further activity. - :type idle_timeout: int - :param properties: Connection properties. - :type properties: dict - :param remote_idle_timeout_empty_frame_send_ratio: Ratio of empty frames to + :paramtype idle_timeout: int + :keyword properties: Connection properties. + :paramtype properties: dict + :keyword remote_idle_timeout_empty_frame_send_ratio: Ratio of empty frames to idle time for Connections with no activity. Value must be between 0.0 and 1.0 inclusive. Default is 0.5. - :type remote_idle_timeout_empty_frame_send_ratio: float - :param incoming_window: The size of the allowed window for incoming messages. - :type incoming_window: int - :param outgoing_window: The size of the allowed window for outgoing messages. - :type outgoing_window: int - :param handle_max: The maximum number of concurrent link handles. - :type handle_max: int - :param on_attach: A callback function to be run on receipt of an ATTACH frame. + :paramtype remote_idle_timeout_empty_frame_send_ratio: float + :keyword incoming_window: The size of the allowed window for incoming messages. + :paramtype incoming_window: int + :keyword outgoing_window: The size of the allowed window for outgoing messages. + :paramtype outgoing_window: int + :keyword handle_max: The maximum number of concurrent link handles. + :paramtype handle_max: int + :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. The function must take 4 arguments: source, target, properties and error. - :type on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.errors.AMQPConnectionError] - :param encoding: The encoding to use for parameters supplied as strings. + :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.errors.AMQPConnectionError] + :keyword encoding: The encoding to use for parameters supplied as strings. Default is 'UTF-8' - :type encoding: str + :paramtype encoding: str """ def __init__(self, hostname, target, auth=None, **kwargs): From 31a538088a3c2ac422f9d8e54d61f228f2a1b36d Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Mon, 1 Aug 2022 13:04:01 -0700 Subject: [PATCH 17/46] making param to keyword in recieveClient docstring --- .../azure/eventhub/_pyamqp/client.py | 84 +++++++++---------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index 84f6fa246414..cdbfd8270597 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -633,75 +633,75 @@ class ReceiveClient(AMQPClient): If no authentication is supplied, SASLAnnoymous will be used by default. :type auth: ~pyamqp.authentication.SASLAnonymous or pyamqp.authentication.SASLPlain or pyamqp.authentication.SASTokenAuth - :param client_name: The name for the client, also known as the Container ID. + :keyword client_name: The name for the client, also known as the Container ID. If no name is provided, a random GUID will be used. - :type client_name: str or bytes - :param debug: Whether to turn on network trace logs. If `True`, trace logs + :paramtype client_name: str or bytes + :keyword debug: Whether to turn on network trace logs. If `True`, trace logs will be logged at INFO level. Default is `False`. - :type debug: bool - :param auto_complete: Whether to automatically settle message received via callback + :paramtype debug: bool + :keyword auto_complete: Whether to automatically settle message received via callback or via iterator. If the message has not been explicitly settled after processing the message will be accepted. Alternatively, when used with batch receive, this setting will determine whether the messages are pre-emptively settled during batching, or otherwise let to the user to be explicitly settled. - :type auto_complete: bool - :param retry_policy: A policy for parsing errors on link, connection and message + :paramtype auto_complete: bool + :keyword retry_policy: A policy for parsing errors on link, connection and message disposition to determine whether the error should be retryable. - :type retry_policy: ~pyamqp.errors.RetryPolicy - :param keep_alive_interval: If set, a thread will be started to keep the connection + :paramtype retry_policy: ~pyamqp.errors.RetryPolicy + :keyword keep_alive_interval: If set, a thread will be started to keep the connection alive during periods of user inactivity. The value will determine how long the thread will sleep (in seconds) between pinging the connection. If 0 or None, no thread will be started. - :type keep_alive_interval: int - :param send_settle_mode: The mode by which to settle message send + :paramtype keep_alive_interval: int + :keyword send_settle_mode: The mode by which to settle message send operations. If set to `Unsettled`, the client will wait for a confirmation from the service that the message was successfully sent. If set to 'Settled', the client will not wait for confirmation and assume success. - :type send_settle_mode: ~pyamqp.constants.SenderSettleMode - :param receive_settle_mode: The mode by which to settle message receive + :paramtype send_settle_mode: ~pyamqp.constants.SenderSettleMode + :keyword receive_settle_mode: The mode by which to settle message receive operations. If set to `PeekLock`, the receiver will lock a message once received until the client accepts or rejects the message. If set to `ReceiveAndDelete`, the service will assume successful receipt of the message and clear it from the queue. The default is `PeekLock`. - :type receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode - :param desired_capabilities: The extension capabilities desired from the peer endpoint. + :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode + :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. To create an desired_capabilities object, please do as follows: - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` - :type desired_capabilities: ~uamqp.c_uamqp.AMQPValue - :param max_message_size: The maximum allowed message size negotiated for the Link. - :type max_message_size: int - :param link_properties: Metadata to be sent in the Link ATTACH frame. - :type link_properties: dict - :param prefetch: The receiver Link credit that determines how many + :paramtype desired_capabilities: ~uamqp.c_uamqp.AMQPValue + :keyword max_message_size: The maximum allowed message size negotiated for the Link. + :paramtype max_message_size: int + :keyword link_properties: Metadata to be sent in the Link ATTACH frame. + :paramtype link_properties: dict + :keyword prefetch: The receiver Link credit that determines how many messages the Link will attempt to handle per connection iteration. The default is 300. - :type prefetch: int - :param max_frame_size: Maximum AMQP frame size. Default is 63488 bytes. - :type max_frame_size: int - :param channel_max: Maximum number of Session channels in the Connection. - :type channel_max: int - :param idle_timeout: Timeout in seconds after which the Connection will close + :paramtype prefetch: int + :keyword max_frame_size: Maximum AMQP frame size. Default is 63488 bytes. + :paramtype max_frame_size: int + :keyword channel_max: Maximum number of Session channels in the Connection. + :paramtype channel_max: int + :keyword idle_timeout: Timeout in seconds after which the Connection will close if there is no further activity. - :type idle_timeout: int - :param properties: Connection properties. - :type properties: dict - :param remote_idle_timeout_empty_frame_send_ratio: Ratio of empty frames to + :paramtype idle_timeout: int + :keyword properties: Connection properties. + :paramtype properties: dict + :keyword remote_idle_timeout_empty_frame_send_ratio: Ratio of empty frames to idle time for Connections with no activity. Value must be between 0.0 and 1.0 inclusive. Default is 0.5. - :type remote_idle_timeout_empty_frame_send_ratio: float - :param incoming_window: The size of the allowed window for incoming messages. - :type incoming_window: int - :param outgoing_window: The size of the allowed window for outgoing messages. - :type outgoing_window: int - :param handle_max: The maximum number of concurrent link handles. - :type handle_max: int - :param on_attach: A callback function to be run on receipt of an ATTACH frame. + :paramtype remote_idle_timeout_empty_frame_send_ratio: float + :keyword incoming_window: The size of the allowed window for incoming messages. + :paramtype incoming_window: int + :keyword outgoing_window: The size of the allowed window for outgoing messages. + :paramtype outgoing_window: int + :keyword handle_max: The maximum number of concurrent link handles. + :paramtype handle_max: int + :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. The function must take 4 arguments: source, target, properties and error. - :type on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.errors.AMQPConnectionError] - :param encoding: The encoding to use for parameters supplied as strings. + :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.errors.AMQPConnectionError] + :keyword encoding: The encoding to use for parameters supplied as strings. Default is 'UTF-8' - :type encoding: str + :paramtype encoding: str """ def __init__(self, source, auth=None, **kwargs): From 293da9d05a479fc308fd74015106a387228c5eec Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Mon, 1 Aug 2022 13:10:14 -0700 Subject: [PATCH 18/46] final uamqp docstring comments - need advice --- sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index cdbfd8270597..1e90fa8de521 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -440,6 +440,7 @@ class SendClient(AMQPClient): - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` :paramtype desired_capabilities: ~uamqp.c_uamqp.AMQPValue +# TODO: is this used by pyamqp? -- desired capabilities :keyword max_message_size: The maximum allowed message size negotiated for the Link. :paramtype max_message_size: int :keyword link_properties: Metadata to be sent in the Link ATTACH frame. @@ -490,6 +491,7 @@ def _client_ready(self): states. :rtype: bool +# TODO: MessageHandlerError in uamqp - do we have an equivalent in pyamqp yet, rn it is commented out - we don't raise anything :raises: ~uamqp.errors.MessageHandlerError if the MessageReceiver goes into an error state. """ @@ -669,6 +671,7 @@ class ReceiveClient(AMQPClient): - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` :paramtype desired_capabilities: ~uamqp.c_uamqp.AMQPValue +# TODO: same thing here - do we use desired capabilities / what would it become :keyword max_message_size: The maximum allowed message size negotiated for the Link. :paramtype max_message_size: int :keyword link_properties: Metadata to be sent in the Link ATTACH frame. @@ -723,6 +726,7 @@ def _client_ready(self): states. :rtype: bool +# TODO: uamqp error handling error here - do we want to raise anything or should this be something else :raises: ~uamqp.errors.MessageHandlerError if the MessageReceiver goes into an error state. """ From f1f2f1b55d0cc0008fc1360679c5b98c02c8306c Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Mon, 1 Aug 2022 13:41:22 -0700 Subject: [PATCH 19/46] renaming mesage to message --- .../azure-eventhub/azure/eventhub/_producer_client.py | 4 ++-- .../azure/eventhub/aio/_producer_client_async.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_producer_client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_producer_client.py index 254126c3b461..b994b41af869 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_producer_client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_producer_client.py @@ -122,7 +122,7 @@ def _get_partitions(self): self._producers[p_id] = None # this is spelled wrong here -- do we change - or were the changes elsewhere - def _get_max_mesage_size(self): + def _get_max_message_size(self): # type: () -> None # pylint: disable=protected-access,line-too-long with self._lock: @@ -348,7 +348,7 @@ def create_batch(self, **kwargs): """ if not self._max_message_size_on_link: - self._get_max_mesage_size() + self._get_max_message_size() max_size_in_bytes = kwargs.get("max_size_in_bytes", None) partition_id = kwargs.get("partition_id", None) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/aio/_producer_client_async.py b/sdk/eventhub/azure-eventhub/azure/eventhub/aio/_producer_client_async.py index ee421c3ca4f2..9868d114b79f 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/aio/_producer_client_async.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/aio/_producer_client_async.py @@ -121,7 +121,7 @@ async def _get_partitions(self) -> None: for p_id in cast(List[str], self._partition_ids): self._producers[p_id] = None - async def _get_max_mesage_size(self) -> None: + async def _get_max_message_size(self) -> None: # pylint: disable=protected-access,line-too-long async with self._lock: if not self._max_message_size_on_link: @@ -378,7 +378,7 @@ async def create_batch( """ if not self._max_message_size_on_link: - await self._get_max_mesage_size() + await self._get_max_message_size() if max_size_in_bytes and max_size_in_bytes > self._max_message_size_on_link: raise ValueError( From 03bf52cbd0cbb8f4793ef015b494b0676c0e24fc Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Mon, 1 Aug 2022 13:44:01 -0700 Subject: [PATCH 20/46] removing comment about typo --- sdk/eventhub/azure-eventhub/azure/eventhub/_producer_client.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_producer_client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_producer_client.py index b994b41af869..495449e38510 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_producer_client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_producer_client.py @@ -121,7 +121,6 @@ def _get_partitions(self): for p_id in cast(List[str], self._partition_ids): self._producers[p_id] = None - # this is spelled wrong here -- do we change - or were the changes elsewhere def _get_max_message_size(self): # type: () -> None # pylint: disable=protected-access,line-too-long From 00b181529ea53982a1ab56fcd0e59b7a1d0f2899 Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Mon, 1 Aug 2022 14:25:11 -0700 Subject: [PATCH 21/46] hostname type string --- sdk/eventhub/azure-eventhub/azure/eventhub/_producer.py | 1 + .../azure-eventhub/azure/eventhub/_pyamqp/client.py | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_producer.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_producer.py index 0ebc1f62a548..f5a5cac24ea1 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_producer.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_producer.py @@ -128,6 +128,7 @@ def _create_handler(self, auth): transport_type = self._client._config.transport_type # pylint:disable=protected-access custom_endpoint_address = self._client._config.custom_endpoint_address # pylint: disable=protected-access hostname = self._client._address.hostname # pylint: disable=protected-access + print(type(hostname)) if transport_type.name == 'AmqpOverWebsocket': hostname += '/$servicebus/websocket/' if custom_endpoint_address: diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index 1e90fa8de521..69ffa4e633b3 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -58,7 +58,7 @@ class AMQPClient(object): """An AMQP client. # TODO: would it be a target or source? :param hostname: The AMQP endpoint to connect to. - :type hostname: str, bytes or ~pyamqp.endpoint.Target or ~pyamqp.endpoint.Source + :type hostname: str :keyword auth: Authentication for the connection. This should be one of the following: - pyamqp.authentication.SASLAnonymous - pyamqp.authentication.SASLPlain @@ -137,7 +137,7 @@ def __init__(self, hostname, **kwargs): self._auth_timeout = kwargs.pop("auth_timeout", DEFAULT_AUTH_TIMEOUT) self._mgmt_links = {} self._retry_policy = kwargs.pop("rety_policy", RetryPolicy()) - self._keep_alive_interval = int(kwargs.pop("keep_alive_interval") or 0) + self._keep_alive_interval = int(kwargs.pop("keep_alive_interval", None) or 0) # Connection settings self._max_frame_size = kwargs.pop('max_frame_size', None) or MAX_FRAME_SIZE_BYTES @@ -392,7 +392,7 @@ class SendClient(AMQPClient): """An AMQP client for sending messages. :param hostname: The AMQP endpoint to connect to. - :type hostname: str, bytes or ~pyamqp.endpoint.Target or ~pyamqp.endpoint.Source + :type hostname: str :param target: The target AMQP service endpoint. This can either be the URI as a string or a ~pyamqp.endpoint.Target object. :type target: str, bytes or ~pyamqp.endpoint.Target @@ -623,7 +623,7 @@ class ReceiveClient(AMQPClient): """An AMQP client for receiving messages. :param hostname: The AMQP endpoint to connect to. - :type hostname: str, bytes or ~pyamqp.endpoint.Target or ~pyamqp.endpoint.Source + :type hostname: str :param source: The source AMQP service endpoint. This can either be the URI as a string or a ~pyamqp.endpoint.Source object. :type source: str, bytes or ~pyamqp.endpoint.Source From f498d101ad3888f13bb44f59ce208b4bd75b4e14 Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Thu, 18 Aug 2022 09:46:35 -0700 Subject: [PATCH 22/46] fixing tests --- .../unittest/test_client_creation_pyamqp.py | 2 ++ .../pyamqp_tests/unittest/test_exceptions_pyamqp.py | 11 ++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_client_creation_pyamqp.py b/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_client_creation_pyamqp.py index b49a240fd532..b0541f11a080 100644 --- a/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_client_creation_pyamqp.py +++ b/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_client_creation_pyamqp.py @@ -9,6 +9,7 @@ def test_send_client_creation(): sender = SendClient( + "fake.host.com", "fake_eh", "my_fake_auth" ) @@ -19,6 +20,7 @@ def test_send_client_creation(): def test_receive_client_creation(): receiver = ReceiveClient( + "fake.host.com", "fake_eh", "my_fake_auth" ) diff --git a/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_exceptions_pyamqp.py b/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_exceptions_pyamqp.py index 17303720ea82..d45f13147d22 100644 --- a/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_exceptions_pyamqp.py +++ b/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_exceptions_pyamqp.py @@ -9,9 +9,10 @@ def test_client_creation_exceptions(): with pytest.raises(TypeError): - sender = SendClient() - # assert sender._remote_address == "fake.host.com" - # We can't test this now b/c the assert would have to be against source and would pass -- maybe remove this test + sender = SendClient( + "fake.host.com", + ) + assert sender._hostname == "fake.host.com" def test_connection_endpoint_exceptions(): with pytest.raises(AMQPConnectionError): @@ -33,7 +34,7 @@ def test_connection_sas_authentication_exception(): password="" ) with pytest.raises(AttributeError): - sender = SendClient(target, auth=sas_auth) + sender = SendClient("fake.host.com", target, auth=sas_auth) sender.client_ready() def test_connection_sasl_annon_authentication_exception(): @@ -44,5 +45,5 @@ def test_connection_sasl_annon_authentication_exception(): sas_auth = authentication.SASLAnonymousCredential() with pytest.raises(AttributeError): - sender = SendClient(target, auth=sas_auth) + sender = SendClient("fake.host.com", target, auth=sas_auth) sender.client_ready() From 3a43101302e20653a1b7751f275f9cdb12dd4374 Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Thu, 18 Aug 2022 09:47:47 -0700 Subject: [PATCH 23/46] removing print --- sdk/eventhub/azure-eventhub/azure/eventhub/_producer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_producer.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_producer.py index f5a5cac24ea1..0ebc1f62a548 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_producer.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_producer.py @@ -128,7 +128,6 @@ def _create_handler(self, auth): transport_type = self._client._config.transport_type # pylint:disable=protected-access custom_endpoint_address = self._client._config.custom_endpoint_address # pylint: disable=protected-access hostname = self._client._address.hostname # pylint: disable=protected-access - print(type(hostname)) if transport_type.name == 'AmqpOverWebsocket': hostname += '/$servicebus/websocket/' if custom_endpoint_address: From 306e0978263dc742e60ce4338fcd5dacb94bd67c Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Thu, 18 Aug 2022 10:30:57 -0700 Subject: [PATCH 24/46] adding hostname --- sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index 69ffa4e633b3..fa71be620b1d 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -707,7 +707,7 @@ class ReceiveClient(AMQPClient): :paramtype encoding: str """ - def __init__(self, source, auth=None, **kwargs): + def __init__(self, hostname, source, auth=None, **kwargs): self.source = source self._streaming_receive = kwargs.pop("streaming_receive", False) # TODO: whether public? self._received_messages = queue.Queue() @@ -717,7 +717,7 @@ def __init__(self, source, auth=None, **kwargs): self._max_message_size = kwargs.pop('max_message_size', None) or MAX_FRAME_SIZE_BYTES self._link_properties = kwargs.pop('link_properties', None) self._link_credit = kwargs.pop('link_credit', 300) - super(ReceiveClient, self).__init__(source, auth=auth, **kwargs) + super(ReceiveClient, self).__init__(hostname, auth=auth, **kwargs) def _client_ready(self): """Determine whether the client is ready to start receiving messages. From 1dad77dd904e658ff151a84f42e4b15045e0c23c Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Mon, 22 Aug 2022 11:10:11 -0700 Subject: [PATCH 25/46] retry spelled wrong --- sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index 90c968b50920..e181a322e4bf 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -136,7 +136,7 @@ def __init__(self, hostname, **kwargs): self._cbs_authenticator = None self._auth_timeout = kwargs.pop("auth_timeout", DEFAULT_AUTH_TIMEOUT) self._mgmt_links = {} - self._retry_policy = kwargs.pop("rety_policy", RetryPolicy()) + self._retry_policy = kwargs.pop("retry_policy", RetryPolicy()) self._keep_alive_interval = int(kwargs.pop("keep_alive_interval", None) or 0) # Connection settings From f687953c3a6cfeb7bdf8fc4f94bb7fa0d29a5827 Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Thu, 25 Aug 2022 15:00:41 -0700 Subject: [PATCH 26/46] git conflict --- sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index 0c3b82086c24..55296700a7d5 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -247,6 +247,7 @@ def open(self, connection=None): :param connection: An existing Connection that may be shared between multiple clients. :type connection: ~pyamqp.Connection + """ # pylint: disable=protected-access if self._session: From 44c42796dc6dc2d8d30941948db147597cc749c9 Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Thu, 25 Aug 2022 15:04:28 -0700 Subject: [PATCH 27/46] removing some todos --- sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index 55296700a7d5..a413d29b47c7 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -66,7 +66,6 @@ class AMQPClient(object): """An AMQP client. -# TODO: would it be a target or source? :param hostname: The AMQP endpoint to connect to. :type hostname: str :keyword auth: Authentication for the connection. This should be one of the following: @@ -451,7 +450,6 @@ class SendClient(AMQPClient): - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` :paramtype desired_capabilities: ~uamqp.c_uamqp.AMQPValue -# TODO: is this used by pyamqp? -- desired capabilities :keyword max_message_size: The maximum allowed message size negotiated for the Link. :paramtype max_message_size: int :keyword link_properties: Metadata to be sent in the Link ATTACH frame. @@ -731,7 +729,7 @@ def _client_ready(self): states. :rtype: bool -# TODO: uamqp error handling error here - do we want to raise anything or should this be something else + # TODO: uamqp error handling error here - do we want to raise anything or should this be something else :raises: ~uamqp.errors.MessageHandlerError if the MessageReceiver goes into an error state. """ From 50211ef8ed392276f0887b8d776378652222604d Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Thu, 25 Aug 2022 15:05:59 -0700 Subject: [PATCH 28/46] async --- .../eventhub/_pyamqp/aio/_client_async.py | 88 +++++++++---------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py index 43e649bd6824..7c0d26e59d5c 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py @@ -54,69 +54,69 @@ class AMQPClientAsync(AMQPClientSync): """An asynchronous AMQP client. - - :param remote_address: The AMQP endpoint to connect to. This could be a send target - or a receive source. - :type remote_address: str, bytes or ~uamqp.address.Address - :param auth: Authentication for the connection. This should be one of the subclasses of - uamqp.authentication.AMQPAuth. Currently this includes: - - uamqp.authentication.SASLAnonymous - - uamqp.authentication.SASLPlain - - uamqp.authentication.SASTokenAsync + + :param hostname: The AMQP endpoint to connect to. + :type hostname: str + :keyword auth: Authentication for the connection. This should be one of the following: + - pyamqp.authentication.SASLAnonymous + - pyamqp.authentication.SASLPlain + - pyamqp.authentication.SASTokenAuth + - pyamqp.authentication.JWTTokenAuth If no authentication is supplied, SASLAnnoymous will be used by default. - :type auth: ~uamqp.authentication.common.AMQPAuth - :param client_name: The name for the client, also known as the Container ID. + :paramtype auth: ~pyamqp.authentication + :keyword client_name: The name for the client, also known as the Container ID. If no name is provided, a random GUID will be used. - :type client_name: str or bytes - :param loop: A user specified event loop. - :type loop: ~asycnio.AbstractEventLoop - :param debug: Whether to turn on network trace logs. If `True`, trace logs + :paramtype client_name: str or bytes + :keyword debug: Whether to turn on network trace logs. If `True`, trace logs will be logged at INFO level. Default is `False`. - :type debug: bool - :param error_policy: A policy for parsing errors on link, connection and message + :paramtype debug: bool + :keyword retry_policy: A policy for parsing errors on link, connection and message disposition to determine whether the error should be retryable. - :type error_policy: ~uamqp.errors.ErrorPolicy - :param keep_alive_interval: If set, a thread will be started to keep the connection + :paramtype retry_policy: ~pyamqp.error.RetryPolicy + :keyword keep_alive_interval: If set, a thread will be started to keep the connection alive during periods of user inactivity. The value will determine how long the thread will sleep (in seconds) between pinging the connection. If 0 or None, no thread will be started. - :type keep_alive_interval: int - :param max_frame_size: Maximum AMQP frame size. Default is 63488 bytes. - :type max_frame_size: int - :param channel_max: Maximum number of Session channels in the Connection. - :type channel_max: int - :param idle_timeout: Timeout in seconds after which the Connection will close + :paramtype keep_alive_interval: int + :keyword max_frame_size: Maximum AMQP frame size. Default is 63488 bytes. + :paramtype max_frame_size: int + :keyword channel_max: Maximum number of Session channels in the Connection. + :paramtype channel_max: int + :keyword idle_timeout: Timeout in seconds after which the Connection will close if there is no further activity. - :type idle_timeout: int - :param properties: Connection properties. - :type properties: dict - :param remote_idle_timeout_empty_frame_send_ratio: Ratio of empty frames to + :paramtype idle_timeout: int + :keyword auth_timeout: Timeout in seconds for CBS authentication. Otherwise this value will be ignored. + Default value is 60s. + :paramtype auth_timeout: int + :keyword properties: Connection properties. + :paramtype properties: dict + :keyword remote_idle_timeout_empty_frame_send_ratio: Ratio of empty frames to idle time for Connections with no activity. Value must be between 0.0 and 1.0 inclusive. Default is 0.5. - :type remote_idle_timeout_empty_frame_send_ratio: float - :param incoming_window: The size of the allowed window for incoming messages. - :type incoming_window: int - :param outgoing_window: The size of the allowed window for outgoing messages. - :type outgoing_window: int - :param handle_max: The maximum number of concurrent link handles. - :type handle_max: int - :param on_attach: A callback function to be run on receipt of an ATTACH frame. + :paramtype remote_idle_timeout_empty_frame_send_ratio: float + :keyword incoming_window: The size of the allowed window for incoming messages. + :paramtype incoming_window: int + :keyword outgoing_window: The size of the allowed window for outgoing messages. + :paramtype outgoing_window: int + :keyword handle_max: The maximum number of concurrent link handles. + :paramtype handle_max: int + :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. The function must take 4 arguments: source, target, properties and error. - :type on_attach: func[~uamqp.address.Source, ~uamqp.address.Target, dict, ~uamqp.errors.AMQPConnectionError] - :param send_settle_mode: The mode by which to settle message send + :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.error.AMQPConnectionError] + :keyword send_settle_mode: The mode by which to settle message send operations. If set to `Unsettled`, the client will wait for a confirmation from the service that the message was successfully sent. If set to 'Settled', the client will not wait for confirmation and assume success. - :type send_settle_mode: ~uamqp.constants.SenderSettleMode - :param receive_settle_mode: The mode by which to settle message receive + :paramtype send_settle_mode: ~pyamqp.constants.SenderSettleMode + :keyword receive_settle_mode: The mode by which to settle message receive operations. If set to `PeekLock`, the receiver will lock a message once received until the client accepts or rejects the message. If set to `ReceiveAndDelete`, the service will assume successful receipt of the message and clear it from the queue. The default is `PeekLock`. - :type receive_settle_mode: ~uamqp.constants.ReceiverSettleMode - :param encoding: The encoding to use for parameters supplied as strings. + :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode + :keyword encoding: The encoding to use for parameters supplied as strings. Default is 'UTF-8' - :type encoding: str + :paramtype encoding: str """ async def __aenter__(self): From 266dd2feb2f995a2149d527e09427fdceb22717e Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Thu, 25 Aug 2022 15:11:32 -0700 Subject: [PATCH 29/46] syncing together docs --- .../eventhub/_pyamqp/aio/_client_async.py | 198 +++++++++++++----- .../azure/eventhub/_pyamqp/client.py | 1 - 2 files changed, 140 insertions(+), 59 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py index 7c0d26e59d5c..f2e5fc2bb325 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py @@ -54,7 +54,7 @@ class AMQPClientAsync(AMQPClientSync): """An asynchronous AMQP client. - + :param hostname: The AMQP endpoint to connect to. :type hostname: str :keyword auth: Authentication for the connection. This should be one of the following: @@ -333,6 +333,91 @@ async def mgmt_request_async(self, message, **kwargs): class SendClientAsync(SendClientSync, AMQPClientAsync): + """An AMQP client for sending messages asynchronously. + + :param hostname: The AMQP endpoint to connect to. + :type hostname: str + :param target: The target AMQP service endpoint. This can either be the URI as + a string or a ~pyamqp.endpoint.Target object. + :type target: str, bytes or ~pyamqp.endpoint.Target + :param auth: Authentication for the connection. This should be one of the subclasses of + pyamqp.authentication.AMQPAuth. Currently this includes: + - pyamqp.authentication.SASLAnonymous + - pyamqp.authentication.SASLPlain + - pyamqp.authentication.SASTokenAuth + If no authentication is supplied, SASLAnnoymous will be used by default. + :type auth: ~pyamqp.authentication.SASLAnonymous or pyamqp.authentication.SASLPlain + or pyamqp.authentication.SASTokenAuth + :keyword client_name: The name for the client, also known as the Container ID. + If no name is provided, a random GUID will be used. + :paramtype client_name: str or bytes + :keyword debug: Whether to turn on network trace logs. If `True`, trace logs + will be logged at INFO level. Default is `False`. + :paramtype debug: bool + :keyword auto_complete: Whether to automatically settle message received via callback + or via iterator. If the message has not been explicitly settled after processing + the message will be accepted. Alternatively, when used with batch receive, this setting + will determine whether the messages are pre-emptively settled during batching, or otherwise + let to the user to be explicitly settled. + :paramtype auto_complete: bool + :keyword retry_policy: A policy for parsing errors on link, connection and message + disposition to determine whether the error should be retryable. + :paramtype retry_policy: ~pyamqp.errors.RetryPolicy + :keyword keep_alive_interval: If set, a thread will be started to keep the connection + alive during periods of user inactivity. The value will determine how long the + thread will sleep (in seconds) between pinging the connection. If 0 or None, no + thread will be started. + :paramtype keep_alive_interval: int + :keyword send_settle_mode: The mode by which to settle message send + operations. If set to `Unsettled`, the client will wait for a confirmation + from the service that the message was successfully sent. If set to 'Settled', + the client will not wait for confirmation and assume success. + :paramtype send_settle_mode: ~pyamqp.constants.SenderSettleMode + :keyword receive_settle_mode: The mode by which to settle message receive + operations. If set to `PeekLock`, the receiver will lock a message once received until + the client accepts or rejects the message. If set to `ReceiveAndDelete`, the service + will assume successful receipt of the message and clear it from the queue. The + default is `PeekLock`. + :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode + :keywprd desired_capabilities: The extension capabilities desired from the peer endpoint. + To create an desired_capabilities object, please do as follows: + - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` + - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` + :paramtype desired_capabilities: ~uamqp.c_uamqp.AMQPValue + :keyword max_message_size: The maximum allowed message size negotiated for the Link. + :paramtype max_message_size: int + :keyword link_properties: Metadata to be sent in the Link ATTACH frame. + :paramtype link_properties: dict + :keyword prefetch: The receiver Link credit that determines how many + messages the Link will attempt to handle per connection iteration. + The default is 300. + :paramtype prefetch: int + :keyword max_frame_size: Maximum AMQP frame size. Default is 63488 bytes. + :paramtype max_frame_size: int + :keyword channel_max: Maximum number of Session channels in the Connection. + :paramtype channel_max: int + :keyword idle_timeout: Timeout in seconds after which the Connection will close + if there is no further activity. + :paramtype idle_timeout: int + :keyword properties: Connection properties. + :paramtype properties: dict + :keyword remote_idle_timeout_empty_frame_send_ratio: Ratio of empty frames to + idle time for Connections with no activity. Value must be between + 0.0 and 1.0 inclusive. Default is 0.5. + :paramtype remote_idle_timeout_empty_frame_send_ratio: float + :keyword incoming_window: The size of the allowed window for incoming messages. + :paramtype incoming_window: int + :keyword outgoing_window: The size of the allowed window for outgoing messages. + :paramtype outgoing_window: int + :keyword handle_max: The maximum number of concurrent link handles. + :paramtype handle_max: int + :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. + The function must take 4 arguments: source, target, properties and error. + :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.errors.AMQPConnectionError] + :keyword encoding: The encoding to use for parameters supplied as strings. + Default is 'UTF-8' + :paramtype encoding: str + """ async def _client_ready_async(self): """Determine whether the client is ready to start receiving messages. @@ -457,93 +542,90 @@ async def send_message_async(self, message, **kwargs): class ReceiveClientAsync(ReceiveClientSync, AMQPClientAsync): - """An AMQP client for receiving messages asynchronously. + """An AMQP client for receiving messages. - :param target: The source AMQP service endpoint. This can either be the URI as - a string or a ~uamqp.address.Source object. - :type target: str, bytes or ~uamqp.address.Source + :param hostname: The AMQP endpoint to connect to. + :type hostname: str + :param source: The source AMQP service endpoint. This can either be the URI as + a string or a ~pyamqp.endpoint.Source object. + :type source: str, bytes or ~pyamqp.endpoint.Source :param auth: Authentication for the connection. This should be one of the subclasses of - uamqp.authentication.AMQPAuth. Currently this includes: - - uamqp.authentication.SASLAnonymous - - uamqp.authentication.SASLPlain - - uamqp.authentication.SASTokenAsync + pyamqp.authentication.AMQPAuth. Currently this includes: + - pyamqp.authentication.SASLAnonymous + - pyamqp.authentication.SASLPlain + - pyamqp.authentication.SASTokenAuth If no authentication is supplied, SASLAnnoymous will be used by default. - :type auth: ~uamqp.authentication.common.AMQPAuth - :param client_name: The name for the client, also known as the Container ID. + :type auth: ~pyamqp.authentication.SASLAnonymous or pyamqp.authentication.SASLPlain + or pyamqp.authentication.SASTokenAuth + :keyword client_name: The name for the client, also known as the Container ID. If no name is provided, a random GUID will be used. - :type client_name: str or bytes - :param loop: A user specified event loop. - :type loop: ~asycnio.AbstractEventLoop - :param debug: Whether to turn on network trace logs. If `True`, trace logs + :paramtype client_name: str or bytes + :keyword debug: Whether to turn on network trace logs. If `True`, trace logs will be logged at INFO level. Default is `False`. - :type debug: bool - :param timeout: A timeout in seconds. The receiver will shut down if no - new messages are received after the specified timeout. If set to 0, the receiver - will never timeout and will continue to listen. The default is 0. - :type timeout: float - :param auto_complete: Whether to automatically settle message received via callback + :paramtype debug: bool + :keyword auto_complete: Whether to automatically settle message received via callback or via iterator. If the message has not been explicitly settled after processing the message will be accepted. Alternatively, when used with batch receive, this setting will determine whether the messages are pre-emptively settled during batching, or otherwise let to the user to be explicitly settled. - :type auto_complete: bool - :param error_policy: A policy for parsing errors on link, connection and message + :paramtype auto_complete: bool + :keyword retry_policy: A policy for parsing errors on link, connection and message disposition to determine whether the error should be retryable. - :type error_policy: ~uamqp.errors.ErrorPolicy - :param keep_alive_interval: If set, a thread will be started to keep the connection + :paramtype retry_policy: ~pyamqp.errors.RetryPolicy + :keyword keep_alive_interval: If set, a thread will be started to keep the connection alive during periods of user inactivity. The value will determine how long the thread will sleep (in seconds) between pinging the connection. If 0 or None, no thread will be started. - :type keep_alive_interval: int - :param send_settle_mode: The mode by which to settle message send + :paramtype keep_alive_interval: int + :keyword send_settle_mode: The mode by which to settle message send operations. If set to `Unsettled`, the client will wait for a confirmation from the service that the message was successfully sent. If set to 'Settled', the client will not wait for confirmation and assume success. - :type send_settle_mode: ~uamqp.constants.SenderSettleMode - :param receive_settle_mode: The mode by which to settle message receive + :paramtype send_settle_mode: ~pyamqp.constants.SenderSettleMode + :keyword receive_settle_mode: The mode by which to settle message receive operations. If set to `PeekLock`, the receiver will lock a message once received until the client accepts or rejects the message. If set to `ReceiveAndDelete`, the service will assume successful receipt of the message and clear it from the queue. The default is `PeekLock`. - :type receive_settle_mode: ~uamqp.constants.ReceiverSettleMode - :param desired_capabilities: The extension capabilities desired from the peer endpoint. + :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode + :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. To create an desired_capabilities object, please do as follows: - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` - :type desired_capabilities: ~uamqp.c_uamqp.AMQPValue - :param max_message_size: The maximum allowed message size negotiated for the Link. - :type max_message_size: int - :param link_properties: Metadata to be sent in the Link ATTACH frame. - :type link_properties: dict - :param prefetch: The receiver Link credit that determines how many + :paramtype desired_capabilities: ~uamqp.c_uamqp.AMQPValue + :keyword max_message_size: The maximum allowed message size negotiated for the Link. + :paramtype max_message_size: int + :keyword link_properties: Metadata to be sent in the Link ATTACH frame. + :paramtype link_properties: dict + :keyword prefetch: The receiver Link credit that determines how many messages the Link will attempt to handle per connection iteration. The default is 300. - :type prefetch: int - :param max_frame_size: Maximum AMQP frame size. Default is 63488 bytes. - :type max_frame_size: int - :param channel_max: Maximum number of Session channels in the Connection. - :type channel_max: int - :param idle_timeout: Timeout in seconds after which the Connection will close + :paramtype prefetch: int + :keyword max_frame_size: Maximum AMQP frame size. Default is 63488 bytes. + :paramtype max_frame_size: int + :keyword channel_max: Maximum number of Session channels in the Connection. + :paramtype channel_max: int + :keyword idle_timeout: Timeout in seconds after which the Connection will close if there is no further activity. - :type idle_timeout: int - :param properties: Connection properties. - :type properties: dict - :param remote_idle_timeout_empty_frame_send_ratio: Ratio of empty frames to + :paramtype idle_timeout: int + :keyword properties: Connection properties. + :paramtype properties: dict + :keyword remote_idle_timeout_empty_frame_send_ratio: Ratio of empty frames to idle time for Connections with no activity. Value must be between 0.0 and 1.0 inclusive. Default is 0.5. - :type remote_idle_timeout_empty_frame_send_ratio: float - :param incoming_window: The size of the allowed window for incoming messages. - :type incoming_window: int - :param outgoing_window: The size of the allowed window for outgoing messages. - :type outgoing_window: int - :param handle_max: The maximum number of concurrent link handles. - :type handle_max: int - :param on_attach: A callback function to be run on receipt of an ATTACH frame. + :paramtype remote_idle_timeout_empty_frame_send_ratio: float + :keyword incoming_window: The size of the allowed window for incoming messages. + :paramtype incoming_window: int + :keyword outgoing_window: The size of the allowed window for outgoing messages. + :paramtype outgoing_window: int + :keyword handle_max: The maximum number of concurrent link handles. + :paramtype handle_max: int + :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. The function must take 4 arguments: source, target, properties and error. - :type on_attach: func[~uamqp.address.Source, ~uamqp.address.Target, dict, ~uamqp.errors.AMQPConnectionError] - :param encoding: The encoding to use for parameters supplied as strings. + :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.errors.AMQPConnectionError] + :keyword encoding: The encoding to use for parameters supplied as strings. Default is 'UTF-8' - :type encoding: str + :paramtype encoding: str """ async def _client_ready_async(self): diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index a413d29b47c7..5d569c5c9056 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -674,7 +674,6 @@ class ReceiveClient(AMQPClient): - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` :paramtype desired_capabilities: ~uamqp.c_uamqp.AMQPValue -# TODO: same thing here - do we use desired capabilities / what would it become :keyword max_message_size: The maximum allowed message size negotiated for the Link. :paramtype max_message_size: int :keyword link_properties: Metadata to be sent in the Link ATTACH frame. From d97ff8ad4f740180f2cf60c4c3f3d5fe9fe4212e Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Fri, 26 Aug 2022 08:45:27 -0700 Subject: [PATCH 30/46] adding in InternalError on client_ready() --- .../eventhub/_pyamqp/aio/_client_async.py | 22 +++++++++++++++--- .../azure/eventhub/_pyamqp/client.py | 23 +++++++++++++++---- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py index f2e5fc2bb325..15e64f982235 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py @@ -426,7 +426,7 @@ async def _client_ready_async(self): states. :rtype: bool - :raises: ~uamqp.errors.MessageHandlerError if the MessageReceiver + :raises: ~pyamqp.error.InternalError if the MessageReceiver goes into an error state. """ # pylint: disable=protected-access @@ -441,6 +441,14 @@ async def _client_ready_async(self): await self._link.attach() return False if self._link.get_state() != LinkState.ATTACHED: # ATTACHED + if self._link.get_state().value == 6: + raise ErrorCondition.InternalError( + "The receiver link is in an error state. " + "Please confirm credentials and access permissions." + "\nSee debug trace for more details." + ) + # TODO: MessageHandlerError in uamqp - do we have an equivalent in pyamqp yet, rn it is commented out - we don't raise anything + # Fix docstring raises needed too return False return True @@ -635,7 +643,7 @@ async def _client_ready_async(self): states. :rtype: bool - :raises: ~uamqp.errors.MessageHandlerError if the MessageReceiver + :raises: ~pyamqp.error.InternalError if the MessageReceiver goes into an error state. """ # pylint: disable=protected-access @@ -653,7 +661,15 @@ async def _client_ready_async(self): ) await self._link.attach() return False - if self._link.get_state() != LinkState.ATTACHED: # ATTACHED + if self._link.get_state().value != 3: # ATTACHED + if self._link.get_state().value == 6: + raise ErrorCondition.InternalError( + "The receiver link is in an error state. " + "Please confirm credentials and access permissions." + "\nSee debug trace for more details." + ) + # TODO: MessageHandlerError in uamqp - do we have an equivalent in pyamqp yet, rn it is commented out - we don't raise anything + # Fix docstring raises needed too return False return True diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index 5d569c5c9056..b2803fda4b84 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -7,6 +7,7 @@ # pylint: disable=too-many-lines import logging +from msilib.schema import Error import time import uuid import certifi @@ -500,8 +501,7 @@ def _client_ready(self): states. :rtype: bool -# TODO: MessageHandlerError in uamqp - do we have an equivalent in pyamqp yet, rn it is commented out - we don't raise anything - :raises: ~uamqp.errors.MessageHandlerError if the MessageReceiver + :raises: ~pyamqp.error.InternalError if the MessageReceiver goes into an error state. """ # pylint: disable=protected-access @@ -516,6 +516,14 @@ def _client_ready(self): self._link.attach() return False if self._link.get_state().value != 3: # ATTACHED + if self._link.get_state().value == 6: + raise ErrorCondition.InternalError( + "The receiver link is in an error state. " + "Please confirm credentials and access permissions." + "\nSee debug trace for more details." + ) + # TODO: MessageHandlerError in uamqp - do we have an equivalent in pyamqp yet, rn it is commented out - we don't raise anything + # Fix docstring raises needed too return False return True @@ -728,8 +736,7 @@ def _client_ready(self): states. :rtype: bool - # TODO: uamqp error handling error here - do we want to raise anything or should this be something else - :raises: ~uamqp.errors.MessageHandlerError if the MessageReceiver + :raises: ~pyamqp.error.InternalError if the MessageReceiver goes into an error state. """ # pylint: disable=protected-access @@ -748,6 +755,14 @@ def _client_ready(self): self._link.attach() return False if self._link.get_state().value != 3: # ATTACHED + if self._link.get_state().value == 6: + raise ErrorCondition.InternalError( + "The receiver link is in an error state. " + "Please confirm credentials and access permissions." + "\nSee debug trace for more details." + ) + # TODO: MessageHandlerError in uamqp - do we have an equivalent in pyamqp yet, rn it is commented out - we don't raise anything + # Fix docstring raises needed too return False return True From b26d4c6d17145e1f2c07b937f4974280f7b1bdbc Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Fri, 26 Aug 2022 08:48:09 -0700 Subject: [PATCH 31/46] made private var public --- .../azure/eventhub/_pyamqp/aio/_client_async.py | 8 ++++---- .../azure-eventhub/azure/eventhub/_pyamqp/client.py | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py index 15e64f982235..41dba7afe035 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py @@ -698,9 +698,9 @@ async def _message_received_async(self, frame, message): :param message: Received message. :type message: ~uamqp.message.Message """ - if self._message_received_callback: - await self._message_received_callback(message) - if not self._streaming_receive: + if self.message_received_callback: + await self.message_received_callback(message) + if not self.streaming_receive: self._received_messages.put((frame, message)) # TODO: do we need settled property for a message? # elif not message.settled: @@ -708,7 +708,7 @@ async def _message_received_async(self, frame, message): # _logger.info("Message was not settled.") async def _receive_message_batch_impl_async(self, max_batch_size=None, on_message_received=None, timeout=0): - self._message_received_callback = on_message_received + self.message_received_callback = on_message_received max_batch_size = max_batch_size or self._link_credit timeout_time = time.time() + timeout if timeout else 0 receiving = True diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index b2803fda4b84..e550a7325acf 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -719,9 +719,9 @@ class ReceiveClient(AMQPClient): def __init__(self, hostname, source, auth=None, **kwargs): self.source = source - self._streaming_receive = kwargs.pop("streaming_receive", False) # TODO: whether public? + self.streaming_receive = kwargs.pop("streaming_receive", False) self._received_messages = queue.Queue() - self._message_received_callback = kwargs.pop("message_received_callback", None) # TODO: whether public? + self.message_received_callback = kwargs.pop("message_received_callback", None) # Sender and Link settings self._max_message_size = kwargs.pop('max_message_size', None) or MAX_FRAME_SIZE_BYTES @@ -791,13 +791,13 @@ def _message_received(self, frame, message): :param message: Received message. :type message: ~pyamqp.message.Message """ - if self._message_received_callback: - self._message_received_callback(message) - if not self._streaming_receive: + if self.message_received_callback: + self.message_received_callback(message) + if not self.streaming_receive: self._received_messages.put((frame, message)) def _receive_message_batch_impl(self, max_batch_size=None, on_message_received=None, timeout=0): - self._message_received_callback = on_message_received + self.message_received_callback = on_message_received max_batch_size = max_batch_size or self._link_credit timeout = time.time() + timeout if timeout else 0 receiving = True From 838383e34e837a16e9c543414b3a9bfd63beb2d1 Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Fri, 26 Aug 2022 08:52:43 -0700 Subject: [PATCH 32/46] removing pylint disable to see --- .../azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py index 41dba7afe035..ac2cc52c82e4 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py @@ -4,9 +4,6 @@ # license information. #-------------------------------------------------------------------------- -# TODO: check this -# pylint: disable=super-init-not-called,too-many-lines - import asyncio import collections.abc import logging From 75598b3bf9da0bfd960a36d8fb981a1358d67bcc Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Fri, 26 Aug 2022 14:28:48 -0700 Subject: [PATCH 33/46] remove auto add --- sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index e550a7325acf..40f33b099f61 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -7,7 +7,6 @@ # pylint: disable=too-many-lines import logging -from msilib.schema import Error import time import uuid import certifi From 6fb6ad8e05da72edc6e87f993487a67f1dcdaa78 Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Mon, 29 Aug 2022 10:23:32 -0700 Subject: [PATCH 34/46] initial pr fixes --- .../azure/eventhub/_pyamqp/aio/_cbs_async.py | 2 +- .../eventhub/_pyamqp/aio/_client_async.py | 66 +++------------- .../azure/eventhub/_pyamqp/cbs.py | 2 +- .../azure/eventhub/_pyamqp/client.py | 79 +++++-------------- 4 files changed, 32 insertions(+), 117 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_cbs_async.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_cbs_async.py index e72c36b2ca2e..3164780cc474 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_cbs_async.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_cbs_async.py @@ -59,7 +59,7 @@ def __init__( self._auth = auth self._encoding = 'UTF-8' - self._auth_timeout = kwargs.pop('auth_timeout', DEFAULT_AUTH_TIMEOUT) + self._auth_timeout = kwargs.get('auth_timeout') self._token_put_time = None self._expires_on = None self._token = None diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py index ac2cc52c82e4..24b7653fbf1f 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py @@ -64,9 +64,9 @@ class AMQPClientAsync(AMQPClientSync): :keyword client_name: The name for the client, also known as the Container ID. If no name is provided, a random GUID will be used. :paramtype client_name: str or bytes - :keyword debug: Whether to turn on network trace logs. If `True`, trace logs + :keyword network_trace: Whether to turn on network trace logs. If `True`, trace logs will be logged at INFO level. Default is `False`. - :paramtype debug: bool + :paramtype network_trace: bool :keyword retry_policy: A policy for parsing errors on link, connection and message disposition to determine whether the error should be retryable. :paramtype retry_policy: ~pyamqp.error.RetryPolicy @@ -111,9 +111,6 @@ class AMQPClientAsync(AMQPClientSync): will assume successful receipt of the message and clear it from the queue. The default is `PeekLock`. :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode - :keyword encoding: The encoding to use for parameters supplied as strings. - Default is 'UTF-8' - :paramtype encoding: str """ async def __aenter__(self): @@ -348,15 +345,9 @@ class SendClientAsync(SendClientSync, AMQPClientAsync): :keyword client_name: The name for the client, also known as the Container ID. If no name is provided, a random GUID will be used. :paramtype client_name: str or bytes - :keyword debug: Whether to turn on network trace logs. If `True`, trace logs + :keyword network_trace: Whether to turn on network trace logs. If `True`, trace logs will be logged at INFO level. Default is `False`. - :paramtype debug: bool - :keyword auto_complete: Whether to automatically settle message received via callback - or via iterator. If the message has not been explicitly settled after processing - the message will be accepted. Alternatively, when used with batch receive, this setting - will determine whether the messages are pre-emptively settled during batching, or otherwise - let to the user to be explicitly settled. - :paramtype auto_complete: bool + :paramtype network_trace: bool :keyword retry_policy: A policy for parsing errors on link, connection and message disposition to determine whether the error should be retryable. :paramtype retry_policy: ~pyamqp.errors.RetryPolicy @@ -411,9 +402,6 @@ class SendClientAsync(SendClientSync, AMQPClientAsync): :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. The function must take 4 arguments: source, target, properties and error. :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.errors.AMQPConnectionError] - :keyword encoding: The encoding to use for parameters supplied as strings. - Default is 'UTF-8' - :paramtype encoding: str """ async def _client_ready_async(self): @@ -423,8 +411,6 @@ async def _client_ready_async(self): states. :rtype: bool - :raises: ~pyamqp.error.InternalError if the MessageReceiver - goes into an error state. """ # pylint: disable=protected-access if not self._link: @@ -438,14 +424,6 @@ async def _client_ready_async(self): await self._link.attach() return False if self._link.get_state() != LinkState.ATTACHED: # ATTACHED - if self._link.get_state().value == 6: - raise ErrorCondition.InternalError( - "The receiver link is in an error state. " - "Please confirm credentials and access permissions." - "\nSee debug trace for more details." - ) - # TODO: MessageHandlerError in uamqp - do we have an equivalent in pyamqp yet, rn it is commented out - we don't raise anything - # Fix docstring raises needed too return False return True @@ -565,15 +543,9 @@ class ReceiveClientAsync(ReceiveClientSync, AMQPClientAsync): :keyword client_name: The name for the client, also known as the Container ID. If no name is provided, a random GUID will be used. :paramtype client_name: str or bytes - :keyword debug: Whether to turn on network trace logs. If `True`, trace logs + :keyword network_trace: Whether to turn on network trace logs. If `True`, trace logs will be logged at INFO level. Default is `False`. - :paramtype debug: bool - :keyword auto_complete: Whether to automatically settle message received via callback - or via iterator. If the message has not been explicitly settled after processing - the message will be accepted. Alternatively, when used with batch receive, this setting - will determine whether the messages are pre-emptively settled during batching, or otherwise - let to the user to be explicitly settled. - :paramtype auto_complete: bool + :paramtype network_trace: bool :keyword retry_policy: A policy for parsing errors on link, connection and message disposition to determine whether the error should be retryable. :paramtype retry_policy: ~pyamqp.errors.RetryPolicy @@ -628,9 +600,6 @@ class ReceiveClientAsync(ReceiveClientSync, AMQPClientAsync): :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. The function must take 4 arguments: source, target, properties and error. :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.errors.AMQPConnectionError] - :keyword encoding: The encoding to use for parameters supplied as strings. - Default is 'UTF-8' - :paramtype encoding: str """ async def _client_ready_async(self): @@ -640,8 +609,6 @@ async def _client_ready_async(self): states. :rtype: bool - :raises: ~pyamqp.error.InternalError if the MessageReceiver - goes into an error state. """ # pylint: disable=protected-access if not self._link: @@ -659,14 +626,6 @@ async def _client_ready_async(self): await self._link.attach() return False if self._link.get_state().value != 3: # ATTACHED - if self._link.get_state().value == 6: - raise ErrorCondition.InternalError( - "The receiver link is in an error state. " - "Please confirm credentials and access permissions." - "\nSee debug trace for more details." - ) - # TODO: MessageHandlerError in uamqp - do we have an equivalent in pyamqp yet, rn it is commented out - we don't raise anything - # Fix docstring raises needed too return False return True @@ -695,9 +654,9 @@ async def _message_received_async(self, frame, message): :param message: Received message. :type message: ~uamqp.message.Message """ - if self.message_received_callback: - await self.message_received_callback(message) - if not self.streaming_receive: + if self._message_received_callback: + await self._message_received_callback(message) + if not self._streaming_receive: self._received_messages.put((frame, message)) # TODO: do we need settled property for a message? # elif not message.settled: @@ -705,7 +664,7 @@ async def _message_received_async(self, frame, message): # _logger.info("Message was not settled.") async def _receive_message_batch_impl_async(self, max_batch_size=None, on_message_received=None, timeout=0): - self.message_received_callback = on_message_received + self._message_received_callback = on_message_received max_batch_size = max_batch_size or self._link_credit timeout_time = time.time() + timeout if timeout else 0 receiving = True @@ -769,11 +728,6 @@ async def receive_message_batch_async(self, **kwargs): available rather than waiting to achieve a specific batch size, and therefore the number of messages returned per call will vary up to the maximum allowed. - If the receive client is configured with `auto_complete=True` then the messages received - in the batch returned by this function will already be settled. Alternatively, if - `auto_complete=False`, then each message will need to be explicitly settled before - it expires and is released. - :param max_batch_size: The maximum number of messages that can be returned in one call. This value cannot be larger than the prefetch value, and if not specified, the prefetch value will be used. diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/cbs.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/cbs.py index d5eec99f048a..ced290d75b70 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/cbs.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/cbs.py @@ -68,7 +68,7 @@ def __init__( self._auth = auth self._encoding = 'UTF-8' - self._auth_timeout = kwargs.pop('auth_timeout', DEFAULT_AUTH_TIMEOUT) + self._auth_timeout = kwargs.get('auth_timeout') self._token_put_time = None self._expires_on = None self._token = None diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index 40f33b099f61..1d22bbe44b09 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -78,9 +78,9 @@ class AMQPClient(object): :keyword client_name: The name for the client, also known as the Container ID. If no name is provided, a random GUID will be used. :paramtype client_name: str or bytes - :keyword debug: Whether to turn on network trace logs. If `True`, trace logs + :keyword network_trace: Whether to turn on network trace logs. If `True`, trace logs will be logged at INFO level. Default is `False`. - :paramtype debug: bool + :paramtype network_trace: bool :keyword retry_policy: A policy for parsing errors on link, connection and message disposition to determine whether the error should be retryable. :paramtype retry_policy: ~pyamqp.error.RetryPolicy @@ -101,9 +101,8 @@ class AMQPClient(object): :paramtype auth_timeout: int :keyword properties: Connection properties. :paramtype properties: dict - :keyword remote_idle_timeout_empty_frame_send_ratio: Ratio of empty frames to - idle time for Connections with no activity. Value must be between - 0.0 and 1.0 inclusive. Default is 0.5. + :keyword remote_idle_timeout_empty_frame_send_ratio: Portion of the idle timeout time to wait before sending an + empty frame. The default portion is 50% of the idle timeout value (i.e. `0.5`). :paramtype remote_idle_timeout_empty_frame_send_ratio: float :keyword incoming_window: The size of the allowed window for incoming messages. :paramtype incoming_window: int @@ -125,9 +124,6 @@ class AMQPClient(object): will assume successful receipt of the message and clear it from the queue. The default is `PeekLock`. :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode - :keyword encoding: The encoding to use for parameters supplied as strings. - Default is 'UTF-8' - :paramtype encoding: str """ def __init__(self, hostname, **kwargs): @@ -417,15 +413,9 @@ class SendClient(AMQPClient): :keyword client_name: The name for the client, also known as the Container ID. If no name is provided, a random GUID will be used. :paramtype client_name: str or bytes - :keyword debug: Whether to turn on network trace logs. If `True`, trace logs + :keyword network_trace: Whether to turn on network trace logs. If `True`, trace logs will be logged at INFO level. Default is `False`. - :paramtype debug: bool - :keyword auto_complete: Whether to automatically settle message received via callback - or via iterator. If the message has not been explicitly settled after processing - the message will be accepted. Alternatively, when used with batch receive, this setting - will determine whether the messages are pre-emptively settled during batching, or otherwise - let to the user to be explicitly settled. - :paramtype auto_complete: bool + :paramtype network_trace: bool :keyword retry_policy: A policy for parsing errors on link, connection and message disposition to determine whether the error should be retryable. :paramtype retry_policy: ~pyamqp.errors.RetryPolicy @@ -467,9 +457,8 @@ class SendClient(AMQPClient): :paramtype idle_timeout: int :keyword properties: Connection properties. :paramtype properties: dict - :keyword remote_idle_timeout_empty_frame_send_ratio: Ratio of empty frames to - idle time for Connections with no activity. Value must be between - 0.0 and 1.0 inclusive. Default is 0.5. + :keyword remote_idle_timeout_empty_frame_send_ratio: Portion of the idle timeout time to wait before sending an + empty frame. The default portion is 50% of the idle timeout value (i.e. `0.5`). :paramtype remote_idle_timeout_empty_frame_send_ratio: float :keyword incoming_window: The size of the allowed window for incoming messages. :paramtype incoming_window: int @@ -480,9 +469,6 @@ class SendClient(AMQPClient): :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. The function must take 4 arguments: source, target, properties and error. :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.errors.AMQPConnectionError] - :keyword encoding: The encoding to use for parameters supplied as strings. - Default is 'UTF-8' - :paramtype encoding: str """ def __init__(self, hostname, target, auth=None, **kwargs): @@ -500,8 +486,6 @@ def _client_ready(self): states. :rtype: bool - :raises: ~pyamqp.error.InternalError if the MessageReceiver - goes into an error state. """ # pylint: disable=protected-access if not self._link: @@ -515,14 +499,6 @@ def _client_ready(self): self._link.attach() return False if self._link.get_state().value != 3: # ATTACHED - if self._link.get_state().value == 6: - raise ErrorCondition.InternalError( - "The receiver link is in an error state. " - "Please confirm credentials and access permissions." - "\nSee debug trace for more details." - ) - # TODO: MessageHandlerError in uamqp - do we have an equivalent in pyamqp yet, rn it is commented out - we don't raise anything - # Fix docstring raises needed too return False return True @@ -648,15 +624,9 @@ class ReceiveClient(AMQPClient): :keyword client_name: The name for the client, also known as the Container ID. If no name is provided, a random GUID will be used. :paramtype client_name: str or bytes - :keyword debug: Whether to turn on network trace logs. If `True`, trace logs + :keyword network_trace: Whether to turn on network trace logs. If `True`, trace logs will be logged at INFO level. Default is `False`. - :paramtype debug: bool - :keyword auto_complete: Whether to automatically settle message received via callback - or via iterator. If the message has not been explicitly settled after processing - the message will be accepted. Alternatively, when used with batch receive, this setting - will determine whether the messages are pre-emptively settled during batching, or otherwise - let to the user to be explicitly settled. - :paramtype auto_complete: bool + :paramtype network_trace: bool :keyword retry_policy: A policy for parsing errors on link, connection and message disposition to determine whether the error should be retryable. :paramtype retry_policy: ~pyamqp.errors.RetryPolicy @@ -698,9 +668,8 @@ class ReceiveClient(AMQPClient): :paramtype idle_timeout: int :keyword properties: Connection properties. :paramtype properties: dict - :keyword remote_idle_timeout_empty_frame_send_ratio: Ratio of empty frames to - idle time for Connections with no activity. Value must be between - 0.0 and 1.0 inclusive. Default is 0.5. + :keyword remote_idle_timeout_empty_frame_send_ratio: Portion of the idle timeout time to wait before sending an + empty frame. The default portion is 50% of the idle timeout value (i.e. `0.5`). :paramtype remote_idle_timeout_empty_frame_send_ratio: float :keyword incoming_window: The size of the allowed window for incoming messages. :paramtype incoming_window: int @@ -711,16 +680,13 @@ class ReceiveClient(AMQPClient): :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. The function must take 4 arguments: source, target, properties and error. :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.errors.AMQPConnectionError] - :keyword encoding: The encoding to use for parameters supplied as strings. - Default is 'UTF-8' - :paramtype encoding: str """ def __init__(self, hostname, source, auth=None, **kwargs): self.source = source - self.streaming_receive = kwargs.pop("streaming_receive", False) + self._streaming_receive = kwargs.pop("streaming_receive", False) self._received_messages = queue.Queue() - self.message_received_callback = kwargs.pop("message_received_callback", None) + self._message_received_callback = kwargs.pop("message_received_callback", None) # Sender and Link settings self._max_message_size = kwargs.pop('max_message_size', None) or MAX_FRAME_SIZE_BYTES @@ -735,7 +701,7 @@ def _client_ready(self): states. :rtype: bool - :raises: ~pyamqp.error.InternalError if the MessageReceiver + :raises: ~pyamqp.error. if the MessageReceiver goes into an error state. """ # pylint: disable=protected-access @@ -755,7 +721,7 @@ def _client_ready(self): return False if self._link.get_state().value != 3: # ATTACHED if self._link.get_state().value == 6: - raise ErrorCondition.InternalError( + raise AMQPLinkError( "The receiver link is in an error state. " "Please confirm credentials and access permissions." "\nSee debug trace for more details." @@ -790,13 +756,13 @@ def _message_received(self, frame, message): :param message: Received message. :type message: ~pyamqp.message.Message """ - if self.message_received_callback: - self.message_received_callback(message) - if not self.streaming_receive: + if self._message_received_callback: + self._message_received_callback(message) + if not self._streaming_receive: self._received_messages.put((frame, message)) def _receive_message_batch_impl(self, max_batch_size=None, on_message_received=None, timeout=0): - self.message_received_callback = on_message_received + self._message_received_callback = on_message_received max_batch_size = max_batch_size or self._link_credit timeout = time.time() + timeout if timeout else 0 receiving = True @@ -852,11 +818,6 @@ def receive_message_batch(self, **kwargs): available rather than waiting to achieve a specific batch size, and therefore the number of messages returned per call will vary up to the maximum allowed. - If the receive client is configured with `auto_complete=True` then the messages received - in the batch returned by this function will already be settled. Alternatively, if - `auto_complete=False`, then each message will need to be explicitly settled before - it expires and is released. - :param max_batch_size: The maximum number of messages that can be returned in one call. This value cannot be larger than the prefetch value, and if not specified, the prefetch value will be used. From 019350a52742147b5e60569a9b68404609062344 Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Mon, 29 Aug 2022 13:23:12 -0700 Subject: [PATCH 35/46] removing desired_capabilities for now, spelling fix adding keywords for http/ce/transporttype --- .../eventhub/_pyamqp/aio/_client_async.py | 68 ++++++++++++--- .../eventhub/_pyamqp/aio/_session_async.py | 2 +- .../azure/eventhub/_pyamqp/client.py | 86 ++++++++++++++----- .../azure/eventhub/_pyamqp/constants.py | 2 +- .../azure/eventhub/_pyamqp/session.py | 2 +- 5 files changed, 125 insertions(+), 35 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py index 24b7653fbf1f..a7313b2f5284 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py @@ -111,6 +111,25 @@ class AMQPClientAsync(AMQPClientSync): will assume successful receipt of the message and clear it from the queue. The default is `PeekLock`. :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode + :keyword transport_type: The type of transport protocol that will be used for communicating with + the service. Default is `TransportType.Amqp` in which case port 5671 is used. + If the port 5671 is unavailable/blocked in the network environment, `TransportType.AmqpOverWebsocket` could + be used instead which uses port 443 for communication. + :paramtype transport_type: ~pyamqp.constants.TransportType + :keyword http_proxy: HTTP proxy settings. This must be a dictionary with the following + keys: `'proxy_hostname'` (str value) and `'proxy_port'` (int value). + Additionally the following keys may also be present: `'username', 'password'`. + :paramtype http_proxy: Dict + :keyword custom_endpoint_address: The custom endpoint address to use for establishing a connection to + the Event Hubs service, allowing network requests to be routed through any application gateways or + other paths needed for the host environment. Default is None. + The format would be like "sb://:". + If port is not specified in the `custom_endpoint_address`, by default port 443 will be used. + :paramtype custom_endpoint_address: str + :keyword connection_verify: Path to the custom CA_BUNDLE file of the SSL certificate which is used to + authenticate the identity of the connection endpoint. + Default is None in which case `certifi.where()` will be used. + :paramtype connection_verify: str """ async def __aenter__(self): @@ -367,11 +386,6 @@ class SendClientAsync(SendClientSync, AMQPClientAsync): will assume successful receipt of the message and clear it from the queue. The default is `PeekLock`. :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode - :keywprd desired_capabilities: The extension capabilities desired from the peer endpoint. - To create an desired_capabilities object, please do as follows: - - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` - - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` - :paramtype desired_capabilities: ~uamqp.c_uamqp.AMQPValue :keyword max_message_size: The maximum allowed message size negotiated for the Link. :paramtype max_message_size: int :keyword link_properties: Metadata to be sent in the Link ATTACH frame. @@ -402,6 +416,25 @@ class SendClientAsync(SendClientSync, AMQPClientAsync): :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. The function must take 4 arguments: source, target, properties and error. :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.errors.AMQPConnectionError] + :keyword transport_type: The type of transport protocol that will be used for communicating with + the service. Default is `TransportType.Amqp` in which case port 5671 is used. + If the port 5671 is unavailable/blocked in the network environment, `TransportType.AmqpOverWebsocket` could + be used instead which uses port 443 for communication. + :paramtype transport_type: ~pyamqp.constants.TransportType + :keyword http_proxy: HTTP proxy settings. This must be a dictionary with the following + keys: `'proxy_hostname'` (str value) and `'proxy_port'` (int value). + Additionally the following keys may also be present: `'username', 'password'`. + :paramtype http_proxy: Dict + :keyword custom_endpoint_address: The custom endpoint address to use for establishing a connection to + the Event Hubs service, allowing network requests to be routed through any application gateways or + other paths needed for the host environment. Default is None. + The format would be like "sb://:". + If port is not specified in the `custom_endpoint_address`, by default port 443 will be used. + :paramtype custom_endpoint_address: str + :keyword connection_verify: Path to the custom CA_BUNDLE file of the SSL certificate which is used to + authenticate the identity of the connection endpoint. + Default is None in which case `certifi.where()` will be used. + :paramtype connection_verify: str """ async def _client_ready_async(self): @@ -565,11 +598,6 @@ class ReceiveClientAsync(ReceiveClientSync, AMQPClientAsync): will assume successful receipt of the message and clear it from the queue. The default is `PeekLock`. :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode - :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. - To create an desired_capabilities object, please do as follows: - - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` - - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` - :paramtype desired_capabilities: ~uamqp.c_uamqp.AMQPValue :keyword max_message_size: The maximum allowed message size negotiated for the Link. :paramtype max_message_size: int :keyword link_properties: Metadata to be sent in the Link ATTACH frame. @@ -600,6 +628,25 @@ class ReceiveClientAsync(ReceiveClientSync, AMQPClientAsync): :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. The function must take 4 arguments: source, target, properties and error. :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.errors.AMQPConnectionError] + :keyword transport_type: The type of transport protocol that will be used for communicating with + the service. Default is `TransportType.Amqp` in which case port 5671 is used. + If the port 5671 is unavailable/blocked in the network environment, `TransportType.AmqpOverWebsocket` could + be used instead which uses port 443 for communication. + :paramtype transport_type: ~pyamqp.constants.TransportType + :keyword http_proxy: HTTP proxy settings. This must be a dictionary with the following + keys: `'proxy_hostname'` (str value) and `'proxy_port'` (int value). + Additionally the following keys may also be present: `'username', 'password'`. + :paramtype http_proxy: Dict + :keyword custom_endpoint_address: The custom endpoint address to use for establishing a connection to + the Event Hubs service, allowing network requests to be routed through any application gateways or + other paths needed for the host environment. Default is None. + The format would be like "sb://:". + If port is not specified in the `custom_endpoint_address`, by default port 443 will be used. + :paramtype custom_endpoint_address: str + :keyword connection_verify: Path to the custom CA_BUNDLE file of the SSL certificate which is used to + authenticate the identity of the connection endpoint. + Default is None in which case `certifi.where()` will be used. + :paramtype connection_verify: str """ async def _client_ready_async(self): @@ -620,7 +667,6 @@ async def _client_ready_async(self): max_message_size=self._max_message_size, on_transfer=self._message_received_async, properties=self._link_properties, - desired_capabilities=self._desired_capabilities, on_attach=self._on_attach ) await self._link.attach() diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_session_async.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_session_async.py index d79c2a484de8..4fc82112c995 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_session_async.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_session_async.py @@ -12,7 +12,7 @@ from ..constants import ( INCOMING_WINDOW, - OUTGOING_WIDNOW, + OUTGOING_WINDOW, ConnectionState, SessionState, SessionTransferState, diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index 1d22bbe44b09..6643a90f64ca 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -51,7 +51,7 @@ AUTH_TYPE_CBS, MAX_FRAME_SIZE_BYTES, INCOMING_WINDOW, - OUTGOING_WIDNOW, + OUTGOING_WINDOW, DEFAULT_AUTH_TIMEOUT, MESSAGE_DELIVERY_DONE_STATES, ) @@ -124,6 +124,25 @@ class AMQPClient(object): will assume successful receipt of the message and clear it from the queue. The default is `PeekLock`. :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode + :keyword transport_type: The type of transport protocol that will be used for communicating with + the service. Default is `TransportType.Amqp` in which case port 5671 is used. + If the port 5671 is unavailable/blocked in the network environment, `TransportType.AmqpOverWebsocket` could + be used instead which uses port 443 for communication. + :paramtype transport_type: ~pyamqp.constants.TransportType + :keyword http_proxy: HTTP proxy settings. This must be a dictionary with the following + keys: `'proxy_hostname'` (str value) and `'proxy_port'` (int value). + Additionally the following keys may also be present: `'username', 'password'`. + :paramtype http_proxy: Dict + :keyword custom_endpoint_address: The custom endpoint address to use for establishing a connection to + the Event Hubs service, allowing network requests to be routed through any application gateways or + other paths needed for the host environment. Default is None. + The format would be like "sb://:". + If port is not specified in the `custom_endpoint_address`, by default port 443 will be used. + :paramtype custom_endpoint_address: str + :keyword connection_verify: Path to the custom CA_BUNDLE file of the SSL certificate which is used to + authenticate the identity of the connection endpoint. + Default is None in which case `certifi.where()` will be used. + :paramtype connection_verify: str """ def __init__(self, hostname, **kwargs): @@ -141,11 +160,11 @@ def __init__(self, hostname, **kwargs): self._auth_timeout = kwargs.pop("auth_timeout", DEFAULT_AUTH_TIMEOUT) self._mgmt_links = {} self._retry_policy = kwargs.pop("retry_policy", RetryPolicy()) - self._keep_alive_interval = int(kwargs.pop("keep_alive_interval", None) or 0) + self._keep_alive_interval = int(kwargs.pop("keep_alive_interval", 0)) # Connection settings - self._max_frame_size = kwargs.pop('max_frame_size', None) or MAX_FRAME_SIZE_BYTES - self._channel_max = kwargs.pop('channel_max', None) or 65535 + self._max_frame_size = kwargs.pop('max_frame_size', MAX_FRAME_SIZE_BYTES) + self._channel_max = kwargs.pop('channel_max', 65535) self._idle_timeout = kwargs.pop('idle_timeout', None) self._properties = kwargs.pop('properties', None) self._remote_idle_timeout_empty_frame_send_ratio = kwargs.pop( @@ -153,15 +172,13 @@ def __init__(self, hostname, **kwargs): self._network_trace = kwargs.pop("network_trace", False) # Session settings - self._outgoing_window = kwargs.pop('outgoing_window', None) or OUTGOING_WIDNOW - self._incoming_window = kwargs.pop('incoming_window', None) or INCOMING_WINDOW + self._outgoing_window = kwargs.pop('outgoing_window', OUTGOING_WINDOW) + self._incoming_window = kwargs.pop('incoming_window', INCOMING_WINDOW) self._handle_max = kwargs.pop('handle_max', None) - self._on_attach = kwargs.pop('on_attach', None) # Link settings self._send_settle_mode = kwargs.pop('send_settle_mode', SenderSettleMode.Unsettled) self._receive_settle_mode = kwargs.pop('receive_settle_mode', ReceiverSettleMode.Second) - self._desired_capabilities = kwargs.pop('desired_capabilities', None) self._on_attach = kwargs.pop('on_attach', None) # transport @@ -435,11 +452,6 @@ class SendClient(AMQPClient): will assume successful receipt of the message and clear it from the queue. The default is `PeekLock`. :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode - :keywprd desired_capabilities: The extension capabilities desired from the peer endpoint. - To create an desired_capabilities object, please do as follows: - - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` - - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` - :paramtype desired_capabilities: ~uamqp.c_uamqp.AMQPValue :keyword max_message_size: The maximum allowed message size negotiated for the Link. :paramtype max_message_size: int :keyword link_properties: Metadata to be sent in the Link ATTACH frame. @@ -469,12 +481,31 @@ class SendClient(AMQPClient): :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. The function must take 4 arguments: source, target, properties and error. :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.errors.AMQPConnectionError] + :keyword transport_type: The type of transport protocol that will be used for communicating with + the service. Default is `TransportType.Amqp` in which case port 5671 is used. + If the port 5671 is unavailable/blocked in the network environment, `TransportType.AmqpOverWebsocket` could + be used instead which uses port 443 for communication. + :paramtype transport_type: ~pyamqp.constants.TransportType + :keyword http_proxy: HTTP proxy settings. This must be a dictionary with the following + keys: `'proxy_hostname'` (str value) and `'proxy_port'` (int value). + Additionally the following keys may also be present: `'username', 'password'`. + :paramtype http_proxy: Dict + :keyword custom_endpoint_address: The custom endpoint address to use for establishing a connection to + the Event Hubs service, allowing network requests to be routed through any application gateways or + other paths needed for the host environment. Default is None. + The format would be like "sb://:". + If port is not specified in the `custom_endpoint_address`, by default port 443 will be used. + :paramtype custom_endpoint_address: str + :keyword connection_verify: Path to the custom CA_BUNDLE file of the SSL certificate which is used to + authenticate the identity of the connection endpoint. + Default is None in which case `certifi.where()` will be used. + :paramtype connection_verify: str """ def __init__(self, hostname, target, auth=None, **kwargs): self.target = target # Sender and Link settings - self._max_message_size = kwargs.pop('max_message_size', None) or MAX_FRAME_SIZE_BYTES + self._max_message_size = kwargs.pop('max_message_size', MAX_FRAME_SIZE_BYTES) self._link_properties = kwargs.pop('link_properties', None) self._link_credit = kwargs.pop('link_credit', None) super(SendClient, self).__init__(hostname, auth=auth, **kwargs) @@ -646,11 +677,6 @@ class ReceiveClient(AMQPClient): will assume successful receipt of the message and clear it from the queue. The default is `PeekLock`. :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode - :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. - To create an desired_capabilities object, please do as follows: - - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` - - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` - :paramtype desired_capabilities: ~uamqp.c_uamqp.AMQPValue :keyword max_message_size: The maximum allowed message size negotiated for the Link. :paramtype max_message_size: int :keyword link_properties: Metadata to be sent in the Link ATTACH frame. @@ -680,6 +706,25 @@ class ReceiveClient(AMQPClient): :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. The function must take 4 arguments: source, target, properties and error. :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.errors.AMQPConnectionError] + :keyword transport_type: The type of transport protocol that will be used for communicating with + the service. Default is `TransportType.Amqp` in which case port 5671 is used. + If the port 5671 is unavailable/blocked in the network environment, `TransportType.AmqpOverWebsocket` could + be used instead which uses port 443 for communication. + :paramtype transport_type: ~pyamqp.constants.TransportType + :keyword http_proxy: HTTP proxy settings. This must be a dictionary with the following + keys: `'proxy_hostname'` (str value) and `'proxy_port'` (int value). + Additionally the following keys may also be present: `'username', 'password'`. + :paramtype http_proxy: Dict + :keyword custom_endpoint_address: The custom endpoint address to use for establishing a connection to + the Event Hubs service, allowing network requests to be routed through any application gateways or + other paths needed for the host environment. Default is None. + The format would be like "sb://:". + If port is not specified in the `custom_endpoint_address`, by default port 443 will be used. + :paramtype custom_endpoint_address: str + :keyword connection_verify: Path to the custom CA_BUNDLE file of the SSL certificate which is used to + authenticate the identity of the connection endpoint. + Default is None in which case `certifi.where()` will be used. + :paramtype connection_verify: str """ def __init__(self, hostname, source, auth=None, **kwargs): @@ -689,7 +734,7 @@ def __init__(self, hostname, source, auth=None, **kwargs): self._message_received_callback = kwargs.pop("message_received_callback", None) # Sender and Link settings - self._max_message_size = kwargs.pop('max_message_size', None) or MAX_FRAME_SIZE_BYTES + self._max_message_size = kwargs.pop('max_message_size', MAX_FRAME_SIZE_BYTES) self._link_properties = kwargs.pop('link_properties', None) self._link_credit = kwargs.pop('link_credit', 300) super(ReceiveClient, self).__init__(hostname, auth=auth, **kwargs) @@ -714,7 +759,6 @@ def _client_ready(self): max_message_size=self._max_message_size, on_transfer=self._message_received, properties=self._link_properties, - desired_capabilities=self._desired_capabilities, on_attach=self._on_attach ) self._link.attach() diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/constants.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/constants.py index 47443c14bcc4..2e26ea451667 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/constants.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/constants.py @@ -60,7 +60,7 @@ MAX_FRAME_SIZE_BYTES = 1024 * 1024 MAX_CHANNELS = 65535 INCOMING_WINDOW = 64 * 1024 -OUTGOING_WIDNOW = 64 * 1024 +OUTGOING_WINDOW = 64 * 1024 DEFAULT_LINK_CREDIT = 10000 diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/session.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/session.py index 42d42a6a2689..590c45c68d65 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/session.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/session.py @@ -11,7 +11,7 @@ from .constants import ( INCOMING_WINDOW, - OUTGOING_WIDNOW, + OUTGOING_WINDOW, ConnectionState, SessionState, SessionTransferState, From 5e08d07acbbd2ceb3eaa5b9ef008d52a35c33fc5 Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Mon, 29 Aug 2022 14:56:16 -0700 Subject: [PATCH 36/46] adding back in desired_cap -- used by consumer --- .../eventhub/_pyamqp/aio/_client_async.py | 16 ++++++++++++ .../azure/eventhub/_pyamqp/client.py | 25 +++++++++++++------ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py index a7313b2f5284..ff8be0e2197e 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py @@ -111,6 +111,11 @@ class AMQPClientAsync(AMQPClientSync): will assume successful receipt of the message and clear it from the queue. The default is `PeekLock`. :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode + :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. + To create an desired_capabilities object, please do as follows: + - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` + - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` + :paramtype desired_capabilities: List :keyword transport_type: The type of transport protocol that will be used for communicating with the service. Default is `TransportType.Amqp` in which case port 5671 is used. If the port 5671 is unavailable/blocked in the network environment, `TransportType.AmqpOverWebsocket` could @@ -416,6 +421,11 @@ class SendClientAsync(SendClientSync, AMQPClientAsync): :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. The function must take 4 arguments: source, target, properties and error. :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.errors.AMQPConnectionError] + :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. + To create an desired_capabilities object, please do as follows: + - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` + - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` + :paramtype desired_capabilities: List :keyword transport_type: The type of transport protocol that will be used for communicating with the service. Default is `TransportType.Amqp` in which case port 5671 is used. If the port 5671 is unavailable/blocked in the network environment, `TransportType.AmqpOverWebsocket` could @@ -628,6 +638,11 @@ class ReceiveClientAsync(ReceiveClientSync, AMQPClientAsync): :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. The function must take 4 arguments: source, target, properties and error. :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.errors.AMQPConnectionError] + :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. + To create an desired_capabilities object, please do as follows: + - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` + - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` + :paramtype desired_capabilities: List :keyword transport_type: The type of transport protocol that will be used for communicating with the service. Default is `TransportType.Amqp` in which case port 5671 is used. If the port 5671 is unavailable/blocked in the network environment, `TransportType.AmqpOverWebsocket` could @@ -667,6 +682,7 @@ async def _client_ready_async(self): max_message_size=self._max_message_size, on_transfer=self._message_received_async, properties=self._link_properties, + desired_capabilities=self._desired_capabilities, on_attach=self._on_attach ) await self._link.attach() diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index 6643a90f64ca..00d8e048936d 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -124,6 +124,11 @@ class AMQPClient(object): will assume successful receipt of the message and clear it from the queue. The default is `PeekLock`. :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode + :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. + To create an desired_capabilities object, please do as follows: + - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` + - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` + :paramtype desired_capabilities: List :keyword transport_type: The type of transport protocol that will be used for communicating with the service. Default is `TransportType.Amqp` in which case port 5671 is used. If the port 5671 is unavailable/blocked in the network environment, `TransportType.AmqpOverWebsocket` could @@ -179,6 +184,7 @@ def __init__(self, hostname, **kwargs): # Link settings self._send_settle_mode = kwargs.pop('send_settle_mode', SenderSettleMode.Unsettled) self._receive_settle_mode = kwargs.pop('receive_settle_mode', ReceiverSettleMode.Second) + self._desired_capabilities = kwargs.pop('desired_capabilities', None) self._on_attach = kwargs.pop('on_attach', None) # transport @@ -452,6 +458,11 @@ class SendClient(AMQPClient): will assume successful receipt of the message and clear it from the queue. The default is `PeekLock`. :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode + :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. + To create an desired_capabilities object, please do as follows: + - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` + - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` + :paramtype desired_capabilities: List :keyword max_message_size: The maximum allowed message size negotiated for the Link. :paramtype max_message_size: int :keyword link_properties: Metadata to be sent in the Link ATTACH frame. @@ -677,6 +688,11 @@ class ReceiveClient(AMQPClient): will assume successful receipt of the message and clear it from the queue. The default is `PeekLock`. :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode + :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. + To create an desired_capabilities object, please do as follows: + - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` + - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` + :paramtype desired_capabilities: List :keyword max_message_size: The maximum allowed message size negotiated for the Link. :paramtype max_message_size: int :keyword link_properties: Metadata to be sent in the Link ATTACH frame. @@ -759,19 +775,12 @@ def _client_ready(self): max_message_size=self._max_message_size, on_transfer=self._message_received, properties=self._link_properties, + desired_capabilities=self._desired_capabilities, on_attach=self._on_attach ) self._link.attach() return False if self._link.get_state().value != 3: # ATTACHED - if self._link.get_state().value == 6: - raise AMQPLinkError( - "The receiver link is in an error state. " - "Please confirm credentials and access permissions." - "\nSee debug trace for more details." - ) - # TODO: MessageHandlerError in uamqp - do we have an equivalent in pyamqp yet, rn it is commented out - we don't raise anything - # Fix docstring raises needed too return False return True From 8272c83577a2be59604d80e2b6d98c99a8fe6212 Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Tue, 30 Aug 2022 08:41:47 -0700 Subject: [PATCH 37/46] adding docstring patch for review --- .../eventhub/_pyamqp/aio/_client_async.py | 204 ++-------------- .../azure/eventhub/_pyamqp/client.py | 217 +++--------------- 2 files changed, 42 insertions(+), 379 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py index ff8be0e2197e..cfe02cff93e2 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py @@ -116,6 +116,14 @@ class AMQPClientAsync(AMQPClientSync): - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` :paramtype desired_capabilities: List + :keyword max_message_size: The maximum allowed message size negotiated for the Link. + :paramtype max_message_size: int + :keyword link_properties: Metadata to be sent in the Link ATTACH frame. + :paramtype link_properties: dict + :keyword prefetch: The receiver Link credit that determines how many + messages the Link will attempt to handle per connection iteration. + The default is 300. + :paramtype prefetch: int :keyword transport_type: The type of transport protocol that will be used for communicating with the service. Default is `TransportType.Amqp` in which case port 5671 is used. If the port 5671 is unavailable/blocked in the network environment, `TransportType.AmqpOverWebsocket` could @@ -351,101 +359,6 @@ async def mgmt_request_async(self, message, **kwargs): class SendClientAsync(SendClientSync, AMQPClientAsync): - """An AMQP client for sending messages asynchronously. - - :param hostname: The AMQP endpoint to connect to. - :type hostname: str - :param target: The target AMQP service endpoint. This can either be the URI as - a string or a ~pyamqp.endpoint.Target object. - :type target: str, bytes or ~pyamqp.endpoint.Target - :param auth: Authentication for the connection. This should be one of the subclasses of - pyamqp.authentication.AMQPAuth. Currently this includes: - - pyamqp.authentication.SASLAnonymous - - pyamqp.authentication.SASLPlain - - pyamqp.authentication.SASTokenAuth - If no authentication is supplied, SASLAnnoymous will be used by default. - :type auth: ~pyamqp.authentication.SASLAnonymous or pyamqp.authentication.SASLPlain - or pyamqp.authentication.SASTokenAuth - :keyword client_name: The name for the client, also known as the Container ID. - If no name is provided, a random GUID will be used. - :paramtype client_name: str or bytes - :keyword network_trace: Whether to turn on network trace logs. If `True`, trace logs - will be logged at INFO level. Default is `False`. - :paramtype network_trace: bool - :keyword retry_policy: A policy for parsing errors on link, connection and message - disposition to determine whether the error should be retryable. - :paramtype retry_policy: ~pyamqp.errors.RetryPolicy - :keyword keep_alive_interval: If set, a thread will be started to keep the connection - alive during periods of user inactivity. The value will determine how long the - thread will sleep (in seconds) between pinging the connection. If 0 or None, no - thread will be started. - :paramtype keep_alive_interval: int - :keyword send_settle_mode: The mode by which to settle message send - operations. If set to `Unsettled`, the client will wait for a confirmation - from the service that the message was successfully sent. If set to 'Settled', - the client will not wait for confirmation and assume success. - :paramtype send_settle_mode: ~pyamqp.constants.SenderSettleMode - :keyword receive_settle_mode: The mode by which to settle message receive - operations. If set to `PeekLock`, the receiver will lock a message once received until - the client accepts or rejects the message. If set to `ReceiveAndDelete`, the service - will assume successful receipt of the message and clear it from the queue. The - default is `PeekLock`. - :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode - :keyword max_message_size: The maximum allowed message size negotiated for the Link. - :paramtype max_message_size: int - :keyword link_properties: Metadata to be sent in the Link ATTACH frame. - :paramtype link_properties: dict - :keyword prefetch: The receiver Link credit that determines how many - messages the Link will attempt to handle per connection iteration. - The default is 300. - :paramtype prefetch: int - :keyword max_frame_size: Maximum AMQP frame size. Default is 63488 bytes. - :paramtype max_frame_size: int - :keyword channel_max: Maximum number of Session channels in the Connection. - :paramtype channel_max: int - :keyword idle_timeout: Timeout in seconds after which the Connection will close - if there is no further activity. - :paramtype idle_timeout: int - :keyword properties: Connection properties. - :paramtype properties: dict - :keyword remote_idle_timeout_empty_frame_send_ratio: Ratio of empty frames to - idle time for Connections with no activity. Value must be between - 0.0 and 1.0 inclusive. Default is 0.5. - :paramtype remote_idle_timeout_empty_frame_send_ratio: float - :keyword incoming_window: The size of the allowed window for incoming messages. - :paramtype incoming_window: int - :keyword outgoing_window: The size of the allowed window for outgoing messages. - :paramtype outgoing_window: int - :keyword handle_max: The maximum number of concurrent link handles. - :paramtype handle_max: int - :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. - The function must take 4 arguments: source, target, properties and error. - :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.errors.AMQPConnectionError] - :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. - To create an desired_capabilities object, please do as follows: - - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` - - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` - :paramtype desired_capabilities: List - :keyword transport_type: The type of transport protocol that will be used for communicating with - the service. Default is `TransportType.Amqp` in which case port 5671 is used. - If the port 5671 is unavailable/blocked in the network environment, `TransportType.AmqpOverWebsocket` could - be used instead which uses port 443 for communication. - :paramtype transport_type: ~pyamqp.constants.TransportType - :keyword http_proxy: HTTP proxy settings. This must be a dictionary with the following - keys: `'proxy_hostname'` (str value) and `'proxy_port'` (int value). - Additionally the following keys may also be present: `'username', 'password'`. - :paramtype http_proxy: Dict - :keyword custom_endpoint_address: The custom endpoint address to use for establishing a connection to - the Event Hubs service, allowing network requests to be routed through any application gateways or - other paths needed for the host environment. Default is None. - The format would be like "sb://:". - If port is not specified in the `custom_endpoint_address`, by default port 443 will be used. - :paramtype custom_endpoint_address: str - :keyword connection_verify: Path to the custom CA_BUNDLE file of the SSL certificate which is used to - authenticate the identity of the connection endpoint. - Default is None in which case `certifi.where()` will be used. - :paramtype connection_verify: str - """ async def _client_ready_async(self): """Determine whether the client is ready to start receiving messages. @@ -567,102 +480,10 @@ async def send_message_async(self, message, **kwargs): await self._do_retryable_operation_async(self._send_message_impl_async, message=message, **kwargs) -class ReceiveClientAsync(ReceiveClientSync, AMQPClientAsync): - """An AMQP client for receiving messages. +SendClientAsync.__doc__ = SendClientSync.__doc__ - :param hostname: The AMQP endpoint to connect to. - :type hostname: str - :param source: The source AMQP service endpoint. This can either be the URI as - a string or a ~pyamqp.endpoint.Source object. - :type source: str, bytes or ~pyamqp.endpoint.Source - :param auth: Authentication for the connection. This should be one of the subclasses of - pyamqp.authentication.AMQPAuth. Currently this includes: - - pyamqp.authentication.SASLAnonymous - - pyamqp.authentication.SASLPlain - - pyamqp.authentication.SASTokenAuth - If no authentication is supplied, SASLAnnoymous will be used by default. - :type auth: ~pyamqp.authentication.SASLAnonymous or pyamqp.authentication.SASLPlain - or pyamqp.authentication.SASTokenAuth - :keyword client_name: The name for the client, also known as the Container ID. - If no name is provided, a random GUID will be used. - :paramtype client_name: str or bytes - :keyword network_trace: Whether to turn on network trace logs. If `True`, trace logs - will be logged at INFO level. Default is `False`. - :paramtype network_trace: bool - :keyword retry_policy: A policy for parsing errors on link, connection and message - disposition to determine whether the error should be retryable. - :paramtype retry_policy: ~pyamqp.errors.RetryPolicy - :keyword keep_alive_interval: If set, a thread will be started to keep the connection - alive during periods of user inactivity. The value will determine how long the - thread will sleep (in seconds) between pinging the connection. If 0 or None, no - thread will be started. - :paramtype keep_alive_interval: int - :keyword send_settle_mode: The mode by which to settle message send - operations. If set to `Unsettled`, the client will wait for a confirmation - from the service that the message was successfully sent. If set to 'Settled', - the client will not wait for confirmation and assume success. - :paramtype send_settle_mode: ~pyamqp.constants.SenderSettleMode - :keyword receive_settle_mode: The mode by which to settle message receive - operations. If set to `PeekLock`, the receiver will lock a message once received until - the client accepts or rejects the message. If set to `ReceiveAndDelete`, the service - will assume successful receipt of the message and clear it from the queue. The - default is `PeekLock`. - :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode - :keyword max_message_size: The maximum allowed message size negotiated for the Link. - :paramtype max_message_size: int - :keyword link_properties: Metadata to be sent in the Link ATTACH frame. - :paramtype link_properties: dict - :keyword prefetch: The receiver Link credit that determines how many - messages the Link will attempt to handle per connection iteration. - The default is 300. - :paramtype prefetch: int - :keyword max_frame_size: Maximum AMQP frame size. Default is 63488 bytes. - :paramtype max_frame_size: int - :keyword channel_max: Maximum number of Session channels in the Connection. - :paramtype channel_max: int - :keyword idle_timeout: Timeout in seconds after which the Connection will close - if there is no further activity. - :paramtype idle_timeout: int - :keyword properties: Connection properties. - :paramtype properties: dict - :keyword remote_idle_timeout_empty_frame_send_ratio: Ratio of empty frames to - idle time for Connections with no activity. Value must be between - 0.0 and 1.0 inclusive. Default is 0.5. - :paramtype remote_idle_timeout_empty_frame_send_ratio: float - :keyword incoming_window: The size of the allowed window for incoming messages. - :paramtype incoming_window: int - :keyword outgoing_window: The size of the allowed window for outgoing messages. - :paramtype outgoing_window: int - :keyword handle_max: The maximum number of concurrent link handles. - :paramtype handle_max: int - :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. - The function must take 4 arguments: source, target, properties and error. - :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.errors.AMQPConnectionError] - :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. - To create an desired_capabilities object, please do as follows: - - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` - - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` - :paramtype desired_capabilities: List - :keyword transport_type: The type of transport protocol that will be used for communicating with - the service. Default is `TransportType.Amqp` in which case port 5671 is used. - If the port 5671 is unavailable/blocked in the network environment, `TransportType.AmqpOverWebsocket` could - be used instead which uses port 443 for communication. - :paramtype transport_type: ~pyamqp.constants.TransportType - :keyword http_proxy: HTTP proxy settings. This must be a dictionary with the following - keys: `'proxy_hostname'` (str value) and `'proxy_port'` (int value). - Additionally the following keys may also be present: `'username', 'password'`. - :paramtype http_proxy: Dict - :keyword custom_endpoint_address: The custom endpoint address to use for establishing a connection to - the Event Hubs service, allowing network requests to be routed through any application gateways or - other paths needed for the host environment. Default is None. - The format would be like "sb://:". - If port is not specified in the `custom_endpoint_address`, by default port 443 will be used. - :paramtype custom_endpoint_address: str - :keyword connection_verify: Path to the custom CA_BUNDLE file of the SSL certificate which is used to - authenticate the identity of the connection endpoint. - Default is None in which case `certifi.where()` will be used. - :paramtype connection_verify: str - """ + +class ReceiveClientAsync(ReceiveClientSync, AMQPClientAsync): async def _client_ready_async(self): """Determine whether the client is ready to start receiving messages. @@ -891,3 +712,6 @@ async def settle_messages_async(self, delivery_id: Union[int, Tuple[int, int]], batchable=batchable, wait=True ) + + +ReceiveClientAsync.__doc__ = ReceiveClientSync.__doc__ \ No newline at end of file diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index 00d8e048936d..811f93a27af9 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -129,6 +129,14 @@ class AMQPClient(object): - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` :paramtype desired_capabilities: List + :keyword max_message_size: The maximum allowed message size negotiated for the Link. + :paramtype max_message_size: int + :keyword link_properties: Metadata to be sent in the Link ATTACH frame. + :paramtype link_properties: dict + :keyword prefetch: The receiver Link credit that determines how many + messages the Link will attempt to handle per connection iteration. + The default is 300. + :paramtype prefetch: int :keyword transport_type: The type of transport protocol that will be used for communicating with the service. Default is `TransportType.Amqp` in which case port 5671 is used. If the port 5671 is unavailable/blocked in the network environment, `TransportType.AmqpOverWebsocket` could @@ -418,103 +426,10 @@ def mgmt_request(self, message, **kwargs): class SendClient(AMQPClient): - """An AMQP client for sending messages. - :param hostname: The AMQP endpoint to connect to. - :type hostname: str - :param target: The target AMQP service endpoint. This can either be the URI as - a string or a ~pyamqp.endpoint.Target object. - :type target: str, bytes or ~pyamqp.endpoint.Target - :param auth: Authentication for the connection. This should be one of the subclasses of - pyamqp.authentication.AMQPAuth. Currently this includes: - - pyamqp.authentication.SASLAnonymous - - pyamqp.authentication.SASLPlain - - pyamqp.authentication.SASTokenAuth - If no authentication is supplied, SASLAnnoymous will be used by default. - :type auth: ~pyamqp.authentication.SASLAnonymous or pyamqp.authentication.SASLPlain - or pyamqp.authentication.SASTokenAuth - :keyword client_name: The name for the client, also known as the Container ID. - If no name is provided, a random GUID will be used. - :paramtype client_name: str or bytes - :keyword network_trace: Whether to turn on network trace logs. If `True`, trace logs - will be logged at INFO level. Default is `False`. - :paramtype network_trace: bool - :keyword retry_policy: A policy for parsing errors on link, connection and message - disposition to determine whether the error should be retryable. - :paramtype retry_policy: ~pyamqp.errors.RetryPolicy - :keyword keep_alive_interval: If set, a thread will be started to keep the connection - alive during periods of user inactivity. The value will determine how long the - thread will sleep (in seconds) between pinging the connection. If 0 or None, no - thread will be started. - :paramtype keep_alive_interval: int - :keyword send_settle_mode: The mode by which to settle message send - operations. If set to `Unsettled`, the client will wait for a confirmation - from the service that the message was successfully sent. If set to 'Settled', - the client will not wait for confirmation and assume success. - :paramtype send_settle_mode: ~pyamqp.constants.SenderSettleMode - :keyword receive_settle_mode: The mode by which to settle message receive - operations. If set to `PeekLock`, the receiver will lock a message once received until - the client accepts or rejects the message. If set to `ReceiveAndDelete`, the service - will assume successful receipt of the message and clear it from the queue. The - default is `PeekLock`. - :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode - :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. - To create an desired_capabilities object, please do as follows: - - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` - - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` - :paramtype desired_capabilities: List - :keyword max_message_size: The maximum allowed message size negotiated for the Link. - :paramtype max_message_size: int - :keyword link_properties: Metadata to be sent in the Link ATTACH frame. - :paramtype link_properties: dict - :keyword prefetch: The receiver Link credit that determines how many - messages the Link will attempt to handle per connection iteration. - The default is 300. - :paramtype prefetch: int - :keyword max_frame_size: Maximum AMQP frame size. Default is 63488 bytes. - :paramtype max_frame_size: int - :keyword channel_max: Maximum number of Session channels in the Connection. - :paramtype channel_max: int - :keyword idle_timeout: Timeout in seconds after which the Connection will close - if there is no further activity. - :paramtype idle_timeout: int - :keyword properties: Connection properties. - :paramtype properties: dict - :keyword remote_idle_timeout_empty_frame_send_ratio: Portion of the idle timeout time to wait before sending an - empty frame. The default portion is 50% of the idle timeout value (i.e. `0.5`). - :paramtype remote_idle_timeout_empty_frame_send_ratio: float - :keyword incoming_window: The size of the allowed window for incoming messages. - :paramtype incoming_window: int - :keyword outgoing_window: The size of the allowed window for outgoing messages. - :paramtype outgoing_window: int - :keyword handle_max: The maximum number of concurrent link handles. - :paramtype handle_max: int - :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. - The function must take 4 arguments: source, target, properties and error. - :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.errors.AMQPConnectionError] - :keyword transport_type: The type of transport protocol that will be used for communicating with - the service. Default is `TransportType.Amqp` in which case port 5671 is used. - If the port 5671 is unavailable/blocked in the network environment, `TransportType.AmqpOverWebsocket` could - be used instead which uses port 443 for communication. - :paramtype transport_type: ~pyamqp.constants.TransportType - :keyword http_proxy: HTTP proxy settings. This must be a dictionary with the following - keys: `'proxy_hostname'` (str value) and `'proxy_port'` (int value). - Additionally the following keys may also be present: `'username', 'password'`. - :paramtype http_proxy: Dict - :keyword custom_endpoint_address: The custom endpoint address to use for establishing a connection to - the Event Hubs service, allowing network requests to be routed through any application gateways or - other paths needed for the host environment. Default is None. - The format would be like "sb://:". - If port is not specified in the `custom_endpoint_address`, by default port 443 will be used. - :paramtype custom_endpoint_address: str - :keyword connection_verify: Path to the custom CA_BUNDLE file of the SSL certificate which is used to - authenticate the identity of the connection endpoint. - Default is None in which case `certifi.where()` will be used. - :paramtype connection_verify: str - """ - - def __init__(self, hostname, target, auth=None, **kwargs): + def __init__(self, hostname, target, **kwargs): self.target = target + auth = kwargs.pop('auth', None) # Sender and Link settings self._max_message_size = kwargs.pop('max_message_size', MAX_FRAME_SIZE_BYTES) self._link_properties = kwargs.pop('link_properties', None) @@ -646,102 +561,17 @@ def send_message(self, message, **kwargs): """ self._do_retryable_operation(self._send_message_impl, message=message, **kwargs) +SendClient.__doc__ = \ +f""" + An AMQP client for sending messages. + {AMQPClient.__doc__[15:93]} + :param target: The target AMQP service endpoint. This can either be the URI as + a string or a ~pyamqp.endpoint.Target object. + :type target: str, bytes or ~pyamqp.endpoint.Target {AMQPClient.__doc__[93::]} +""" -class ReceiveClient(AMQPClient): - """An AMQP client for receiving messages. - :param hostname: The AMQP endpoint to connect to. - :type hostname: str - :param source: The source AMQP service endpoint. This can either be the URI as - a string or a ~pyamqp.endpoint.Source object. - :type source: str, bytes or ~pyamqp.endpoint.Source - :param auth: Authentication for the connection. This should be one of the subclasses of - pyamqp.authentication.AMQPAuth. Currently this includes: - - pyamqp.authentication.SASLAnonymous - - pyamqp.authentication.SASLPlain - - pyamqp.authentication.SASTokenAuth - If no authentication is supplied, SASLAnnoymous will be used by default. - :type auth: ~pyamqp.authentication.SASLAnonymous or pyamqp.authentication.SASLPlain - or pyamqp.authentication.SASTokenAuth - :keyword client_name: The name for the client, also known as the Container ID. - If no name is provided, a random GUID will be used. - :paramtype client_name: str or bytes - :keyword network_trace: Whether to turn on network trace logs. If `True`, trace logs - will be logged at INFO level. Default is `False`. - :paramtype network_trace: bool - :keyword retry_policy: A policy for parsing errors on link, connection and message - disposition to determine whether the error should be retryable. - :paramtype retry_policy: ~pyamqp.errors.RetryPolicy - :keyword keep_alive_interval: If set, a thread will be started to keep the connection - alive during periods of user inactivity. The value will determine how long the - thread will sleep (in seconds) between pinging the connection. If 0 or None, no - thread will be started. - :paramtype keep_alive_interval: int - :keyword send_settle_mode: The mode by which to settle message send - operations. If set to `Unsettled`, the client will wait for a confirmation - from the service that the message was successfully sent. If set to 'Settled', - the client will not wait for confirmation and assume success. - :paramtype send_settle_mode: ~pyamqp.constants.SenderSettleMode - :keyword receive_settle_mode: The mode by which to settle message receive - operations. If set to `PeekLock`, the receiver will lock a message once received until - the client accepts or rejects the message. If set to `ReceiveAndDelete`, the service - will assume successful receipt of the message and clear it from the queue. The - default is `PeekLock`. - :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode - :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. - To create an desired_capabilities object, please do as follows: - - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` - - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` - :paramtype desired_capabilities: List - :keyword max_message_size: The maximum allowed message size negotiated for the Link. - :paramtype max_message_size: int - :keyword link_properties: Metadata to be sent in the Link ATTACH frame. - :paramtype link_properties: dict - :keyword prefetch: The receiver Link credit that determines how many - messages the Link will attempt to handle per connection iteration. - The default is 300. - :paramtype prefetch: int - :keyword max_frame_size: Maximum AMQP frame size. Default is 63488 bytes. - :paramtype max_frame_size: int - :keyword channel_max: Maximum number of Session channels in the Connection. - :paramtype channel_max: int - :keyword idle_timeout: Timeout in seconds after which the Connection will close - if there is no further activity. - :paramtype idle_timeout: int - :keyword properties: Connection properties. - :paramtype properties: dict - :keyword remote_idle_timeout_empty_frame_send_ratio: Portion of the idle timeout time to wait before sending an - empty frame. The default portion is 50% of the idle timeout value (i.e. `0.5`). - :paramtype remote_idle_timeout_empty_frame_send_ratio: float - :keyword incoming_window: The size of the allowed window for incoming messages. - :paramtype incoming_window: int - :keyword outgoing_window: The size of the allowed window for outgoing messages. - :paramtype outgoing_window: int - :keyword handle_max: The maximum number of concurrent link handles. - :paramtype handle_max: int - :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. - The function must take 4 arguments: source, target, properties and error. - :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.errors.AMQPConnectionError] - :keyword transport_type: The type of transport protocol that will be used for communicating with - the service. Default is `TransportType.Amqp` in which case port 5671 is used. - If the port 5671 is unavailable/blocked in the network environment, `TransportType.AmqpOverWebsocket` could - be used instead which uses port 443 for communication. - :paramtype transport_type: ~pyamqp.constants.TransportType - :keyword http_proxy: HTTP proxy settings. This must be a dictionary with the following - keys: `'proxy_hostname'` (str value) and `'proxy_port'` (int value). - Additionally the following keys may also be present: `'username', 'password'`. - :paramtype http_proxy: Dict - :keyword custom_endpoint_address: The custom endpoint address to use for establishing a connection to - the Event Hubs service, allowing network requests to be routed through any application gateways or - other paths needed for the host environment. Default is None. - The format would be like "sb://:". - If port is not specified in the `custom_endpoint_address`, by default port 443 will be used. - :paramtype custom_endpoint_address: str - :keyword connection_verify: Path to the custom CA_BUNDLE file of the SSL certificate which is used to - authenticate the identity of the connection endpoint. - Default is None in which case `certifi.where()` will be used. - :paramtype connection_verify: str - """ +class ReceiveClient(AMQPClient): def __init__(self, hostname, source, auth=None, **kwargs): self.source = source @@ -972,3 +802,12 @@ def settle_messages(self, delivery_id: Union[int, Tuple[int, int]], outcome: str batchable=batchable, wait=True ) + +ReceiveClient.__doc__ = \ +f""" + An AMQP client for receiving messages. + {AMQPClient.__doc__[15:93]} + :param source: The source AMQP service endpoint. This can either be the URI as + a string or a ~pyamqp.endpoint.Source object. + :type source: str, bytes or ~pyamqp.endpoint.Source {AMQPClient.__doc__[93::]} +""" \ No newline at end of file From 4bd01aef7de3807fb2914d0f7a63253a2fd79816 Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Tue, 30 Aug 2022 08:44:49 -0700 Subject: [PATCH 38/46] auth as keyword --- .../azure-eventhub/azure/eventhub/_pyamqp/client.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index 811f93a27af9..ffb3b47d82b5 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -429,12 +429,11 @@ class SendClient(AMQPClient): def __init__(self, hostname, target, **kwargs): self.target = target - auth = kwargs.pop('auth', None) # Sender and Link settings self._max_message_size = kwargs.pop('max_message_size', MAX_FRAME_SIZE_BYTES) self._link_properties = kwargs.pop('link_properties', None) self._link_credit = kwargs.pop('link_credit', None) - super(SendClient, self).__init__(hostname, auth=auth, **kwargs) + super(SendClient, self).__init__(hostname, **kwargs) def _client_ready(self): """Determine whether the client is ready to start receiving messages. @@ -573,7 +572,7 @@ def send_message(self, message, **kwargs): class ReceiveClient(AMQPClient): - def __init__(self, hostname, source, auth=None, **kwargs): + def __init__(self, hostname, source, **kwargs): self.source = source self._streaming_receive = kwargs.pop("streaming_receive", False) self._received_messages = queue.Queue() @@ -583,7 +582,7 @@ def __init__(self, hostname, source, auth=None, **kwargs): self._max_message_size = kwargs.pop('max_message_size', MAX_FRAME_SIZE_BYTES) self._link_properties = kwargs.pop('link_properties', None) self._link_credit = kwargs.pop('link_credit', 300) - super(ReceiveClient, self).__init__(hostname, auth=auth, **kwargs) + super(ReceiveClient, self).__init__(hostname, **kwargs) def _client_ready(self): """Determine whether the client is ready to start receiving messages. From 9c518f176ef35d11e3af92d6d13a8fe9aea9135d Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Tue, 30 Aug 2022 09:27:22 -0700 Subject: [PATCH 39/46] renaming prefetch to link_credit to match code --- .../azure/eventhub/_pyamqp/aio/_client_async.py | 5 ++--- .../azure-eventhub/azure/eventhub/_pyamqp/client.py | 7 +++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py index cfe02cff93e2..f3eb98cb9c39 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py @@ -120,10 +120,10 @@ class AMQPClientAsync(AMQPClientSync): :paramtype max_message_size: int :keyword link_properties: Metadata to be sent in the Link ATTACH frame. :paramtype link_properties: dict - :keyword prefetch: The receiver Link credit that determines how many + :keyword link_credit: The Link credit that determines how many messages the Link will attempt to handle per connection iteration. The default is 300. - :paramtype prefetch: int + :paramtype link_credit: int :keyword transport_type: The type of transport protocol that will be used for communicating with the service. Default is `TransportType.Amqp` in which case port 5671 is used. If the port 5671 is unavailable/blocked in the network environment, `TransportType.AmqpOverWebsocket` could @@ -136,7 +136,6 @@ class AMQPClientAsync(AMQPClientSync): :keyword custom_endpoint_address: The custom endpoint address to use for establishing a connection to the Event Hubs service, allowing network requests to be routed through any application gateways or other paths needed for the host environment. Default is None. - The format would be like "sb://:". If port is not specified in the `custom_endpoint_address`, by default port 443 will be used. :paramtype custom_endpoint_address: str :keyword connection_verify: Path to the custom CA_BUNDLE file of the SSL certificate which is used to diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index ffb3b47d82b5..bace3a8557d8 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -133,10 +133,10 @@ class AMQPClient(object): :paramtype max_message_size: int :keyword link_properties: Metadata to be sent in the Link ATTACH frame. :paramtype link_properties: dict - :keyword prefetch: The receiver Link credit that determines how many + :keyword link_credit: The Link credit that determines how many messages the Link will attempt to handle per connection iteration. The default is 300. - :paramtype prefetch: int + :paramtype link_credit: int :keyword transport_type: The type of transport protocol that will be used for communicating with the service. Default is `TransportType.Amqp` in which case port 5671 is used. If the port 5671 is unavailable/blocked in the network environment, `TransportType.AmqpOverWebsocket` could @@ -147,9 +147,8 @@ class AMQPClient(object): Additionally the following keys may also be present: `'username', 'password'`. :paramtype http_proxy: Dict :keyword custom_endpoint_address: The custom endpoint address to use for establishing a connection to - the Event Hubs service, allowing network requests to be routed through any application gateways or + the service, allowing network requests to be routed through any application gateways or other paths needed for the host environment. Default is None. - The format would be like "sb://:". If port is not specified in the `custom_endpoint_address`, by default port 443 will be used. :paramtype custom_endpoint_address: str :keyword connection_verify: Path to the custom CA_BUNDLE file of the SSL certificate which is used to From b67fa9c5b475624425e3a61de16c4f4f692f1a42 Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Tue, 30 Aug 2022 10:02:08 -0700 Subject: [PATCH 40/46] swathi pr comments --- .../eventhub/_pyamqp/aio/_client_async.py | 19 ++++++++----------- .../azure/eventhub/_pyamqp/client.py | 3 --- .../unittest/test_client_creation_pyamqp.py | 4 ++-- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py index f3eb98cb9c39..18f1e0e4b9b8 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py @@ -112,9 +112,6 @@ class AMQPClientAsync(AMQPClientSync): default is `PeekLock`. :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. - To create an desired_capabilities object, please do as follows: - - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` - - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` :paramtype desired_capabilities: List :keyword max_message_size: The maximum allowed message size negotiated for the Link. :paramtype max_message_size: int @@ -610,18 +607,18 @@ async def receive_message_batch_async(self, **kwargs): available rather than waiting to achieve a specific batch size, and therefore the number of messages returned per call will vary up to the maximum allowed. - :param max_batch_size: The maximum number of messages that can be returned in + :keyword max_batch_size: The maximum number of messages that can be returned in one call. This value cannot be larger than the prefetch value, and if not specified, the prefetch value will be used. - :type max_batch_size: int - :param on_message_received: A callback to process messages as they arrive from the - service. It takes a single argument, a ~uamqp.message.Message object. - :type on_message_received: callable[~uamqp.message.Message] - :param timeout: Timeout in seconds for which to wait to receive any messages. + :paramtype max_batch_size: int + :keyword on_message_received: A callback to process messages as they arrive from the + service. It takes a single argument, a ~pyamqp.message.Message object. + :paramtype on_message_received: callable[~pyamqp.message.Message] + :keyword timeout: Timeout in seconds for which to wait to receive any messages. If no messages are received in this time, an empty list will be returned. If set to 0, the client will continue to wait until at least one message is received. The default is 0. - :type timeout: float + :paramtype timeout: float """ return await self._do_retryable_operation_async( self._receive_message_batch_impl_async, @@ -713,4 +710,4 @@ async def settle_messages_async(self, delivery_id: Union[int, Tuple[int, int]], ) -ReceiveClientAsync.__doc__ = ReceiveClientSync.__doc__ \ No newline at end of file +ReceiveClientAsync.__doc__ = ReceiveClientSync.__doc__ diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index bace3a8557d8..272663b9800a 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -125,9 +125,6 @@ class AMQPClient(object): default is `PeekLock`. :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. - To create an desired_capabilities object, please do as follows: - - 1. Create an array of desired capability symbols: `capabilities_symbol_array = [types.AMQPSymbol(string)]` - - 2. Transform the array to AMQPValue object: `utils.data_factory(types.AMQPArray(capabilities_symbol_array))` :paramtype desired_capabilities: List :keyword max_message_size: The maximum allowed message size negotiated for the Link. :paramtype max_message_size: int diff --git a/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_client_creation_pyamqp.py b/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_client_creation_pyamqp.py index b0541f11a080..bb777b53c0cc 100644 --- a/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_client_creation_pyamqp.py +++ b/sdk/eventhub/azure-eventhub/tests/pyamqp_tests/unittest/test_client_creation_pyamqp.py @@ -11,7 +11,7 @@ def test_send_client_creation(): sender = SendClient( "fake.host.com", "fake_eh", - "my_fake_auth" + auth="my_fake_auth" ) assert sender.target == "fake_eh" assert sender._auth == "my_fake_auth" @@ -22,7 +22,7 @@ def test_receive_client_creation(): receiver = ReceiveClient( "fake.host.com", "fake_eh", - "my_fake_auth" + auth="my_fake_auth" ) assert receiver.source == "fake_eh" assert receiver._auth == "my_fake_auth" From 8a83c0e0adb7019946c81f113ba0513a809e50e0 Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Wed, 31 Aug 2022 07:12:03 -0700 Subject: [PATCH 41/46] making pr comment changes --- .../eventhub/_pyamqp/aio/_client_async.py | 20 +++++++++---------- .../azure/eventhub/_pyamqp/client.py | 15 +++++++------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py index 18f1e0e4b9b8..4f9551f554ac 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py @@ -3,7 +3,7 @@ # Licensed under the MIT License. See License.txt in the project root for # license information. #-------------------------------------------------------------------------- - +# TODO: Check types of kwargs (issue exists for this) import asyncio import collections.abc import logging @@ -86,7 +86,7 @@ class AMQPClientAsync(AMQPClientSync): Default value is 60s. :paramtype auth_timeout: int :keyword properties: Connection properties. - :paramtype properties: dict + :paramtype properties: dict[str, any] :keyword remote_idle_timeout_empty_frame_send_ratio: Ratio of empty frames to idle time for Connections with no activity. Value must be between 0.0 and 1.0 inclusive. Default is 0.5. @@ -112,11 +112,11 @@ class AMQPClientAsync(AMQPClientSync): default is `PeekLock`. :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. - :paramtype desired_capabilities: List + :paramtype desired_capabilities: list[any] :keyword max_message_size: The maximum allowed message size negotiated for the Link. :paramtype max_message_size: int :keyword link_properties: Metadata to be sent in the Link ATTACH frame. - :paramtype link_properties: dict + :paramtype link_properties: dict[str, any] :keyword link_credit: The Link credit that determines how many messages the Link will attempt to handle per connection iteration. The default is 300. @@ -129,7 +129,7 @@ class AMQPClientAsync(AMQPClientSync): :keyword http_proxy: HTTP proxy settings. This must be a dictionary with the following keys: `'proxy_hostname'` (str value) and `'proxy_port'` (int value). Additionally the following keys may also be present: `'username', 'password'`. - :paramtype http_proxy: Dict + :paramtype http_proxy: dict[str, str] :keyword custom_endpoint_address: The custom endpoint address to use for establishing a connection to the Event Hubs service, allowing network requests to be routed through any application gateways or other paths needed for the host environment. Default is None. @@ -303,7 +303,7 @@ async def do_work_async(self, **kwargs): to be shut down. :rtype: bool - :raises: TimeoutError or ~uamqp.errors.ClientTimeout if CBS authentication timeout reached. + :raises: TimeoutError if CBS authentication timeout reached. """ if self._shutdown: return False @@ -314,7 +314,7 @@ async def do_work_async(self, **kwargs): async def mgmt_request_async(self, message, **kwargs): """ :param message: The message to send in the management request. - :type message: ~uamqp.message.Message + :type message: ~pyamqp.message.Message :keyword str operation: The type of operation to be performed. This value will be service-specific, but common values include READ, CREATE and UPDATE. This value will be added as an application property on the message. @@ -324,7 +324,7 @@ async def mgmt_request_async(self, message, **kwargs): :keyword str node: The target node. Default node is `$management`. :keyword float timeout: Provide an optional timeout in seconds within which a response to the management request must be received. - :rtype: ~uamqp.message.Message + :rtype: ~pyamqp.message.Message """ # The method also takes "status_code_field" and "status_description_field" @@ -470,7 +470,7 @@ async def _send_message_impl_async(self, message, **kwargs): async def send_message_async(self, message, **kwargs): """ - :param ~uamqp.message.Message message: + :param ~pyamqp.message.Message message: :param int timeout: timeout in seconds """ await self._do_retryable_operation_async(self._send_message_impl_async, message=message, **kwargs) @@ -531,7 +531,7 @@ async def _message_received_async(self, frame, message): or iterator, the message will be added to an internal queue. :param message: Received message. - :type message: ~uamqp.message.Message + :type message: ~pyamqp.message.Message """ if self._message_received_callback: await self._message_received_callback(message) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index 272663b9800a..b30b022364ea 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -5,7 +5,7 @@ #-------------------------------------------------------------------------- # pylint: disable=too-many-lines - +# TODO: Check types of kwargs (issue exists for this) import logging import time import uuid @@ -41,6 +41,7 @@ ) from .constants import ( + MAX_CHANNELS, MessageDeliveryState, SenderSettleMode, ReceiverSettleMode, @@ -100,7 +101,7 @@ class AMQPClient(object): Default value is 60s. :paramtype auth_timeout: int :keyword properties: Connection properties. - :paramtype properties: dict + :paramtype properties: dict[str, any] :keyword remote_idle_timeout_empty_frame_send_ratio: Portion of the idle timeout time to wait before sending an empty frame. The default portion is 50% of the idle timeout value (i.e. `0.5`). :paramtype remote_idle_timeout_empty_frame_send_ratio: float @@ -125,11 +126,11 @@ class AMQPClient(object): default is `PeekLock`. :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. - :paramtype desired_capabilities: List + :paramtype desired_capabilities: list[any] :keyword max_message_size: The maximum allowed message size negotiated for the Link. :paramtype max_message_size: int :keyword link_properties: Metadata to be sent in the Link ATTACH frame. - :paramtype link_properties: dict + :paramtype link_properties: dict[str, any] :keyword link_credit: The Link credit that determines how many messages the Link will attempt to handle per connection iteration. The default is 300. @@ -142,7 +143,7 @@ class AMQPClient(object): :keyword http_proxy: HTTP proxy settings. This must be a dictionary with the following keys: `'proxy_hostname'` (str value) and `'proxy_port'` (int value). Additionally the following keys may also be present: `'username', 'password'`. - :paramtype http_proxy: Dict + :paramtype http_proxy: dict[str, str] :keyword custom_endpoint_address: The custom endpoint address to use for establishing a connection to the service, allowing network requests to be routed through any application gateways or other paths needed for the host environment. Default is None. @@ -173,7 +174,7 @@ def __init__(self, hostname, **kwargs): # Connection settings self._max_frame_size = kwargs.pop('max_frame_size', MAX_FRAME_SIZE_BYTES) - self._channel_max = kwargs.pop('channel_max', 65535) + self._channel_max = kwargs.pop('channel_max', MAX_CHANNELS) self._idle_timeout = kwargs.pop('idle_timeout', None) self._properties = kwargs.pop('properties', None) self._remote_idle_timeout_empty_frame_send_ratio = kwargs.pop( @@ -703,7 +704,7 @@ def receive_message_batch(self, **kwargs): :param on_message_received: A callback to process messages as they arrive from the service. It takes a single argument, a ~pyamqp.message.Message object. :type on_message_received: callable[~pyamqp.message.Message] - :param timeout: I timeout in milliseconds for which to wait to receive any messages. + :param timeout: The timeout in milliseconds for which to wait to receive any messages. If no messages are received in this time, an empty list will be returned. If set to 0, the client will continue to wait until at least one message is received. The default is 0. From b1f34b4c388af34e859e8b1f4001a31bb9901768 Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Wed, 31 Aug 2022 07:27:55 -0700 Subject: [PATCH 42/46] nonetype err --- sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index b30b022364ea..2bf550a52917 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -170,7 +170,7 @@ def __init__(self, hostname, **kwargs): self._auth_timeout = kwargs.pop("auth_timeout", DEFAULT_AUTH_TIMEOUT) self._mgmt_links = {} self._retry_policy = kwargs.pop("retry_policy", RetryPolicy()) - self._keep_alive_interval = int(kwargs.pop("keep_alive_interval", 0)) + self._keep_alive_interval = int(kwargs.get("keep_alive_interval") or 0) # Connection settings self._max_frame_size = kwargs.pop('max_frame_size', MAX_FRAME_SIZE_BYTES) From 6c4e933f4f7ea63cd3898d2e48968e8b230c4708 Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Wed, 31 Aug 2022 08:17:35 -0700 Subject: [PATCH 43/46] fixing docstring async --- .../azure/eventhub/_pyamqp/aio/_client_async.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py index 4f9551f554ac..94979029da87 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py @@ -476,7 +476,8 @@ async def send_message_async(self, message, **kwargs): await self._do_retryable_operation_async(self._send_message_impl_async, message=message, **kwargs) -SendClientAsync.__doc__ = SendClientSync.__doc__ +SendClientAsync.__doc__ = \ + f"""{SendClientSync.__doc__[0:41]} asynchronously{SendClientSync.__doc__[41::]}""" class ReceiveClientAsync(ReceiveClientSync, AMQPClientAsync): @@ -710,4 +711,5 @@ async def settle_messages_async(self, delivery_id: Union[int, Tuple[int, int]], ) -ReceiveClientAsync.__doc__ = ReceiveClientSync.__doc__ +ReceiveClientAsync.__doc__ = \ + f"""{ReceiveClientSync.__doc__[0:43]} asynchronously{ReceiveClientSync.__doc__[43::]}""" From e817f4bf864b3569a76299699c7aff6c32ac0a56 Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Wed, 31 Aug 2022 09:39:22 -0700 Subject: [PATCH 44/46] making this uniform with sync side --- .../azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py index 94979029da87..308d657c6d9f 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py @@ -375,7 +375,7 @@ async def _client_ready_async(self): properties=self._link_properties) await self._link.attach() return False - if self._link.get_state() != LinkState.ATTACHED: # ATTACHED + if self._link.get_state().value != 3: # ATTACHED return False return True From ced95bcf657d7c94238223f0f38302fa4b34d1e2 Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Wed, 31 Aug 2022 09:42:52 -0700 Subject: [PATCH 45/46] fixing leftover doc issue --- sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index 2bf550a52917..cd6b5c4ab57b 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -588,8 +588,6 @@ def _client_ready(self): states. :rtype: bool - :raises: ~pyamqp.error. if the MessageReceiver - goes into an error state. """ # pylint: disable=protected-access if not self._link: @@ -806,4 +804,4 @@ def settle_messages(self, delivery_id: Union[int, Tuple[int, int]], outcome: str :param source: The source AMQP service endpoint. This can either be the URI as a string or a ~pyamqp.endpoint.Source object. :type source: str, bytes or ~pyamqp.endpoint.Source {AMQPClient.__doc__[93::]} -""" \ No newline at end of file +""" From 975db5930cd3ce8f60f18c900acbb532d3b66172 Mon Sep 17 00:00:00 2001 From: l0lawrence Date: Tue, 6 Sep 2022 08:07:30 -0700 Subject: [PATCH 46/46] str->bytes, removing __doc__ override --- .../eventhub/_pyamqp/aio/_client_async.py | 192 ++++++++++++++++- .../azure/eventhub/_pyamqp/client.py | 200 ++++++++++++++++-- 2 files changed, 365 insertions(+), 27 deletions(-) diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py index 308d657c6d9f..a68ae7d79b74 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/aio/_client_async.py @@ -112,7 +112,7 @@ class AMQPClientAsync(AMQPClientSync): default is `PeekLock`. :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. - :paramtype desired_capabilities: list[any] + :paramtype desired_capabilities: list[bytes] :keyword max_message_size: The maximum allowed message size negotiated for the Link. :paramtype max_message_size: int :keyword link_properties: Metadata to be sent in the Link ATTACH frame. @@ -356,6 +356,98 @@ async def mgmt_request_async(self, message, **kwargs): class SendClientAsync(SendClientSync, AMQPClientAsync): + """An asynchronous AMQP client. + + :param target: The target AMQP service endpoint. This can either be the URI as + a string or a ~pyamqp.endpoint.Target object. + :type target: str, bytes or ~pyamqp.endpoint.Target + :keyword auth: Authentication for the connection. This should be one of the following: + - pyamqp.authentication.SASLAnonymous + - pyamqp.authentication.SASLPlain + - pyamqp.authentication.SASTokenAuth + - pyamqp.authentication.JWTTokenAuth + If no authentication is supplied, SASLAnnoymous will be used by default. + :paramtype auth: ~pyamqp.authentication + :keyword client_name: The name for the client, also known as the Container ID. + If no name is provided, a random GUID will be used. + :paramtype client_name: str or bytes + :keyword network_trace: Whether to turn on network trace logs. If `True`, trace logs + will be logged at INFO level. Default is `False`. + :paramtype network_trace: bool + :keyword retry_policy: A policy for parsing errors on link, connection and message + disposition to determine whether the error should be retryable. + :paramtype retry_policy: ~pyamqp.error.RetryPolicy + :keyword keep_alive_interval: If set, a thread will be started to keep the connection + alive during periods of user inactivity. The value will determine how long the + thread will sleep (in seconds) between pinging the connection. If 0 or None, no + thread will be started. + :paramtype keep_alive_interval: int + :keyword max_frame_size: Maximum AMQP frame size. Default is 63488 bytes. + :paramtype max_frame_size: int + :keyword channel_max: Maximum number of Session channels in the Connection. + :paramtype channel_max: int + :keyword idle_timeout: Timeout in seconds after which the Connection will close + if there is no further activity. + :paramtype idle_timeout: int + :keyword auth_timeout: Timeout in seconds for CBS authentication. Otherwise this value will be ignored. + Default value is 60s. + :paramtype auth_timeout: int + :keyword properties: Connection properties. + :paramtype properties: dict[str, any] + :keyword remote_idle_timeout_empty_frame_send_ratio: Ratio of empty frames to + idle time for Connections with no activity. Value must be between + 0.0 and 1.0 inclusive. Default is 0.5. + :paramtype remote_idle_timeout_empty_frame_send_ratio: float + :keyword incoming_window: The size of the allowed window for incoming messages. + :paramtype incoming_window: int + :keyword outgoing_window: The size of the allowed window for outgoing messages. + :paramtype outgoing_window: int + :keyword handle_max: The maximum number of concurrent link handles. + :paramtype handle_max: int + :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. + The function must take 4 arguments: source, target, properties and error. + :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.error.AMQPConnectionError] + :keyword send_settle_mode: The mode by which to settle message send + operations. If set to `Unsettled`, the client will wait for a confirmation + from the service that the message was successfully sent. If set to 'Settled', + the client will not wait for confirmation and assume success. + :paramtype send_settle_mode: ~pyamqp.constants.SenderSettleMode + :keyword receive_settle_mode: The mode by which to settle message receive + operations. If set to `PeekLock`, the receiver will lock a message once received until + the client accepts or rejects the message. If set to `ReceiveAndDelete`, the service + will assume successful receipt of the message and clear it from the queue. The + default is `PeekLock`. + :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode + :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. + :paramtype desired_capabilities: list[bytes] + :keyword max_message_size: The maximum allowed message size negotiated for the Link. + :paramtype max_message_size: int + :keyword link_properties: Metadata to be sent in the Link ATTACH frame. + :paramtype link_properties: dict[str, any] + :keyword link_credit: The Link credit that determines how many + messages the Link will attempt to handle per connection iteration. + The default is 300. + :paramtype link_credit: int + :keyword transport_type: The type of transport protocol that will be used for communicating with + the service. Default is `TransportType.Amqp` in which case port 5671 is used. + If the port 5671 is unavailable/blocked in the network environment, `TransportType.AmqpOverWebsocket` could + be used instead which uses port 443 for communication. + :paramtype transport_type: ~pyamqp.constants.TransportType + :keyword http_proxy: HTTP proxy settings. This must be a dictionary with the following + keys: `'proxy_hostname'` (str value) and `'proxy_port'` (int value). + Additionally the following keys may also be present: `'username', 'password'`. + :paramtype http_proxy: dict[str, str] + :keyword custom_endpoint_address: The custom endpoint address to use for establishing a connection to + the Event Hubs service, allowing network requests to be routed through any application gateways or + other paths needed for the host environment. Default is None. + If port is not specified in the `custom_endpoint_address`, by default port 443 will be used. + :paramtype custom_endpoint_address: str + :keyword connection_verify: Path to the custom CA_BUNDLE file of the SSL certificate which is used to + authenticate the identity of the connection endpoint. + Default is None in which case `certifi.where()` will be used. + :paramtype connection_verify: str + """ + async def _client_ready_async(self): """Determine whether the client is ready to start receiving messages. To be ready, the connection must be open and authentication complete, @@ -476,11 +568,98 @@ async def send_message_async(self, message, **kwargs): await self._do_retryable_operation_async(self._send_message_impl_async, message=message, **kwargs) -SendClientAsync.__doc__ = \ - f"""{SendClientSync.__doc__[0:41]} asynchronously{SendClientSync.__doc__[41::]}""" - - class ReceiveClientAsync(ReceiveClientSync, AMQPClientAsync): + """An asynchronous AMQP client. + + :param source: The source AMQP service endpoint. This can either be the URI as + a string or a ~pyamqp.endpoint.Source object. + :type source: str, bytes or ~pyamqp.endpoint.Source + :keyword auth: Authentication for the connection. This should be one of the following: + - pyamqp.authentication.SASLAnonymous + - pyamqp.authentication.SASLPlain + - pyamqp.authentication.SASTokenAuth + - pyamqp.authentication.JWTTokenAuth + If no authentication is supplied, SASLAnnoymous will be used by default. + :paramtype auth: ~pyamqp.authentication + :keyword client_name: The name for the client, also known as the Container ID. + If no name is provided, a random GUID will be used. + :paramtype client_name: str or bytes + :keyword network_trace: Whether to turn on network trace logs. If `True`, trace logs + will be logged at INFO level. Default is `False`. + :paramtype network_trace: bool + :keyword retry_policy: A policy for parsing errors on link, connection and message + disposition to determine whether the error should be retryable. + :paramtype retry_policy: ~pyamqp.error.RetryPolicy + :keyword keep_alive_interval: If set, a thread will be started to keep the connection + alive during periods of user inactivity. The value will determine how long the + thread will sleep (in seconds) between pinging the connection. If 0 or None, no + thread will be started. + :paramtype keep_alive_interval: int + :keyword max_frame_size: Maximum AMQP frame size. Default is 63488 bytes. + :paramtype max_frame_size: int + :keyword channel_max: Maximum number of Session channels in the Connection. + :paramtype channel_max: int + :keyword idle_timeout: Timeout in seconds after which the Connection will close + if there is no further activity. + :paramtype idle_timeout: int + :keyword auth_timeout: Timeout in seconds for CBS authentication. Otherwise this value will be ignored. + Default value is 60s. + :paramtype auth_timeout: int + :keyword properties: Connection properties. + :paramtype properties: dict[str, any] + :keyword remote_idle_timeout_empty_frame_send_ratio: Ratio of empty frames to + idle time for Connections with no activity. Value must be between + 0.0 and 1.0 inclusive. Default is 0.5. + :paramtype remote_idle_timeout_empty_frame_send_ratio: float + :keyword incoming_window: The size of the allowed window for incoming messages. + :paramtype incoming_window: int + :keyword outgoing_window: The size of the allowed window for outgoing messages. + :paramtype outgoing_window: int + :keyword handle_max: The maximum number of concurrent link handles. + :paramtype handle_max: int + :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. + The function must take 4 arguments: source, target, properties and error. + :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.error.AMQPConnectionError] + :keyword send_settle_mode: The mode by which to settle message send + operations. If set to `Unsettled`, the client will wait for a confirmation + from the service that the message was successfully sent. If set to 'Settled', + the client will not wait for confirmation and assume success. + :paramtype send_settle_mode: ~pyamqp.constants.SenderSettleMode + :keyword receive_settle_mode: The mode by which to settle message receive + operations. If set to `PeekLock`, the receiver will lock a message once received until + the client accepts or rejects the message. If set to `ReceiveAndDelete`, the service + will assume successful receipt of the message and clear it from the queue. The + default is `PeekLock`. + :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode + :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. + :paramtype desired_capabilities: list[bytes] + :keyword max_message_size: The maximum allowed message size negotiated for the Link. + :paramtype max_message_size: int + :keyword link_properties: Metadata to be sent in the Link ATTACH frame. + :paramtype link_properties: dict[str, any] + :keyword link_credit: The Link credit that determines how many + messages the Link will attempt to handle per connection iteration. + The default is 300. + :paramtype link_credit: int + :keyword transport_type: The type of transport protocol that will be used for communicating with + the service. Default is `TransportType.Amqp` in which case port 5671 is used. + If the port 5671 is unavailable/blocked in the network environment, `TransportType.AmqpOverWebsocket` could + be used instead which uses port 443 for communication. + :paramtype transport_type: ~pyamqp.constants.TransportType + :keyword http_proxy: HTTP proxy settings. This must be a dictionary with the following + keys: `'proxy_hostname'` (str value) and `'proxy_port'` (int value). + Additionally the following keys may also be present: `'username', 'password'`. + :paramtype http_proxy: dict[str, str] + :keyword custom_endpoint_address: The custom endpoint address to use for establishing a connection to + the Event Hubs service, allowing network requests to be routed through any application gateways or + other paths needed for the host environment. Default is None. + If port is not specified in the `custom_endpoint_address`, by default port 443 will be used. + :paramtype custom_endpoint_address: str + :keyword connection_verify: Path to the custom CA_BUNDLE file of the SSL certificate which is used to + authenticate the identity of the connection endpoint. + Default is None in which case `certifi.where()` will be used. + :paramtype connection_verify: str + """ async def _client_ready_async(self): """Determine whether the client is ready to start receiving messages. @@ -710,6 +889,3 @@ async def settle_messages_async(self, delivery_id: Union[int, Tuple[int, int]], wait=True ) - -ReceiveClientAsync.__doc__ = \ - f"""{ReceiveClientSync.__doc__[0:43]} asynchronously{ReceiveClientSync.__doc__[43::]}""" diff --git a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py index cd6b5c4ab57b..db0a6e38d520 100644 --- a/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py +++ b/sdk/eventhub/azure-eventhub/azure/eventhub/_pyamqp/client.py @@ -126,7 +126,7 @@ class AMQPClient(object): default is `PeekLock`. :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. - :paramtype desired_capabilities: list[any] + :paramtype desired_capabilities: list[bytes] :keyword max_message_size: The maximum allowed message size negotiated for the Link. :paramtype max_message_size: int :keyword link_properties: Metadata to be sent in the Link ATTACH frame. @@ -423,6 +423,96 @@ def mgmt_request(self, message, **kwargs): class SendClient(AMQPClient): + """ + An AMQP client for sending messages. + :param target: The target AMQP service endpoint. This can either be the URI as + a string or a ~pyamqp.endpoint.Target object. + :type target: str, bytes or ~pyamqp.endpoint.Target + :keyword auth: Authentication for the connection. This should be one of the following: + - pyamqp.authentication.SASLAnonymous + - pyamqp.authentication.SASLPlain + - pyamqp.authentication.SASTokenAuth + - pyamqp.authentication.JWTTokenAuth + If no authentication is supplied, SASLAnnoymous will be used by default. + :paramtype auth: ~pyamqp.authentication + :keyword client_name: The name for the client, also known as the Container ID. + If no name is provided, a random GUID will be used. + :paramtype client_name: str or bytes + :keyword network_trace: Whether to turn on network trace logs. If `True`, trace logs + will be logged at INFO level. Default is `False`. + :paramtype network_trace: bool + :keyword retry_policy: A policy for parsing errors on link, connection and message + disposition to determine whether the error should be retryable. + :paramtype retry_policy: ~pyamqp.error.RetryPolicy + :keyword keep_alive_interval: If set, a thread will be started to keep the connection + alive during periods of user inactivity. The value will determine how long the + thread will sleep (in seconds) between pinging the connection. If 0 or None, no + thread will be started. + :paramtype keep_alive_interval: int + :keyword max_frame_size: Maximum AMQP frame size. Default is 63488 bytes. + :paramtype max_frame_size: int + :keyword channel_max: Maximum number of Session channels in the Connection. + :paramtype channel_max: int + :keyword idle_timeout: Timeout in seconds after which the Connection will close + if there is no further activity. + :paramtype idle_timeout: int + :keyword auth_timeout: Timeout in seconds for CBS authentication. Otherwise this value will be ignored. + Default value is 60s. + :paramtype auth_timeout: int + :keyword properties: Connection properties. + :paramtype properties: dict[str, any] + :keyword remote_idle_timeout_empty_frame_send_ratio: Portion of the idle timeout time to wait before sending an + empty frame. The default portion is 50% of the idle timeout value (i.e. `0.5`). + :paramtype remote_idle_timeout_empty_frame_send_ratio: float + :keyword incoming_window: The size of the allowed window for incoming messages. + :paramtype incoming_window: int + :keyword outgoing_window: The size of the allowed window for outgoing messages. + :paramtype outgoing_window: int + :keyword handle_max: The maximum number of concurrent link handles. + :paramtype handle_max: int + :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. + The function must take 4 arguments: source, target, properties and error. + :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.error.AMQPConnectionError] + :keyword send_settle_mode: The mode by which to settle message send + operations. If set to `Unsettled`, the client will wait for a confirmation + from the service that the message was successfully sent. If set to 'Settled', + the client will not wait for confirmation and assume success. + :paramtype send_settle_mode: ~pyamqp.constants.SenderSettleMode + :keyword receive_settle_mode: The mode by which to settle message receive + operations. If set to `PeekLock`, the receiver will lock a message once received until + the client accepts or rejects the message. If set to `ReceiveAndDelete`, the service + will assume successful receipt of the message and clear it from the queue. The + default is `PeekLock`. + :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode + :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. + :paramtype desired_capabilities: list[bytes] + :keyword max_message_size: The maximum allowed message size negotiated for the Link. + :paramtype max_message_size: int + :keyword link_properties: Metadata to be sent in the Link ATTACH frame. + :paramtype link_properties: dict[str, any] + :keyword link_credit: The Link credit that determines how many + messages the Link will attempt to handle per connection iteration. + The default is 300. + :paramtype link_credit: int + :keyword transport_type: The type of transport protocol that will be used for communicating with + the service. Default is `TransportType.Amqp` in which case port 5671 is used. + If the port 5671 is unavailable/blocked in the network environment, `TransportType.AmqpOverWebsocket` could + be used instead which uses port 443 for communication. + :paramtype transport_type: ~pyamqp.constants.TransportType + :keyword http_proxy: HTTP proxy settings. This must be a dictionary with the following + keys: `'proxy_hostname'` (str value) and `'proxy_port'` (int value). + Additionally the following keys may also be present: `'username', 'password'`. + :paramtype http_proxy: dict[str, str] + :keyword custom_endpoint_address: The custom endpoint address to use for establishing a connection to + the service, allowing network requests to be routed through any application gateways or + other paths needed for the host environment. Default is None. + If port is not specified in the `custom_endpoint_address`, by default port 443 will be used. + :paramtype custom_endpoint_address: str + :keyword connection_verify: Path to the custom CA_BUNDLE file of the SSL certificate which is used to + authenticate the identity of the connection endpoint. + Default is None in which case `certifi.where()` will be used. + :paramtype connection_verify: str + """ def __init__(self, hostname, target, **kwargs): self.target = target @@ -557,17 +647,98 @@ def send_message(self, message, **kwargs): """ self._do_retryable_operation(self._send_message_impl, message=message, **kwargs) -SendClient.__doc__ = \ -f""" - An AMQP client for sending messages. - {AMQPClient.__doc__[15:93]} - :param target: The target AMQP service endpoint. This can either be the URI as - a string or a ~pyamqp.endpoint.Target object. - :type target: str, bytes or ~pyamqp.endpoint.Target {AMQPClient.__doc__[93::]} -""" - class ReceiveClient(AMQPClient): + """ + An AMQP client for receiving messages. + :param source: The source AMQP service endpoint. This can either be the URI as + a string or a ~pyamqp.endpoint.Source object. + :type source: str, bytes or ~pyamqp.endpoint.Source + :keyword auth: Authentication for the connection. This should be one of the following: + - pyamqp.authentication.SASLAnonymous + - pyamqp.authentication.SASLPlain + - pyamqp.authentication.SASTokenAuth + - pyamqp.authentication.JWTTokenAuth + If no authentication is supplied, SASLAnnoymous will be used by default. + :paramtype auth: ~pyamqp.authentication + :keyword client_name: The name for the client, also known as the Container ID. + If no name is provided, a random GUID will be used. + :paramtype client_name: str or bytes + :keyword network_trace: Whether to turn on network trace logs. If `True`, trace logs + will be logged at INFO level. Default is `False`. + :paramtype network_trace: bool + :keyword retry_policy: A policy for parsing errors on link, connection and message + disposition to determine whether the error should be retryable. + :paramtype retry_policy: ~pyamqp.error.RetryPolicy + :keyword keep_alive_interval: If set, a thread will be started to keep the connection + alive during periods of user inactivity. The value will determine how long the + thread will sleep (in seconds) between pinging the connection. If 0 or None, no + thread will be started. + :paramtype keep_alive_interval: int + :keyword max_frame_size: Maximum AMQP frame size. Default is 63488 bytes. + :paramtype max_frame_size: int + :keyword channel_max: Maximum number of Session channels in the Connection. + :paramtype channel_max: int + :keyword idle_timeout: Timeout in seconds after which the Connection will close + if there is no further activity. + :paramtype idle_timeout: int + :keyword auth_timeout: Timeout in seconds for CBS authentication. Otherwise this value will be ignored. + Default value is 60s. + :paramtype auth_timeout: int + :keyword properties: Connection properties. + :paramtype properties: dict[str, any] + :keyword remote_idle_timeout_empty_frame_send_ratio: Portion of the idle timeout time to wait before sending an + empty frame. The default portion is 50% of the idle timeout value (i.e. `0.5`). + :paramtype remote_idle_timeout_empty_frame_send_ratio: float + :keyword incoming_window: The size of the allowed window for incoming messages. + :paramtype incoming_window: int + :keyword outgoing_window: The size of the allowed window for outgoing messages. + :paramtype outgoing_window: int + :keyword handle_max: The maximum number of concurrent link handles. + :paramtype handle_max: int + :keyword on_attach: A callback function to be run on receipt of an ATTACH frame. + The function must take 4 arguments: source, target, properties and error. + :paramtype on_attach: func[~pyamqp.endpoint.Source, ~pyamqp.endpoint.Target, dict, ~pyamqp.error.AMQPConnectionError] + :keyword send_settle_mode: The mode by which to settle message send + operations. If set to `Unsettled`, the client will wait for a confirmation + from the service that the message was successfully sent. If set to 'Settled', + the client will not wait for confirmation and assume success. + :paramtype send_settle_mode: ~pyamqp.constants.SenderSettleMode + :keyword receive_settle_mode: The mode by which to settle message receive + operations. If set to `PeekLock`, the receiver will lock a message once received until + the client accepts or rejects the message. If set to `ReceiveAndDelete`, the service + will assume successful receipt of the message and clear it from the queue. The + default is `PeekLock`. + :paramtype receive_settle_mode: ~pyamqp.constants.ReceiverSettleMode + :keyword desired_capabilities: The extension capabilities desired from the peer endpoint. + :paramtype desired_capabilities: list[bytes] + :keyword max_message_size: The maximum allowed message size negotiated for the Link. + :paramtype max_message_size: int + :keyword link_properties: Metadata to be sent in the Link ATTACH frame. + :paramtype link_properties: dict[str, any] + :keyword link_credit: The Link credit that determines how many + messages the Link will attempt to handle per connection iteration. + The default is 300. + :paramtype link_credit: int + :keyword transport_type: The type of transport protocol that will be used for communicating with + the service. Default is `TransportType.Amqp` in which case port 5671 is used. + If the port 5671 is unavailable/blocked in the network environment, `TransportType.AmqpOverWebsocket` could + be used instead which uses port 443 for communication. + :paramtype transport_type: ~pyamqp.constants.TransportType + :keyword http_proxy: HTTP proxy settings. This must be a dictionary with the following + keys: `'proxy_hostname'` (str value) and `'proxy_port'` (int value). + Additionally the following keys may also be present: `'username', 'password'`. + :paramtype http_proxy: dict[str, str] + :keyword custom_endpoint_address: The custom endpoint address to use for establishing a connection to + the service, allowing network requests to be routed through any application gateways or + other paths needed for the host environment. Default is None. + If port is not specified in the `custom_endpoint_address`, by default port 443 will be used. + :paramtype custom_endpoint_address: str + :keyword connection_verify: Path to the custom CA_BUNDLE file of the SSL certificate which is used to + authenticate the identity of the connection endpoint. + Default is None in which case `certifi.where()` will be used. + :paramtype connection_verify: str + """ def __init__(self, hostname, source, **kwargs): self.source = source @@ -796,12 +967,3 @@ def settle_messages(self, delivery_id: Union[int, Tuple[int, int]], outcome: str batchable=batchable, wait=True ) - -ReceiveClient.__doc__ = \ -f""" - An AMQP client for receiving messages. - {AMQPClient.__doc__[15:93]} - :param source: The source AMQP service endpoint. This can either be the URI as - a string or a ~pyamqp.endpoint.Source object. - :type source: str, bytes or ~pyamqp.endpoint.Source {AMQPClient.__doc__[93::]} -"""