Exemplo n.º 1
0
    def __init__(self, wrapped_obj):

        # make sure our object is wrapped by containment only
        try:
            self.path = '/'.join(wrapped_obj.getPhysicalPath())
        except AttributeError:
            self.path = None

        # If the path ends with /, it means the object had an empty id.
        # This means it's not yet added to the container, and so we have
        # to defer.
        if self.path is not None and self.path.endswith('/'):
            raise NotYet(wrapped_obj)
        self.object = aq_base(wrapped_obj)
        connection = IConnection(wrapped_obj, None)

        if not getattr(self.object, '_p_oid', None):
            if connection is None:
                raise NotYet(wrapped_obj)
            connection.add(self.object)

        try:
            root = get_root(wrapped_obj)
        except AttributeError:
            # If the object is unwrapped we can try to use the Site from the
            # threadlocal as our acquisition context, hopefully it's not
            # something odd.
            root = get_root(getSite())
        self.root_oid = root._p_oid
        self.root_dbname = IConnection(root).db().database_name
        self.oid = self.object._p_oid
        self.dbname = connection.db().database_name
Exemplo n.º 2
0
def hash_persistent(obj):
    oid = obj._p_oid
    connection = obj._p_jar
    if oid is None or connection is None:
        connection = IConnection(obj, None)
        if connection is None:
            raise zope.keyreference.interfaces.NotYet(obj)
        connection.add(obj)
        oid = obj._p_oid
    database_name = connection.db().database_name
    return hash((database_name, oid))
Exemplo n.º 3
0
def hash_persistent(obj):
    oid = obj._p_oid
    connection = obj._p_jar
    if oid is None or connection is None:
        connection = IConnection(obj, None)
        if connection is None:
            raise zope.keyreference.interfaces.NotYet(obj)
        connection.add(obj)
        oid = obj._p_oid
    database_name = connection.db().database_name
    return hash((database_name, oid))
Exemplo n.º 4
0
def to_external_oid(self,
                    default=None,
                    add_to_connection=False,
                    add_to_intids=False,
                    use_cache=True):
    # Override the signature to *not* document use_cache.
    """
    to_external_oid(self, default=None, add_to_connection=False, add_to_intids=False) -> bytes

    For a `persistent object <persistent.Persistent>`, returns its
    `persistent OID <persistent.interfaces.IPersistent._p_oid>` in a parseable external format (see
    :func:`.from_external_oid`). This format includes the database name
    (so it works in a ZODB multi-database) and the integer ID from the
    closest :class:`zope.intid.interfaces.IIntIds` utility.

    If the object implements a method ``toExternalOID()``, that method
    will be called and its result (or the *default*) will be returned.
    This should generally be considered legacy behaviour.

    If the object has not been saved, and *add_to_connection* is
    `False` (the default) returns the *default*.

    :param bool add_to_connection: If the object is persistent but not
        yet added to a connection, setting this to true will attempt
        to add it to the nearest connection in its containment tree,
        thus letting it have an OID.
    :param bool add_to_intids: If we can obtain an OID for this
        object, but it does not have an intid, and an intid utility is
        available, then if this is `True` (not the default) we will
        register it with the utility.

    :return: A :class:`bytes` string.
    """
    # TODO: Simplify
    # pylint:disable=too-many-branches
    try:
        return self.toExternalOID() or default
    except AttributeError:
        pass

    if use_cache:
        # XXX: And yet we still set it always.
        try:
            # See comments in to_external_ntiid_oid
            return getattr(self, '_v_to_external_oid')
        except AttributeError:
            pass

    # because if it was proxied, we should still read the right thing above;
    # this saves time
    self = removeAllProxies(self)
    try:
        oid = self._p_oid
    except AttributeError:
        return default

    jar = None
    if not oid:
        if add_to_connection:
            try:
                jar = IConnection(self)
            except TypeError:
                return default

            jar.add(self)
            oid = self._p_oid
        else:
            return default

    # The object ID is defined to be 8 charecters long. It gets
    # padded with null chars to get to that length; we strip
    # those out. Finally, it probably has chars that
    # aren't legal in UTF or ASCII, so we go to hex and prepend
    # a flag, '0x'
    # TODO: Why are we keeping this as a bytes string, not unicode?
    oid = oid.lstrip(b'\x00')
    oid = b'0x' + binascii.hexlify(oid)
    try:
        jar = jar or self._p_jar
    except AttributeError:
        pass

    if jar:
        db_name = jar.db().database_name
        oid = oid + b':' + binascii.hexlify(bytes_(db_name))
    intutility = component.queryUtility(IIntIds)
    if intutility is not None:
        intid = intutility.queryId(self)
        if intid is None and add_to_intids:
            intid = intutility.register(self)
        if intid is not None:
            if not jar:
                oid = oid + b':'  # Ensure intid is always the third part
            oid = oid + b':' + bytes_(to_external_string(intid))

    try:
        setattr(self, str('_v_to_external_oid'), oid)
    except (AttributeError, TypeError):  # pragma: no cover
        pass
    return oid