obspy.core.event.resourceid.ResourceIdentifier

class ResourceIdentifier(id=None, prefix='smi:local', referred_object=None, parent=None)[source]

Bases: object

Unique identifier referring to a resource.

In QuakeML many elements and types can have a unique id that other elements use to refer to it. This is called a ResourceIdentifier and it is used for the same purpose in the obspy.core.event classes. The id must be a string.

In QuakeML it has to be of the following regex form:

(smi|quakeml):[\w\d][\w\d\-\.\*\(\)_~']{2,}/[\w\d\-\.\*\(\)_~']
[\w\d\-\.\*\(\)\+\?_~'=,;#/&]*

e.g.

  • smi:sub.website.org/event/12345678

  • quakeml:google.org/pick/unique_pick_id

smi stands for “seismological meta-information”.

Parameters:
  • id (str, optional) – A string to uniquely identify a resource. If no resource_id is given, uuid.uuid4() will be used to create one which assures uniqueness within the current Python run. If no fixed id is provided, the ID will be built from prefix and a random uuid hash. The random hash can be regenerated by the referred object automatically if it gets changed.

  • prefix (str, optional) – An optional identifier that will be put in front of any automatically created resource id. The prefix will only have an effect if id is not specified (for a fixed ID string). Makes automatically generated resource ids more reasonable. By default “smi:local” is used which ensures a QuakeML compliant resource identifier.

  • referred_object (object, optional) – The object (resource) to which this instance refers. All instances created with the same resource_id will be able to access the object as long as at least one instance actually has a reference to it. Additionally, ResourceIdentifier instances that have the same id but refer to different objects will still return the correct referred object, provided it doesn’t get garbage collected. If the referred object no longer exists the last object registered with the same id will be returned, or None if no such object exists.

  • parent (hashable) – The parent to use as a namespace for the resource identifier. This allows potentially interconnected resource identifiers to be sensibly grouped together, ensuring that objects belonging to the same parent are returned by resource ids of the parent. Used primarily to ensure resource_ids in an event refer to other objects in the same event. All resource ids must be unique within the parent namespace.

General Usage

>>> ResourceIdentifier('2012-04-11--385392')
ResourceIdentifier(id="2012-04-11--385392")
>>> # If 'id' is not specified it will be generated automatically.
>>> ResourceIdentifier()  
ResourceIdentifier(id="smi:local/...")
>>> # Supplying a prefix will simply prefix the automatically generated ID
>>> ResourceIdentifier(prefix='event')  
ResourceIdentifier(id="event/...")

ResourceIdentifiers can, and oftentimes should, carry a reference to the object they refer to. This is a weak reference which means that if the object get deleted or runs out of scope, e.g. gets garbage collected, the reference will cease to exist.

>>> from obspy.core.event import Event
>>> event = Event()
>>> import sys
>>> ref_count = sys.getrefcount(event)
>>> res_id = ResourceIdentifier(referred_object=event)
>>> # The reference does not changed the reference count of the object.
>>> print(ref_count == sys.getrefcount(event))
True
>>> # It actually is the same object.
>>> print(event is res_id.get_referred_object())
True
>>> # Deleting it, or letting the garbage collector handle the object will
>>> # invalidate the reference.
>>> del event
>>> print(res_id.get_referred_object())  
None

The most powerful ability (and reason why one would want to use a resource identifier class in the first place) is that once a ResourceIdentifier with an attached referred object has been created, any other ResourceIdentifier instances with the same ID can retrieve that object. This works across all ResourceIdentifiers that have been instantiated within one Python run. This enables, e.g. the resource references between the different QuakeML elements to work in a rather natural way.

>>> event_object = Event()
>>> obj_id = id(event_object)
>>> res_id = "obspy.org/event/test"
>>> ref_a = ResourceIdentifier(res_id)
>>> # The object is refers to cannot be found yet. Because no instance that
>>> # an attached object has been created so far.
>>> print(ref_a.get_referred_object())
None
>>> # This instance has an attached object.
>>> ref_b = ResourceIdentifier(res_id, referred_object=event_object)
>>> ref_c = ResourceIdentifier(res_id)
>>> # All ResourceIdentifiers will refer to the same object.
>>> assert ref_a.get_referred_object() is event_object
>>> assert ref_b.get_referred_object() is event_object
>>> assert ref_c.get_referred_object() is event_object

Resource identifiers are bound to an object once the get_referred_object method has been called. The results is that get_referred_object will always return the same object it did on the first call as long as the object still exists. If the bound object gets garage collected a warning will be issued and another object with the same resource_id will be returned (if one exists). If no other object is associated with the same resource_id, an additional warning will be issued and None returned.

>>> from obspy import UTCDateTime
>>> res_id = 'obspy.org/tests/test_resource_doc_example'
>>> obj_a = UTCDateTime(10)
>>> obj_b = UTCDateTime(10)
>>> ref_a = ResourceIdentifier(res_id, referred_object=obj_a)
>>> ref_b = ResourceIdentifier(res_id, referred_object=obj_b)
>>> assert ref_a.get_referred_object() == ref_b.get_referred_object()
>>> assert ref_a.get_referred_object() is not ref_b.get_referred_object()
>>> assert ref_a.get_referred_object() is obj_a
>>> assert ref_b.get_referred_object() is obj_b
>>> del obj_b  # obj_b gets garbage collected
>>> assert ref_b.get_referred_object() is obj_a  
>>> del obj_a  # now no object with res_id exists
>>> assert ref_b.get_referred_object() is None  

ResourceIdentifiers are considered identical if the IDs are the same.

>>> # Create two different resource identifiers.
>>> res_id_1 = ResourceIdentifier()
>>> res_id_2 = ResourceIdentifier()
>>> res_id_3 = ResourceIdentifier(id=res_id_2.id)
>>> assert res_id_1 != res_id_2
>>> assert res_id_2 == res_id_3

ResourceIdentifier instances can be used as dictionary keys.

>>> dictionary = {}
>>> res_id = ResourceIdentifier(id="foo")
>>> dictionary[res_id] = "bar1"
>>> # The same ID can still be used as a key.
>>> dictionary["foo"] = "bar2"
>>> items = sorted(dictionary.items(), key=lambda kv: kv[1])
>>> for k, v in items:  
...     print(repr(k), v)
ResourceIdentifier(id="foo") bar1
...'foo' bar2

Because ResourceIdentifier instances are hashed based on their id attribute, you should never change it once it has been set. Create a new ResourceIdentifier object instead.

Attributes

id

Unique identifier of the current instance.

prefix

resource_id

uuid

Public Methods

convert_id_to_quakeml_uri

Converts the current ID to a valid QuakeML URI.

copy

Returns a copy of the ResourceIdentifier.

get_quakeml_id

Returns a resource id with a valid QuakeML URI.

get_quakeml_uri

This method is deprecated, use get_quakeml_uri_str() instead.

get_quakeml_uri_str

Returns an id with a valid QuakeML URI.

get_referred_object

Returns the object associated with the resource identifier.

regenerate_uuid

Regenerates the uuid part of the ID.

register_get_object_hook

Register a callable to return referred object if normal means fail.

remove_get_object_hook

Remove a callable from the registered get_object hooks.

set_referred_object

Bind an object to the ResourceIdentifier instance.

Private Methods

Warning

Private methods are mainly for internal/developer use and their API might change without notice.

classmethod ResourceIdentifier._bind_class_state(state_dict)[source]

Bind the state contained in state_dict to ResourceIdentifier class.

classmethod ResourceIdentifier._debug_class_state()[source]

Context manager for debugging the class level state for Resource Ids.

Replaces the current resource_id and unbound mappings returning a dictionary with the new mappings as values and “rdict”, and “unbound” as keys. This function restores original mappings upon exit.

ResourceIdentifier._get_newest_object_with_same_resource_id()[source]

Return the newest object which has been bound to the same resource_id. If No such object exists return None.

ResourceIdentifier._get_object_from_parent_scope()[source]

Find an object in the same parent scope with the same resource_id. If No such object is found return None.

ResourceIdentifier._get_similar_referred_object()[source]

Find an object with the same resource id.

If the resource_identifier instance is not bound to a specific object, or the bound object has been garbage collected, try to find another object that was assigned the same resource_id.

The parent_id_tree will be scanned first to see if any object_ids have been assigned to the same resource_id in the parent scope. If not simply use the last object assigned the resource_id. If no object is found return None.

ResourceIdentifier._repr_pretty_(p, cycle)[source]

Special Methods

ResourceIdentifier.__call__()

Returns the object associated with the resource identifier.

This works as long as at least one ResourceIdentifier with the same ID as this instance has an associated object. If not, this method will return None.

ResourceIdentifier.__deepcopy__(memodict={})[source]
ResourceIdentifier.__delattr__(name, /)

Implement delattr(self, name).

ResourceIdentifier.__dir__()

Default dir() implementation.

ResourceIdentifier.__eq__(other)[source]
ResourceIdentifier.__format__(format_spec, /)

Default object formatter.

ResourceIdentifier.__ge__(value, /)

Return self>=value.

ResourceIdentifier.__getattribute__(name, /)

Return getattr(self, name).

ResourceIdentifier.__gt__(value, /)

Return self>value.

ResourceIdentifier.__hash__()[source]

Uses the same hash as the resource id. This means that class instances can be used in dictionaries and other hashed types. Both the object and it’s id can still be independently used as dictionary keys.

ResourceIdentifier.__init__(id=None, prefix='smi:local', referred_object=None, parent=None)[source]
ResourceIdentifier.__init_subclass__()

This method is called when a class is subclassed.

The default implementation does nothing. It may be overridden to extend subclasses.

ResourceIdentifier.__le__(value, /)

Return self<=value.

ResourceIdentifier.__lt__(value, /)

Return self<value.

ResourceIdentifier.__ne__(other)[source]
ResourceIdentifier.__new__(**kwargs)
ResourceIdentifier.__reduce__()

Helper for pickle.

ResourceIdentifier.__reduce_ex__(protocol, /)

Helper for pickle.

ResourceIdentifier.__repr__()[source]
ResourceIdentifier.__setattr__(name, value, /)

Implement setattr(self, name, value).

ResourceIdentifier.__setstate__(state)[source]

Make sure the resource_key follows the singleton pattern.

ResourceIdentifier.__sizeof__()

Size of object in memory, in bytes.

ResourceIdentifier.__str__()[source]
ResourceIdentifier.__subclasshook__()

Abstract classes can override this to customize issubclass().

This is invoked early on by abc.ABCMeta.__subclasscheck__(). It should return True, False or NotImplemented. If it returns NotImplemented, the normal algorithm is used. Otherwise, it overrides the normal algorithm (and the outcome is cached).