def update_iris_station_xml(req, output_file, options=None): """ Pull the latest IRIS complete station inventory (down to station level, not including instrument responses) from IRIS web service and save to file in FDSN station xml format. :param req: Request object to use for URI query :type req: Object conforming to interface of 'requests' library :param output_file: Destination file to generate :type output_file: str :param options: Filtering options for network, station and channel codes, defaults to None :param options: Python dict of key-values pairs matching command line options, optional """ iris_url = form_channel_request_url( ) if options is None else form_channel_request_url(**options) # Download latest IRIS station database as FDSN station xml. try: print("Requesting data from server...") iris = req.get(iris_url) set_text_encoding(iris) except req.exceptions.RequestException: print("FAILED to retrieve URL content at " + iris_url) return # Repair errors with IRIS data print("Correcting known data errors...") iris_fixed = repair_iris_metadata(iris) # Close the query to free resources iris.close() with open(output_file, 'w') as f: f.write(iris_fixed) # Create human-readable text form of the IRIS station inventory (Pandas stringified table) output_txt = os.path.splitext(output_file)[0] + ".txt" regenerate_human_readable(iris_fixed, output_txt)
def obtain_nominal_instrument_response(netcode, statcode, chcode, req): """ For given network, station and channel code, find suitable response(s) in IRIS database and return as dict of obspy instrument responses. :param netcode: Network code (may include wildcards) :type netcode: str :param statcode: Station code (may include wildcards) :type statcode: str :param chcode: Channel code (may include wildcards) :type chcode: str :param req: Request object to use for URI query :type req: Object conforming to interface of 'requests' library :return: Dictionary of instrument responses from IRIS for given network(s), station(s) and channel(s). :rtype: dict of {str, Instrument(obspy.core.inventory.util.Equipment, obspy.core.inventory.response.Response)} """ from obspy.core.util.obspy_types import FloatWithUncertaintiesAndUnit query_url = form_response_request_url(netcode, statcode, chcode) tries = 10 while tries > 0: try: tries -= 1 response_xml = req.get(query_url) first_line = sio.StringIO(response_xml.text).readline().rstrip() assert 'Error 404' not in first_line break except req.exceptions.RequestException as e: # pylint: disable=unused-variable time.sleep(1) assert tries > 0 set_text_encoding(response_xml, quiet=True) # This line decodes when .text attribute is extracted, then encodes to utf-8 obspy_input = bio.BytesIO(response_xml.text.encode('utf-8')) try: channel_data = read_inventory(obspy_input) responses = { cha.code: Instrument(cha.sensor, cha.response) for net in channel_data.networks for sta in net.stations for cha in sta.channels if cha.code is not None and cha.response is not None } # Make responses valid for Seiscomp3 for inst in responses.values(): assert inst.response for rs in inst.response.response_stages: if rs.decimation_delay is None: rs.decimation_delay = FloatWithUncertaintiesAndUnit(0) if rs.decimation_correction is None: rs.decimation_correction = FloatWithUncertaintiesAndUnit(0) except ValueError: responses = {} return responses
def test_set_text_encoding(iris_mocker): """Test detection of encoding from XML and setting it in the response object. :param iris_mocker: Automatic fixture object passed by pytest which duck types requests :type iris_mocker: tests.mocks.inventory.mock_fdsn_xml.MockIrisResponse """ default_channel_query = iris_query.form_channel_request_url() iris_mocker.get(default_channel_query, text=iris_mocker.get_full_response()) response = requests.get(default_channel_query) assert response.encoding != "ISO-8859-1" iris_query.set_text_encoding(response) assert response.encoding == "ISO-8859-1"