rabbitmq-amqp-python-client 0.7.0__tar.gz → 0.8.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/PKG-INFO +2 -2
  2. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/README.md +1 -1
  3. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/pyproject.toml +1 -1
  4. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/__init__.py +2 -0
  5. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/asyncio/environment.py +32 -13
  6. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/connection.py +3 -0
  7. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/entities.py +42 -0
  8. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/environment.py +30 -12
  9. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/utils.py +3 -2
  10. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/LICENSE +0 -0
  11. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/address_helper.py +0 -0
  12. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/amqp_consumer_handler.py +0 -0
  13. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/asyncio/__init__.py +0 -0
  14. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/asyncio/connection.py +0 -0
  15. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/asyncio/consumer.py +0 -0
  16. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/asyncio/management.py +0 -0
  17. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/asyncio/publisher.py +0 -0
  18. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/common.py +0 -0
  19. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/consumer.py +0 -0
  20. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/delivery_context.py +0 -0
  21. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/exceptions.py +0 -0
  22. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/management.py +0 -0
  23. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/options.py +0 -0
  24. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/publisher.py +0 -0
  25. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/py.typed +0 -0
  26. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/__init__.py +0 -0
  27. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/_common.py +0 -0
  28. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/_condition.py +0 -0
  29. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/_data.py +0 -0
  30. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/_delivery.py +0 -0
  31. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/_endpoints.py +0 -0
  32. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/_events.py +0 -0
  33. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/_exceptions.py +0 -0
  34. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/_flow_properties.py +0 -0
  35. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/_handler.py +0 -0
  36. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/_handlers.py +0 -0
  37. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/_io.py +0 -0
  38. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/_message.py +0 -0
  39. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/_reactor.py +0 -0
  40. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/_selectable.py +0 -0
  41. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/_tracing.py +0 -0
  42. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/_transport.py +0 -0
  43. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/_url.py +0 -0
  44. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/_utils.py +0 -0
  45. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/_wrapper.py +0 -0
  46. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/handlers.py +0 -0
  47. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/py.typed +0 -0
  48. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/reactor.py +0 -0
  49. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/tracing.py +0 -0
  50. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/qpid/proton/utils.py +0 -0
  51. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/queues.py +0 -0
  52. {rabbitmq_amqp_python_client-0.7.0 → rabbitmq_amqp_python_client-0.8.0}/rabbitmq_amqp_python_client/ssl_configuration.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rabbitmq-amqp-python-client
3
- Version: 0.7.0
3
+ Version: 0.8.0
4
4
  Summary: Python RabbitMQ client for AMQP 1.0 protocol
5
5
  License: Apache-2.0 license
6
6
  License-File: LICENSE
@@ -19,7 +19,7 @@ Requires-Dist: typing-extensions (>=4.15.0,<5.0.0)
19
19
  Description-Content-Type: text/markdown
20
20
 
21
21
  ## RabbitMQ AMQP 1.0 Python Client
22
- This library is meant to be used with RabbitMQ `4.x`. Suitable for testing in pre-production environments.
22
+ This library is meant to be used with RabbitMQ `4.x`.
23
23
 
