Package proton

[frames] | no frames]

# Source Code for Package proton

       1  #
       2  # Licensed to the Apache Software Foundation (ASF) under one
       3  # or more contributor license agreements.  See the NOTICE file
       4  # distributed with this work for additional information
       5  # regarding copyright ownership.  The ASF licenses this file
       6  # to you under the Apache License, Version 2.0 (the
       7  # "License"); you may not use this file except in compliance
       8  # with the License.  You may obtain a copy of the License at
       9  #
      10  #   http://www.apache.org/licenses/LICENSE-2.0
      11  #
      12  # Unless required by applicable law or agreed to in writing,
      13  # software distributed under the License is distributed on an
      14  # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
      15  # KIND, either express or implied.  See the License for the
      16  # specific language governing permissions and limitations
      17  # under the License.
      18  #
      19
      20  """
      21  The proton module defines a suite of APIs that implement the AMQP 1.0
      22  protocol.
      23
      24  The proton APIs consist of the following classes:
      25
      26   - L{Messenger} -- A messaging endpoint.
      27   - L{Message}   -- A class for creating and/or accessing AMQP message content.
      28   - L{Data}      -- A class for creating and/or accessing arbitrary AMQP encoded
      29                    data.
      30
      31  """
      32  from __future__ import absolute_import
      33
      34  from cproton import *
      35  from .wrapper import Wrapper
      36  from proton import _compat
      37
      38  import weakref, socket, sys, threading
      39
      40  try:
      41    import uuid
      42
      43 -  def generate_uuid():
      44      return uuid.uuid4()
      45
      46  except ImportError:
      47    """
      48    No 'native' UUID support.  Provide a very basic UUID type that is a compatible subset of the uuid type provided by more modern python releases.
      49    """
      50    import struct
      51 -  class uuid:
      52 -    class UUID:
      53 -      def __init__(self, hex=None, bytes=None):
      54          if [hex, bytes].count(None) != 1:
      55            raise TypeError("need one of hex or bytes")
      56          if bytes is not None:
      57            self.bytes = bytes
      58          elif hex is not None:
      59            fields=hex.split("-")
      60            fields[4:5] = [fields[4][:4], fields[4][4:]]
      61            self.bytes = struct.pack("!LHHHHL", *[int(x,16) for x in fields])
      62
      63 -      def __cmp__(self, other):
      64          if isinstance(other, uuid.UUID):
      65            return cmp(self.bytes, other.bytes)
      66          else:
      67            return -1
      68
      69 -      def __str__(self):
      70          return "%08x-%04x-%04x-%04x-%04x%08x" % struct.unpack("!LHHHHL", self.bytes)
      71
      72 -      def __repr__(self):
      73          return "UUID(%r)" % str(self)
      74
      75 -      def __hash__(self):
      76          return self.bytes.__hash__()
      77
      78    import os, random, time
      79    rand = random.Random()
      80    rand.seed((os.getpid(), time.time(), socket.gethostname()))
      81 -  def random_uuid():
      82      data = [rand.randint(0, 255) for i in xrange(16)]
      83
      84      # From RFC4122, the version bits are set to 0100
      85      data[6] &= 0x0F
      86      data[6] |= 0x40
      87
      88      # From RFC4122, the top two bits of byte 8 get set to 01
      89      data[8] &= 0x3F
      90      data[8] |= 0x80
      91      return "".join(map(chr, data))
      92
      93 -  def uuid4():
      94      return uuid.UUID(bytes=random_uuid())
      95
      96 -  def generate_uuid():
      97      return uuid4()
      98
      99  #
     100  # Hacks to provide Python2 <---> Python3 compatibility
     101  #
     102  try:
     103    bytes()
     104  except NameError:
     105    bytes = str
     106  try:
     107    long()
     108  except NameError:
     109    long = int
     110  try:
     111    unicode()
     112  except NameError:
     113    unicode = str
     114
     115
     116  VERSION_MAJOR = PN_VERSION_MAJOR
     117  VERSION_MINOR = PN_VERSION_MINOR
     118  VERSION_POINT = PN_VERSION_POINT
     119  VERSION = (VERSION_MAJOR, VERSION_MINOR, VERSION_POINT)
     120  API_LANGUAGE = "C"
     121  IMPLEMENTATION_LANGUAGE = "C"
     122
     123 -class Constant(object):
     124
     125 -  def __init__(self, name):
     126      self.name = name
     127
     128 -  def __repr__(self):
     129      return self.name
     130
     131 -class ProtonException(Exception):
     132    """
     133    The root of the proton exception hierarchy. All proton exception
     134    classes derive from this exception.
     135    """
     136    pass
     137
     138 -class Timeout(ProtonException):
     139    """
     140    A timeout exception indicates that a blocking operation has timed
     141    out.
     142    """
     143    pass
     144
     145 -class Interrupt(ProtonException):
     146    """
     147    An interrupt exception indicaes that a blocking operation was interrupted.
     148    """
     149    pass
     150
     151 -class MessengerException(ProtonException):
     152    """
     153    The root of the messenger exception hierarchy. All exceptions
     154    generated by the messenger class derive from this exception.
     155    """
     156    pass
     157
     158 -class MessageException(ProtonException):
     159    """
     160    The MessageException class is the root of the message exception
     161    hierarhcy. All exceptions generated by the Message class derive from
     162    this exception.
     163    """
     164    pass
     165
     166  EXCEPTIONS = {
     167    PN_TIMEOUT: Timeout,
     168    PN_INTR: Interrupt
     169    }
     170
     171  PENDING = Constant("PENDING")
     172  ACCEPTED = Constant("ACCEPTED")
     173  REJECTED = Constant("REJECTED")
     174  RELEASED = Constant("RELEASED")
     175  MODIFIED = Constant("MODIFIED")
     176  ABORTED = Constant("ABORTED")
     177  SETTLED = Constant("SETTLED")
     178
     179  STATUSES = {
     180    PN_STATUS_ABORTED: ABORTED,
     181    PN_STATUS_ACCEPTED: ACCEPTED,
     182    PN_STATUS_REJECTED: REJECTED,
     183    PN_STATUS_RELEASED: RELEASED,
     184    PN_STATUS_MODIFIED: MODIFIED,
     185    PN_STATUS_PENDING: PENDING,
     186    PN_STATUS_SETTLED: SETTLED,
     187    PN_STATUS_UNKNOWN: None
     188    }
     189
     190  AUTOMATIC = Constant("AUTOMATIC")
     191  MANUAL = Constant("MANUAL")
     192
     193 -class Messenger(object):
     194    """
     195    The L{Messenger} class defines a high level interface for sending
     196    and receiving L{Messages<Message>}. Every L{Messenger} contains a
     197    single logical queue of incoming messages and a single logical queue
     198    of outgoing messages. These messages in these queues may be destined
     199    for, or originate from, a variety of addresses.
     200
     201    The messenger interface is single-threaded.  All methods
     202    except one (L{interrupt}) are intended to be used from within
     203    the messenger thread.
     204
     205
     206    Address Syntax
     207    ==============
     208
     209    An address has the following form::
     210
     211      [ amqp[s]:// ] [user[:password]@] domain [/[name]]
     212
     213    Where domain can be one of::
     214
     215      host | host:port | ip | ip:port | name
     216
     217    The following are valid examples of addresses:
     218
     219     - example.org
     220     - example.org:1234
     221     - amqp://example.org
     222     - amqps://example.org
     223     - example.org/incoming
     224     - amqps://example.org/outgoing
     225     - amqps://fred:trustno1@example.org
     226     - 127.0.0.1:1234
     227     - amqps://127.0.0.1:1234
     228
     229    Sending & Receiving Messages
     230    ============================
     231
     232    The L{Messenger} class works in conjuction with the L{Message} class. The
     233    L{Message} class is a mutable holder of message content.
     234
     235    The L{put} method copies its L{Message} to the outgoing queue, and may
     236    send queued messages if it can do so without blocking.  The L{send}
     237    method blocks until it has sent the requested number of messages,
     238    or until a timeout interrupts the attempt.
     239
     240
     241      >>> message = Message()
     242      >>> for i in range(3):
     243      ...   message.address = "amqp://host/queue"
     244      ...   message.subject = "Hello World %i" % i
     245      ...   messenger.put(message)
     246      >>> messenger.send()
     247
     248    Similarly, the L{recv} method receives messages into the incoming
     249    queue, and may block as it attempts to receive the requested number
     250    of messages,  or until timeout is reached. It may receive fewer
     251    than the requested number.  The L{get} method pops the
     252    eldest L{Message} off the incoming queue and copies it into the L{Message}
     253    object that you supply.  It will not block.
     254
     255
     256      >>> message = Message()
     257      >>> messenger.recv(10):
     258      >>> while messenger.incoming > 0:
     259      ...   messenger.get(message)
     260      ...   print message.subject
     261      Hello World 0
     262      Hello World 1
     263      Hello World 2
     264
     265    The blocking flag allows you to turn off blocking behavior entirely,
     266    in which case L{send} and L{recv} will do whatever they can without
     267    blocking, and then return.  You can then look at the number
     268    of incoming and outgoing messages to see how much outstanding work
     269    still remains.
     270    """
     271
     272 -  def __init__(self, name=None):
     273      """
     274      Construct a new L{Messenger} with the given name. The name has
     275      global scope. If a NULL name is supplied, a UUID based name will
     276      be chosen.
     277
     278      @type name: string
     279      @param name: the name of the messenger or None
     280
     281      """
     282      self._mng = pn_messenger(name)
     283      self._selectables = {}
     284
     285 -  def __del__(self):
     286      """
     287      Destroy the L{Messenger}.  This will close all connections that
     288      are managed by the L{Messenger}.  Call the L{stop} method before
     289      destroying the L{Messenger}.
     290      """
     291      if hasattr(self, "_mng"):
     292        pn_messenger_free(self._mng)
     293        del self._mng
     294
     295 -  def _check(self, err):
     296      if err < 0:
     297        if (err == PN_INPROGRESS):
     298          return
     299        exc = EXCEPTIONS.get(err, MessengerException)
     300        raise exc("[%s]: %s" % (err, pn_error_text(pn_messenger_error(self._mng))))
     301      else:
     302        return err
     303
     304    @property
     305 -  def name(self):
     306      """
     307      The name of the L{Messenger}.
     308      """
     309      return pn_messenger_name(self._mng)
     310
     311 -  def _get_certificate(self):
     312      return pn_messenger_get_certificate(self._mng)
     313
     314 -  def _set_certificate(self, value):
     315      self._check(pn_messenger_set_certificate(self._mng, value))
     316
     317    certificate = property(_get_certificate, _set_certificate,
     318                           doc="""
     319  Path to a certificate file for the L{Messenger}. This certificate is
     320  used when the L{Messenger} accepts or establishes SSL/TLS connections.
     321  This property must be specified for the L{Messenger} to accept
     322  incoming SSL/TLS connections and to establish client authenticated
     323  outgoing SSL/TLS connection. Non client authenticated outgoing SSL/TLS
     324  connections do not require this property.
     325  """)
     326
     327 -  def _get_private_key(self):
     328      return pn_messenger_get_private_key(self._mng)
     329
     330 -  def _set_private_key(self, value):
     331      self._check(pn_messenger_set_private_key(self._mng, value))
     332
     333    private_key = property(_get_private_key, _set_private_key,
     334                           doc="""
     335  Path to a private key file for the L{Messenger's<Messenger>}
     336  certificate. This property must be specified for the L{Messenger} to
     337  accept incoming SSL/TLS connections and to establish client
     338  authenticated outgoing SSL/TLS connection. Non client authenticated
     339  SSL/TLS connections do not require this property.
     340  """)
     341
     342 -  def _get_password(self):
     343      return pn_messenger_get_password(self._mng)
     344
     345 -  def _set_password(self, value):
     346      self._check(pn_messenger_set_password(self._mng, value))
     347
     348    password = property(_get_password, _set_password,
     349                        doc="""
     350  This property contains the password for the L{Messenger.private_key}
     351  file, or None if the file is not encrypted.
     352  """)
     353
     354 -  def _get_trusted_certificates(self):
     355      return pn_messenger_get_trusted_certificates(self._mng)
     356
     357 -  def _set_trusted_certificates(self, value):
     358      self._check(pn_messenger_set_trusted_certificates(self._mng, value))
     359
     360    trusted_certificates = property(_get_trusted_certificates,
     361                                    _set_trusted_certificates,
     362                                    doc="""
     363  A path to a database of trusted certificates for use in verifying the
     364  peer on an SSL/TLS connection. If this property is None, then the peer
     365  will not be verified.
     366  """)
     367
     368 -  def _get_timeout(self):
     369      t = pn_messenger_get_timeout(self._mng)
     370      if t == -1:
     371        return None
     372      else:
     373        return millis2secs(t)
     374
     375 -  def _set_timeout(self, value):
     376      if value is None:
     377        t = -1
     378      else:
     379        t = secs2millis(value)
     380      self._check(pn_messenger_set_timeout(self._mng, t))
     381
     382    timeout = property(_get_timeout, _set_timeout,
     383                       doc="""
     384  The timeout property contains the default timeout for blocking
     385  operations performed by the L{Messenger}.
     386  """)
     387
     388 -  def _is_blocking(self):
     389      return pn_messenger_is_blocking(self._mng)
     390
     391 -  def _set_blocking(self, b):
     392      self._check(pn_messenger_set_blocking(self._mng, b))
     393
     394    blocking = property(_is_blocking, _set_blocking,
     395                        doc="""
     396  Enable or disable blocking behavior during L{Message} sending
     397  and receiving.  This affects every blocking call, with the
     398  exception of L{work}.  Currently, the affected calls are
     399  L{send}, L{recv}, and L{stop}.
     400  """)
     401
     402 -  def _is_passive(self):
     403      return pn_messenger_is_passive(self._mng)
     404
     405 -  def _set_passive(self, b):
     406      self._check(pn_messenger_set_passive(self._mng, b))
     407
     408    passive = property(_is_passive, _set_passive,
     409                        doc="""
     410  When passive is set to true, Messenger will not attempt to perform I/O
     411  internally. In this mode it is necessary to use the selectables API to
     412  drive any I/O needed to perform requested actions. In this mode
     413  Messenger will never block.
     414  """)
     415
     416 -  def _get_incoming_window(self):
     417      return pn_messenger_get_incoming_window(self._mng)
     418
     419 -  def _set_incoming_window(self, window):
     420      self._check(pn_messenger_set_incoming_window(self._mng, window))
     421
     422    incoming_window = property(_get_incoming_window, _set_incoming_window,
     423                               doc="""
     424  The incoming tracking window for the messenger. The messenger will
     425  track the remote status of this many incoming deliveries after they
     426  have been accepted or rejected. Defaults to zero.
     427
     428  L{Messages<Message>} enter this window only when you take them into your application
     429  using L{get}.  If your incoming window size is I{n}, and you get I{n}+1 L{messages<Message>}
     430  without explicitly accepting or rejecting the oldest message, then the
     431  message that passes beyond the edge of the incoming window will be assigned
     432  the default disposition of its link.
     433  """)
     434
     435 -  def _get_outgoing_window(self):
     436      return pn_messenger_get_outgoing_window(self._mng)
     437
     438 -  def _set_outgoing_window(self, window):
     439      self._check(pn_messenger_set_outgoing_window(self._mng, window))
     440
     441    outgoing_window = property(_get_outgoing_window, _set_outgoing_window,
     442                               doc="""
     443  The outgoing tracking window for the messenger. The messenger will
     444  track the remote status of this many outgoing deliveries after calling
     445  send. Defaults to zero.
     446
     447  A L{Message} enters this window when you call the put() method with the
     448  message.  If your outgoing window size is I{n}, and you call L{put} I{n}+1
     449  times, status information will no longer be available for the
     450  first message.
     451  """)
     452
     453 -  def start(self):
     454      """
     455      Currently a no-op placeholder.
     456      For future compatibility, do not L{send} or L{recv} messages
     457      before starting the L{Messenger}.
     458      """
     459      self._check(pn_messenger_start(self._mng))
     460
     461 -  def stop(self):
     462      """
     463      Transitions the L{Messenger} to an inactive state. An inactive
     464      L{Messenger} will not send or receive messages from its internal
     465      queues. A L{Messenger} should be stopped before being discarded to
     466      ensure a clean shutdown handshake occurs on any internally managed
     467      connections.
     468      """
     469      self._check(pn_messenger_stop(self._mng))
     470
     471    @property
     472 -  def stopped(self):
     473      """
     474      Returns true iff a L{Messenger} is in the stopped state.
     475      This function does not block.
     476      """
     477      return pn_messenger_stopped(self._mng)
     478
     479 -  def subscribe(self, source):
     480      """
     481      Subscribes the L{Messenger} to messages originating from the
     482      specified source. The source is an address as specified in the
     483      L{Messenger} introduction with the following addition. If the
     484      domain portion of the address begins with the '~' character, the
     485      L{Messenger} will interpret the domain as host/port, bind to it,
     486      and listen for incoming messages. For example "~0.0.0.0",
     487      "amqp://~0.0.0.0", and "amqps://~0.0.0.0" will all bind to any
     488      local interface and listen for incoming messages with the last
     489      variant only permitting incoming SSL connections.
     490
     491      @type source: string
     492      @param source: the source of messages to subscribe to
     493      """
     494      sub_impl = pn_messenger_subscribe(self._mng, source)
     495      if not sub_impl:
     496        self._check(pn_error_code(pn_messenger_error(self._mng)))
     497        raise MessengerException("Cannot subscribe to %s"%source)
     498      return Subscription(sub_impl)
     499
     500 -  def put(self, message):
     501      """
     502      Places the content contained in the message onto the outgoing
     503      queue of the L{Messenger}. This method will never block, however
     504      it will send any unblocked L{Messages<Message>} in the outgoing
     505      queue immediately and leave any blocked L{Messages<Message>}
     506      remaining in the outgoing queue. The L{send} call may be used to
     507      block until the outgoing queue is empty. The L{outgoing} property
     508      may be used to check the depth of the outgoing queue.
     509
     510      When the content in a given L{Message} object is copied to the outgoing
     511      message queue, you may then modify or discard the L{Message} object
     512      without having any impact on the content in the outgoing queue.
     513
     514      This method returns an outgoing tracker for the L{Message}.  The tracker
     515      can be used to determine the delivery status of the L{Message}.
     516
     517      @type message: Message
     518      @param message: the message to place in the outgoing queue
     519      @return: a tracker
     520      """
     521      message._pre_encode()
     522      self._check(pn_messenger_put(self._mng, message._msg))
     523      return pn_messenger_outgoing_tracker(self._mng)
     524
     525 -  def status(self, tracker):
     526      """
     527      Gets the last known remote state of the delivery associated with
     528      the given tracker.
     529
     530      @type tracker: tracker
     531      @param tracker: the tracker whose status is to be retrieved
     532
     533      @return: one of None, PENDING, REJECTED, MODIFIED, or ACCEPTED
     534      """
     535      disp = pn_messenger_status(self._mng, tracker);
     536      return STATUSES.get(disp, disp)
     537
     538 -  def buffered(self, tracker):
     539      """
     540      Checks if the delivery associated with the given tracker is still
     541      waiting to be sent.
     542
     543      @type tracker: tracker
     544      @param tracker: the tracker whose status is to be retrieved
     545
     546      @return: true if delivery is still buffered
     547      """
     548      return pn_messenger_buffered(self._mng, tracker);
     549
     550 -  def settle(self, tracker=None):
     551      """
     552      Frees a L{Messenger} from tracking the status associated with a given
     553      tracker. If you don't supply a tracker, all outgoing L{messages<Message>} up
     554      to the most recent will be settled.
     555      """
     556      if tracker is None:
     557        tracker = pn_messenger_outgoing_tracker(self._mng)
     558        flags = PN_CUMULATIVE
     559      else:
     560        flags = 0
     561      self._check(pn_messenger_settle(self._mng, tracker, flags))
     562
     563 -  def send(self, n=-1):
     564      """
     565      This call will block until the indicated number of L{messages<Message>}
     566      have been sent, or until the operation times out.  If n is -1 this call will
     567      block until all outgoing L{messages<Message>} have been sent. If n is 0 then
     568      this call will send whatever it can without blocking.
     569      """
     570      self._check(pn_messenger_send(self._mng, n))
     571
     572 -  def recv(self, n=None):
     573      """
     574      Receives up to I{n} L{messages<Message>} into the incoming queue.  If no value
     575      for I{n} is supplied, this call will receive as many L{messages<Message>} as it
     576      can buffer internally.  If the L{Messenger} is in blocking mode, this
     577      call will block until at least one L{Message} is available in the
     578      incoming queue.
     579      """
     580      if n is None:
     581        n = -1
     582      self._check(pn_messenger_recv(self._mng, n))
     583
     584 -  def work(self, timeout=None):
     585      """
     586      Sends or receives any outstanding L{messages<Message>} queued for a L{Messenger}.
     587      This will block for the indicated timeout.
     588      This method may also do I/O work other than sending and receiving
     589      L{messages<Message>}.  For example, closing connections after messenger.L{stop}()
     590      has been called.
     591      """
     592      if timeout is None:
     593        t = -1
     594      else:
     595        t = secs2millis(timeout)
     596      err = pn_messenger_work(self._mng, t)
     597      if (err == PN_TIMEOUT):
     598        return False
     599      else:
     600        self._check(err)
     601        return True
     602
     603    @property
     604 -  def receiving(self):
     605      return pn_messenger_receiving(self._mng)
     606
     607 -  def interrupt(self):
     608      """
     609      The L{Messenger} interface is single-threaded.
     610      This is the only L{Messenger} function intended to be called
     611      from outside of the L{Messenger} thread.
     612      Call this from a non-messenger thread to interrupt
     613      a L{Messenger} that is blocking.
     614      This will cause any in-progress blocking call to throw
     615      the L{Interrupt} exception.  If there is no currently blocking
     616      call, then the next blocking call will be affected, even if it
     617      is within the same thread that interrupt was called from.
     618      """
     619      self._check(pn_messenger_interrupt(self._mng))
     620
     621 -  def get(self, message=None):
     622      """
     623      Moves the message from the head of the incoming message queue into
     624      the supplied message object. Any content in the message will be
     625      overwritten.
     626
     627      A tracker for the incoming L{Message} is returned.  The tracker can
     628      later be used to communicate your acceptance or rejection of the
     629      L{Message}.
     630
     631      If None is passed in for the L{Message} object, the L{Message}
     632      popped from the head of the queue is discarded.
     633
     634      @type message: Message
     635      @param message: the destination message object
     636      @return: a tracker
     637      """
     638      if message is None:
     639        impl = None
     640      else:
     641        impl = message._msg
     642      self._check(pn_messenger_get(self._mng, impl))
     643      if message is not None:
     644        message._post_decode()
     645      return pn_messenger_incoming_tracker(self._mng)
     646
     647 -  def accept(self, tracker=None):
     648      """
     649      Signal the sender that you have acted on the L{Message}
     650      pointed to by the tracker.  If no tracker is supplied,
     651      then all messages that have been returned by the L{get}
     652      method are accepted, except those that have already been
     653      auto-settled by passing beyond your incoming window size.
     654
     655      @type tracker: tracker
     656      @param tracker: a tracker as returned by get
     657      """
     658      if tracker is None:
     659        tracker = pn_messenger_incoming_tracker(self._mng)
     660        flags = PN_CUMULATIVE
     661      else:
     662        flags = 0
     663      self._check(pn_messenger_accept(self._mng, tracker, flags))
     664
     665 -  def reject(self, tracker=None):
     666      """
     667      Rejects the L{Message} indicated by the tracker.  If no tracker
     668      is supplied, all messages that have been returned by the L{get}
     669      method are rejected, except those that have already been auto-settled
     670      by passing beyond your outgoing window size.
     671
     672      @type tracker: tracker
     673      @param tracker: a tracker as returned by get
     674      """
     675      if tracker is None:
     676        tracker = pn_messenger_incoming_tracker(self._mng)
     677        flags = PN_CUMULATIVE
     678      else:
     679        flags = 0
     680      self._check(pn_messenger_reject(self._mng, tracker, flags))
     681
     682    @property
     683 -  def outgoing(self):
     684      """
     685      The outgoing queue depth.
     686      """
     687      return pn_messenger_outgoing(self._mng)
     688
     689    @property
     690 -  def incoming(self):
     691      """
     692      The incoming queue depth.
     693      """
     694      return pn_messenger_incoming(self._mng)
     695
     696 -  def route(self, pattern, address):
     697      """
     698            Adds a routing rule to a L{Messenger's<Messenger>} internal routing table.
     699
     700            The route procedure may be used to influence how a L{Messenger} will
     701            internally treat a given address or class of addresses. Every call
     702            to the route procedure will result in L{Messenger} appending a routing
     703            rule to its internal routing table.
     704
     705            Whenever a L{Message} is presented to a L{Messenger} for delivery, it
     706            will match the address of this message against the set of routing
     707            rules in order. The first rule to match will be triggered, and
     708            instead of routing based on the address presented in the message,
     709            the L{Messenger} will route based on the address supplied in the rule.
     710
     711            The pattern matching syntax supports two types of matches, a '%'
     712            will match any character except a '/', and a '*' will match any
     713            character including a '/'.
     714
     715            A routing address is specified as a normal AMQP address, however it
     716            may additionally use substitution variables from the pattern match
     717            that triggered the rule.
     718
     719            Any message sent to "foo" will be routed to "amqp://foo.com":
     720
     721               >>> messenger.route("foo", "amqp://foo.com");
     722
     723            Any message sent to "foobar" will be routed to
     724            "amqp://foo.com/bar":
     725
     726               >>> messenger.route("foobar", "amqp://foo.com/bar");
     727
     728            Any message sent to bar/<path> will be routed to the corresponding
     729            path within the amqp://bar.com domain:
     730
     731               >>> messenger.route("bar/*", "amqp://bar.com/$1");
     732
     733            Route all L{messages<Message>} over TLS:
     734
     735               >>> messenger.route("amqp:*", "amqps:$1")
     736
     737            Supply credentials for foo.com:
     738
     739               >>> messenger.route("amqp://foo.com/*", "amqp://user:password@foo.com/$1");
     740
     741            Supply credentials for all domains:
     742
     743               >>> messenger.route("amqp://*", "amqp://user:password@$1");
     744
     745            Route all addresses through a single proxy while preserving the
     746            original destination:
     747
     748               >>> messenger.route("amqp://%/*", "amqp://user:password@proxy/$1/$2");
     749
     750            Route any address through a single broker:
     751
     752               >>> messenger.route("*", "amqp://user:password@broker/$1");
     753      """
     754      self._check(pn_messenger_route(self._mng, unicode2utf8(pattern), unicode2utf8(address)))
     755
     756 -  def rewrite(self, pattern, address):
     757      """
     758      Similar to route(), except that the destination of
     759      the L{Message} is determined before the message address is rewritten.
     760
     761      The outgoing address is only rewritten after routing has been
     762      finalized.  If a message has an outgoing address of
     763      "amqp://0.0.0.0:5678", and a rewriting rule that changes its
     764      outgoing address to "foo", it will still arrive at the peer that
     765      is listening on "amqp://0.0.0.0:5678", but when it arrives there,
     766      the receiver will see its outgoing address as "foo".
     767
     768      The default rewrite rule removes username and password from addresses
     769      before they are transmitted.
     770      """
     771      self._check(pn_messenger_rewrite(self._mng, unicode2utf8(pattern), unicode2utf8(address)))
     772
     773 -  def selectable(self):
     774      return Selectable.wrap(pn_messenger_selectable(self._mng))
     775
     776    @property
     777 -  def deadline(self):
     778      tstamp = pn_messenger_deadline(self._mng)
     779      if tstamp:
     780        return millis2secs(tstamp)
     781      else:
     782        return None
     783
     784 -class Message(object):
     785    """The L{Message} class is a mutable holder of message content.
     786
     787    @ivar instructions: delivery instructions for the message
     788    @type instructions: dict
     789    @ivar annotations: infrastructure defined message annotations
     790    @type annotations: dict
     791    @ivar properties: application defined message properties
     792    @type properties: dict
     793    @ivar body: message body
     794    @type body: bytes | unicode | dict | list | int | long | float | UUID
     795    """
     796
     797    DEFAULT_PRIORITY = PN_DEFAULT_PRIORITY
     798
     799 -  def __init__(self, body=None, **kwargs):
     800      """
     801      @param kwargs: Message property name/value pairs to initialise the Message
     802      """
     803      self._msg = pn_message()
     804      self._id = Data(pn_message_id(self._msg))
     805      self._correlation_id = Data(pn_message_correlation_id(self._msg))
     806      self.instructions = None
     807      self.annotations = None
     808      self.properties = None
     809      self.body = body
     810      for k,v in _compat.iteritems(kwargs):
     811        getattr(self, k)          # Raise exception if it's not a valid attribute.
     812        setattr(self, k, v)
     813
     814 -  def __del__(self):
     815      if hasattr(self, "_msg"):
     816        pn_message_free(self._msg)
     817        del self._msg
     818
     819 -  def _check(self, err):
     820      if err < 0:
     821        exc = EXCEPTIONS.get(err, MessageException)
     822        raise exc("[%s]: %s" % (err, pn_error_text(pn_message_error(self._msg))))
     823      else:
     824        return err
     825
     826 -  def _pre_encode(self):
     827      inst = Data(pn_message_instructions(self._msg))
     828      ann = Data(pn_message_annotations(self._msg))
     829      props = Data(pn_message_properties(self._msg))
     830      body = Data(pn_message_body(self._msg))
     831
     832      inst.clear()
     833      if self.instructions is not None:
     834        inst.put_object(self.instructions)
     835      ann.clear()
     836      if self.annotations is not None:
     837        ann.put_object(self.annotations)
     838      props.clear()
     839      if self.properties is not None:
     840        props.put_object(self.properties)
     841      body.clear()
     842      if self.body is not None:
     843        body.put_object(self.body)
     844
     845 -  def _post_decode(self):
     846      inst = Data(pn_message_instructions(self._msg))
     847      ann = Data(pn_message_annotations(self._msg))
     848      props = Data(pn_message_properties(self._msg))
     849      body = Data(pn_message_body(self._msg))
     850
     851      if inst.next():
     852        self.instructions = inst.get_object()
     853      else:
     854        self.instructions = None
     855      if ann.next():
     856        self.annotations = ann.get_object()
     857      else:
     858        self.annotations = None
     859      if props.next():
     860        self.properties = props.get_object()
     861      else:
     862        self.properties = None
     863      if body.next():
     864        self.body = body.get_object()
     865      else:
     866        self.body = None
     867
     868 -  def clear(self):
     869      """
     870      Clears the contents of the L{Message}. All fields will be reset to
     871      their default values.
     872      """
     873      pn_message_clear(self._msg)
     874      self.instructions = None
     875      self.annotations = None
     876      self.properties = None
     877      self.body = None
     878
     879 -  def _is_inferred(self):
     880      return pn_message_is_inferred(self._msg)
     881
     882 -  def _set_inferred(self, value):
     883      self._check(pn_message_set_inferred(self._msg, bool(value)))
     884
     885    inferred = property(_is_inferred, _set_inferred, doc="""
     886  The inferred flag for a message indicates how the message content
     887  is encoded into AMQP sections. If inferred is true then binary and
     888  list values in the body of the message will be encoded as AMQP DATA
     889  and AMQP SEQUENCE sections, respectively. If inferred is false,
     890  then all values in the body of the message will be encoded as AMQP
     891  VALUE sections regardless of their type.
     892  """)
     893
     894 -  def _is_durable(self):
     895      return pn_message_is_durable(self._msg)
     896
     897 -  def _set_durable(self, value):
     898      self._check(pn_message_set_durable(self._msg, bool(value)))
     899
     900    durable = property(_is_durable, _set_durable,
     901                       doc="""
     902  The durable property indicates that the message should be held durably
     903  by any intermediaries taking responsibility for the message.
     904  """)
     905
     906 -  def _get_priority(self):
     907      return pn_message_get_priority(self._msg)
     908
     909 -  def _set_priority(self, value):
     910      self._check(pn_message_set_priority(self._msg, value))
     911
     912    priority = property(_get_priority, _set_priority,
     913                        doc="""
     914  The priority of the message.
     915  """)
     916
     917 -  def _get_ttl(self):
     918      return millis2secs(pn_message_get_ttl(self._msg))
     919
     920 -  def _set_ttl(self, value):
     921      self._check(pn_message_set_ttl(self._msg, secs2millis(value)))
     922
     923    ttl = property(_get_ttl, _set_ttl,
     924                   doc="""
     925  The time to live of the message measured in seconds. Expired messages
     926  may be dropped.
     927  """)
     928
     929 -  def _is_first_acquirer(self):
     930      return pn_message_is_first_acquirer(self._msg)
     931
     932 -  def _set_first_acquirer(self, value):
     933      self._check(pn_message_set_first_acquirer(self._msg, bool(value)))
     934
     935    first_acquirer = property(_is_first_acquirer, _set_first_acquirer,
     936                              doc="""
     937  True iff the recipient is the first to acquire the message.
     938  """)
     939
     940 -  def _get_delivery_count(self):
     941      return pn_message_get_delivery_count(self._msg)
     942
     943 -  def _set_delivery_count(self, value):
     944      self._check(pn_message_set_delivery_count(self._msg, value))
     945
     946    delivery_count = property(_get_delivery_count, _set_delivery_count,
     947                              doc="""
     948  The number of delivery attempts made for this message.
     949  """)
     950
     951
     952 -  def _get_id(self):
     953      return self._id.get_object()
     954 -  def _set_id(self, value):
     955      if type(value) in _compat.INT_TYPES:
     956        value = ulong(value)
     957      self._id.rewind()
     958      self._id.put_object(value)
     959    id = property(_get_id, _set_id,
     960                  doc="""
     961  The id of the message.
     962  """)
     963
     964 -  def _get_user_id(self):
     965      return pn_message_get_user_id(self._msg)
     966
     967 -  def _set_user_id(self, value):
     968      self._check(pn_message_set_user_id(self._msg, value))
     969
     970    user_id = property(_get_user_id, _set_user_id,
     971                       doc="""
     972  The user id of the message creator.
     973  """)
     974
     975 -  def _get_address(self):
     976      return utf82unicode(pn_message_get_address(self._msg))
     977
     978 -  def _set_address(self, value):
     979      self._check(pn_message_set_address(self._msg, unicode2utf8(value)))
     980
     981    address = property(_get_address, _set_address,
     982                       doc="""
     983  The address of the message.
     984  """)
     985
     986 -  def _get_subject(self):
     987      return utf82unicode(pn_message_get_subject(self._msg))
     988
     989 -  def _set_subject(self, value):
     990      self._check(pn_message_set_subject(self._msg, unicode2utf8(value)))
     991
     992    subject = property(_get_subject, _set_subject,
     993                       doc="""
     994  The subject of the message.
     995  """)
     996
     997 -  def _get_reply_to(self):
     998      return utf82unicode(pn_message_get_reply_to(self._msg))
     999
    1000 -  def _set_reply_to(self, value):
    1001      self._check(pn_message_set_reply_to(self._msg, unicode2utf8(value)))
    1002
    1003    reply_to = property(_get_reply_to, _set_reply_to,
    1004                        doc="""
    1005  The reply-to address for the message.
    1006  """)
    1007
    1008 -  def _get_correlation_id(self):
    1009      return self._correlation_id.get_object()
    1010 -  def _set_correlation_id(self, value):
    1011      if type(value) in _compat.INT_TYPES:
    1012        value = ulong(value)
    1013      self._correlation_id.rewind()
    1014      self._correlation_id.put_object(value)
    1015
    1016    correlation_id = property(_get_correlation_id, _set_correlation_id,
    1017                              doc="""
    1018  The correlation-id for the message.
    1019  """)
    1020
    1021 -  def _get_content_type(self):
    1022      return symbol(utf82unicode(pn_message_get_content_type(self._msg)))
    1023
    1024 -  def _set_content_type(self, value):
    1025      self._check(pn_message_set_content_type(self._msg, unicode2utf8(value)))
    1026
    1027    content_type = property(_get_content_type, _set_content_type,
    1028                            doc="""
    1029  The content-type of the message.
    1030  """)
    1031
    1032 -  def _get_content_encoding(self):
    1033      return symbol(utf82unicode(pn_message_get_content_encoding(self._msg)))
    1034
    1035 -  def _set_content_encoding(self, value):
    1036      self._check(pn_message_set_content_encoding(self._msg, unicode2utf8(value)))
    1037
    1038    content_encoding = property(_get_content_encoding, _set_content_encoding,
    1039                                doc="""
    1040  The content-encoding of the message.
    1041  """)
    1042
    1043 -  def _get_expiry_time(self):
    1044      return millis2secs(pn_message_get_expiry_time(self._msg))
    1045
    1046 -  def _set_expiry_time(self, value):
    1047      self._check(pn_message_set_expiry_time(self._msg, secs2millis(value)))
    1048
    1049    expiry_time = property(_get_expiry_time, _set_expiry_time,
    1050                           doc="""
    1051  The expiry time of the message.
    1052  """)
    1053
    1054 -  def _get_creation_time(self):
    1055      return millis2secs(pn_message_get_creation_time(self._msg))
    1056
    1057 -  def _set_creation_time(self, value):
    1058      self._check(pn_message_set_creation_time(self._msg, secs2millis(value)))
    1059
    1060    creation_time = property(_get_creation_time, _set_creation_time,
    1061                             doc="""
    1062  The creation time of the message.
    1063  """)
    1064
    1065 -  def _get_group_id(self):
    1066      return utf82unicode(pn_message_get_group_id(self._msg))
    1067
    1068 -  def _set_group_id(self, value):
    1069      self._check(pn_message_set_group_id(self._msg, unicode2utf8(value)))
    1070
    1071    group_id = property(_get_group_id, _set_group_id,
    1072                        doc="""
    1073  The group id of the message.
    1074  """)
    1075
    1076 -  def _get_group_sequence(self):
    1077      return pn_message_get_group_sequence(self._msg)
    1078
    1079 -  def _set_group_sequence(self, value):
    1080      self._check(pn_message_set_group_sequence(self._msg, value))
    1081
    1082    group_sequence = property(_get_group_sequence, _set_group_sequence,
    1083                              doc="""
    1084  The sequence of the message within its group.
    1085  """)
    1086
    1087 -  def _get_reply_to_group_id(self):
    1088      return utf82unicode(pn_message_get_reply_to_group_id(self._msg))
    1089
    1090 -  def _set_reply_to_group_id(self, value):
    1091      self._check(pn_message_set_reply_to_group_id(self._msg, unicode2utf8(value)))
    1092
    1093    reply_to_group_id = property(_get_reply_to_group_id, _set_reply_to_group_id,
    1094                                 doc="""
    1095  The group-id for any replies.
    1096  """)
    1097
    1098 -  def encode(self):
    1099      self._pre_encode()
    1100      sz = 16
    1101      while True:
    1102        err, data = pn_message_encode(self._msg, sz)
    1103        if err == PN_OVERFLOW:
    1104          sz *= 2
    1105          continue
    1106        else:
    1107          self._check(err)
    1108          return data
    1109
    1110 -  def decode(self, data):
    1111      self._check(pn_message_decode(self._msg, data))
    1112      self._post_decode()
    1113
    1114 -  def send(self, sender, tag=None):
    1115      dlv = sender.delivery(tag or sender.delivery_tag())
    1116      encoded = self.encode()
    1117      sender.stream(encoded)
    1118      sender.advance()
    1119      if sender.snd_settle_mode == Link.SND_SETTLED:
    1120        dlv.settle()
    1121      return dlv
    1122
    1123 -  def recv(self, link):
    1124      """
    1125      Receives and decodes the message content for the current delivery
    1126      from the link. Upon success it will return the current delivery
    1127      for the link. If there is no current delivery, or if the current
    1128      delivery is incomplete, or if the link is not a receiver, it will
    1129      return None.
    1130
    1131      @type link: Link
    1132      @param link: the link to receive a message from
    1133      @return the delivery associated with the decoded message (or None)
    1134
    1135      """
    1136      if link.is_sender: return None
    1137      dlv = link.current
    1138      if not dlv or dlv.partial: return None
    1139      dlv.encoded = link.recv(dlv.pending)
    1140      link.advance()
    1141      # the sender has already forgotten about the delivery, so we might
    1142      # as well too
    1143      if link.remote_snd_settle_mode == Link.SND_SETTLED:
    1144        dlv.settle()
    1145      self.decode(dlv.encoded)
    1146      return dlv
    1147
    1148 -  def __repr2__(self):
    1149      props = []
    1150      for attr in ("inferred", "address", "reply_to", "durable", "ttl",
    1151                   "priority", "first_acquirer", "delivery_count", "id",
    1152                   "correlation_id", "user_id", "group_id", "group_sequence",
    1153                   "reply_to_group_id", "instructions", "annotations",
    1154                   "properties", "body"):
    1155        value = getattr(self, attr)
    1156        if value: props.append("%s=%r" % (attr, value))
    1157      return "Message(%s)" % ", ".join(props)
    1158
    1159 -  def __repr__(self):
    1160      tmp = pn_string(None)
    1161      err = pn_inspect(self._msg, tmp)
    1162      result = pn_string_get(tmp)
    1163      pn_free(tmp)
    1164      self._check(err)
    1165      return result
    1166
    1167 -class Subscription(object):
    1168
    1169 -  def __init__(self, impl):
    1170      self._impl = impl
    1171
    1172    @property
    1173 -  def address(self):
    1174      return pn_subscription_address(self._impl)
    1175
    1176  _DEFAULT = object()
    1177
    1178 -class Selectable(Wrapper):
    1179
    1180    @staticmethod
    1181 -  def wrap(impl):
    1182      if impl is None:
    1183        return None
    1184      else:
    1185        return Selectable(impl)
    1186
    1187 -  def __init__(self, impl):
    1188      Wrapper.__init__(self, impl, pn_selectable_attachments)
    1189
    1190 -  def _init(self):
    1191      pass
    1192
    1193 -  def fileno(self, fd = _DEFAULT):
    1194      if fd is _DEFAULT:
    1195        return pn_selectable_get_fd(self._impl)
    1196      elif fd is None:
    1197        pn_selectable_set_fd(self._impl, PN_INVALID_SOCKET)
    1198      else:
    1199        pn_selectable_set_fd(self._impl, fd)
    1200
    1201 -  def _is_reading(self):
    1202      return pn_selectable_is_reading(self._impl)
    1203
    1204 -  def _set_reading(self, val):
    1205      pn_selectable_set_reading(self._impl, bool(val))
    1206
    1207    reading = property(_is_reading, _set_reading)
    1208
    1209 -  def _is_writing(self):
    1210      return pn_selectable_is_writing(self._impl)
    1211
    1212 -  def _set_writing(self, val):
    1213      pn_selectable_set_writing(self._impl, bool(val))
    1214
    1215    writing = property(_is_writing, _set_writing)
    1216
    1217 -  def _get_deadline(self):
    1218      tstamp = pn_selectable_get_deadline(self._impl)
    1219      if tstamp:
    1220        return millis2secs(tstamp)
    1221      else:
    1222        return None
    1223
    1224 -  def _set_deadline(self, deadline):
    1225      pn_selectable_set_deadline(self._impl, secs2millis(deadline))
    1226
    1227    deadline = property(_get_deadline, _set_deadline)
    1228
    1229 -  def readable(self):
    1230      pn_selectable_readable(self._impl)
    1231
    1232 -  def writable(self):
    1233      pn_selectable_writable(self._impl)
    1234
    1235 -  def expired(self):
    1236      pn_selectable_expired(self._impl)
    1237
    1238 -  def _is_registered(self):
    1239      return pn_selectable_is_registered(self._impl)
    1240
    1241 -  def _set_registered(self, registered):
    1242      pn_selectable_set_registered(self._impl, registered)
    1243
    1244    registered = property(_is_registered, _set_registered,
    1245                      doc="""
    1246  The registered property may be get/set by an I/O polling system to
    1247  indicate whether the fd has been registered or not.
    1248  """)
    1249
    1250    @property
    1251 -  def is_terminal(self):
    1252      return pn_selectable_is_terminal(self._impl)
    1253
    1254 -  def terminate(self):
    1255      pn_selectable_terminate(self._impl)
    1256
    1257 -  def release(self):
    1258      pn_selectable_release(self._impl)
    1259
    1260 -class DataException(ProtonException):
    1261    """
    1262    The DataException class is the root of the Data exception hierarchy.
    1263    All exceptions raised by the Data class extend this exception.
    1264    """
    1265    pass
    1266
    1267 -class UnmappedType:
    1268
    1269 -  def __init__(self, msg):
    1270      self.msg = msg
    1271
    1272 -  def __repr__(self):
    1273      return "UnmappedType(%s)" % self.msg
    1274
    1275 -class ulong(long):
    1276
    1277 -  def __repr__(self):
    1278      return "ulong(%s)" % long.__repr__(self)
    1279
    1280 -class timestamp(long):
    1281
    1282 -  def __repr__(self):
    1283      return "timestamp(%s)" % long.__repr__(self)
    1284
    1285 -class symbol(unicode):
    1286
    1287 -  def __repr__(self):
    1288      return "symbol(%s)" % unicode.__repr__(self)
    1289
    1290 -class char(unicode):
    1291
    1292 -  def __repr__(self):
    1293      return "char(%s)" % unicode.__repr__(self)
    1294
    1295 -class byte(int):
    1296
    1297 -  def __repr__(self):
    1298      return "byte(%s)" % int.__repr__(self)
    1299
    1300 -class short(int):
    1301
    1302 -  def __repr__(self):
    1303      return "short(%s)" % int.__repr__(self)
    1304
    1305 -class int32(int):
    1306
    1307 -  def __repr__(self):
    1308        return "int32(%s)" % int.__repr__(self)
    1309
    1310 -class ubyte(int):
    1311
    1312 -  def __repr__(self):
    1313      return "ubyte(%s)" % int.__repr__(self)
    1314
    1315 -class ushort(int):
    1316
    1317 -  def __repr__(self):
    1318      return "ushort(%s)" % int.__repr__(self)
    1319
    1320 -class uint(long):
    1321
    1322 -  def __repr__(self):
    1323        return "uint(%s)" % long.__repr__(self)
    1324
    1325 -class float32(float):
    1326
    1327 -  def __repr__(self):
    1328      return "float32(%s)" % float.__repr__(self)
    1329
    1330 -class decimal32(int):
    1331
    1332 -  def __repr__(self):
    1333      return "decimal32(%s)" % int.__repr__(self)
    1334
    1335 -class decimal64(long):
    1336
    1337 -  def __repr__(self):
    1338      return "decimal64(%s)" % long.__repr__(self)
    1339
    1340 -class decimal128(bytes):
    1341
    1342 -  def __repr__(self):
    1343      return "decimal128(%s)" % bytes.__repr__(self)
    1344
    1345 -class Described(object):
    1346
    1347 -  def __init__(self, descriptor, value):
    1348      self.descriptor = descriptor
    1349      self.value = value
    1350
    1351 -  def __repr__(self):
    1352      return "Described(%r, %r)" % (self.descriptor, self.value)
    1353
    1354 -  def __eq__(self, o):
    1355      if isinstance(o, Described):
    1356        return self.descriptor == o.descriptor and self.value == o.value
    1357      else:
    1358        return False
    1359
    1360  UNDESCRIBED = Constant("UNDESCRIBED")
    1361
    1362 -class Array(object):
    1363
    1364 -  def __init__(self, descriptor, type, *elements):
    1365      self.descriptor = descriptor
    1366      self.type = type
    1367      self.elements = elements
    1368
    1369 -  def __iter__(self):
    1370      return iter(self.elements)
    1371
    1372 -  def __repr__(self):
    1373      if self.elements:
    1374        els = ", %s"  % (", ".join(map(repr, self.elements)))
    1375      else:
    1376        els = ""
    1377      return "Array(%r, %r%s)" % (self.descriptor, self.type, els)
    1378
    1379 -  def __eq__(self, o):
    1380      if isinstance(o, Array):
    1381        return self.descriptor == o.descriptor and \
    1382            self.type == o.type and self.elements == o.elements
    1383      else:
    1384        return False
    1385
    1386 -class Data:
    1387    """
    1388    The L{Data} class provides an interface for decoding, extracting,
    1389    creating, and encoding arbitrary AMQP data. A L{Data} object
    1390    contains a tree of AMQP values. Leaf nodes in this tree correspond
    1391    to scalars in the AMQP type system such as L{ints<INT>} or
    1392    L{strings<STRING>}. Non-leaf nodes in this tree correspond to
    1393    compound values in the AMQP type system such as L{lists<LIST>},
    1394    L{maps<MAP>}, L{arrays<ARRAY>}, or L{described values<DESCRIBED>}.
    1395    The root node of the tree is the L{Data} object itself and can have
    1396    an arbitrary number of children.
    1397
    1398    A L{Data} object maintains the notion of the current sibling node
    1399    and a current parent node. Siblings are ordered within their parent.
    1400    Values are accessed and/or added by using the L{next}, L{prev},
    1401    L{enter}, and L{exit} methods to navigate to the desired location in
    1402    the tree and using the supplied variety of put_*/get_* methods to
    1403    access or add a value of the desired type.
    1404
    1405    The put_* methods will always add a value I{after} the current node
    1406    in the tree. If the current node has a next sibling the put_* method
    1407    will overwrite the value on this node. If there is no current node
    1408    or the current node has no next sibling then one will be added. The
    1409    put_* methods always set the added/modified node to the current
    1410    node. The get_* methods read the value of the current node and do
    1411    not change which node is current.
    1412
    1413    The following types of scalar values are supported:
    1414
    1415     - L{NULL}
    1416     - L{BOOL}
    1417     - L{UBYTE}
    1418     - L{USHORT}
    1419     - L{SHORT}
    1420     - L{UINT}
    1421     - L{INT}
    1422     - L{ULONG}
    1423     - L{LONG}
    1424     - L{FLOAT}
    1425     - L{DOUBLE}
    1426     - L{BINARY}
    1427     - L{STRING}
    1428     - L{SYMBOL}
    1429
    1430    The following types of compound values are supported:
    1431
    1432     - L{DESCRIBED}
    1433     - L{ARRAY}
    1434     - L{LIST}
    1435     - L{MAP}
    1436    """
    1437
    1438    NULL = PN_NULL; "A null value."
    1439    BOOL = PN_BOOL; "A boolean value."
    1440    UBYTE = PN_UBYTE; "An unsigned byte value."
    1441    BYTE = PN_BYTE; "A signed byte value."
    1442    USHORT = PN_USHORT; "An unsigned short value."
    1443    SHORT = PN_SHORT; "A short value."
    1444    UINT = PN_UINT; "An unsigned int value."
    1445    INT = PN_INT; "A signed int value."
    1446    CHAR = PN_CHAR; "A character value."
    1447    ULONG = PN_ULONG; "An unsigned long value."
    1448    LONG = PN_LONG; "A signed long value."
    1449    TIMESTAMP = PN_TIMESTAMP; "A timestamp value."
    1450    FLOAT = PN_FLOAT; "A float value."
    1451    DOUBLE = PN_DOUBLE; "A double value."
    1452    DECIMAL32 = PN_DECIMAL32; "A DECIMAL32 value."
    1453    DECIMAL64 = PN_DECIMAL64; "A DECIMAL64 value."
    1454    DECIMAL128 = PN_DECIMAL128; "A DECIMAL128 value."
    1455    UUID = PN_UUID; "A UUID value."
    1456    BINARY = PN_BINARY; "A binary string."
    1457    STRING = PN_STRING; "A unicode string."
    1458    SYMBOL = PN_SYMBOL; "A symbolic string."
    1459    DESCRIBED = PN_DESCRIBED; "A described value."
    1460    ARRAY = PN_ARRAY; "An array value."
    1461    LIST = PN_LIST; "A list value."
    1462    MAP = PN_MAP; "A map value."
    1463
    1464    type_names = {
    1465      NULL: "null",
    1466      BOOL: "bool",
    1467      BYTE: "byte",
    1468      UBYTE: "ubyte",
    1469      SHORT: "short",
    1470      USHORT: "ushort",
    1471      INT: "int",
    1472      UINT: "uint",
    1473      CHAR: "char",
    1474      LONG: "long",
    1475      ULONG: "ulong",
    1476      TIMESTAMP: "timestamp",
    1477      FLOAT: "float",
    1478      DOUBLE: "double",
    1479      DECIMAL32: "decimal32",
    1480      DECIMAL64: "decimal64",
    1481      DECIMAL128: "decimal128",
    1482      UUID: "uuid",
    1483      BINARY: "binary",
    1484      STRING: "string",
    1485      SYMBOL: "symbol",
    1486      DESCRIBED: "described",
    1487      ARRAY: "array",
    1488      LIST: "list",
    1489      MAP: "map"
    1490      }
    1491
    1492    @classmethod
    1493 -  def type_name(type): return Data.type_names[type]
    1494
    1495 -  def __init__(self, capacity=16):
    1496      if type(capacity) in _compat.INT_TYPES:
    1497        self._data = pn_data(capacity)
    1498        self._free = True
    1499      else:
    1500        self._data = capacity
    1501        self._free = False
    1502
    1503 -  def __del__(self):
    1504      if self._free and hasattr(self, "_data"):
    1505        pn_data_free(self._data)
    1506        del self._data
    1507
    1508 -  def _check(self, err):
    1509      if err < 0:
    1510        exc = EXCEPTIONS.get(err, DataException)
    1511        raise exc("[%s]: %s" % (err, pn_error_text(pn_data_error(self._data))))
    1512      else:
    1513        return err
    1514
    1515 -  def clear(self):
    1516      """
    1517      Clears the data object.
    1518      """
    1519      pn_data_clear(self._data)
    1520
    1521 -  def rewind(self):
    1522      """
    1523      Clears current node and sets the parent to the root node.  Clearing the
    1524      current node sets it _before_ the first node, calling next() will advance to
    1525      the first node.
    1526      """
    1527      assert self._data is not None
    1528      pn_data_rewind(self._data)
    1529
    1530 -  def next(self):
    1531      """
    1532      Advances the current node to its next sibling and returns its
    1533      type. If there is no next sibling the current node remains
    1534      unchanged and None is returned.
    1535      """
    1536      found = pn_data_next(self._data)
    1537      if found:
    1538        return self.type()
    1539      else:
    1540        return None
    1541
    1542 -  def prev(self):
    1543      """
    1544      Advances the current node to its previous sibling and returns its
    1545      type. If there is no previous sibling the current node remains
    1546      unchanged and None is returned.
    1547      """
    1548      found = pn_data_prev(self._data)
    1549      if found:
    1550        return self.type()
    1551      else:
    1552        return None
    1553
    1554 -  def enter(self):
    1555      """
    1556      Sets the parent node to the current node and clears the current node.
    1557      Clearing the current node sets it _before_ the first child,
    1558      call next() advances to the first child.
    1559      """
    1560      return pn_data_enter(self._data)
    1561
    1562 -  def exit(self):
    1563      """
    1564      Sets the current node to the parent node and the parent node to
    1565      its own parent.
    1566      """
    1567      return pn_data_exit(self._data)
    1568
    1569 -  def lookup(self, name):
    1570      return pn_data_lookup(self._data, name)
    1571
    1572 -  def narrow(self):
    1573      pn_data_narrow(self._data)
    1574
    1575 -  def widen(self):
    1576      pn_data_widen(self._data)
    1577
    1578 -  def type(self):
    1579      """
    1580      Returns the type of the current node.
    1581      """
    1582      dtype = pn_data_type(self._data)
    1583      if dtype == -1:
    1584        return None
    1585      else:
    1586        return dtype
    1587
    1588 -  def encoded_size(self):
    1589      """
    1590      Returns the size in bytes needed to encode the data in AMQP format.
    1591      """
    1592      return pn_data_encoded_size(self._data)
    1593
    1594 -  def encode(self):
    1595      """
    1596      Returns a representation of the data encoded in AMQP format.
    1597      """
    1598      size = 1024
    1599      while True:
    1600        cd, enc = pn_data_encode(self._data, size)
    1601        if cd == PN_OVERFLOW:
    1602          size *= 2
    1603        elif cd >= 0:
    1604          return enc
    1605        else:
    1606          self._check(cd)
    1607
    1608 -  def decode(self, encoded):
    1609      """
    1610      Decodes the first value from supplied AMQP data and returns the
    1611      number of bytes consumed.
    1612
    1613      @type encoded: binary
    1614      @param encoded: AMQP encoded binary data
    1615      """
    1616      return self._check(pn_data_decode(self._data, encoded))
    1617
    1618 -  def put_list(self):
    1619      """
    1620      Puts a list value. Elements may be filled by entering the list
    1621      node and putting element values.
    1622
    1623        >>> data = Data()
    1624        >>> data.put_list()
    1625        >>> data.enter()
    1626        >>> data.put_int(1)
    1627        >>> data.put_int(2)
    1628        >>> data.put_int(3)
    1629        >>> data.exit()
    1630      """
    1631      self._check(pn_data_put_list(self._data))
    1632
    1633 -  def put_map(self):
    1634      """
    1635      Puts a map value. Elements may be filled by entering the map node
    1636      and putting alternating key value pairs.
    1637
    1638        >>> data = Data()
    1639        >>> data.put_map()
    1640        >>> data.enter()
    1641        >>> data.put_string("key")
    1642        >>> data.put_string("value")
    1643        >>> data.exit()
    1644      """
    1645      self._check(pn_data_put_map(self._data))
    1646
    1647 -  def put_array(self, described, element_type):
    1648      """
    1649      Puts an array value. Elements may be filled by entering the array
    1650      node and putting the element values. The values must all be of the
    1651      specified array element type. If an array is described then the
    1652      first child value of the array is the descriptor and may be of any
    1653      type.
    1654
    1655        >>> data = Data()
    1656        >>>
    1657        >>> data.put_array(False, Data.INT)
    1658        >>> data.enter()
    1659        >>> data.put_int(1)
    1660        >>> data.put_int(2)
    1661        >>> data.put_int(3)
    1662        >>> data.exit()
    1663        >>>
    1664        >>> data.put_array(True, Data.DOUBLE)
    1665        >>> data.enter()
    1666        >>> data.put_symbol("array-descriptor")
    1667        >>> data.put_double(1.1)
    1668        >>> data.put_double(1.2)
    1669        >>> data.put_double(1.3)
    1670        >>> data.exit()
    1671
    1672      @type described: bool
    1673      @param described: specifies whether the array is described
    1674      @type element_type: int
    1675      @param element_type: the type of the array elements
    1676      """
    1677      self._check(pn_data_put_array(self._data, described, element_type))
    1678
    1679 -  def put_described(self):
    1680      """
    1681      Puts a described value. A described node has two children, the
    1682      descriptor and the value. These are specified by entering the node
    1683      and putting the desired values.
    1684
    1685        >>> data = Data()
    1686        >>> data.put_described()
    1687        >>> data.enter()
    1688        >>> data.put_symbol("value-descriptor")
    1689        >>> data.put_string("the value")
    1690        >>> data.exit()
    1691      """
    1692      self._check(pn_data_put_described(self._data))
    1693
    1694 -  def put_null(self):
    1695      """
    1696      Puts a null value.
    1697      """
    1698      self._check(pn_data_put_null(self._data))
    1699
    1700 -  def put_bool(self, b):
    1701      """
    1702      Puts a boolean value.
    1703
    1704      @param b: a boolean value
    1705      """
    1706      self._check(pn_data_put_bool(self._data, b))
    1707
    1708 -  def put_ubyte(self, ub):
    1709      """
    1710      Puts an unsigned byte value.
    1711
    1712      @param ub: an integral value
    1713      """
    1714      self._check(pn_data_put_ubyte(self._data, ub))
    1715
    1716 -  def put_byte(self, b):
    1717      """
    1718      Puts a signed byte value.
    1719
    1720      @param b: an integral value
    1721      """
    1722      self._check(pn_data_put_byte(self._data, b))
    1723
    1724 -  def put_ushort(self, us):
    1725      """
    1726      Puts an unsigned short value.
    1727
    1728      @param us: an integral value.
    1729      """
    1730      self._check(pn_data_put_ushort(self._data, us))
    1731
    1732 -  def put_short(self, s):
    1733      """
    1734      Puts a signed short value.
    1735
    1736      @param s: an integral value
    1737      """
    1738      self._check(pn_data_put_short(self._data, s))
    1739
    1740 -  def put_uint(self, ui):
    1741      """
    1742      Puts an unsigned int value.
    1743
    1744      @param ui: an integral value
    1745      """
    1746      self._check(pn_data_put_uint(self._data, ui))
    1747
    1748 -  def put_int(self, i):
    1749      """
    1750      Puts a signed int value.
    1751
    1752      @param i: an integral value
    1753      """
    1754      self._check(pn_data_put_int(self._data, i))
    1755
    1756 -  def put_char(self, c):
    1757      """
    1758      Puts a char value.
    1759
    1760      @param c: a single character
    1761      """
    1762      self._check(pn_data_put_char(self._data, ord(c)))
    1763
    1764 -  def put_ulong(self, ul):
    1765      """
    1766      Puts an unsigned long value.
    1767
    1768      @param ul: an integral value
    1769      """
    1770      self._check(pn_data_put_ulong(self._data, ul))
    1771
    1772 -  def put_long(self, l):
    1773      """
    1774      Puts a signed long value.
    1775
    1776      @param l: an integral value
    1777      """
    1778      self._check(pn_data_put_long(self._data, l))
    1779
    1780 -  def put_timestamp(self, t):
    1781      """
    1782      Puts a timestamp value.
    1783
    1784      @param t: an integral value
    1785      """
    1786      self._check(pn_data_put_timestamp(self._data, t))
    1787
    1788 -  def put_float(self, f):
    1789      """
    1790      Puts a float value.
    1791
    1792      @param f: a floating point value
    1793      """
    1794      self._check(pn_data_put_float(self._data, f))
    1795
    1796 -  def put_double(self, d):
    1797      """
    1798      Puts a double value.
    1799
    1800      @param d: a floating point value.
    1801      """
    1802      self._check(pn_data_put_double(self._data, d))
    1803
    1804 -  def put_decimal32(self, d):
    1805      """
    1806      Puts a decimal32 value.
    1807
    1808      @param d: a decimal32 value
    1809      """
    1810      self._check(pn_data_put_decimal32(self._data, d))
    1811
    1812 -  def put_decimal64(self, d):
    1813      """
    1814      Puts a decimal64 value.
    1815
    1816      @param d: a decimal64 value
    1817      """
    1818      self._check(pn_data_put_decimal64(self._data, d))
    1819
    1820 -  def put_decimal128(self, d):
    1821      """
    1822      Puts a decimal128 value.
    1823
    1824      @param d: a decimal128 value
    1825      """
    1826      self._check(pn_data_put_decimal128(self._data, d))
    1827
    1828 -  def put_uuid(self, u):
    1829      """
    1830      Puts a UUID value.
    1831
    1832      @param u: a uuid value
    1833      """
    1834      self._check(pn_data_put_uuid(self._data, u.bytes))
    1835
    1836 -  def put_binary(self, b):
    1837      """
    1838      Puts a binary value.
    1839
    1840      @type b: binary
    1841      @param b: a binary value
    1842      """
    1843      self._check(pn_data_put_binary(self._data, b))
    1844
    1845 -  def put_string(self, s):
    1846      """
    1847      Puts a unicode value.
    1848
    1849      @type s: unicode
    1850      @param s: a unicode value
    1851      """
    1852      self._check(pn_data_put_string(self._data, s.encode("utf8")))
    1853
    1854 -  def put_symbol(self, s):
    1855      """
    1856      Puts a symbolic value.
    1857
    1858      @type s: string
    1859      @param s: the symbol name
    1860      """
    1861      self._check(pn_data_put_symbol(self._data, s.encode('ascii')))
    1862
    1863 -  def get_list(self):
    1864      """
    1865      If the current node is a list, return the number of elements,
    1866      otherwise return zero. List elements can be accessed by entering
    1867      the list.
    1868
    1869        >>> count = data.get_list()
    1870        >>> data.enter()
    1871        >>> for i in range(count):
    1872        ...   type = data.next()
    1873        ...   if type == Data.STRING:
    1874        ...     print data.get_string()
    1875        ...   elif type == ...:
    1876        ...     ...
    1877        >>> data.exit()
    1878      """
    1879      return pn_data_get_list(self._data)
    1880
    1881 -  def get_map(self):
    1882      """
    1883      If the current node is a map, return the number of child elements,
    1884      otherwise return zero. Key value pairs can be accessed by entering
    1885      the map.
    1886
    1887        >>> count = data.get_map()
    1888        >>> data.enter()
    1889        >>> for i in range(count/2):
    1890        ...   type = data.next()
    1891        ...   if type == Data.STRING:
    1892        ...     print data.get_string()
    1893        ...   elif type == ...:
    1894        ...     ...
    1895        >>> data.exit()
    1896      """
    1897      return pn_data_get_map(self._data)
    1898
    1899 -  def get_array(self):
    1900      """
    1901      If the current node is an array, return a tuple of the element
    1902      count, a boolean indicating whether the array is described, and
    1903      the type of each element, otherwise return (0, False, None). Array
    1904      data can be accessed by entering the array.
    1905
    1906        >>> # read an array of strings with a symbolic descriptor
    1907        >>> count, described, type = data.get_array()
    1908        >>> data.enter()
    1909        >>> data.next()
    1910        >>> print "Descriptor:", data.get_symbol()
    1911        >>> for i in range(count):
    1912        ...    data.next()
    1913        ...    print "Element:", data.get_string()
    1914        >>> data.exit()
    1915      """
    1916      count = pn_data_get_array(self._data)
    1917      described = pn_data_is_array_described(self._data)
    1918      type = pn_data_get_array_type(self._data)
    1919      if type == -1:
    1920        type = None
    1921      return count, described, type
    1922
    1923 -  def is_described(self):
    1924      """
    1925      Checks if the current node is a described value. The descriptor
    1926      and value may be accessed by entering the described value.
    1927
    1928        >>> # read a symbolically described string
    1929        >>> assert data.is_described() # will error if the current node is not described
    1930        >>> data.enter()
    1931        >>> data.next()
    1932        >>> print data.get_symbol()
    1933        >>> data.next()
    1934        >>> print data.get_string()
    1935        >>> data.exit()
    1936      """
    1937      return pn_data_is_described(self._data)
    1938
    1939 -  def is_null(self):
    1940      """
    1941      Checks if the current node is a null.
    1942      """
    1943      return pn_data_is_null(self._data)
    1944
    1945 -  def get_bool(self):
    1946      """
    1947      If the current node is a boolean, returns its value, returns False
    1948      otherwise.
    1949      """
    1950      return pn_data_get_bool(self._data)
    1951
    1952 -  def get_ubyte(self):
    1953      """
    1954      If the current node is an unsigned byte, returns its value,
    1955      returns 0 otherwise.
    1956      """
    1957      return ubyte(pn_data_get_ubyte(self._data))
    1958
    1959 -  def get_byte(self):
    1960      """
    1961      If the current node is a signed byte, returns its value, returns 0
    1962      otherwise.
    1963      """
    1964      return byte(pn_data_get_byte(self._data))
    1965
    1966 -  def get_ushort(self):
    1967      """
    1968      If the current node is an unsigned short, returns its value,
    1969      returns 0 otherwise.
    1970      """
    1971      return ushort(pn_data_get_ushort(self._data))
    1972
    1973 -  def get_short(self):
    1974      """
    1975      If the current node is a signed short, returns its value, returns
    1976      0 otherwise.
    1977      """
    1978      return short(pn_data_get_short(self._data))
    1979
    1980 -  def get_uint(self):
    1981      """
    1982      If the current node is an unsigned int, returns its value, returns
    1983      0 otherwise.
    1984      """
    1985      return uint(pn_data_get_uint(self._data))
    1986
    1987 -  def get_int(self):
    1988      """
    1989      If the current node is a signed int, returns its value, returns 0
    1990      otherwise.
    1991      """
    1992      return int32(pn_data_get_int(self._data))
    1993
    1994 -  def get_char(self):
    1995      """
    1996      If the current node is a char, returns its value, returns 0
    1997      otherwise.
    1998      """
    1999      return char(_compat.unichar(pn_data_get_char(self._data)))
    2000
    2001 -  def get_ulong(self):
    2002      """
    2003      If the current node is an unsigned long, returns its value,
    2004      returns 0 otherwise.
    2005      """
    2006      return ulong(pn_data_get_ulong(self._data))
    2007
    2008 -  def get_long(self):
    2009      """
    2010      If the current node is an signed long, returns its value, returns
    2011      0 otherwise.
    2012      """
    2013      return long(pn_data_get_long(self._data))
    2014
    2015 -  def get_timestamp(self):
    2016      """
    2017      If the current node is a timestamp, returns its value, returns 0
    2018      otherwise.
    2019      """
    2020      return timestamp(pn_data_get_timestamp(self._data))
    2021
    2022 -  def get_float(self):
    2023      """
    2024      If the current node is a float, returns its value, raises 0
    2025      otherwise.
    2026      """
    2027      return float32(pn_data_get_float(self._data))
    2028
    2029 -  def get_double(self):
    2030      """
    2031      If the current node is a double, returns its value, returns 0
    2032      otherwise.
    2033      """
    2034      return pn_data_get_double(self._data)
    2035
    2036    # XXX: need to convert
    2037 -  def get_decimal32(self):
    2038      """
    2039      If the current node is a decimal32, returns its value, returns 0
    2040      otherwise.
    2041      """
    2042      return decimal32(pn_data_get_decimal32(self._data))
    2043
    2044    # XXX: need to convert
    2045 -  def get_decimal64(self):
    2046      """
    2047      If the current node is a decimal64, returns its value, returns 0
    2048      otherwise.
    2049      """
    2050      return decimal64(pn_data_get_decimal64(self._data))
    2051
    2052    # XXX: need to convert
    2053 -  def get_decimal128(self):
    2054      """
    2055      If the current node is a decimal128, returns its value, returns 0
    2056      otherwise.
    2057      """
    2058      return decimal128(pn_data_get_decimal128(self._data))
    2059
    2060 -  def get_uuid(self):
    2061      """
    2062      If the current node is a UUID, returns its value, returns None
    2063      otherwise.
    2064      """
    2065      if pn_data_type(self._data) == Data.UUID:
    2066        return uuid.UUID(bytes=pn_data_get_uuid(self._data))
    2067      else:
    2068        return None
    2069
    2070 -  def get_binary(self):
    2071      """
    2072      If the current node is binary, returns its value, returns ""
    2073      otherwise.
    2074      """
    2075      return pn_data_get_binary(self._data)
    2076
    2077 -  def get_string(self):
    2078      """
    2079      If the current node is a string, returns its value, returns ""
    2080      otherwise.
    2081      """
    2082      return pn_data_get_string(self._data).decode("utf8")
    2083
    2084 -  def get_symbol(self):
    2085      """
    2086      If the current node is a symbol, returns its value, returns ""
    2087      otherwise.
    2088      """
    2089      return symbol(pn_data_get_symbol(self._data).decode('ascii'))
    2090
    2091 -  def copy(self, src):
    2092      self._check(pn_data_copy(self._data, src._data))
    2093
    2094 -  def format(self):
    2095      sz = 16
    2096      while True:
    2097        err, result = pn_data_format(self._data, sz)
    2098        if err == PN_OVERFLOW:
    2099          sz *= 2
    2100          continue
    2101        else:
    2102          self._check(err)
    2103          return result
    2104
    2105 -  def dump(self):
    2106      pn_data_dump(self._data)
    2107
    2108 -  def put_dict(self, d):
    2109      self.put_map()
    2110      self.enter()
    2111      try:
    2112        for k, v in d.items():
    2113          self.put_object(k)
    2114          self.put_object(v)
    2115      finally:
    2116        self.exit()
    2117
    2118 -  def get_dict(self):
    2119      if self.enter():
    2120        try:
    2121          result = {}
    2122          while self.next():
    2123            k = self.get_object()
    2124            if self.next():
    2125              v = self.get_object()
    2126            else:
    2127              v = None
    2128            result[k] = v
    2129        finally:
    2130          self.exit()
    2131        return result
    2132
    2133 -  def put_sequence(self, s):
    2134      self.put_list()
    2135      self.enter()
    2136      try:
    2137        for o in s:
    2138          self.put_object(o)
    2139      finally:
    2140        self.exit()
    2141
    2142 -  def get_sequence(self):
    2143      if self.enter():
    2144        try:
    2145          result = []
    2146          while self.next():
    2147            result.append(self.get_object())
    2148        finally:
    2149          self.exit()
    2150        return result
    2151
    2152 -  def get_py_described(self):
    2153      if self.enter():
    2154        try:
    2155          self.next()
    2156          descriptor = self.get_object()
    2157          self.next()
    2158          value = self.get_object()
    2159        finally:
    2160          self.exit()
    2161        return Described(descriptor, value)
    2162
    2163 -  def put_py_described(self, d):
    2164      self.put_described()
    2165      self.enter()
    2166      try:
    2167        self.put_object(d.descriptor)
    2168        self.put_object(d.value)
    2169      finally:
    2170        self.exit()
    2171
    2172 -  def get_py_array(self):
    2173      """
    2174      If the current node is an array, return an Array object
    2175      representing the array and its contents. Otherwise return None.
    2176      This is a convenience wrapper around get_array, enter, etc.
    2177      """
    2178
    2179      count, described, type = self.get_array()
    2180      if type is None: return None
    2181      if self.enter():
    2182        try:
    2183          if described:
    2184            self.next()
    2185            descriptor = self.get_object()
    2186          else:
    2187            descriptor = UNDESCRIBED
    2188          elements = []
    2189          while self.next():
    2190            elements.append(self.get_object())
    2191        finally:
    2192          self.exit()
    2193        return Array(descriptor, type, *elements)
    2194
    2195 -  def put_py_array(self, a):
    2196      described = a.descriptor != UNDESCRIBED
    2197      self.put_array(described, a.type)
    2198      self.enter()
    2199      try:
    2200        if described:
    2201          self.put_object(a.descriptor)
    2202        for e in a.elements:
    2203          self.put_object(e)
    2204      finally:
    2205        self.exit()
    2206
    2207    put_mappings = {
    2208      None.__class__: lambda s, _: s.put_null(),
    2209      bool: put_bool,
    2210      ubyte: put_ubyte,
    2211      ushort: put_ushort,
    2212      uint: put_uint,
    2213      ulong: put_ulong,
    2214      byte: put_byte,
    2215      short: put_short,
    2216      int32: put_int,
    2217      long: put_long,
    2218      float32: put_float,
    2219      float: put_double,
    2220      decimal32: put_decimal32,
    2221      decimal64: put_decimal64,
    2222      decimal128: put_decimal128,
    2223      char: put_char,
    2224      timestamp: put_timestamp,
    2225      uuid.UUID: put_uuid,
    2226      bytes: put_binary,
    2227      unicode: put_string,
    2228      symbol: put_symbol,
    2229      list: put_sequence,
    2230      tuple: put_sequence,
    2231      dict: put_dict,
    2232      Described: put_py_described,
    2233      Array: put_py_array
    2234      }
    2235    # for python 3.x, long is merely an alias for int, but for python 2.x
    2236    # we need to add an explicit int since it is a different type
    2237    if int not in put_mappings:
    2238        put_mappings[int] = put_int
    2239
    2240    get_mappings = {
    2241      NULL: lambda s: None,
    2242      BOOL: get_bool,
    2243      BYTE: get_byte,
    2244      UBYTE: get_ubyte,
    2245      SHORT: get_short,
    2246      USHORT: get_ushort,
    2247      INT: get_int,
    2248      UINT: get_uint,
    2249      CHAR: get_char,
    2250      LONG: get_long,
    2251      ULONG: get_ulong,
    2252      TIMESTAMP: get_timestamp,
    2253      FLOAT: get_float,
    2254      DOUBLE: get_double,
    2255      DECIMAL32: get_decimal32,
    2256      DECIMAL64: get_decimal64,
    2257      DECIMAL128: get_decimal128,
    2258      UUID: get_uuid,
    2259      BINARY: get_binary,
    2260      STRING: get_string,
    2261      SYMBOL: get_symbol,
    2262      DESCRIBED: get_py_described,
    2263      ARRAY: get_py_array,
    2264      LIST: get_sequence,
    2265      MAP: get_dict
    2266      }
    2267
    2268
    2269 -  def put_object(self, obj):
    2270      putter = self.put_mappings[obj.__class__]
    2271      putter(self, obj)
    2272
    2273 -  def get_object(self):
    2274      type = self.type()
    2275      if type is None: return None
    2276      getter = self.get_mappings.get(type)
    2277      if getter:
    2278        return getter(self)
    2279      else:
    2280        return UnmappedType(str(type))
    2281
    2282 -class ConnectionException(ProtonException):
    2283    pass
    2284
    2285 -class Endpoint(object):
    2286
    2287    LOCAL_UNINIT = PN_LOCAL_UNINIT
    2288    REMOTE_UNINIT = PN_REMOTE_UNINIT
    2289    LOCAL_ACTIVE = PN_LOCAL_ACTIVE
    2290    REMOTE_ACTIVE = PN_REMOTE_ACTIVE
    2291    LOCAL_CLOSED = PN_LOCAL_CLOSED
    2292    REMOTE_CLOSED  = PN_REMOTE_CLOSED
    2293
    2294 -  def _init(self):
    2295      self.condition = None
    2296
    2297 -  def _update_cond(self):
    2298      obj2cond(self.condition, self._get_cond_impl())
    2299
    2300    @property
    2301 -  def remote_condition(self):
    2302      return cond2obj(self._get_remote_cond_impl())
    2303
    2304    # the following must be provided by subclasses
    2305 -  def _get_cond_impl(self):
    2306        assert False, "Subclass must override this!"
    2307
    2308 -  def _get_remote_cond_impl(self):
    2309        assert False, "Subclass must override this!"
    2310
    2311 -  def _get_handler(self):
    2312      from . import reactor
    2313      ractor = reactor.Reactor.wrap(pn_object_reactor(self._impl))
    2314      if ractor:
    2315        on_error = ractor.on_error
    2316      else:
    2317        on_error = None
    2318      record = self._get_attachments()
    2319      return WrappedHandler.wrap(pn_record_get_handler(record), on_error)
    2320
    2321 -  def _set_handler(self, handler):
    2322      from . import reactor
    2323      ractor = reactor.Reactor.wrap(pn_object_reactor(self._impl))
    2324      if ractor:
    2325        on_error = ractor.on_error
    2326      else:
    2327        on_error = None
    2328      impl = _chandler(handler, on_error)
    2329      record = self._get_attachments()
    2330      pn_record_set_handler(record, impl)
    2331      pn_decref(impl)
    2332
    2333    handler = property(_get_handler, _set_handler)
    2334
    2335    @property
    2336 -  def transport(self):
    2337      return self.connection.transport
    2338
    2339 -class Condition:
    2340
    2341 -  def __init__(self, name, description=None, info=None):
    2342      self.name = name
    2343      self.description = description
    2344      self.info = info
    2345
    2346 -  def __repr__(self):
    2347      return "Condition(%s)" % ", ".join([repr(x) for x in
    2348                                          (self.name, self.description, self.info)
    2349                                          if x])
    2350
    2351 -  def __eq__(self, o):
    2352      if not isinstance(o, Condition): return False
    2353      return self.name == o.name and \
    2354          self.description == o.description and \
    2355          self.info == o.info
    2356
    2357 -def obj2cond(obj, cond):
    2358    pn_condition_clear(cond)
    2359    if obj:
    2360      pn_condition_set_name(cond, str(obj.name))
    2361      pn_condition_set_description(cond, obj.description)
    2362      info = Data(pn_condition_info(cond))
    2363      if obj.info:
    2364        info.put_object(obj.info)
    2365
    2366 -def cond2obj(cond):
    2367    if pn_condition_is_set(cond):
    2368      return Condition(pn_condition_get_name(cond),
    2369                       pn_condition_get_description(cond),
    2370                       dat2obj(pn_condition_info(cond)))
    2371    else:
    2372      return None
    2373
    2374 -def dat2obj(dimpl):
    2375    if dimpl:
    2376      d = Data(dimpl)
    2377      d.rewind()
    2378      d.next()
    2379      obj = d.get_object()
    2380      d.rewind()
    2381      return obj
    2382
    2383 -def obj2dat(obj, dimpl):
    2384    if obj is not None:
    2385      d = Data(dimpl)
    2386      d.put_object(obj)
    2387
    2388 -def secs2millis(secs):
    2389    return long(secs*1000)
    2390
    2391 -def millis2secs(millis):
    2392    return float(millis)/1000.0
    2393
    2394 -def timeout2millis(secs):
    2395    if secs is None: return PN_MILLIS_MAX
    2396    return secs2millis(secs)
    2397
    2398 -def millis2timeout(millis):
    2399    if millis == PN_MILLIS_MAX: return None
    2400    return millis2secs(millis)
    2401
    2402 -def unicode2utf8(string):
    2403      """Some Proton APIs expect a null terminated string. Convert python text
    2404      types to UTF8 to avoid zero bytes introduced by other multi-byte encodings.
    2405      This method will throw if the string cannot be converted.
    2406      """
    2407      if string is None:
    2408          return None
    2409      if _compat.IS_PY2:
    2410          if isinstance(string, unicode):
    2411              return string.encode('utf-8')
    2412          elif isinstance(string, str):
    2413              return string
    2414      else:
    2415          # decoding a string results in bytes
    2416          if isinstance(string, str):
    2417              string = string.encode('utf-8')
    2418              # fall through
    2419          if isinstance(string, bytes):
    2420              return string.decode('utf-8')
    2421      raise TypeError("Unrecognized string type: %r (%s)" % (string, type(string)))
    2422
    2423 -def utf82unicode(string):
    2424      """Covert C strings returned from proton-c into python unicode"""
    2425      if string is None:
    2426          return None
    2427      if isinstance(string, _compat.TEXT_TYPES):
    2428          # already unicode
    2429          return string
    2430      elif isinstance(string, _compat.BINARY_TYPES):
    2431          return string.decode('utf8')
    2432      else:
    2433          raise TypeError("Unrecognized string type")
    2434
    2435 -class Connection(Wrapper, Endpoint):
    2436    """
    2437    A representation of an AMQP connection
    2438    """
    2439
    2440    @staticmethod
    2441 -  def wrap(impl):
    2442      if impl is None:
    2443        return None
    2444      else:
    2445        return Connection(impl)
    2446
    2447 -  def __init__(self, impl = pn_connection):
    2448      Wrapper.__init__(self, impl, pn_connection_attachments)
    2449
    2450 -  def _init(self):
    2451      Endpoint._init(self)
    2452      self.offered_capabilities = None
    2453      self.desired_capabilities = None
    2454      self.properties = None
    2455
    2456 -  def _get_attachments(self):
    2457      return pn_connection_attachments(self._impl)
    2458
    2459    @property
    2460 -  def connection(self):
    2461      return self
    2462
    2463    @property
    2464 -  def transport(self):
    2465      return Transport.wrap(pn_connection_transport(self._impl))
    2466
    2467 -  def _check(self, err):
    2468      if err < 0:
    2469        exc = EXCEPTIONS.get(err, ConnectionException)
    2470        raise exc("[%s]: %s" % (err, pn_connection_error(self._impl)))
    2471      else:
    2472        return err
    2473
    2474 -  def _get_cond_impl(self):
    2475      return pn_connection_condition(self._impl)
    2476
    2477 -  def _get_remote_cond_impl(self):
    2478      return pn_connection_remote_condition(self._impl)
    2479
    2480 -  def collect(self, collector):
    2481      if collector is None:
    2482        pn_connection_collect(self._impl, None)
    2483      else:
    2484        pn_connection_collect(self._impl, collector._impl)
    2485      self._collector = weakref.ref(collector)
    2486
    2487 -  def _get_container(self):
    2488      return utf82unicode(pn_connection_get_container(self._impl))
    2489 -  def _set_container(self, name):
    2490      return pn_connection_set_container(self._impl, unicode2utf8(name))
    2491
    2492    container = property(_get_container, _set_container)
    2493
    2494 -  def _get_hostname(self):
    2495      return utf82unicode(pn_connection_get_hostname(self._impl))
    2496 -  def _set_hostname(self, name):
    2497      return pn_connection_set_hostname(self._impl, unicode2utf8(name))
    2498
    2499    hostname = property(_get_hostname, _set_hostname,
    2500                        doc="""
    2501  Set the name of the host (either fully qualified or relative) to which this
    2502  connection is connecting to.  This information may be used by the remote
    2503  peer to determine the correct back-end service to connect the client to.
    2504  This value will be sent in the Open performative, and will be used by SSL
    2505  and SASL layers to identify the peer.
    2506  """)
    2507
    2508 -  def _get_user(self):
    2509      return utf82unicode(pn_connection_get_user(self._impl))
    2510 -  def _set_user(self, name):
    2511      return pn_connection_set_user(self._impl, unicode2utf8(name))
    2512
    2513    user = property(_get_user, _set_user)
    2514
    2515 -  def _get_password(self):
    2516      return None
    2517 -  def _set_password(self, name):
    2518      return pn_connection_set_password(self._impl, unicode2utf8(name))
    2519
    2520    password = property(_get_password, _set_password)
    2521
    2522    @property
    2523 -  def remote_container(self):
    2524      """The container identifier specified by the remote peer for this connection."""
    2525      return pn_connection_remote_container(self._impl)
    2526
    2527    @property
    2528 -  def remote_hostname(self):
    2529      """The hostname specified by the remote peer for this connection."""
    2530      return pn_connection_remote_hostname(self._impl)
    2531
    2532    @property
    2533 -  def remote_offered_capabilities(self):
    2534      """The capabilities offered by the remote peer for this connection."""
    2535      return dat2obj(pn_connection_remote_offered_capabilities(self._impl))
    2536
    2537    @property
    2538 -  def remote_desired_capabilities(self):
    2539      """The capabilities desired by the remote peer for this connection."""
    2540      return dat2obj(pn_connection_remote_desired_capabilities(self._impl))
    2541
    2542    @property
    2543 -  def remote_properties(self):
    2544      """The properties specified by the remote peer for this connection."""
    2545      return dat2obj(pn_connection_remote_properties(self._impl))
    2546
    2547 -  def open(self):
    2548      """
    2549      Opens the connection.
    2550
    2551      In more detail, this moves the local state of the connection to
    2552      the ACTIVE state and triggers an open frame to be sent to the
    2553      peer. A connection is fully active once both peers have opened it.
    2554      """
    2555      obj2dat(self.offered_capabilities,
    2556              pn_connection_offered_capabilities(self._impl))
    2557      obj2dat(self.desired_capabilities,
    2558              pn_connection_desired_capabilities(self._impl))
    2559      obj2dat(self.properties, pn_connection_properties(self._impl))
    2560      pn_connection_open(self._impl)
    2561
    2562 -  def close(self):
    2563      """
    2564      Closes the connection.
    2565
    2566      In more detail, this moves the local state of the connection to
    2567      the CLOSED state and triggers a close frame to be sent to the
    2568      peer. A connection is fully closed once both peers have closed it.
    2569      """
    2570      self._update_cond()
    2571      pn_connection_close(self._impl)
    2572
    2573    @property
    2574 -  def state(self):
    2575      """
    2576      The state of the connection as a bit field. The state has a local
    2577      and a remote component. Each of these can be in one of three
    2578      states: UNINIT, ACTIVE or CLOSED. These can be tested by masking
    2579      against LOCAL_UNINIT, LOCAL_ACTIVE, LOCAL_CLOSED, REMOTE_UNINIT,
    2580      REMOTE_ACTIVE and REMOTE_CLOSED.
    2581      """
    2582      return pn_connection_state(self._impl)
    2583
    2584 -  def session(self):
    2585      """
    2586      Returns a new session on this connection.
    2587      """
    2588      ssn = pn_session(self._impl)
    2589      if ssn is None:
    2590        raise(SessionException("Session allocation failed."))
    2591      else:
    2592        return Session(ssn)
    2593
    2594 -  def session_head(self, mask):
    2595      return Session.wrap(pn_session_head(self._impl, mask))
    2596
    2597 -  def link_head(self, mask):
    2598      return Link.wrap(pn_link_head(self._impl, mask))
    2599
    2600    @property
    2601 -  def work_head(self):
    2602      return Delivery.wrap(pn_work_head(self._impl))
    2603
    2604    @property
    2605 -  def error(self):
    2606      return pn_error_code(pn_connection_error(self._impl))
    2607
    2608 -  def free(self):
    2609      pn_connection_release(self._impl)
    2610
    2611 -class SessionException(ProtonException):
    2612    pass
    2613
    2614 -class Session(Wrapper, Endpoint):
    2615
    2616    @staticmethod
    2617 -  def wrap(impl):
    2618      if impl is None:
    2619        return None
    2620      else:
    2621        return Session(impl)
    2622
    2623 -  def __init__(self, impl):
    2624      Wrapper.__init__(self, impl, pn_session_attachments)
    2625
    2626 -  def _get_attachments(self):
    2627      return pn_session_attachments(self._impl)
    2628
    2629 -  def _get_cond_impl(self):
    2630      return pn_session_condition(self._impl)
    2631
    2632 -  def _get_remote_cond_impl(self):
    2633      return pn_session_remote_condition(self._impl)
    2634
    2635 -  def _get_incoming_capacity(self):
    2636      return pn_session_get_incoming_capacity(self._impl)
    2637
    2638 -  def _set_incoming_capacity(self, capacity):
    2639      pn_session_set_incoming_capacity(self._impl, capacity)
    2640
    2641    incoming_capacity = property(_get_incoming_capacity, _set_incoming_capacity)
    2642
    2643 -  def _get_outgoing_window(self):
    2644      return pn_session_get_outgoing_window(self._impl)
    2645
    2646 -  def _set_outgoing_window(self, window):
    2647      pn_session_set_outgoing_window(self._impl, window)
    2648
    2649    outgoing_window = property(_get_outgoing_window, _set_outgoing_window)
    2650
    2651    @property
    2652 -  def outgoing_bytes(self):
    2653      return pn_session_outgoing_bytes(self._impl)
    2654
    2655    @property
    2656 -  def incoming_bytes(self):
    2657      return pn_session_incoming_bytes(self._impl)
    2658
    2659 -  def open(self):
    2660      pn_session_open(self._impl)
    2661
    2662 -  def close(self):
    2663      self._update_cond()
    2664      pn_session_close(self._impl)
    2665
    2666 -  def next(self, mask):
    2667      return Session.wrap(pn_session_next(self._impl, mask))
    2668
    2669    @property
    2670 -  def state(self):
    2671      return pn_session_state(self._impl)
    2672
    2673    @property
    2674 -  def connection(self):
    2675      return Connection.wrap(pn_session_connection(self._impl))
    2676
    2677 -  def sender(self, name):
    2678      return Sender(pn_sender(self._impl, unicode2utf8(name)))
    2679
    2680 -  def receiver(self, name):
    2681      return Receiver(pn_receiver(self._impl, unicode2utf8(name)))
    2682
    2683 -  def free(self):
    2684      pn_session_free(self._impl)
    2685
    2686 -class LinkException(ProtonException):
    2687    pass
    2688
    2689 -class Link(Wrapper, Endpoint):
    2690    """
    2691    A representation of an AMQP link, of which there are two concrete
    2692    implementations, Sender and Receiver.
    2693    """
    2694
    2695    SND_UNSETTLED = PN_SND_UNSETTLED
    2696    SND_SETTLED = PN_SND_SETTLED
    2697    SND_MIXED = PN_SND_MIXED
    2698
    2699    RCV_FIRST = PN_RCV_FIRST
    2700    RCV_SECOND = PN_RCV_SECOND
    2701
    2702    @staticmethod
    2703 -  def wrap(impl):
    2704      if impl is None: return None
    2705      if pn_link_is_sender(impl):
    2706        return Sender(impl)
    2707      else:
    2708        return Receiver(impl)
    2709
    2710 -  def __init__(self, impl):
    2711      Wrapper.__init__(self, impl, pn_link_attachments)
    2712
    2713 -  def _get_attachments(self):
    2714      return pn_link_attachments(self._impl)
    2715
    2716 -  def _check(self, err):
    2717      if err < 0:
    2718        exc = EXCEPTIONS.get(err, LinkException)
    2719        raise exc("[%s]: %s" % (err, pn_error_text(pn_link_error(self._impl))))
    2720      else:
    2721        return err
    2722
    2723 -  def _get_cond_impl(self):
    2724      return pn_link_condition(self._impl)
    2725
    2726 -  def _get_remote_cond_impl(self):
    2727      return pn_link_remote_condition(self._impl)
    2728
    2729 -  def open(self):
    2730      """
    2731      Opens the link.
    2732
    2733      In more detail, this moves the local state of the link to the
    2734      ACTIVE state and triggers an attach frame to be sent to the
    2735      peer. A link is fully active once both peers have attached it.
    2736      """
    2737      pn_link_open(self._impl)
    2738
    2739 -  def close(self):
    2740      """
    2741      Closes the link.
    2742
    2743      In more detail, this moves the local state of the link to the
    2744      CLOSED state and triggers an detach frame (with the closed flag
    2745      set) to be sent to the peer. A link is fully closed once both
    2746      peers have detached it.
    2747      """
    2748      self._update_cond()
    2749      pn_link_close(self._impl)
    2750
    2751    @property
    2752 -  def state(self):
    2753      """
    2754      The state of the link as a bit field. The state has a local
    2755      and a remote component. Each of these can be in one of three
    2756      states: UNINIT, ACTIVE or CLOSED. These can be tested by masking
    2757      against LOCAL_UNINIT, LOCAL_ACTIVE, LOCAL_CLOSED, REMOTE_UNINIT,
    2758      REMOTE_ACTIVE and REMOTE_CLOSED.
    2759      """
    2760      return pn_link_state(self._impl)
    2761
    2762    @property
    2763 -  def source(self):
    2764      """The source of the link as described by the local peer."""
    2765      return Terminus(pn_link_source(self._impl))
    2766
    2767    @property
    2768 -  def target(self):
    2769      """The target of the link as described by the local peer."""
    2770      return Terminus(pn_link_target(self._impl))
    2771
    2772    @property
    2773 -  def remote_source(self):
    2774      """The source of the link as described by the remote peer."""
    2775      return Terminus(pn_link_remote_source(self._impl))
    2776    @property
    2777 -  def remote_target(self):
    2778      """The target of the link as described by the remote peer."""
    2779      return Terminus(pn_link_remote_target(self._impl))
    2780
    2781    @property
    2782 -  def session(self):
    2783      return Session.wrap(pn_link_session(self._impl))
    2784
    2785    @property
    2786 -  def connection(self):
    2787      """The connection on which this link was attached."""
    2788      return self.session.connection
    2789
    2790 -  def delivery(self, tag):
    2791      return Delivery(pn_delivery(self._impl, tag))
    2792
    2793    @property
    2794 -  def current(self):
    2795      return Delivery.wrap(pn_link_current(self._impl))
    2796
    2797 -  def advance(self):
    2798      return pn_link_advance(self._impl)
    2799
    2800    @property
    2801 -  def unsettled(self):
    2802      return pn_link_unsettled(self._impl)
    2803
    2804    @property
    2805 -  def credit(self):
    2806      """The amount of oustanding credit on this link."""
    2807      return pn_link_credit(self._impl)
    2808
    2809    @property
    2810 -  def available(self):
    2811      return pn_link_available(self._impl)
    2812
    2813    @property
    2814 -  def queued(self):
    2815      return pn_link_queued(self._impl)
    2816
    2817 -  def next(self, mask):
    2818      return Link.wrap(pn_link_next(self._impl, mask))
    2819
    2820    @property
    2821 -  def name(self):
    2822      """Returns the name of the link"""
    2823      return utf82unicode(pn_link_name(self._impl))
    2824
    2825    @property
    2826 -  def is_sender(self):
    2827      """Returns true if this link is a sender."""
    2828      return pn_link_is_sender(self._impl)
    2829
    2830    @property
    2831 -  def is_receiver(self):
    2832      """Returns true if this link is a receiver."""
    2833      return pn_link_is_receiver(self._impl)
    2834
    2835    @property
    2836 -  def remote_snd_settle_mode(self):
    2837      return pn_link_remote_snd_settle_mode(self._impl)
    2838
    2839    @property
    2840 -  def remote_rcv_settle_mode(self):
    2841      return pn_link_remote_rcv_settle_mode(self._impl)
    2842
    2843 -  def _get_snd_settle_mode(self):
    2844      return pn_link_snd_settle_mode(self._impl)
    2845 -  def _set_snd_settle_mode(self, mode):
    2846      pn_link_set_snd_settle_mode(self._impl, mode)
    2847    snd_settle_mode = property(_get_snd_settle_mode, _set_snd_settle_mode)
    2848
    2849 -  def _get_rcv_settle_mode(self):
    2850      return pn_link_rcv_settle_mode(self._impl)
    2851 -  def _set_rcv_settle_mode(self, mode):
    2852      pn_link_set_rcv_settle_mode(self._impl, mode)
    2853    rcv_settle_mode = property(_get_rcv_settle_mode, _set_rcv_settle_mode)
    2854
    2855 -  def _get_drain(self):
    2856      return pn_link_get_drain(self._impl)
    2857
    2858 -  def _set_drain(self, b):
    2859      pn_link_set_drain(self._impl, bool(b))
    2860
    2861    drain_mode = property(_get_drain, _set_drain)
    2862
    2863 -  def drained(self):
    2864      return pn_link_drained(self._impl)
    2865
    2866 -  def detach(self):
    2867      return pn_link_detach(self._impl)
    2868
    2869 -  def free(self):
    2870      pn_link_free(self._impl)
    2871
    2872 -class Terminus(object):
    2873
    2874    UNSPECIFIED = PN_UNSPECIFIED
    2875    SOURCE = PN_SOURCE
    2876    TARGET = PN_TARGET
    2877    COORDINATOR = PN_COORDINATOR
    2878
    2879    NONDURABLE = PN_NONDURABLE
    2880    CONFIGURATION = PN_CONFIGURATION
    2881    DELIVERIES = PN_DELIVERIES
    2882
    2883    DIST_MODE_UNSPECIFIED = PN_DIST_MODE_UNSPECIFIED
    2884    DIST_MODE_COPY = PN_DIST_MODE_COPY
    2885    DIST_MODE_MOVE = PN_DIST_MODE_MOVE
    2886
    2887    EXPIRE_WITH_LINK = PN_EXPIRE_WITH_LINK
    2888    EXPIRE_WITH_SESSION = PN_EXPIRE_WITH_SESSION
    2889    EXPIRE_WITH_CONNECTION = PN_EXPIRE_WITH_CONNECTION
    2890    EXPIRE_NEVER = PN_EXPIRE_NEVER
    2891
    2892 -  def __init__(self, impl):
    2893      self._impl = impl
    2894
    2895 -  def _check(self, err):
    2896      if err < 0:
    2897        exc = EXCEPTIONS.get(err, LinkException)
    2898        raise exc("[%s]" % err)
    2899      else:
    2900        return err
    2901
    2902 -  def _get_type(self):
    2903      return pn_terminus_get_type(self._impl)
    2904 -  def _set_type(self, type):
    2905      self._check(pn_terminus_set_type(self._impl, type))
    2906    type = property(_get_type, _set_type)
    2907
    2908 -  def _get_address(self):
    2909      """The address that identifies the source or target node"""
    2910      return utf82unicode(pn_terminus_get_address(self._impl))
    2911 -  def _set_address(self, address):
    2912      self._check(pn_terminus_set_address(self._impl, unicode2utf8(address)))
    2913    address = property(_get_address, _set_address)
    2914
    2915 -  def _get_durability(self):
    2916      return pn_terminus_get_durability(self._impl)
    2917 -  def _set_durability(self, seconds):
    2918      self._check(pn_terminus_set_durability(self._impl, seconds))
    2919    durability = property(_get_durability, _set_durability)
    2920
    2921 -  def _get_expiry_policy(self):
    2922      return pn_terminus_get_expiry_policy(self._impl)
    2923 -  def _set_expiry_policy(self, seconds):
    2924      self._check(pn_terminus_set_expiry_policy(self._impl, seconds))
    2925    expiry_policy = property(_get_expiry_policy, _set_expiry_policy)
    2926
    2927 -  def _get_timeout(self):
    2928      return pn_terminus_get_timeout(self._impl)
    2929 -  def _set_timeout(self, seconds):
    2930      self._check(pn_terminus_set_timeout(self._impl, seconds))
    2931    timeout = property(_get_timeout, _set_timeout)
    2932
    2933 -  def _is_dynamic(self):
    2934      """Indicates whether the source or target node was dynamically
    2935      created"""
    2936      return pn_terminus_is_dynamic(self._impl)
    2937 -  def _set_dynamic(self, dynamic):
    2938      self._check(pn_terminus_set_dynamic(self._impl, dynamic))
    2939    dynamic = property(_is_dynamic, _set_dynamic)
    2940
    2941 -  def _get_distribution_mode(self):
    2942      return pn_terminus_get_distribution_mode(self._impl)
    2943 -  def _set_distribution_mode(self, mode):
    2944      self._check(pn_terminus_set_distribution_mode(self._impl, mode))
    2945    distribution_mode = property(_get_distribution_mode, _set_distribution_mode)
    2946
    2947    @property
    2948 -  def properties(self):
    2949      """Properties of a dynamic source or target."""
    2950      return Data(pn_terminus_properties(self._impl))
    2951
    2952    @property
    2953 -  def capabilities(self):
    2954      """Capabilities of the source or target."""
    2955      return Data(pn_terminus_capabilities(self._impl))
    2956
    2957    @property
    2958 -  def outcomes(self):
    2959      return Data(pn_terminus_outcomes(self._impl))
    2960
    2961    @property
    2962 -  def filter(self):
    2963      """A filter on a source allows the set of messages transfered over
    2964      the link to be restricted"""
    2965      return Data(pn_terminus_filter(self._impl))
    2966
    2967 -  def copy(self, src):
    2968      self._check(pn_terminus_copy(self._impl, src._impl))
    2969
    2970 -class Sender(Link):
    2971    """
    2972    A link over which messages are sent.
    2973    """
    2974
    2975 -  def offered(self, n):
    2976      pn_link_offered(self._impl, n)
    2977
    2978 -  def stream(self, data):
    2979      """
    2980      Send specified data as part of the current delivery
    2981
    2982      @type data: binary
    2983      @param data: data to send
    2984      """
    2985      return self._check(pn_link_send(self._impl, data))
    2986
    2987 -  def send(self, obj, tag=None):
    2988      """
    2989      Send specified object over this sender; the object is expected to
    2990      have a send() method on it that takes the sender and an optional
    2991      tag as arguments.
    2992
    2993      Where the object is a Message, this will send the message over
    2994      this link, creating a new delivery for the purpose.
    2995      """
    2996      if hasattr(obj, 'send'):
    2997        return obj.send(self, tag=tag)
    2998      else:
    2999        # treat object as bytes
    3000        return self.stream(obj)
    3001
    3002 -  def delivery_tag(self):
    3003      if not hasattr(self, 'tag_generator'):
    3004        def simple_tags():
    3005          count = 1
    3006          while True:
    3007            yield str(count)
    3008            count += 1
    3009        self.tag_generator = simple_tags()
    3010      return next(self.tag_generator)
    3011
    3012 -class Receiver(Link):
    3013    """
    3014    A link over which messages are received.
    3015    """
    3016
    3017 -  def flow(self, n):
    3018      """Increases the credit issued to the remote sender by the specified number of messages."""
    3019      pn_link_flow(self._impl, n)
    3020
    3021 -  def recv(self, limit):
    3022      n, binary = pn_link_recv(self._impl, limit)
    3023      if n == PN_EOS:
    3024        return None
    3025      else:
    3026        self._check(n)
    3027        return binary
    3028
    3029 -  def drain(self, n):
    3030      pn_link_drain(self._impl, n)
    3031
    3032 -  def draining(self):
    3033      return pn_link_draining(self._impl)
    3034
    3035 -class NamedInt(int):
    3036
    3037    values = {}
    3038
    3039 -  def __new__(cls, i, name):
    3040      ni = super(NamedInt, cls).__new__(cls, i)
    3041      cls.values[i] = ni
    3042      return ni
    3043
    3044 -  def __init__(self, i, name):
    3045      self.name = name
    3046
    3047 -  def __repr__(self):
    3048      return self.name
    3049
    3050 -  def __str__(self):
    3051      return self.name
    3052
    3053    @classmethod
    3054 -  def get(cls, i):
    3055      return cls.values.get(i, i)
    3056
    3057 -class DispositionType(NamedInt):
    3058    values = {}
    3059
    3060 -class Disposition(object):
    3061
    3062    RECEIVED = DispositionType(PN_RECEIVED, "RECEIVED")
    3063    ACCEPTED = DispositionType(PN_ACCEPTED, "ACCEPTED")
    3064    REJECTED = DispositionType(PN_REJECTED, "REJECTED")
    3065    RELEASED = DispositionType(PN_RELEASED, "RELEASED")
    3066    MODIFIED = DispositionType(PN_MODIFIED, "MODIFIED")
    3067
    3068 -  def __init__(self, impl, local):
    3069      self._impl = impl
    3070      self.local = local
    3071      self._data = None
    3072      self._condition = None
    3073      self._annotations = None
    3074
    3075    @property
    3076 -  def type(self):
    3077      return DispositionType.get(pn_disposition_type(self._impl))
    3078
    3079 -  def _get_section_number(self):
    3080      return pn_disposition_get_section_number(self._impl)
    3081 -  def _set_section_number(self, n):
    3082      pn_disposition_set_section_number(self._impl, n)
    3083    section_number = property(_get_section_number, _set_section_number)
    3084
    3085 -  def _get_section_offset(self):
    3086      return pn_disposition_get_section_offset(self._impl)
    3087 -  def _set_section_offset(self, n):
    3088      pn_disposition_set_section_offset(self._impl, n)
    3089    section_offset = property(_get_section_offset, _set_section_offset)
    3090
    3091 -  def _get_failed(self):
    3092      return pn_disposition_is_failed(self._impl)
    3093 -  def _set_failed(self, b):
    3094      pn_disposition_set_failed(self._impl, b)
    3095    failed = property(_get_failed, _set_failed)
    3096
    3097 -  def _get_undeliverable(self):
    3098      return pn_disposition_is_undeliverable(self._impl)
    3099 -  def _set_undeliverable(self, b):
    3100      pn_disposition_set_undeliverable(self._impl, b)
    3101    undeliverable = property(_get_undeliverable, _set_undeliverable)
    3102
    3103 -  def _get_data(self):
    3104      if self.local:
    3105        return self._data
    3106      else:
    3107        return dat2obj(pn_disposition_data(self._impl))
    3108 -  def _set_data(self, obj):
    3109      if self.local:
    3110        self._data = obj
    3111      else:
    3112        raise AttributeError("data attribute is read-only")
    3113    data = property(_get_data, _set_data)
    3114
    3115 -  def _get_annotations(self):
    3116      if self.local:
    3117        return self._annotations
    3118      else:
    3119        return dat2obj(pn_disposition_annotations(self._impl))
    3120 -  def _set_annotations(self, obj):
    3121      if self.local:
    3122        self._annotations = obj
    3123      else:
    3124        raise AttributeError("annotations attribute is read-only")
    3125    annotations = property(_get_annotations, _set_annotations)
    3126
    3127 -  def _get_condition(self):
    3128      if self.local:
    3129        return self._condition
    3130      else:
    3131        return cond2obj(pn_disposition_condition(self._impl))
    3132 -  def _set_condition(self, obj):
    3133      if self.local:
    3134        self._condition = obj
    3135      else:
    3136        raise AttributeError("condition attribute is read-only")
    3137    condition = property(_get_condition, _set_condition)
    3138
    3139 -class Delivery(Wrapper):
    3140    """
    3141    Tracks and/or records the delivery of a message over a link.
    3142    """
    3143
    3144    RECEIVED = Disposition.RECEIVED
    3145    ACCEPTED = Disposition.ACCEPTED
    3146    REJECTED = Disposition.REJECTED
    3147    RELEASED = Disposition.RELEASED
    3148    MODIFIED = Disposition.MODIFIED
    3149
    3150    @staticmethod
    3151 -  def wrap(impl):
    3152      if impl is None:
    3153        return None
    3154      else:
    3155        return Delivery(impl)
    3156
    3157 -  def __init__(self, impl):
    3158      Wrapper.__init__(self, impl, pn_delivery_attachments)
    3159
    3160 -  def _init(self):
    3161      self.local = Disposition(pn_delivery_local(self._impl), True)
    3162      self.remote = Disposition(pn_delivery_remote(self._impl), False)
    3163
    3164    @property
    3165 -  def tag(self):
    3166      """The identifier for the delivery."""
    3167      return pn_delivery_tag(self._impl)
    3168
    3169    @property
    3170 -  def writable(self):
    3171      """Returns true for an outgoing delivery to which data can now be written."""
    3172      return pn_delivery_writable(self._impl)
    3173
    3174    @property
    3175 -  def readable(self):
    3176      """Returns true for an incoming delivery that has data to read."""
    3177      return pn_delivery_readable(self._impl)
    3178
    3179    @property
    3180 -  def updated(self):
    3181      """Returns true if the state of the delivery has been updated
    3182      (e.g. it has been settled and/or accepted, rejected etc)."""
    3183      return pn_delivery_updated(self._impl)
    3184
    3185 -  def update(self, state):
    3186      """
    3187      Set the local state of the delivery e.g. ACCEPTED, REJECTED, RELEASED.
    3188      """
    3189      obj2dat(self.local._data, pn_disposition_data(self.local._impl))
    3190      obj2dat(self.local._annotations, pn_disposition_annotations(self.local._impl))
    3191      obj2cond(self.local._condition, pn_disposition_condition(self.local._impl))
    3192      pn_delivery_update(self._impl, state)
    3193
    3194    @property
    3195 -  def pending(self):
    3196      return pn_delivery_pending(self._impl)
    3197
    3198    @property
    3199 -  def partial(self):
    3200      """
    3201      Returns true for an incoming delivery if not all the data is
    3202      yet available.
    3203      """
    3204      return pn_delivery_partial(self._impl)
    3205
    3206    @property
    3207 -  def local_state(self):
    3208      """Returns the local state of the delivery."""
    3209      return DispositionType.get(pn_delivery_local_state(self._impl))
    3210
    3211    @property
    3212 -  def remote_state(self):
    3213      """
    3214      Returns the state of the delivery as indicated by the remote
    3215      peer.
    3216      """
    3217      return DispositionType.get(pn_delivery_remote_state(self._impl))
    3218
    3219    @property
    3220 -  def settled(self):
    3221      """
    3222      Returns true if the delivery has been settled by the remote peer.
    3223      """
    3224      return pn_delivery_settled(self._impl)
    3225
    3226 -  def settle(self):
    3227      """
    3228      Settles the delivery locally. This indicates the aplication
    3229      considers the delivery complete and does not wish to receive any
    3230      further events about it. Every delivery should be settled locally.
    3231      """
    3232      pn_delivery_settle(self._impl)
    3233
    3234    @property
    3235 -  def work_next(self):
    3236      return Delivery.wrap(pn_work_next(self._impl))
    3237
    3238    @property
    3239 -  def link(self):
    3240      """
    3241      Returns the link on which the delivery was sent or received.
    3242      """
    3243      return Link.wrap(pn_delivery_link(self._impl))
    3244
    3245    @property
    3246 -  def session(self):
    3247      """
    3248      Returns the session over which the delivery was sent or received.
    3249      """
    3250      return self.link.session
    3251
    3252    @property
    3253 -  def connection(self):
    3254      """
    3255      Returns the connection over which the delivery was sent or received.
    3256      """
    3257      return self.session.connection
    3258
    3259    @property
    3260 -  def transport(self):
    3261      return self.connection.transport
    3262
    3263 -class TransportException(ProtonException):
    3264    pass
    3265
    3266 -class TraceAdapter:
    3267
    3268 -  def __init__(self, tracer):
    3269      self.tracer = tracer
    3270
    3271 -  def __call__(self, trans_impl, message):
    3272      self.tracer(Transport.wrap(trans_impl), message)
    3273
    3274 -class Transport(Wrapper):
    3275
    3276    TRACE_OFF = PN_TRACE_OFF
    3277    TRACE_DRV = PN_TRACE_DRV
    3278    TRACE_FRM = PN_TRACE_FRM
    3279    TRACE_RAW = PN_TRACE_RAW
    3280
    3281    CLIENT = 1
    3282    SERVER = 2
    3283
    3284    @staticmethod
    3285 -  def wrap(impl):
    3286      if impl is None:
    3287        return None
    3288      else:
    3289        return Transport(_impl=impl)
    3290
    3291 -  def __init__(self, mode=None, _impl = pn_transport):
    3292      Wrapper.__init__(self, _impl, pn_transport_attachments)
    3293      if mode == Transport.SERVER:
    3294        pn_transport_set_server(self._impl)
    3295      elif mode is None or mode==Transport.CLIENT:
    3296        pass
    3297      else:
    3298        raise TransportException("Cannot initialise Transport from mode: %s" % str(mode))
    3299
    3300 -  def _init(self):
    3301      self._sasl = None
    3302      self._ssl = None
    3303
    3304 -  def _check(self, err):
    3305      if err < 0:
    3306        exc = EXCEPTIONS.get(err, TransportException)
    3307        raise exc("[%s]: %s" % (err, pn_error_text(pn_transport_error(self._impl))))
    3308      else:
    3309        return err
    3310
    3311 -  def _set_tracer(self, tracer):
    3312      pn_transport_set_pytracer(self._impl, TraceAdapter(tracer));
    3313
    3314 -  def _get_tracer(self):
    3315      adapter = pn_transport_get_pytracer(self._impl)
    3316      if adapter:
    3317        return adapter.tracer
    3318      else:
    3319        return None
    3320
    3321    tracer = property(_get_tracer, _set_tracer,
    3322                              doc="""
    3323  A callback for trace logging. The callback is passed the transport and log message.
    3324  """)
    3325
    3326 -  def log(self, message):
    3327      pn_transport_log(self._impl, message)
    3328
    3329 -  def require_auth(self, bool):
    3330      pn_transport_require_auth(self._impl, bool)
    3331
    3332    @property
    3333 -  def authenticated(self):
    3334      return pn_transport_is_authenticated(self._impl)
    3335
    3336 -  def require_encryption(self, bool):
    3337      pn_transport_require_encryption(self._impl, bool)
    3338
    3339    @property
    3340 -  def encrypted(self):
    3341      return pn_transport_is_encrypted(self._impl)
    3342
    3343    @property
    3344 -  def user(self):
    3345      return pn_transport_get_user(self._impl)
    3346
    3347 -  def bind(self, connection):
    3348      """Assign a connection to the transport"""
    3349      self._check(pn_transport_bind(self._impl, connection._impl))
    3350
    3351 -  def unbind(self):
    3352      """Release the connection"""
    3353      self._check(pn_transport_unbind(self._impl))
    3354
    3355 -  def trace(self, n):
    3356      pn_transport_trace(self._impl, n)
    3357
    3358 -  def tick(self, now):
    3359      """Process any timed events (like heartbeat generation).
    3360      now = seconds since epoch (float).
    3361      """
    3362      return millis2secs(pn_transport_tick(self._impl, secs2millis(now)))
    3363
    3364 -  def capacity(self):
    3365      c = pn_transport_capacity(self._impl)
    3366      if c >= PN_EOS:
    3367        return c
    3368      else:
    3369        return self._check(c)
    3370
    3371 -  def push(self, binary):
    3372      n = self._check(pn_transport_push(self._impl, binary))
    3373      if n != len(binary):
    3374        raise OverflowError("unable to process all bytes: %s, %s" % (n, len(binary)))
    3375
    3376 -  def close_tail(self):
    3377      self._check(pn_transport_close_tail(self._impl))
    3378
    3379 -  def pending(self):
    3380      p = pn_transport_pending(self._impl)
    3381      if p >= PN_EOS:
    3382        return p
    3383      else:
    3384        return self._check(p)
    3385
    3386 -  def peek(self, size):
    3387      cd, out = pn_transport_peek(self._impl, size)
    3388      if cd == PN_EOS:
    3389        return None
    3390      else:
    3391        self._check(cd)
    3392        return out
    3393
    3394 -  def pop(self, size):
    3395      pn_transport_pop(self._impl, size)
    3396
    3397 -  def close_head(self):
    3398      self._check(pn_transport_close_head(self._impl))
    3399
    3400    @property
    3401 -  def closed(self):
    3402      return pn_transport_closed(self._impl)
    3403
    3404    # AMQP 1.0 max-frame-size
    3405 -  def _get_max_frame_size(self):
    3406      return pn_transport_get_max_frame(self._impl)
    3407
    3408 -  def _set_max_frame_size(self, value):
    3409      pn_transport_set_max_frame(self._impl, value)
    3410
    3411    max_frame_size = property(_get_max_frame_size, _set_max_frame_size,
    3412                              doc="""
    3413  Sets the maximum size for received frames (in bytes).
    3414  """)
    3415
    3416    @property
    3417 -  def remote_max_frame_size(self):
    3418      return pn_transport_get_remote_max_frame(self._impl)
    3419
    3420 -  def _get_channel_max(self):
    3421      return pn_transport_get_channel_max(self._impl)
    3422
    3423 -  def _set_channel_max(self, value):
    3424      if pn_transport_set_channel_max(self._impl, value):
    3425        raise SessionException("Too late to change channel max.")
    3426
    3427    channel_max = property(_get_channel_max, _set_channel_max,
    3428                           doc="""
    3429  Sets the maximum channel that may be used on the transport.
    3430  """)
    3431
    3432    @property
    3433 -  def remote_channel_max(self):
    3434      return pn_transport_remote_channel_max(self._impl)
    3435
    3436    # AMQP 1.0 idle-time-out
    3437 -  def _get_idle_timeout(self):
    3438      return millis2secs(pn_transport_get_idle_timeout(self._impl))
    3439
    3440 -  def _set_idle_timeout(self, sec):
    3441      pn_transport_set_idle_timeout(self._impl, secs2millis(sec))
    3442
    3443    idle_timeout = property(_get_idle_timeout, _set_idle_timeout,
    3444                            doc="""
    3445  The idle timeout of the connection (float, in seconds).
    3446  """)
    3447
    3448    @property
    3449 -  def remote_idle_timeout(self):
    3450      return millis2secs(pn_transport_get_remote_idle_timeout(self._impl))
    3451
    3452    @property
    3453 -  def frames_output(self):
    3454      return pn_transport_get_frames_output(self._impl)
    3455
    3456    @property
    3457 -  def frames_input(self):
    3458      return pn_transport_get_frames_input(self._impl)
    3459
    3460 -  def sasl(self):
    3461      return SASL(self)
    3462
    3463 -  def ssl(self, domain=None, session_details=None):
    3464      # SSL factory (singleton for this transport)
    3465      if not self._ssl:
    3466        self._ssl = SSL(self, domain, session_details)
    3467      return self._ssl
    3468
    3469    @property
    3470 -  def condition(self):
    3471      return cond2obj(pn_transport_condition(self._impl))
    3472
    3473    @property
    3474 -  def connection(self):
    3475      return Connection.wrap(pn_transport_connection(self._impl))
    3476
    3477 -class SASLException(TransportException):
    3478    pass
    3479
    3480 -class SASL(Wrapper):
    3481
    3482    OK = PN_SASL_OK
    3483    AUTH = PN_SASL_AUTH
    3484    SYS = PN_SASL_SYS
    3485    PERM = PN_SASL_PERM
    3486    TEMP = PN_SASL_TEMP
    3487
    3488    @staticmethod
    3489 -  def extended():
    3490      return pn_sasl_extended()
    3491
    3492 -  def __init__(self, transport):
    3493      Wrapper.__init__(self, transport._impl, pn_transport_attachments)
    3494      self._sasl = pn_sasl(transport._impl)
    3495
    3496 -  def _check(self, err):
    3497      if err < 0:
    3498        exc = EXCEPTIONS.get(err, SASLException)
    3499        raise exc("[%s]" % (err))
    3500      else:
    3501        return err
    3502
    3503    @property
    3504 -  def user(self):
    3505      return pn_sasl_get_user(self._sasl)
    3506
    3507    @property
    3508 -  def mech(self):
    3509      return pn_sasl_get_mech(self._sasl)
    3510
    3511    @property
    3512 -  def outcome(self):
    3513      outcome = pn_sasl_outcome(self._sasl)
    3514      if outcome == PN_SASL_NONE:
    3515        return None
    3516      else:
    3517        return outcome
    3518
    3519 -  def allowed_mechs(self, mechs):
    3520      pn_sasl_allowed_mechs(self._sasl, mechs)
    3521
    3522 -  def _get_allow_insecure_mechs(self):
    3523      return pn_sasl_get_allow_insecure_mechs(self._sasl)
    3524
    3525 -  def _set_allow_insecure_mechs(self, insecure):
    3526      pn_sasl_set_allow_insecure_mechs(self._sasl, insecure)
    3527
    3528    allow_insecure_mechs = property(_get_allow_insecure_mechs, _set_allow_insecure_mechs,
    3529                                    doc="""
    3530  Allow unencrypted cleartext passwords (PLAIN mech)
    3531  """)
    3532
    3533 -  def done(self, outcome):
    3534      pn_sasl_done(self._sasl, outcome)
    3535
    3536 -  def config_name(self, name):
    3537      pn_sasl_config_name(self._sasl, name)
    3538
    3539 -  def config_path(self, path):
    3540      pn_sasl_config_path(self._sasl, path)
    3541
    3542 -class SSLException(TransportException):
    3543    pass
    3544
    3545 -class SSLUnavailable(SSLException):
    3546    pass
    3547
    3548 -class SSLDomain(object):
    3549
    3550    MODE_CLIENT = PN_SSL_MODE_CLIENT
    3551    MODE_SERVER = PN_SSL_MODE_SERVER
    3552    VERIFY_PEER = PN_SSL_VERIFY_PEER
    3553    VERIFY_PEER_NAME = PN_SSL_VERIFY_PEER_NAME
    3554    ANONYMOUS_PEER = PN_SSL_ANONYMOUS_PEER
    3555
    3556 -  def __init__(self, mode):
    3557      self._domain = pn_ssl_domain(mode)
    3558      if self._domain is None:
    3559        raise SSLUnavailable()
    3560
    3561 -  def _check(self, err):
    3562      if err < 0:
    3563        exc = EXCEPTIONS.get(err, SSLException)
    3564        raise exc("SSL failure.")
    3565      else:
    3566        return err
    3567
    3568 -  def set_credentials(self, cert_file, key_file, password):
    3569      return self._check( pn_ssl_domain_set_credentials(self._domain,
    3570                                                        cert_file, key_file,
    3571                                                        password) )
    3572 -  def set_trusted_ca_db(self, certificate_db):
    3573      return self._check( pn_ssl_domain_set_trusted_ca_db(self._domain,
    3574                                                          certificate_db) )
    3575 -  def set_peer_authentication(self, verify_mode, trusted_CAs=None):
    3576      return self._check( pn_ssl_domain_set_peer_authentication(self._domain,
    3577                                                                verify_mode,
    3578                                                                trusted_CAs) )
    3579
    3580 -  def allow_unsecured_client(self):
    3581      return self._check( pn_ssl_domain_allow_unsecured_client(self._domain) )
    3582
    3583 -  def __del__(self):
    3584      pn_ssl_domain_free(self._domain)
    3585
    3586 -class SSL(object):
    3587
    3588    @staticmethod
    3589 -  def present():
    3590      return pn_ssl_present()
    3591
    3592 -  def _check(self, err):
    3593      if err < 0:
    3594        exc = EXCEPTIONS.get(err, SSLException)
    3595        raise exc("SSL failure.")
    3596      else:
    3597        return err
    3598
    3599 -  def __new__(cls, transport, domain, session_details=None):
    3600      """Enforce a singleton SSL object per Transport"""
    3601      if transport._ssl:
    3602        # unfortunately, we've combined the allocation and the configuration in a
    3603        # single step.  So catch any attempt by the application to provide what
    3604        # may be a different configuration than the original (hack)
    3605        ssl = transport._ssl
    3606        if (domain and (ssl._domain is not domain) or
    3607            session_details and (ssl._session_details is not session_details)):
    3608          raise SSLException("Cannot re-configure existing SSL object!")
    3609      else:
    3610        obj = super(SSL, cls).__new__(cls)
    3611        obj._domain = domain
    3612        obj._session_details = session_details
    3613        session_id = None
    3614        if session_details:
    3615          session_id = session_details.get_session_id()
    3616        obj._ssl = pn_ssl( transport._impl )
    3617        if obj._ssl is None:
    3618          raise SSLUnavailable()
    3619        if domain:
    3620          pn_ssl_init( obj._ssl, domain._domain, session_id )
    3621        transport._ssl = obj
    3622      return transport._ssl
    3623
    3624 -  def cipher_name(self):
    3625      rc, name = pn_ssl_get_cipher_name( self._ssl, 128 )
    3626      if rc:
    3627        return name
    3628      return None
    3629
    3630 -  def protocol_name(self):
    3631      rc, name = pn_ssl_get_protocol_name( self._ssl, 128 )
    3632      if rc:
    3633        return name
    3634      return None
    3635
    3636    SHA1 = PN_SSL_SHA1
    3637    SHA256 = PN_SSL_SHA256
    3638    SHA512 = PN_SSL_SHA512
    3639    MD5 = PN_SSL_MD5
    3640
    3641    CERT_COUNTRY_NAME = PN_SSL_CERT_SUBJECT_COUNTRY_NAME
    3642    CERT_STATE_OR_PROVINCE = PN_SSL_CERT_SUBJECT_STATE_OR_PROVINCE
    3643    CERT_CITY_OR_LOCALITY = PN_SSL_CERT_SUBJECT_CITY_OR_LOCALITY
    3644    CERT_ORGANIZATION_NAME = PN_SSL_CERT_SUBJECT_ORGANIZATION_NAME
    3645    CERT_ORGANIZATION_UNIT = PN_SSL_CERT_SUBJECT_ORGANIZATION_UNIT
    3646    CERT_COMMON_NAME = PN_SSL_CERT_SUBJECT_COMMON_NAME
    3647
    3648 -  def get_cert_subject_subfield(self, subfield_name):
    3649      subfield_value = pn_ssl_get_remote_subject_subfield(self._ssl, subfield_name)
    3650      return subfield_value
    3651
    3652 -  def get_cert_subject(self):
    3653      subject = pn_ssl_get_remote_subject(self._ssl)
    3654      return subject
    3655
    3656 -  def _get_cert_subject_unknown_subfield(self):
    3657      # Pass in an unhandled enum
    3658      return self.get_cert_subject_subfield(10)
    3659
    3660    # Convenience functions for obtaining the subfields of the subject field.
    3661 -  def get_cert_common_name(self):
    3662      return self.get_cert_subject_subfield(SSL.CERT_COMMON_NAME)
    3663
    3664 -  def get_cert_organization(self):
    3665      return self.get_cert_subject_subfield(SSL.CERT_ORGANIZATION_NAME)
    3666
    3667 -  def get_cert_organization_unit(self):
    3668      return self.get_cert_subject_subfield(SSL.CERT_ORGANIZATION_UNIT)
    3669
    3670 -  def get_cert_locality_or_city(self):
    3671      return self.get_cert_subject_subfield(SSL.CERT_CITY_OR_LOCALITY)
    3672
    3673 -  def get_cert_country(self):
    3674      return self.get_cert_subject_subfield(SSL.CERT_COUNTRY_NAME)
    3675
    3676 -  def get_cert_state_or_province(self):
    3677      return self.get_cert_subject_subfield(SSL.CERT_STATE_OR_PROVINCE)
    3678
    3679 -  def get_cert_fingerprint(self, fingerprint_length, digest_name):
    3680      rc, fingerprint_str = pn_ssl_get_cert_fingerprint(self._ssl, fingerprint_length, digest_name)
    3681      if rc == PN_OK:
    3682        return fingerprint_str
    3683      return None
    3684
    3685    # Convenience functions for obtaining fingerprint for specific hashing algorithms
    3686 -  def _get_cert_fingerprint_unknown_hash_alg(self):
    3687      return self.get_cert_fingerprint(41, 10)
    3688
    3689 -  def get_cert_fingerprint_sha1(self):
    3690      return self.get_cert_fingerprint(41, SSL.SHA1)
    3691
    3692 -  def get_cert_fingerprint_sha256(self):
    3693      # sha256 produces a fingerprint that is 64 characters long
    3694      return self.get_cert_fingerprint(65, SSL.SHA256)
    3695
    3696 -  def get_cert_fingerprint_sha512(self):
    3697      # sha512 produces a fingerprint that is 128 characters long
    3698      return self.get_cert_fingerprint(129, SSL.SHA512)
    3699
    3700 -  def get_cert_fingerprint_md5(self):
    3701      return self.get_cert_fingerprint(33, SSL.MD5)
    3702
    3703    @property
    3704 -  def remote_subject(self):
    3705      return pn_ssl_get_remote_subject( self._ssl )
    3706
    3707    RESUME_UNKNOWN = PN_SSL_RESUME_UNKNOWN
    3708    RESUME_NEW = PN_SSL_RESUME_NEW
    3709    RESUME_REUSED = PN_SSL_RESUME_REUSED
    3710
    3711 -  def resume_status(self):
    3712      return pn_ssl_resume_status( self._ssl )
    3713
    3714 -  def _set_peer_hostname(self, hostname):
    3715      self._check(pn_ssl_set_peer_hostname( self._ssl, unicode2utf8(hostname) ))
    3716 -  def _get_peer_hostname(self):
    3717      err, name = pn_ssl_get_peer_hostname( self._ssl, 1024 )
    3718      self._check(err)
    3719      return utf82unicode(name)
    3720    peer_hostname = property(_get_peer_hostname, _set_peer_hostname,
    3721                             doc="""
    3722  Manage the expected name of the remote peer.  Used to authenticate the remote.
    3723  """)
    3724
    3725
    3726 -class SSLSessionDetails(object):
    3727    """ Unique identifier for the SSL session.  Used to resume previous session on a new
    3728    SSL connection.
    3729    """
    3730
    3731 -  def __init__(self, session_id):
    3732      self._session_id = session_id
    3733
    3734 -  def get_session_id(self):
    3735      return self._session_id
    3736
    3737
    3738  wrappers = {
    3739    "pn_void": lambda x: pn_void2py(x),
    3740    "pn_pyref": lambda x: pn_void2py(x),
    3741    "pn_connection": lambda x: Connection.wrap(pn_cast_pn_connection(x)),
    3742    "pn_session": lambda x: Session.wrap(pn_cast_pn_session(x)),
    3743    "pn_link": lambda x: Link.wrap(pn_cast_pn_link(x)),
    3744    "pn_delivery": lambda x: Delivery.wrap(pn_cast_pn_delivery(x)),
    3745    "pn_transport": lambda x: Transport.wrap(pn_cast_pn_transport(x)),
    3746    "pn_selectable": lambda x: Selectable.wrap(pn_cast_pn_selectable(x))
    3747  }
    3748
    3749 -class Collector:
    3750
    3751 -  def __init__(self):
    3752      self._impl = pn_collector()
    3753
    3754 -  def put(self, obj, etype):
    3755      pn_collector_put(self._impl, PN_PYREF, pn_py2void(obj), etype.number)
    3756
    3757 -  def peek(self):
    3758      return Event.wrap(pn_collector_peek(self._impl))
    3759
    3760 -  def pop(self):
    3761      ev = self.peek()
    3762      pn_collector_pop(self._impl)
    3763
    3764 -  def __del__(self):
    3765      pn_collector_free(self._impl)
    3766      del self._impl
    3767
    3768  if "TypeExtender" not in globals():
    3769 -  class TypeExtender:
    3770 -    def __init__(self, number):
    3771        self.number = number
    3772 -    def next(self):
    3773        try:
    3774          return self.number
    3775        finally:
    3776          self.number += 1
    3777
    3778 -class EventType(object):
    3779
    3780    _lock = threading.Lock()
    3781    _extended = TypeExtender(10000)
    3782    TYPES = {}
    3783
    3784 -  def __init__(self, name=None, number=None, method=None):
    3785      if name is None and number is None:
    3786        raise TypeError("extended events require a name")
    3787      try:
    3788        self._lock.acquire()
    3789        if name is None:
    3790          name = pn_event_type_name(number)
    3791
    3792        if number is None:
    3793          number = self._extended.next()
    3794
    3795        if method is None:
    3796          method = "on_%s" % name
    3797
    3798        self.name = name
    3799        self.number = number
    3800        self.method = method
    3801
    3802        self.TYPES[number] = self
    3803      finally:
    3804        self._lock.release()
    3805
    3806 -  def __repr__(self):
    3807      return self.name
    3808
    3809 -def dispatch(handler, method, *args):
    3810    m = getattr(handler, method, None)
    3811    if m:
    3812      return m(*args)
    3813    elif hasattr(handler, "on_unhandled"):
    3814      return handler.on_unhandled(method, *args)
    3815
    3816 -class EventBase(object):
    3817
    3818 -  def __init__(self, clazz, context, type):
    3819      self.clazz = clazz
    3820      self.context = context
    3821      self.type = type
    3822
    3823 -  def dispatch(self, handler):
    3824      return dispatch(handler, self.type.method, self)
    3825
    3826 -def _none(x): return None
    3827
    3828  DELEGATED = Constant("DELEGATED")
    3829
    3830 -def _core(number, method):
    3831    return EventType(number=number, method=method)
    3832
    3833 -class Event(Wrapper, EventBase):
    3834
    3835    REACTOR_INIT = _core(PN_REACTOR_INIT, "on_reactor_init")
    3836    REACTOR_QUIESCED = _core(PN_REACTOR_QUIESCED, "on_reactor_quiesced")
    3837    REACTOR_FINAL = _core(PN_REACTOR_FINAL, "on_reactor_final")
    3838
    3839    TIMER_TASK = _core(PN_TIMER_TASK, "on_timer_task")
    3840
    3841    CONNECTION_INIT = _core(PN_CONNECTION_INIT, "on_connection_init")
    3842    CONNECTION_BOUND = _core(PN_CONNECTION_BOUND, "on_connection_bound")
    3843    CONNECTION_UNBOUND = _core(PN_CONNECTION_UNBOUND, "on_connection_unbound")
    3844    CONNECTION_LOCAL_OPEN = _core(PN_CONNECTION_LOCAL_OPEN, "on_connection_local_open")
    3845    CONNECTION_LOCAL_CLOSE = _core(PN_CONNECTION_LOCAL_CLOSE, "on_connection_local_close")
    3846    CONNECTION_REMOTE_OPEN = _core(PN_CONNECTION_REMOTE_OPEN, "on_connection_remote_open")
    3847    CONNECTION_REMOTE_CLOSE = _core(PN_CONNECTION_REMOTE_CLOSE, "on_connection_remote_close")
    3848    CONNECTION_FINAL = _core(PN_CONNECTION_FINAL, "on_connection_final")
    3849
    3850    SESSION_INIT = _core(PN_SESSION_INIT, "on_session_init")
    3851    SESSION_LOCAL_OPEN = _core(PN_SESSION_LOCAL_OPEN, "on_session_local_open")
    3852    SESSION_LOCAL_CLOSE = _core(PN_SESSION_LOCAL_CLOSE, "on_session_local_close")
    3853    SESSION_REMOTE_OPEN = _core(PN_SESSION_REMOTE_OPEN, "on_session_remote_open")
    3854    SESSION_REMOTE_CLOSE = _core(PN_SESSION_REMOTE_CLOSE, "on_session_remote_close")
    3855    SESSION_FINAL = _core(PN_SESSION_FINAL, "on_session_final")
    3856
    3857    LINK_INIT = _core(PN_LINK_INIT, "on_link_init")
    3858    LINK_LOCAL_OPEN = _core(PN_LINK_LOCAL_OPEN, "on_link_local_open")
    3859    LINK_LOCAL_CLOSE = _core(PN_LINK_LOCAL_CLOSE, "on_link_local_close")
    3860    LINK_LOCAL_DETACH = _core(PN_LINK_LOCAL_DETACH, "on_link_local_detach")
    3861    LINK_REMOTE_OPEN = _core(PN_LINK_REMOTE_OPEN, "on_link_remote_open")
    3862    LINK_REMOTE_CLOSE = _core(PN_LINK_REMOTE_CLOSE, "on_link_remote_close")
    3863    LINK_REMOTE_DETACH = _core(PN_LINK_REMOTE_DETACH, "on_link_remote_detach")
    3864    LINK_FLOW = _core(PN_LINK_FLOW, "on_link_flow")
    3865    LINK_FINAL = _core(PN_LINK_FINAL, "on_link_final")
    3866
    3867    DELIVERY = _core(PN_DELIVERY, "on_delivery")
    3868
    3869    TRANSPORT = _core(PN_TRANSPORT, "on_transport")
    3870    TRANSPORT_ERROR = _core(PN_TRANSPORT_ERROR, "on_transport_error")
    3871    TRANSPORT_HEAD_CLOSED = _core(PN_TRANSPORT_HEAD_CLOSED, "on_transport_head_closed")
    3872    TRANSPORT_TAIL_CLOSED = _core(PN_TRANSPORT_TAIL_CLOSED, "on_transport_tail_closed")
    3873    TRANSPORT_CLOSED = _core(PN_TRANSPORT_CLOSED, "on_transport_closed")
    3874
    3875    SELECTABLE_INIT = _core(PN_SELECTABLE_INIT, "on_selectable_init")
    3876    SELECTABLE_UPDATED = _core(PN_SELECTABLE_UPDATED, "on_selectable_updated")
    3877    SELECTABLE_READABLE = _core(PN_SELECTABLE_READABLE, "on_selectable_readable")
    3878    SELECTABLE_WRITABLE = _core(PN_SELECTABLE_WRITABLE, "on_selectable_writable")
    3879    SELECTABLE_EXPIRED = _core(PN_SELECTABLE_EXPIRED, "on_selectable_expired")
    3880    SELECTABLE_ERROR = _core(PN_SELECTABLE_ERROR, "on_selectable_error")
    3881    SELECTABLE_FINAL = _core(PN_SELECTABLE_FINAL, "on_selectable_final")
    3882
    3883    @staticmethod
    3884 -  def wrap(impl, number=None):
    3885      if impl is None:
    3886        return None
    3887
    3888      if number is None:
    3889        number = pn_event_type(impl)
    3890
    3891      event = Event(impl, number)
    3892
    3893      if isinstance(event.context, EventBase):
    3894        return event.context
    3895      else:
    3896        return event
    3897
    3898 -  def __init__(self, impl, number):
    3899      Wrapper.__init__(self, impl, pn_event_attachments)
    3900      self.__dict__["type"] = EventType.TYPES[number]
    3901
    3902 -  def _init(self):
    3903      pass
    3904
    3905 -  def copy(self):
    3906      copy = pn_event_copy(self._impl)
    3907      return Event.wrap(copy)
    3908
    3909    @property
    3910 -  def clazz(self):
    3911      cls = pn_event_class(self._impl)
    3912      if cls:
    3913        return pn_class_name(cls)
    3914      else:
    3915        return None
    3916
    3917    @property
    3918 -  def root(self):
    3919      return WrappedHandler.wrap(pn_event_root(self._impl))
    3920
    3921    @property
    3922 -  def context(self):
    3923      """Returns the context object associated with the event. The type of this depend on the type of event."""
    3924      return wrappers[self.clazz](pn_event_context(self._impl))
    3925
    3926 -  def dispatch(self, handler, type=None):
    3927      type = type or self.type
    3928      if isinstance(handler, WrappedHandler):
    3929        pn_handler_dispatch(handler._impl, self._impl, type.number)
    3930      else:
    3931        result = dispatch(handler, type.method, self)
    3932        if result != DELEGATED and hasattr(handler, "handlers"):
    3933          for h in handler.handlers:
    3934            self.dispatch(h, type)
    3935
    3936
    3937    @property
    3938 -  def reactor(self):
    3939      """Returns the reactor associated with the event."""
    3940      return wrappers.get("pn_reactor", _none)(pn_event_reactor(self._impl))
    3941
    3942 -  def __getattr__(self, name):
    3943      r = self.reactor
    3944      if r and hasattr(r, 'subclass') and r.subclass.__name__.lower() == name:
    3945        return r
    3946      else:
    3947        return super(Event, self).__getattr__(name)
    3948
    3949    @property
    3950 -  def transport(self):
    3951      """Returns the transport associated with the event, or null if none is associated with it."""
    3952      return Transport.wrap(pn_event_transport(self._impl))
    3953
    3954    @property
    3955 -  def connection(self):
    3956      """Returns the connection associated with the event, or null if none is associated with it."""
    3957      return Connection.wrap(pn_event_connection(self._impl))
    3958
    3959    @property
    3960 -  def session(self):
    3961      """Returns the session associated with the event, or null if none is associated with it."""
    3962      return Session.wrap(pn_event_session(self._impl))
    3963
    3964    @property
    3965 -  def link(self):
    3966      """Returns the link associated with the event, or null if none is associated with it."""
    3967      return Link.wrap(pn_event_link(self._impl))
    3968
    3969    @property
    3970 -  def sender(self):
    3971      """Returns the sender link associated with the event, or null if
    3972         none is associated with it. This is essentially an alias for
    3973         link(), that does an additional checkon the type of the
    3974         link."""
    3975      l = self.link
    3976      if l and l.is_sender:
    3977        return l
    3978      else:
    3979        return None
    3980
    3981    @property
    3982 -  def receiver(self):
    3983      """Returns the receiver link associated with the event, or null if
    3984         none is associated with it. This is essentially an alias for
    3985         link(), that does an additional checkon the type of the link."""
    3986      l = self.link
    3987      if l and l.is_receiver:
    3988        return l
    3989      else:
    3990        return None
    3991
    3992    @property
    3993 -  def delivery(self):
    3994      """Returns the delivery associated with the event, or null if none is associated with it."""
    3995      return Delivery.wrap(pn_event_delivery(self._impl))
    3996
    3997 -  def __repr__(self):
    3998      return "%s(%s)" % (self.type, self.context)
    3999
    4000 -class LazyHandlers(object):
    4001 -  def __get__(self, obj, clazz):
    4002      if obj is None:
    4003        return self
    4004      ret = []
    4005      obj.__dict__['handlers'] = ret
    4006      return ret
    4007
    4008 -class Handler(object):
    4009    handlers = LazyHandlers()
    4010
    4011 -  def on_unhandled(self, method, *args):
    4012      pass
    4013
    4014 -class _cadapter:
    4015
    4016 -  def __init__(self, handler, on_error=None):
    4017      self.handler = handler
    4018      self.on_error = on_error
    4019
    4020 -  def dispatch(self, cevent, ctype):
    4021      ev = Event.wrap(cevent, ctype)
    4022      ev.dispatch(self.handler)
    4023
    4024 -  def exception(self, exc, val, tb):
    4025      if self.on_error is None:
    4026        _compat.raise_(exc, val, tb)
    4027      else:
    4028        self.on_error((exc, val, tb))
    4029
    4030 -class WrappedHandlersChildSurrogate:
    4031 -    def __init__(self, delegate):
    4032          self.handlers = []
    4033          self.delegate = weakref.ref(delegate)
    4034
    4035 -    def on_unhandled(self, method, event):
    4036          delegate = self.delegate()
    4037          if delegate:
    4038              dispatch(delegate, method, event)
    4039
    4040
    4041 -class WrappedHandlersProperty(object):
    4042 -    def __get__(self, obj, clazz):
    4043          if obj is None:
    4044              return None
    4045          return self.surrogate(obj).handlers
    4046
    4047 -    def __set__(self, obj, value):
    4048          self.surrogate(obj).handlers = value
    4049
    4050 -    def surrogate(self, obj):
    4051          key = "_surrogate"
    4052          objdict = obj.__dict__
    4053          surrogate = objdict.get(key, None)
    4054          if surrogate is None:
    4055              objdict[key] = surrogate = WrappedHandlersChildSurrogate(obj)
    4056              obj.add(surrogate)
    4057          return surrogate
    4058
    4059 -class WrappedHandler(Wrapper):
    4060
    4061    handlers = WrappedHandlersProperty()
    4062
    4063    @classmethod
    4064 -  def wrap(cls, impl, on_error=None):
    4065      if impl is None:
    4066        return None
    4067      else:
    4068        handler = cls(impl)
    4069        handler.__dict__["on_error"] = on_error
    4070        return handler
    4071
    4072 -  def __init__(self, impl_or_constructor):
    4073      Wrapper.__init__(self, impl_or_constructor)
    4074      if list(self.__class__.__mro__).index(WrappedHandler) > 1:
    4075        # instantiate the surrogate
    4076        self.handlers.extend([])
    4077
    4078 -  def _on_error(self, info):
    4079      on_error = getattr(self, "on_error", None)
    4080      if on_error is None:
    4081        _compat.raise_(info[0], info[1], info[2])
    4082      else:
    4083        on_error(info)
    4084
    4085 -  def add(self, handler):
    4086      if handler is None: return
    4087      impl = _chandler(handler, self._on_error)
    4088      pn_handler_add(self._impl, impl)
    4089      pn_decref(impl)
    4090
    4091 -  def clear(self):
    4092      pn_handler_clear(self._impl)
    4093
    4094 -def _chandler(obj, on_error=None):
    4095    if obj is None:
    4096      return None
    4097    elif isinstance(obj, WrappedHandler):
    4098      impl = obj._impl
    4099      pn_incref(impl)
    4100      return impl
    4101    else:
    4102      return pn_pyhandler(_cadapter(obj, on_error))
    4103
    4104 -class Url(object):
    4105    """
    4106    Simple URL parser/constructor, handles URLs of the form:
    4107
    4108    <scheme>://<user>:<password>@<host>:<port>/<path>
    4109
    4110    All components can be None if not specifeid in the URL string.
    4111
    4112    The port can be specified as a service name, e.g. 'amqp' in the
    4113    URL string but Url.port always gives the integer value.
    4114
    4115    @ivar scheme: Url scheme e.g. 'amqp' or 'amqps'
    4116    @ivar user: Username
    4117    @ivar password: Password
    4118    @ivar host: Host name, ipv6 literal or ipv4 dotted quad.
    4119    @ivar port: Integer port.
    4120    @ivar host_port: Returns host:port
    4121    """
    4122
    4123    AMQPS = "amqps"
    4124    AMQP = "amqp"
    4125
    4126 -  class Port(int):
    4127      """An integer port number that can be constructed from a service name string"""
    4128
    4129 -    def __new__(cls, value):
    4130        """@param value: integer port number or string service name."""
    4131        port = super(Url.Port, cls).__new__(cls, cls._port_int(value))
    4132        setattr(port, 'name', str(value))
    4133        return port
    4134
    4135 -    def __eq__(self, x): return str(self) == x or int(self) == x
    4136 -    def __ne__(self, x): return not self == x
    4137 -    def __str__(self): return str(self.name)
    4138
    4139      @staticmethod
    4140 -    def _port_int(value):
    4141        """Convert service, an integer or a service name, into an integer port number."""
    4142        try:
    4143          return int(value)
    4144        except ValueError:
    4145          try:
    4146            return socket.getservbyname(value)
    4147          except socket.error:
    4148            # Not every system has amqp/amqps defined as a service
    4149            if value == Url.AMQPS:  return 5671
    4150            elif value == Url.AMQP: return 5672
    4151            else:
    4152              raise ValueError("Not a valid port number or service name: '%s'" % value)
    4153
    4154 -  def __init__(self, url=None, defaults=True, **kwargs):
    4155      """
    4156      @param url: URL string to parse.
    4157      @param defaults: If true, fill in missing default values in the URL.
    4158          If false, you can fill them in later by calling self.defaults()
    4159      @param kwargs: scheme, user, password, host, port, path.
    4160        If specified, replaces corresponding part in url string.
    4161      """
    4162      if url:
    4163        self._url = pn_url_parse(unicode2utf8(str(url)))
    4164        if not self._url: raise ValueError("Invalid URL '%s'" % url)
    4165      else:
    4166        self._url = pn_url()
    4167      for k in kwargs:            # Let kwargs override values parsed from url
    4168        getattr(self, k)          # Check for invalid kwargs
    4169        setattr(self, k, kwargs[k])
    4170      if defaults: self.defaults()
    4171
    4172 -  class PartDescriptor(object):
    4173 -    def __init__(self, part):
    4174        self.getter = globals()["pn_url_get_%s" % part]
    4175        self.setter = globals()["pn_url_set_%s" % part]
    4176 -    def __get__(self, obj, type=None): return self.getter(obj._url)
    4177 -    def __set__(self, obj, value): return self.setter(obj._url, str(value))
    4178
    4179    scheme = PartDescriptor('scheme')
    4180    username = PartDescriptor('username')
    4181    password = PartDescriptor('password')
    4182    host = PartDescriptor('host')
    4183    path = PartDescriptor('path')
    4184
    4185 -  def _get_port(self):
    4186      portstr = pn_url_get_port(self._url)
    4187      return portstr and Url.Port(portstr)
    4188
    4189 -  def _set_port(self, value):
    4190      if value is None: pn_url_set_port(self._url, None)
    4191      else: pn_url_set_port(self._url, str(Url.Port(value)))
    4192
    4193    port = property(_get_port, _set_port)
    4194
    4195 -  def __str__(self): return pn_url_str(self._url)
    4196
    4197 -  def __repr__(self): return "Url(%r)" % str(self)
    4198
    4199 -  def __eq__(self, x): return str(self) == str(x)
    4200 -  def __ne__(self, x): return not self == x
    4201
    4202 -  def __del__(self):
    4203      pn_url_free(self._url);
    4204      del self._url
    4205
    4206 -  def defaults(self):
    4207      """
    4208      Fill in missing values (scheme, host or port) with defaults
    4209      @return: self
    4210      """
    4211      self.scheme = self.scheme or self.AMQP
    4212      self.host = self.host or '0.0.0.0'
    4213      self.port = self.port or self.Port(self.scheme)
    4214      return self
    4215
    4216  __all__ = [
    4217             "API_LANGUAGE",
    4218             "IMPLEMENTATION_LANGUAGE",
    4219             "ABORTED",
    4220             "ACCEPTED",
    4221             "AUTOMATIC",
    4222             "PENDING",
    4223             "MANUAL",
    4224             "REJECTED",
    4225             "RELEASED",
    4226             "MODIFIED",
    4227             "SETTLED",
    4228             "UNDESCRIBED",
    4229             "Array",
    4230             "Collector",
    4231             "Condition",
    4232             "Connection",
    4233             "Data",
    4234             "Delivery",
    4235             "Disposition",
    4236             "Described",
    4237             "Endpoint",
    4238             "Event",
    4239             "EventType",
    4240             "Handler",
    4241             "Link",
    4242             "Message",
    4243             "MessageException",
    4244             "Messenger",
    4245             "MessengerException",
    4246             "ProtonException",
    4247             "VERSION_MAJOR",
    4248             "VERSION_MINOR",
    4249             "Receiver",
    4250             "SASL",
    4251             "Sender",
    4252             "Session",
    4253             "SessionException",
    4254             "SSL",
    4255             "SSLDomain",
    4256             "SSLSessionDetails",
    4257             "SSLUnavailable",
    4258             "SSLException",
    4259             "Terminus",
    4260             "Timeout",
    4261             "Interrupt",
    4262             "Transport",
    4263             "TransportException",
    4264             "Url",
    4265             "char",
    4266             "dispatch",
    4267             "symbol",
    4268             "timestamp",
    4269             "ulong",
    4270             "byte",
    4271             "short",
    4272             "int32",
    4273             "ubyte",
    4274             "ushort",
    4275             "uint",
    4276             "float32",
    4277             "decimal32",
    4278             "decimal64",
    4279             "decimal128"
    4280             ]
    4281