Coverage for /opt/obspy/update-docs/src/obspy/obspy/seishub/client : 67%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# -*- coding: utf-8 -*- SeisHub database client for ObsPy.
:copyright: The ObsPy Development Team (devs@obspy.org) :license: GNU Lesser General Public License, Version 3 (http://www.gnu.org/copyleft/lesser.html) """
HTTP_ACCEPTED_NODATA_METHODS
'location': 'location_id', 'channel': 'channel_id', 'starttime': 'start_datetime', 'endtime': 'end_datetime'}
""" This is a decorator to intercept a change in the arg list for seishub.client.station.getPAZ() with revision [3778].
* throw a DeprecationWarning * make the correct call """ def new_func(*args, **kwargs): # function itself is first arg so len(args) == 3 means we got 2 args. "Please update your code! The old call syntax has been " + \ "deprecated and will stop working with the next version." "supported anymore."
""" SeisHub database request Client class.
The following classes are automatically linked with initialization. Follow the links in "Linked Class" for more information. They register via the name listed in "Entry Point".
=================== ==================================================== Entry Point Linked Class =================== ==================================================== ``Client.waveform`` :class:`~obspy.seishub.client._WaveformMapperClient` ``Client.station`` :class:`~obspy.seishub.client._StationMapperClient` ``Client.event`` :class:`~obspy.seishub.client._EventMapperClient` =================== ====================================================
.. rubric:: Example
>>> from obspy.seishub import Client >>> from obspy import UTCDateTime >>> >>> t = UTCDateTime("2009-09-03 00:00:00") >>> client = Client() >>> >>> st = client.waveform.getWaveform("BW", "RTPI", "", "EHZ", t, t + 20) >>> print(st) # doctest: +ELLIPSIS 1 Trace(s) in Stream: BW.RTPI..EHZ | 2009-09-03T00:00:00.000000Z - ... | 250.0 Hz, 5001 samples """ user="admin", password="admin", timeout=10, debug=False, retries=3): """ Initializes the SeisHub Web service client.
:type base_url: str, optional :param base_url: SeisHub connection string. Defaults to 'http://teide.geophysik.uni-muenchen.de:8080'. :type user: str, optional :param user: The user name used for identification with the Web service. Defaults to ``'admin'``. :type password: str, optional :param password: A password used for authentication with the Web service. Defaults to ``'admin'``. :type timeout: int, optional :param timeout: Seconds before a connection timeout is raised (default is 10 seconds). Available only for Python >= 2.6.x. :type debug: boolean, optional :param debug: Enables verbose output. :type retries: int :param retries: Number of retries for failing requests. """ # Create an OpenerDirector for Basic HTTP Authentication # install globally
""" Ping the SeisHub server. """ except: None
""" Test if authentication information is valid. Raises an Exception if status code of response is not 200 (OK) or 401 (Forbidden).
:rtype: bool :return: ``True`` if OK, ``False`` if invalid. """ (code, _msg) = self._HTTP_request(self.base_url + "/xml/", method="HEAD") if code == 200: return True elif code == 401: return False else: raise Exception("Unexpected request status code: %s" % code)
# map keywords # check for ranges and empty values params['min_' + str(key)] = str(value[0]) params['max_' + str(key)] = str(value[1]) params['min_' + str(key)] = str(value[0]) params['max_' + str(key)] = str(value[1]) else: # replace special characters if self.debug: print('\nRequesting %s' % (remoteaddr)) # certain requests randomly fail on rare occasions, retry # XXX currently there are random problems with SeisHub's internal # XXX sql database access ("cannot operate on a closed database"). # XXX this can be circumvented by issuing the same request again.. except Exception: continue response = urllib2.urlopen(remoteaddr, timeout=self.timeout) doc = response.read() return doc
""" Send a HTTP request via urllib2.
:type url: String :param url: Complete URL of resource :type method: String :param method: HTTP method of request, e.g. "PUT" :type headers: dict :param headers: Header information for request, e.g. {'User-Agent': "obspyck"} :type xml_string: String :param xml_string: XML for a send request (PUT/POST) """ if method not in HTTP_ACCEPTED_METHODS: raise ValueError("Method must be one of %s" % \ HTTP_ACCEPTED_METHODS) if method in HTTP_ACCEPTED_DATA_METHODS and not xml_string: raise TypeError("Missing data for %s request." % method) elif method in HTTP_ACCEPTED_NODATA_METHODS and xml_string: raise TypeError("Unexpected data for %s request." % method)
req = _RequestWithMethod(method=method, url=url, data=xml_string, headers=headers) # it seems the following always ends in a urllib2.HTTPError even with # nice status codes...?!? try: response = urllib2.urlopen(req) return response.code, response.msg except urllib2.HTTPError, e: return e.code, e.msg
""" Gets a resource.
:type resource_name: str :param resource_name: Name of the resource. :type format: str, optional :param format: Format string, e.g. ``'xml'`` or ``'map'``. :return: Resource """ # NOTHING goes ABOVE this line! resource_name
""" Gets a XML resource.
:type resource_name: str :param resource_name: Name of the resource. :return: Resource as :class:`lxml.objectify.ObjectifiedElement` """ url = '/xml/' + self.package + '/' + self.resourcetype + '/' + \ resource_name return self.client._objectify(url, **kwargs)
""" PUTs a XML resource.
:type resource_name: str :param resource_name: Name of the resource. :type headers: dict :param headers: Header information for request, e.g. ``{'User-Agent': "obspyck"}`` :type xml_string: str :param xml_string: XML for a send request (PUT/POST) :rtype: tuple :return: (HTTP status code, HTTP status message) """ url = '/'.join([self.client.base_url, 'xml', self.package, self.resourcetype, resource_name]) return self.client._HTTP_request(url, method="PUT", xml_string=xml_string, headers=headers)
""" DELETEs a XML resource.
:type resource_name: str :param resource_name: Name of the resource. :type headers: dict :param headers: Header information for request, e.g. ``{'User-Agent': "obspyck"}`` :return: (HTTP status code, HTTP status message) """ url = '/'.join([self.client.base_url, 'xml', self.package, self.resourcetype, resource_name]) return self.client._HTTP_request(url, method="DELETE", headers=headers)
""" Interface to access the SeisHub Waveform Web service.
.. warning:: This function should NOT be initialized directly, instead access the object via the :attr:`obspy.seishub.Client.waveform` attribute.
.. seealso:: https://github.com/barsch/seishub.plugins.seismology/blob/\ master/seishub/plugins/seismology/waveform.py """
""" Gets a list of network ids.
:rtype: list :return: List of containing network ids. """
""" Gets a list of station ids.
:type network: str :param network: Network code, e.g. ``'BW'``. :rtype: list :return: List of containing station ids. """ # NOTHING goes ABOVE this line!
""" Gets a list of location ids.
:type network: str :param network: Network code, e.g. ``'BW'``. :type station: str :param station: Station code, e.g. ``'MANZ'``. :rtype: list :return: List of containing location ids. """ # NOTHING goes ABOVE this line!
**kwargs): """ Gets a list of channel ids.
:type network: str :param network: Network code, e.g. ``'BW'``. :type station: str :param station: Station code, e.g. ``'MANZ'``. :type location: str :param location: Location code, e.g. ``'00'``. :rtype: list :return: List of containing channel ids. """ # NOTHING goes ABOVE this line!
channel=None, **kwargs): """ Gets a list of network latency values.
:type network: str :param network: Network code, e.g. ``'BW'``. :type station: str :param station: Station code, e.g. ``'MANZ'``. :type location: str :param location: Location code, e.g. ``'00'``. :type channel: str :param channel: Channel code, e.g. ``'EHE'``. :rtype: list :return: List of dictionaries containing latency information. """ # NOTHING goes ABOVE this line! for key, value in locals().iteritems(): if key not in ["self", "kwargs"]: kwargs[key] = value url = '/seismology/waveform/getLatency' root = self.client._objectify(url, **kwargs) return [dict(((k, v.pyval) for k, v in node.__dict__.iteritems())) \ for node in root.getchildren()]
starttime=None, endtime=None, apply_filter=False, getPAZ=False, getCoordinates=False, metadata_timecheck=True, **kwargs): """ Gets a ObsPy Stream object.
:type network: str :param network: Network code, e.g. ``'BW'``. :type station: str :param station: Station code, e.g. ``'MANZ'``. :type location: str :param location: Location code, e.g. ``'00'``. :type channel: str :param channel: Channel code, supporting wildcard for component, e.g. ``'EHE'`` or ``'EH*'``. :type starttime: :class:`~obspy.core.utcdatetime.UTCDateTime` :param starttime: Start date and time. :type endtime: :class:`~obspy.core.utcdatetime.UTCDateTime` :param endtime: End date and time. :type apply_filter: bool, optional :param apply_filter: Apply filter (default is ``False``). :type getPAZ: bool, optional :param getPAZ: Fetch PAZ information and append to :class:`~obspy.core.trace.Stats` of all fetched traces. This considerably slows down the request (default is ``False``). :type getCoordinates: bool, optional :param getCoordinates: Fetch coordinate information and append to :class:`~obspy.core.trace.Stats` of all fetched traces. This considerably slows down the request (default is ``False``). :type metadata_timecheck: bool, optional :param metadata_timecheck: For ``getPAZ`` and ``getCoordinates`` check if metadata information is changing from start to end time. Raises an Exception if this is the case. This can be deactivated to save time. :rtype: :class:`~obspy.core.stream.Stream` :return: A ObsPy Stream object. """ # NOTHING goes ABOVE this line! # append all args to kwargs, thus having everything in one dictionary
# allow time strings in arguments kwargs[time] = UTCDateTime(kwargs[time])
# we expand the requested timespan on both ends by two samples in # order to be able to make use of the nearest_sample option of # stream.trim(). (see trim() and tickets #95 and #105) # only possible if a channel is specified otherwise delta = 0
raise Exception("No waveform data available") # unpickle
# trimming needs to be done only if we extend the datetime above datetime=starttime) datetime=endtime) " end time."
station=station, location=location, datetime=starttime) coords_check = self.client.station.getCoordinates( network=network, station=station, location=location, datetime=endtime) if coords != coords_check: msg = "Coordinate information changing from start " + \ "time to end time." raise Exception(msg)
starttime=None, endtime=None, trace_ids=None, **kwargs): """ Gets a preview of a ObsPy Stream object.
:type network: str :param network: Network code, e.g. ``'BW'``. :type station: str :param station: Station code, e.g. ``'MANZ'``. :type location: str :param location: Location code, e.g. ``'00'``. :type channel: str :param channel: Channel code, supporting wildcard for component, e.g. ``'EHE'`` or ``'EH*'``. :type starttime: :class:`~obspy.core.utcdatetime.UTCDateTime` :param starttime: Start date and time. :type endtime: :class:`~obspy.core.utcdatetime.UTCDateTime` :param endtime: End date and time. :rtype: :class:`~obspy.core.stream.Stream` :return: Waveform preview as ObsPy Stream object. """ # NOTHING goes ABOVE this line!
raise Exception("No waveform data available") # unpickle
**kwargs): """ Gets a preview of a ObsPy Stream object.
:type trace_ids: list :type trace_ids: List of trace IDs, e.g. ``['BW.MANZ..EHE']``. :type starttime: :class:`~obspy.core.utcdatetime.UTCDateTime` :param starttime: Start date and time. :type endtime: :class:`~obspy.core.utcdatetime.UTCDateTime` :param endtime: End date and time. :rtype: :class:`~obspy.core.stream.Stream` :return: Waveform preview as ObsPy Stream object. """ # NOTHING goes ABOVE this line! # concatenate list of IDs into string raise Exception("No waveform data available") # unpickle
""" Interface to access the SeisHub Station Web service.
.. warning:: This function should NOT be initialized directly, instead access the object via the :attr:`obspy.seishub.Client.station` attribute.
.. seealso:: https://github.com/barsch/seishub.plugins.seismology/blob/\ master/seishub/plugins/seismology/waveform.py """
""" Gets a list of station information.
:type network: str :param network: Network code, e.g. ``'BW'``. :type station: str :param station: Station code, e.g. ``'MANZ'``. :rtype: list :return: List of dictionaries containing station information. """ # NOTHING goes ABOVE this line! for node in root.getchildren()]
""" Get coordinate information.
Returns a dictionary with coordinate information for specified station at the specified time.
:type network: str :param network: Network code, e.g. ``'BW'``. :type station: str :param station: Station code, e.g. ``'MANZ'``. :type datetime: :class:`~obspy.core.utcdatetime.UTCDateTime` :param datetime: Time for which the PAZ is requested, e.g. ``'2010-01-01 12:00:00'``. :type location: str :param location: Location code, e.g. ``'00'``. :rtype: dict :return: Dictionary containing station coordinate information. """ # NOTHING goes ABOVE this line!
# try to read coordinates from previously obtained station lists # check if starttime is present and fitting pass continue # check if endtime is present and fitting
msg = "No coordinates for station %s.%s at %s" % \ (network, station, datetime) raise Exception(msg) warnings.warn("Received more than one metadata set. Using first.")
def getPAZ(self, seed_id, datetime): """ Get PAZ for a station at given time span. Gain is the A0 normalization constant for the poles and zeros.
:type seed_id: str :param seed_id: SEED or channel id, e.g. ``"BW.RJOB..EHZ"`` or ``"EHE"``. :type datetime: :class:`~obspy.core.utcdatetime.UTCDateTime` :param datetime: Time for which the PAZ is requested, e.g. ``'2010-01-01 12:00:00'``. :rtype: dict :return: Dictionary containing zeros, poles, gain and sensitivity.
.. rubric:: Example
>>> c = Client() >>> paz = c.station.getPAZ('BW.MANZ..EHZ', '20090707') >>> paz['zeros'] [0j, 0j] >>> len(paz['poles']) 5 >>> print(paz['poles'][0]) (-0.037004+0.037016j) >>> paz['gain'] 60077000.0 >>> paz['sensitivity'] 2516800000.0 """ # try to read PAZ from previously obtained XSEED data datetime=UTCDateTime(datetime)) # request station information datetime=datetime) return {} # don't allow wild cards
warnings.warn("Received more than one XSEED file. Using first.")
""" Interface to access the SeisHub Event Web service.
.. warning:: This function should NOT be initialized directly, instead access the object via the :attr:`obspy.seishub.Client.event` attribute.
.. seealso:: https://github.com/barsch/seishub.plugins.seismology/blob/\ master/seishub/plugins/seismology/event.py """
account=None, user=None, min_datetime=None, max_datetime=None, first_pick=None, last_pick=None, min_latitude=None, max_latitude=None, min_longitude=None, max_longitude=None, min_magnitude=None, max_magnitude=None, min_depth=None, max_depth=None, used_p=None, min_used_p=None, max_used_p=None, used_s=None, min_used_s=None, max_used_s=None, document_id=None, **kwargs): """ Gets a list of event information.
:rtype: list :return: List of dictionaries containing event information.
The number of resulting events is by default limited to 50 entries from a SeisHub server. You may raise this by setting the ``limit`` option to a maximal value of 2500. Numbers above 2500 will result into an exception. """ # check limit msg = "Maximal allowed limit is 2500 entries." raise ValueError(msg) # NOTHING goes ABOVE this line! for node in root.getchildren()] limit == None and len(results) == 50 or \ len(results) == 2500: msg = "List of results might be incomplete due to option 'limit'." warnings.warn(msg)
""" Posts an event.getList() and returns the results as a KML file. For optional arguments, see documentation of :meth:`~obspy.seishub.client._EventMapperClient.getList()`
:type nolabels: bool :param nolabels: Hide labels of events in KML. Can be useful with large data sets. :rtype: str :return: String containing KML information of all matching events. This string can be written to a file and loaded into e.g. Google Earth. """ events = self.getList(**kwargs) timestamp = datetime.now()
# construct the KML file kml = Element("kml") kml.set("xmlns", "http://www.opengis.net/kml/2.2")
document = SubElement(kml, "Document") SubElement(document, "name").text = "Seishub Event Locations"
# style definitions for earthquakes style = SubElement(document, "Style") style.set("id", "earthquake")
iconstyle = SubElement(style, "IconStyle") SubElement(iconstyle, "scale").text = "0.5" icon = SubElement(iconstyle, "Icon") SubElement(icon, "href").text = \ "http://maps.google.com/mapfiles/kml/shapes/earthquake.png" hotspot = SubElement(iconstyle, "hotSpot") hotspot.set("x", "0.5") hotspot.set("y", "0") hotspot.set("xunits", "fraction") hotspot.set("yunits", "fraction")
labelstyle = SubElement(style, "LabelStyle") SubElement(labelstyle, "color").text = "ff0000ff" SubElement(labelstyle, "scale").text = "0.8"
folder = SubElement(document, "Folder") SubElement(folder, "name").text = "SeisHub Events (%s)" % \ timestamp.date() SubElement(folder, "open").text = "1"
# additional descriptions for the folder descrip_str = "Fetched from: %s" % self.client.base_url descrip_str += "\nFetched at: %s" % timestamp descrip_str += "\n\nSearch options:\n" descrip_str += "\n".join(["=".join((str(k), str(v))) \ for k, v in kwargs.items()]) SubElement(folder, "description").text = descrip_str
style = SubElement(folder, "Style") liststyle = SubElement(style, "ListStyle") SubElement(liststyle, "listItemType").text = "check" SubElement(liststyle, "bgColor").text = "00ffffff" SubElement(liststyle, "maxSnippetLines").text = "5"
# add one marker per event interesting_keys = ['resource_name', 'localisation_method', 'account', 'user', 'public', 'datetime', 'longitude', 'latitude', 'depth', 'magnitude', 'used_p', 'used_s'] for event_dict in events: placemark = SubElement(folder, "Placemark") date = str(event_dict['datetime']).split(" ")[0] mag = str(event_dict['magnitude'])
# scale marker size to magnitude if this information is present if mag: mag = float(mag) label = "%s: %.1f" % (date, mag) try: icon_size = 1.2 * log(1.5 + mag) except ValueError: icon_size = 0.1 else: label = date icon_size = 0.5 if nolabels: SubElement(placemark, "name").text = "" else: SubElement(placemark, "name").text = label SubElement(placemark, "styleUrl").text = "#earthquake" style = SubElement(placemark, "Style") icon_style = SubElement(style, "IconStyle") liststyle = SubElement(style, "ListStyle") SubElement(liststyle, "maxSnippetLines").text = "5" SubElement(icon_style, "scale").text = str(icon_size) point = SubElement(placemark, "Point") SubElement(point, "coordinates").text = "%.10f,%.10f,0" % \ (event_dict['longitude'], event_dict['latitude'])
# detailed information on the event for the description descrip_str = "" for key in interesting_keys: if not key in event_dict: continue descrip_str += "\n%s: %s" % (key, event_dict[key]) SubElement(placemark, "description").text = descrip_str
# generate and return KML string return tostring(kml, pretty_print=True, xml_declaration=True)
""" Posts an event.getList() and writes the results as a KML file. For optional arguments, see help for :meth:`~obspy.seishub.client._EventMapperClient.getList()` and :meth:`~obspy.seishub.client._EventMapperClient.getKML()`
:type filename: str :param filename: Filename (complete path) to save KML to. :type overwrite: bool :param overwrite: Overwrite existing file, otherwise if file exists an Exception is raised. :type nolabels: bool :param nolabels: Hide labels of events in KML. Can be useful with large data sets. :rtype: str :return: String containing KML information of all matching events. This string can be written to a file and loaded into e.g. Google Earth. """ if not overwrite and os.path.lexists(filename): raise OSError("File %s exists and overwrite=False." % filename) kml_string = self.getKML(**kwargs) open(filename, "wt").write(kml_string) return
""" Improved urllib2.Request Class for which the HTTP Method can be set to values other than only GET and POST. See http://benjamin.smedbergs.us/blog/2008-10-21/\ putting-and-deleteing-in-python-urllib2/ """ if method not in HTTP_ACCEPTED_METHODS: msg = "HTTP Method not supported. " + \ "Supported are: %s." % HTTP_ACCEPTED_METHODS raise ValueError(msg) urllib2.Request.__init__(self, *args, **kwargs) self._method = method
return self._method
if __name__ == '__main__': import doctest doctest.testmod(exclude_empty=True) |