24
24
  The client is distributed via [`PIP`](https://pypi.org/project/rabbitmq-amqp-python-client/):
25
25
  ```bash
@@ -1,5 +1,5 @@
1
1
  ## RabbitMQ AMQP 1.0 Python Client
2
- This library is meant to be used with RabbitMQ `4.x`. Suitable for testing in pre-production environments.
2
+ This library is meant to be used with RabbitMQ `4.x`.
3
3
 
4
4
  The client is distributed via [`PIP`](https://pypi.org/project/rabbitmq-amqp-python-client/):
5
5
  ```bash
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "rabbitmq-amqp-python-client"
3
- version = "0.7.0"
3
+ version = "0.8.0"
4
4
  description = "Python RabbitMQ client for AMQP 1.0 protocol"
5
5
  authors = ["RabbitMQ team"]
6
6
  license = "Apache-2.0 license"
@@ -15,6 +15,7 @@ from .connection import Connection
15
15
  from .consumer import Consumer
16
16
  from .entities import (
17
17
  AbcConsumerOptions,
18
+ AmqpUri,
18
19
  ConsumerOptions,
19
20
  ConsumerSettleStrategy,
20
21
  ExchangeCustomSpecification,
@@ -73,6 +74,7 @@ del metadata
73
74
  OutcomeState = Disposition
74
75
 
75
76
  __all__ = [
77
+ "AmqpUri",
76
78
  "Connection",
77
79
  "Management",
78
80
  "ExchangeSpecification",
@@ -4,7 +4,11 @@ import asyncio
4
4
  import logging
5
5
  from typing import Optional, Union
6
6
 
7
- from ..entities import OAuth2Options, RecoveryConfiguration
7
+ from ..entities import (
8
+ AmqpUri,
9
+ OAuth2Options,
10
+ RecoveryConfiguration,
11
+ )
8
12
  from ..ssl_configuration import (
9
13
  PosixSslConfigurationContext,
10
14
  WinSslConfigurationContext,
@@ -38,6 +42,8 @@ class AsyncEnvironment:
38
42
  uri: Optional[str] = None,
39
43
  # multi-node mode
40
44
  uris: Optional[list[str]] = None,
45
+ # structured single-node mode
46
+ amqp_uri: Optional[AmqpUri] = None,
41
47
  ssl_context: Union[
42
48
  PosixSslConfigurationContext, WinSslConfigurationContext, None
43
49
  ] = None,
@@ -47,25 +53,38 @@ class AsyncEnvironment:
47
53
  """
48
54
  Initialize AsyncEnvironment.
49
55
 
56
+ Exactly one of ``uri``, ``uris``, or ``amqp_uri`` must be provided.
57
+
50
58
  Args:
51
- uri: Single node connection URI
52
- uris: List of URIs for multi-node setup
53
- ssl_context: SSL configuration for secure connections
54
- oauth2_options: OAuth2 options for authentication
55
- recovery_configuration: Configuration for connection recovery
59
+ uri: Single node connection URI string (e.g. ``"amqp://guest:guest@localhost:5672/"``).
60
+ uris: List of URI strings for multi-node setup.
61
+ amqp_uri: Structured single-node connection parameters as an :class:`AmqpUri`
62
+ instance. Converted to a URI string internally.
63
+ ssl_context: SSL configuration for secure connections.
64
+ oauth2_options: OAuth2 options for authentication.
65
+ recovery_configuration: Configuration for connection recovery.
56
66
 
57
67
  Raises:
58
- ValueError: If both 'uri' and 'uris' are specified or if neither is specified.
68
+ ValueError: If more than one of 'uri', 'uris', 'amqp_uri' is specified,
69
+ or if none is specified.
59
70
  """
60
- if uri is not None and uris is not None:
71
+ set_count = sum(x is not None for x in [uri, uris, amqp_uri])
72
+ if set_count > 1:
73
+ raise ValueError(
74
+ "Cannot specify more than one of 'uri', 'uris', or 'amqp_uri'. "
75
+ "Choose one connection mode."
76
+ )
77
+ if set_count == 0:
61
78
  raise ValueError(
62
- "Cannot specify both 'uri' and 'uris'. Choose one connection mode."
79
+ "Must specify exactly one of 'uri', 'uris', or 'amqp_uri' for connection."
63
80
  )
64
- if uri is None and uris is None:
65
- raise ValueError("Must specify either 'uri' or 'uris' for connection.")
66
81
 
67
- self._uri = uri
68
- self._uris = uris
82
+ if amqp_uri is not None:
83
+ self._uri: Optional[str] = amqp_uri.to_uri()
84
+ self._uris: Optional[list[str]] = None
85
+ else:
86
+ self._uri = uri
87
+ self._uris = uris
69
88
  self._ssl_context = ssl_context
70
89
  self._oauth2_options = oauth2_options
71
90
  self._recovery_configuration = recovery_configuration
@@ -274,6 +274,9 @@ class Connection:
274
274
  else:
275
275
  typing_extensions.assert_never(self._conf_ssl_context)
276
276
  self._ssl_domain.set_trusted_ca_db(ca_cert)
277
+ self._ssl_domain.set_peer_authentication(
278
+ SSLDomain.VERIFY_PEER_NAME, ca_cert
279
+ )
277
280
 
278
281
  # for mutual authentication
279
282
  if self._conf_ssl_context.client_cert is not None:
@@ -551,6 +551,48 @@ class RecoveryConfiguration:
551
551
  MaxReconnectAttempts: int = 5
552
552
 
553
553
 
554
+ @dataclass
555
+ class AmqpUri:
556
+ """
557
+ Configuration for an AMQP connection using individual fields.
558
+
559
+ Provides a structured alternative to a raw URI string, building the
560
+ connection URI from its component parts.
561
+
562
+ Attributes:
563
+ schema: The URI scheme (``"amqp"`` or ``"amqps"``). Defaults to ``"amqp"``.
564
+ host: The broker hostname or IP address. Defaults to ``"localhost"``.
565
+ port: The broker port. Defaults to ``5672``.
566
+ user: The authentication username. Defaults to ``"guest"``.
567
+ password: The authentication password. Defaults to ``"guest"``.
568
+ vhost: The target virtual host. Defaults to ``"/"``.
569
+ """
570
+
571
+ schema: str = "amqp"
572
+ host: str = "localhost"
573
+ port: int = 5672
574
+ user: str = "guest"
575
+ password: str = "guest"
576
+ vhost: str = "/"
577
+
578
+ def to_uri(self) -> str:
579
+ """
580
+ Build an AMQP URI string from the individual fields.
581
+
582
+ Returns:
583
+ str: A URI in the form ``schema://user:password@host:port/vhost``.
584
+ """
585
+ from urllib.parse import quote
586
+
587
+ user_enc = quote(self.user, safe="")
588
+ password_enc = quote(self.password, safe="")
589
+ if self.vhost == "/":
590
+ vhost_path = "/"
591
+ else:
592
+ vhost_path = "/" + quote(self.vhost, safe="")
593
+ return f"{self.schema}://{user_enc}:{password_enc}@{self.host}:{self.port}{vhost_path}"
594
+
595
+
554
596
  @dataclass
555
597
  class OAuth2Options:
556
598
  token: str
@@ -9,7 +9,11 @@ from typing import (
9
9
  )
10
10
 
11
11
  from .connection import Connection
12
- from .entities import OAuth2Options, RecoveryConfiguration
12
+ from .entities import (
13
+ AmqpUri,
14
+ OAuth2Options,
15
+ RecoveryConfiguration,
16
+ )
13
17
  from .ssl_configuration import (
14
18
  PosixSslConfigurationContext,
15
19
  WinSslConfigurationContext,
@@ -38,6 +42,8 @@ class Environment:
38
42
  uri: Optional[str] = None,
39
43
  # multi-node mode
40
44
  uris: Optional[list[str]] = None,
45
+ # structured single-node mode
46
+ amqp_uri: Optional[AmqpUri] = None,
41
47
  ssl_context: Union[
42
48
  PosixSslConfigurationContext, WinSslConfigurationContext, None
43
49
  ] = None,
@@ -49,21 +55,33 @@ class Environment:
49
55
 
50
56
  Creates an empty list to track active connections.
51
57
 
52
- Args:
53
- uri: Single node connection URI
54
- uris: List of URIs for multi-node setup
55
- ssl_context: SSL configuration for secure connections
56
- on_disconnection_handler: Callback for handling disconnection events
58
+ Exactly one of ``uri``, ``uris``, or ``amqp_uri`` must be provided.
57
59
 
60
+ Args:
61
+ uri: Single node connection URI string (e.g. ``"amqp://guest:guest@localhost:5672/"``).
62
+ uris: List of URI strings for multi-node setup.
63
+ amqp_uri: Structured single-node connection parameters as an :class:`AmqpUri`
64
+ instance. Converted to a URI string internally.
65
+ ssl_context: SSL configuration for secure connections.
66
+ oauth2_options: OAuth2 authentication options.
67
+ recovery_configuration: Automatic reconnection configuration.
58
68
  """
59
- if uri is not None and uris is not None:
69
+ set_count = sum(x is not None for x in [uri, uris, amqp_uri])
70
+ if set_count > 1:
71
+ raise ValueError(
72
+ "Cannot specify more than one of 'uri', 'uris', or 'amqp_uri'. "
73
+ "Choose one connection mode."
74
+ )
75
+ if set_count == 0:
60
76
  raise ValueError(
61
- "Cannot specify both 'uri' and 'uris'. Choose one connection mode."
77
+ "Must specify exactly one of 'uri', 'uris', or 'amqp_uri' for connection."
62
78
  )
63
- if uri is None and uris is None:
64
- raise ValueError("Must specify either 'uri' or 'uris' for connection.")
65
- self._uri = uri
66
- self._uris = uris
79
+ if amqp_uri is not None:
80
+ self._uri: Optional[str] = amqp_uri.to_uri()
81
+ self._uris: Optional[list[str]] = None
82
+ else:
83
+ self._uri = uri
84
+ self._uris = uris
67
85
  self._ssl_context = ssl_context
68
86
  self._recovery_configuration = recovery_configuration
69
87
  self._connections: list[Connection] = []
@@ -12,17 +12,18 @@ def validate_annotations(annotations: []) -> bool: # type: ignore
12
12
  class Converter:
13
13
 
14
14
  @staticmethod
15
- def bytes_to_string(body: bytes) -> str:
15
+ def bytes_to_string(body: bytes, encoding: str = "utf-8") -> str:
16
16
  """
17
17
  Convert the body of a message to a string.
18
18
 
19
19
  Args:
20
20
  body: The body of the message
21
+ encoding: The character encoding to use for decoding (default: utf-8)
21
22
 
22
23
  Returns:
23
24
  str: The string representation of the body
24
25
  """
25
- return "".join(map(chr, body))
26
+ return bytes(body).decode(encoding)
26
27
 
27
28
  @staticmethod
28
29
  def string_to_bytes(body: str) -> bytes: