We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
IRIS federator routing client does not match https:// URLs — affects RASPISHAKE
### Avoid duplicates

- [X] I searched existing issues

### Bug Summary

I noticed that the `RoutingClient('iris-federator')` was never returning stations / data from the RASPISHAKE data center. Digging in, I found this line in the **federator** `_split_routing_response()` method: https://github.com/obspy/obspy/blob/9659cf3e4499fe15fa71bd0bd3a9600aca7f180e/obspy/clients/fdsn/routing/federator_routing_client.py#L167

Compare to this line in the **eidaws** `_split_routing_response()` method:
https://github.com/obspy/obspy/blob/9659cf3e4499fe15fa71bd0bd3a9600aca7f180e/obspy/clients/fdsn/routing/eidaws_routing_client.py#L195

Note the difference is that the **federator** ignores `https://` URLs. Well, RASPISHAKE's URL is `https://`, see [here](http://service.iris.edu/irisws/fedcatalog/1/query?net=AM&sta=RAF63&format=request&includeoverlaps=false&nodata=404):

> ```
> DATASELECTSERVICE=https://fdsnws.raspberryshakedata.com/fdsnws/dataselect/1/
> STATIONSERVICE=https://fdsnws.raspberryshakedata.com/fdsnws/station/1/
> ```

### Possible fix?

I imagine this is a quick fix, changing `"http://"` to `"http"` on line 167 to match how the **eidaws** URLs are handled. If this is indeed the case, I'm happy to make a PR.

### Code to Reproduce

```python
from obspy.clients.fdsn import Client, RoutingClient

kwargs = dict(network='AM', station='RAF63')

Client('RASPISHAKE').get_stations(**kwargs)  # GOOD: Returns Inventory with "Sending institution: SeisComP (RaspberryShake)"
RoutingClient('iris-federator').get_stations(**kwargs)  # BAD: Raises FDSNNoDataException, see attached error traceback
```


### Error Traceback

```Python traceback
---------------------------------------------------------------------------
FDSNNoDataException                       Traceback (most recent call last)
Input In [7], in <cell line: 1>()
----> 1 RoutingClient('iris-federator').get_stations(**kwargs)

File ~/miniconda3/envs/sonify/lib/python3.9/site-packages/decorator.py:232, in decorate.<locals>.fun(*args, **kw)
    230 if not kwsyntax:
    231     args, kw = fix(args, kw, sig)
--> 232 return caller(func, *(extras + args), **kw)

File ~/miniconda3/envs/sonify/lib/python3.9/site-packages/obspy/clients/fdsn/routing/routing_client.py:78, in _assert_filename_not_in_kwargs(f, *args, **kwargs)
     76 if "filename" in kwargs:
     77     raise ValueError("The `filename` argument is not supported")
---> 78 return f(*args, **kwargs)

File ~/miniconda3/envs/sonify/lib/python3.9/site-packages/obspy/clients/fdsn/routing/federator_routing_client.py:105, in FederatorRoutingClient.get_stations(self, **kwargs)
     88 @_assert_filename_not_in_kwargs
     89 def get_stations(self, **kwargs):
     90     """
     91     Get stations from multiple data centers.
     92
   (...)
    103     for details.
    104     """
--> 105     return super(FederatorRoutingClient, self).get_stations(**kwargs)

File ~/miniconda3/envs/sonify/lib/python3.9/site-packages/decorator.py:232, in decorate.<locals>.fun(*args, **kw)
    230 if not kwsyntax:
    231     args, kw = fix(args, kw, sig)
--> 232 return caller(func, *(extras + args), **kw)

File ~/miniconda3/envs/sonify/lib/python3.9/site-packages/obspy/clients/fdsn/routing/routing_client.py:78, in _assert_filename_not_in_kwargs(f, *args, **kwargs)
     76 if "filename" in kwargs:
     77     raise ValueError("The `filename` argument is not supported")
---> 78 return f(*args, **kwargs)

File ~/miniconda3/envs/sonify/lib/python3.9/site-packages/obspy/clients/fdsn/routing/routing_client.py:367, in BaseRoutingClient.get_stations(self, **kwargs)
    363 # Just pass these to the bulk request.
    364 bulk = [kwargs.pop(key, '*') for key in (
    365         "network", "station", "location", "channel", "starttime",
    366         "endtime")]
--> 367 return self.get_stations_bulk([bulk], **kwargs)

File ~/miniconda3/envs/sonify/lib/python3.9/site-packages/decorator.py:232, in decorate.<locals>.fun(*args, **kw)
    230 if not kwsyntax:
    231     args, kw = fix(args, kw, sig)
--> 232 return caller(func, *(extras + args), **kw)

File ~/miniconda3/envs/sonify/lib/python3.9/site-packages/obspy/clients/fdsn/routing/routing_client.py:78, in _assert_filename_not_in_kwargs(f, *args, **kwargs)
     76 if "filename" in kwargs:
     77     raise ValueError("The `filename` argument is not supported")
---> 78 return f(*args, **kwargs)

File ~/miniconda3/envs/sonify/lib/python3.9/site-packages/obspy/clients/fdsn/routing/federator_routing_client.py:142, in FederatorRoutingClient.get_stations_bulk(self, bulk, **kwargs)
    138 r = self._download(self._url + "/query", data=bulk_str)
    139 split = self._split_routing_response(
    140     r.content.decode() if hasattr(r.content, "decode") else r.content,
    141     service="station")
--> 142 return self._download_stations(split, **kwargs)

File ~/miniconda3/envs/sonify/lib/python3.9/site-packages/obspy/clients/fdsn/routing/routing_client.py:238, in BaseRoutingClient._download_stations(self, split, **kwargs)
    237 def _download_stations(self, split, **kwargs):
--> 238     return self._download_parallel(split, data_type="station", **kwargs)

File ~/miniconda3/envs/sonify/lib/python3.9/site-packages/obspy/clients/fdsn/routing/routing_client.py:245, in BaseRoutingClient._download_parallel(self, split, data_type, **kwargs)
    242 split = self._filter_requests(split)
    244 if not split:
--> 245     raise FDSNNoDataException(
    246         "Nothing remains to download after the provider "
    247         "inclusion/exclusion filters have been applied.")
    249 if data_type not in ["waveform", "station"]:  # pragma: no cover
    250     raise ValueError("Invalid data type.")

FDSNNoDataException: Nothing remains to download after the provider inclusion/exclusion filters have been applied.
```


### ObsPy Version?

1.3.0

### Operating System?

macOS

### Python Version?

3.9.12

### Installation Method?

conda

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `obspy/clients/fdsn/routing/federator_routing_client.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 """
3 Routing client for the IRIS federator routing service.
4 
5 :copyright:
6     The ObsPy Development Team (devs@obspy.org)
7     Celso G Reyes, 2017
8     IRIS-DMC
9 :license:
10     GNU Lesser General Public License, Version 3
11     (https://www.gnu.org/copyleft/lesser.html)
12 """
13 import collections
14 
15 from ..client import get_bulk_string
16 from .routing_client import (
17     BaseRoutingClient, _assert_filename_not_in_kwargs,
18     _assert_attach_response_not_in_kwargs)
19 
20 
21 class FederatorRoutingClient(BaseRoutingClient):
22     def __init__(self, url="http://service.iris.edu/irisws/fedcatalog/1",
23                  include_providers=None, exclude_providers=None,
24                  debug=False, timeout=120, **kwargs):
25         """
26         Initialize a federated routing client.
27 
28         All parameters except ``url`` are passed on to the
29         :class:`~obspy.clients.fdsn.routing.routing_client.BaseRoutingClient`
30         parent class
31 
32         :param url: The URL of the routing service.
33         :type url: str
34         """
35         BaseRoutingClient.__init__(self, debug=debug, timeout=timeout,
36                                    include_providers=include_providers,
37                                    exclude_providers=exclude_providers,
38                                    **kwargs)
39         self._url = url
40 
41         # Parameters the routing service can work with. If this becomes a
42         # standardized service and more implementations show up we should also
43         # parse the WADL files - but right now this would just complicate
44         # things.
45         self.kwargs_of_interest = [
46             "includeoverlaps", "level", "network", "station", "channel",
47             "location", "starttime", "endtime", "startbefore", "endbefore",
48             "startafter", "endafter", "minlatitude", "maxlatitude",
49             "minlongitude", "maxlongitude", "latitude", "longitude",
50             "minradius", "maxradius"]
51 
52     @_assert_attach_response_not_in_kwargs
53     @_assert_filename_not_in_kwargs
54     def get_waveforms_bulk(self, bulk, **kwargs):
55         """
56         Get waveforms from multiple data centers.
57 
58         It will pass on most parameters to the federated routing service.
59         They will also be passed on to the individual FDSNWS implementations
60         if a service supports them.
61 
62         The ``filename`` and ``attach_response`` parameters of the single
63         provider FDSN client are not supported.
64 
65         This can route on a number of different parameters, please see the
66         web site of the
67         `IRIS Federator  <https://service.iris.edu/irisws/fedcatalog/1/>`_
68         for details.
69         """
70         bulk_params = ["network", "station", "location", "channel",
71                        "starttime", "endtime"]
72         for _i in bulk_params:
73             if _i in kwargs:
74                 raise ValueError("`%s` must not be part of the optional "
75                                  "parameters in a bulk request." % _i)
76 
77         params = {k: str(kwargs[k])
78                   for k in self.kwargs_of_interest if k in kwargs}
79         params["format"] = "request"
80 
81         bulk_str = get_bulk_string(bulk, params)
82         r = self._download(self._url + "/query", data=bulk_str)
83         split = self._split_routing_response(
84             r.content.decode() if hasattr(r.content, "decode") else r.content,
85             service="dataselect")
86         return self._download_waveforms(split, **kwargs)
87 
88     @_assert_filename_not_in_kwargs
89     def get_stations(self, **kwargs):
90         """
91         Get stations from multiple data centers.
92 
93         It will pass on most parameters to the federated routing service.
94         They will also be passed on to the individual FDSNWS implementations
95         if a service supports them.
96 
97         The ``filename`` parameter of the single provider FDSN client is not
98         supported.
99 
100         This can route on a number of different parameters, please see the
101         web site of the
102         `IRIS Federator  <https://service.iris.edu/irisws/fedcatalog/1/>`_
103         for details.
104         """
105         return super(FederatorRoutingClient, self).get_stations(**kwargs)
106 
107     @_assert_filename_not_in_kwargs
108     def get_stations_bulk(self, bulk, **kwargs):
109         """
110         Get stations from multiple data centers.
111 
112         It will pass on most parameters to the federated routing service.
113         They will also be passed on to the individual FDSNWS implementations
114         if a service supports them.
115 
116         The ``filename`` parameter of the single provider FDSN client is not
117         supported.
118 
119         This can route on a number of different parameters, please see the
120         web site of the
121         `IRIS Federator  <https://service.iris.edu/irisws/fedcatalog/1/>`_
122         for details.
123         """
124         bulk_params = ["network", "station", "location", "channel",
125                        "starttime", "endtime"]
126         for _i in bulk_params:
127             if _i in kwargs:
128                 raise ValueError("`%s` must not be part of the optional "
129                                  "parameters in a bulk request." % _i)
130 
131         params = collections.OrderedDict()
132         for k in self.kwargs_of_interest:
133             if k in kwargs:
134                 params[k] = str(kwargs[k])
135         params["format"] = "request"
136 
137         bulk_str = get_bulk_string(bulk, params)
138         r = self._download(self._url + "/query", data=bulk_str)
139         split = self._split_routing_response(
140             r.content.decode() if hasattr(r.content, "decode") else r.content,
141             service="station")
142         return self._download_stations(split, **kwargs)
143 
144     @staticmethod
145     def _split_routing_response(data, service):
146         """
147         Splits the routing responses per data center for the federator output.
148 
149         Returns a dictionary with the keys being the root URLs of the fdsnws
150         endpoints and the values the data payloads for that endpoint.
151 
152         :param data: The return value from the EIDAWS routing service.
153         """
154         if service.lower() == "dataselect":
155             key = "DATASELECTSERVICE"
156         elif service.lower() == "station":
157             key = "STATIONSERVICE"
158         else:
159             raise ValueError("Service must be 'dataselect' or 'station'.")
160 
161         split = collections.defaultdict(list)
162         current_key = None
163         for line in data.splitlines():
164             line = line.strip()
165             if not line:
166                 continue
167             if "http://" in line:
168                 if key not in line:
169                     continue
170                 current_key = line[len(key) + 1:line.rfind("/fdsnws")]
171                 continue
172             # Anything before the first data center can be ignored.
173             if current_key is None:
174                 continue
175             split[current_key].append(line)
176 
177         return {k: "\n".join(v) for k, v in split.items()}
178
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/obspy/clients/fdsn/routing/federator_routing_client.py b/obspy/clients/fdsn/routing/federator_routing_client.py
--- a/obspy/clients/fdsn/routing/federator_routing_client.py
+++ b/obspy/clients/fdsn/routing/federator_routing_client.py
@@ -164,7 +164,7 @@
             line = line.strip()
             if not line:
                 continue
-            if "http://" in line:
+            if "http://" in line or "https://" in line:
                 if key not in line:
                     continue
                 current_key = line[len(key) + 1:line.rfind("/fdsnws")]

{"golden_diff": "diff --git a/obspy/clients/fdsn/routing/federator_routing_client.py b/obspy/clients/fdsn/routing/federator_routing_client.py\n--- a/obspy/clients/fdsn/routing/federator_routing_client.py\n+++ b/obspy/clients/fdsn/routing/federator_routing_client.py\n@@ -164,7 +164,7 @@\n             line = line.strip()\n             if not line:\n                 continue\n-            if \"http://\" in line:\n+            if \"http://\" in line or \"https://\" in line:\n                 if key not in line:\n                     continue\n                 current_key = line[len(key) + 1:line.rfind(\"/fdsnws\")]\n", "issue": "IRIS federator routing client does not match https:// URLs \u2014 affects RASPISHAKE\n### Avoid duplicates\r\n\r\n- [X] I searched existing issues\r\n\r\n### Bug Summary\r\n\r\nI noticed that the `RoutingClient('iris-federator')` was never returning stations / data from the RASPISHAKE data center. Digging in, I found this line in the **federator** `_split_routing_response()` method: https://github.com/obspy/obspy/blob/9659cf3e4499fe15fa71bd0bd3a9600aca7f180e/obspy/clients/fdsn/routing/federator_routing_client.py#L167\r\n\r\nCompare to this line in the **eidaws** `_split_routing_response()` method:\r\nhttps://github.com/obspy/obspy/blob/9659cf3e4499fe15fa71bd0bd3a9600aca7f180e/obspy/clients/fdsn/routing/eidaws_routing_client.py#L195\r\n\r\nNote the difference is that the **federator** ignores `https://` URLs. Well, RASPISHAKE's URL is `https://`, see [here](http://service.iris.edu/irisws/fedcatalog/1/query?net=AM&sta=RAF63&format=request&includeoverlaps=false&nodata=404):\r\n\r\n> ```\r\n> DATASELECTSERVICE=https://fdsnws.raspberryshakedata.com/fdsnws/dataselect/1/\r\n> STATIONSERVICE=https://fdsnws.raspberryshakedata.com/fdsnws/station/1/\r\n> ```\r\n\r\n### Possible fix?\r\n\r\nI imagine this is a quick fix, changing `\"http://\"` to `\"http\"` on line 167 to match how the **eidaws** URLs are handled. If this is indeed the case, I'm happy to make a PR.\r\n\r\n### Code to Reproduce\r\n\r\n```python\r\nfrom obspy.clients.fdsn import Client, RoutingClient\r\n\r\nkwargs = dict(network='AM', station='RAF63')\r\n\r\nClient('RASPISHAKE').get_stations(**kwargs)  # GOOD: Returns Inventory with \"Sending institution: SeisComP (RaspberryShake)\"\r\nRoutingClient('iris-federator').get_stations(**kwargs)  # BAD: Raises FDSNNoDataException, see attached error traceback\r\n```\r\n\r\n\r\n### Error Traceback\r\n\r\n```Python traceback\r\n---------------------------------------------------------------------------\r\nFDSNNoDataException                       Traceback (most recent call last)\r\nInput In [7], in <cell line: 1>()\r\n----> 1 RoutingClient('iris-federator').get_stations(**kwargs)\r\n\r\nFile ~/miniconda3/envs/sonify/lib/python3.9/site-packages/decorator.py:232, in decorate.<locals>.fun(*args, **kw)\r\n    230 if not kwsyntax:\r\n    231     args, kw = fix(args, kw, sig)\r\n--> 232 return caller(func, *(extras + args), **kw)\r\n\r\nFile ~/miniconda3/envs/sonify/lib/python3.9/site-packages/obspy/clients/fdsn/routing/routing_client.py:78, in _assert_filename_not_in_kwargs(f, *args, **kwargs)\r\n     76 if \"filename\" in kwargs:\r\n     77     raise ValueError(\"The `filename` argument is not supported\")\r\n---> 78 return f(*args, **kwargs)\r\n\r\nFile ~/miniconda3/envs/sonify/lib/python3.9/site-packages/obspy/clients/fdsn/routing/federator_routing_client.py:105, in FederatorRoutingClient.get_stations(self, **kwargs)\r\n     88 @_assert_filename_not_in_kwargs\r\n     89 def get_stations(self, **kwargs):\r\n     90     \"\"\"\r\n     91     Get stations from multiple data centers.\r\n     92\r\n   (...)\r\n    103     for details.\r\n    104     \"\"\"\r\n--> 105     return super(FederatorRoutingClient, self).get_stations(**kwargs)\r\n\r\nFile ~/miniconda3/envs/sonify/lib/python3.9/site-packages/decorator.py:232, in decorate.<locals>.fun(*args, **kw)\r\n    230 if not kwsyntax:\r\n    231     args, kw = fix(args, kw, sig)\r\n--> 232 return caller(func, *(extras + args), **kw)\r\n\r\nFile ~/miniconda3/envs/sonify/lib/python3.9/site-packages/obspy/clients/fdsn/routing/routing_client.py:78, in _assert_filename_not_in_kwargs(f, *args, **kwargs)\r\n     76 if \"filename\" in kwargs:\r\n     77     raise ValueError(\"The `filename` argument is not supported\")\r\n---> 78 return f(*args, **kwargs)\r\n\r\nFile ~/miniconda3/envs/sonify/lib/python3.9/site-packages/obspy/clients/fdsn/routing/routing_client.py:367, in BaseRoutingClient.get_stations(self, **kwargs)\r\n    363 # Just pass these to the bulk request.\r\n    364 bulk = [kwargs.pop(key, '*') for key in (\r\n    365         \"network\", \"station\", \"location\", \"channel\", \"starttime\",\r\n    366         \"endtime\")]\r\n--> 367 return self.get_stations_bulk([bulk], **kwargs)\r\n\r\nFile ~/miniconda3/envs/sonify/lib/python3.9/site-packages/decorator.py:232, in decorate.<locals>.fun(*args, **kw)\r\n    230 if not kwsyntax:\r\n    231     args, kw = fix(args, kw, sig)\r\n--> 232 return caller(func, *(extras + args), **kw)\r\n\r\nFile ~/miniconda3/envs/sonify/lib/python3.9/site-packages/obspy/clients/fdsn/routing/routing_client.py:78, in _assert_filename_not_in_kwargs(f, *args, **kwargs)\r\n     76 if \"filename\" in kwargs:\r\n     77     raise ValueError(\"The `filename` argument is not supported\")\r\n---> 78 return f(*args, **kwargs)\r\n\r\nFile ~/miniconda3/envs/sonify/lib/python3.9/site-packages/obspy/clients/fdsn/routing/federator_routing_client.py:142, in FederatorRoutingClient.get_stations_bulk(self, bulk, **kwargs)\r\n    138 r = self._download(self._url + \"/query\", data=bulk_str)\r\n    139 split = self._split_routing_response(\r\n    140     r.content.decode() if hasattr(r.content, \"decode\") else r.content,\r\n    141     service=\"station\")\r\n--> 142 return self._download_stations(split, **kwargs)\r\n\r\nFile ~/miniconda3/envs/sonify/lib/python3.9/site-packages/obspy/clients/fdsn/routing/routing_client.py:238, in BaseRoutingClient._download_stations(self, split, **kwargs)\r\n    237 def _download_stations(self, split, **kwargs):\r\n--> 238     return self._download_parallel(split, data_type=\"station\", **kwargs)\r\n\r\nFile ~/miniconda3/envs/sonify/lib/python3.9/site-packages/obspy/clients/fdsn/routing/routing_client.py:245, in BaseRoutingClient._download_parallel(self, split, data_type, **kwargs)\r\n    242 split = self._filter_requests(split)\r\n    244 if not split:\r\n--> 245     raise FDSNNoDataException(\r\n    246         \"Nothing remains to download after the provider \"\r\n    247         \"inclusion/exclusion filters have been applied.\")\r\n    249 if data_type not in [\"waveform\", \"station\"]:  # pragma: no cover\r\n    250     raise ValueError(\"Invalid data type.\")\r\n\r\nFDSNNoDataException: Nothing remains to download after the provider inclusion/exclusion filters have been applied.\r\n```\r\n\r\n\r\n### ObsPy Version?\r\n\r\n1.3.0\r\n\r\n### Operating System?\r\n\r\nmacOS\r\n\r\n### Python Version?\r\n\r\n3.9.12\r\n\r\n### Installation Method?\r\n\r\nconda\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\"\"\"\nRouting client for the IRIS federator routing service.\n\n:copyright:\n    The ObsPy Development Team (devs@obspy.org)\n    Celso G Reyes, 2017\n    IRIS-DMC\n:license:\n    GNU Lesser General Public License, Version 3\n    (https://www.gnu.org/copyleft/lesser.html)\n\"\"\"\nimport collections\n\nfrom ..client import get_bulk_string\nfrom .routing_client import (\n    BaseRoutingClient, _assert_filename_not_in_kwargs,\n    _assert_attach_response_not_in_kwargs)\n\n\nclass FederatorRoutingClient(BaseRoutingClient):\n    def __init__(self, url=\"http://service.iris.edu/irisws/fedcatalog/1\",\n                 include_providers=None, exclude_providers=None,\n                 debug=False, timeout=120, **kwargs):\n        \"\"\"\n        Initialize a federated routing client.\n\n        All parameters except ``url`` are passed on to the\n        :class:`~obspy.clients.fdsn.routing.routing_client.BaseRoutingClient`\n        parent class\n\n        :param url: The URL of the routing service.\n        :type url: str\n        \"\"\"\n        BaseRoutingClient.__init__(self, debug=debug, timeout=timeout,\n                                   include_providers=include_providers,\n                                   exclude_providers=exclude_providers,\n                                   **kwargs)\n        self._url = url\n\n        # Parameters the routing service can work with. If this becomes a\n        # standardized service and more implementations show up we should also\n        # parse the WADL files - but right now this would just complicate\n        # things.\n        self.kwargs_of_interest = [\n            \"includeoverlaps\", \"level\", \"network\", \"station\", \"channel\",\n            \"location\", \"starttime\", \"endtime\", \"startbefore\", \"endbefore\",\n            \"startafter\", \"endafter\", \"minlatitude\", \"maxlatitude\",\n            \"minlongitude\", \"maxlongitude\", \"latitude\", \"longitude\",\n            \"minradius\", \"maxradius\"]\n\n    @_assert_attach_response_not_in_kwargs\n    @_assert_filename_not_in_kwargs\n    def get_waveforms_bulk(self, bulk, **kwargs):\n        \"\"\"\n        Get waveforms from multiple data centers.\n\n        It will pass on most parameters to the federated routing service.\n        They will also be passed on to the individual FDSNWS implementations\n        if a service supports them.\n\n        The ``filename`` and ``attach_response`` parameters of the single\n        provider FDSN client are not supported.\n\n        This can route on a number of different parameters, please see the\n        web site of the\n        `IRIS Federator  <https://service.iris.edu/irisws/fedcatalog/1/>`_\n        for details.\n        \"\"\"\n        bulk_params = [\"network\", \"station\", \"location\", \"channel\",\n                       \"starttime\", \"endtime\"]\n        for _i in bulk_params:\n            if _i in kwargs:\n                raise ValueError(\"`%s` must not be part of the optional \"\n                                 \"parameters in a bulk request.\" % _i)\n\n        params = {k: str(kwargs[k])\n                  for k in self.kwargs_of_interest if k in kwargs}\n        params[\"format\"] = \"request\"\n\n        bulk_str = get_bulk_string(bulk, params)\n        r = self._download(self._url + \"/query\", data=bulk_str)\n        split = self._split_routing_response(\n            r.content.decode() if hasattr(r.content, \"decode\") else r.content,\n            service=\"dataselect\")\n        return self._download_waveforms(split, **kwargs)\n\n    @_assert_filename_not_in_kwargs\n    def get_stations(self, **kwargs):\n        \"\"\"\n        Get stations from multiple data centers.\n\n        It will pass on most parameters to the federated routing service.\n        They will also be passed on to the individual FDSNWS implementations\n        if a service supports them.\n\n        The ``filename`` parameter of the single provider FDSN client is not\n        supported.\n\n        This can route on a number of different parameters, please see the\n        web site of the\n        `IRIS Federator  <https://service.iris.edu/irisws/fedcatalog/1/>`_\n        for details.\n        \"\"\"\n        return super(FederatorRoutingClient, self).get_stations(**kwargs)\n\n    @_assert_filename_not_in_kwargs\n    def get_stations_bulk(self, bulk, **kwargs):\n        \"\"\"\n        Get stations from multiple data centers.\n\n        It will pass on most parameters to the federated routing service.\n        They will also be passed on to the individual FDSNWS implementations\n        if a service supports them.\n\n        The ``filename`` parameter of the single provider FDSN client is not\n        supported.\n\n        This can route on a number of different parameters, please see the\n        web site of the\n        `IRIS Federator  <https://service.iris.edu/irisws/fedcatalog/1/>`_\n        for details.\n        \"\"\"\n        bulk_params = [\"network\", \"station\", \"location\", \"channel\",\n                       \"starttime\", \"endtime\"]\n        for _i in bulk_params:\n            if _i in kwargs:\n                raise ValueError(\"`%s` must not be part of the optional \"\n                                 \"parameters in a bulk request.\" % _i)\n\n        params = collections.OrderedDict()\n        for k in self.kwargs_of_interest:\n            if k in kwargs:\n                params[k] = str(kwargs[k])\n        params[\"format\"] = \"request\"\n\n        bulk_str = get_bulk_string(bulk, params)\n        r = self._download(self._url + \"/query\", data=bulk_str)\n        split = self._split_routing_response(\n            r.content.decode() if hasattr(r.content, \"decode\") else r.content,\n            service=\"station\")\n        return self._download_stations(split, **kwargs)\n\n    @staticmethod\n    def _split_routing_response(data, service):\n        \"\"\"\n        Splits the routing responses per data center for the federator output.\n\n        Returns a dictionary with the keys being the root URLs of the fdsnws\n        endpoints and the values the data payloads for that endpoint.\n\n        :param data: The return value from the EIDAWS routing service.\n        \"\"\"\n        if service.lower() == \"dataselect\":\n            key = \"DATASELECTSERVICE\"\n        elif service.lower() == \"station\":\n            key = \"STATIONSERVICE\"\n        else:\n            raise ValueError(\"Service must be 'dataselect' or 'station'.\")\n\n        split = collections.defaultdict(list)\n        current_key = None\n        for line in data.splitlines():\n            line = line.strip()\n            if not line:\n                continue\n            if \"http://\" in line:\n                if key not in line:\n                    continue\n                current_key = line[len(key) + 1:line.rfind(\"/fdsnws\")]\n                continue\n            # Anything before the first data center can be ignored.\n            if current_key is None:\n                continue\n            split[current_key].append(line)\n\n        return {k: \"\\n\".join(v) for k, v in split.items()}\n", "path": "obspy/clients/fdsn/routing/federator_routing_client.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\"\"\"\nRouting client for the IRIS federator routing service.\n\n:copyright:\n    The ObsPy Development Team (devs@obspy.org)\n    Celso G Reyes, 2017\n    IRIS-DMC\n:license:\n    GNU Lesser General Public License, Version 3\n    (https://www.gnu.org/copyleft/lesser.html)\n\"\"\"\nimport collections\n\nfrom ..client import get_bulk_string\nfrom .routing_client import (\n    BaseRoutingClient, _assert_filename_not_in_kwargs,\n    _assert_attach_response_not_in_kwargs)\n\n\nclass FederatorRoutingClient(BaseRoutingClient):\n    def __init__(self, url=\"http://service.iris.edu/irisws/fedcatalog/1\",\n                 include_providers=None, exclude_providers=None,\n                 debug=False, timeout=120, **kwargs):\n        \"\"\"\n        Initialize a federated routing client.\n\n        All parameters except ``url`` are passed on to the\n        :class:`~obspy.clients.fdsn.routing.routing_client.BaseRoutingClient`\n        parent class\n\n        :param url: The URL of the routing service.\n        :type url: str\n        \"\"\"\n        BaseRoutingClient.__init__(self, debug=debug, timeout=timeout,\n                                   include_providers=include_providers,\n                                   exclude_providers=exclude_providers,\n                                   **kwargs)\n        self._url = url\n\n        # Parameters the routing service can work with. If this becomes a\n        # standardized service and more implementations show up we should also\n        # parse the WADL files - but right now this would just complicate\n        # things.\n        self.kwargs_of_interest = [\n            \"includeoverlaps\", \"level\", \"network\", \"station\", \"channel\",\n            \"location\", \"starttime\", \"endtime\", \"startbefore\", \"endbefore\",\n            \"startafter\", \"endafter\", \"minlatitude\", \"maxlatitude\",\n            \"minlongitude\", \"maxlongitude\", \"latitude\", \"longitude\",\n            \"minradius\", \"maxradius\"]\n\n    @_assert_attach_response_not_in_kwargs\n    @_assert_filename_not_in_kwargs\n    def get_waveforms_bulk(self, bulk, **kwargs):\n        \"\"\"\n        Get waveforms from multiple data centers.\n\n        It will pass on most parameters to the federated routing service.\n        They will also be passed on to the individual FDSNWS implementations\n        if a service supports them.\n\n        The ``filename`` and ``attach_response`` parameters of the single\n        provider FDSN client are not supported.\n\n        This can route on a number of different parameters, please see the\n        web site of the\n        `IRIS Federator  <https://service.iris.edu/irisws/fedcatalog/1/>`_\n        for details.\n        \"\"\"\n        bulk_params = [\"network\", \"station\", \"location\", \"channel\",\n                       \"starttime\", \"endtime\"]\n        for _i in bulk_params:\n            if _i in kwargs:\n                raise ValueError(\"`%s` must not be part of the optional \"\n                                 \"parameters in a bulk request.\" % _i)\n\n        params = {k: str(kwargs[k])\n                  for k in self.kwargs_of_interest if k in kwargs}\n        params[\"format\"] = \"request\"\n\n        bulk_str = get_bulk_string(bulk, params)\n        r = self._download(self._url + \"/query\", data=bulk_str)\n        split = self._split_routing_response(\n            r.content.decode() if hasattr(r.content, \"decode\") else r.content,\n            service=\"dataselect\")\n        return self._download_waveforms(split, **kwargs)\n\n    @_assert_filename_not_in_kwargs\n    def get_stations(self, **kwargs):\n        \"\"\"\n        Get stations from multiple data centers.\n\n        It will pass on most parameters to the federated routing service.\n        They will also be passed on to the individual FDSNWS implementations\n        if a service supports them.\n\n        The ``filename`` parameter of the single provider FDSN client is not\n        supported.\n\n        This can route on a number of different parameters, please see the\n        web site of the\n        `IRIS Federator  <https://service.iris.edu/irisws/fedcatalog/1/>`_\n        for details.\n        \"\"\"\n        return super(FederatorRoutingClient, self).get_stations(**kwargs)\n\n    @_assert_filename_not_in_kwargs\n    def get_stations_bulk(self, bulk, **kwargs):\n        \"\"\"\n        Get stations from multiple data centers.\n\n        It will pass on most parameters to the federated routing service.\n        They will also be passed on to the individual FDSNWS implementations\n        if a service supports them.\n\n        The ``filename`` parameter of the single provider FDSN client is not\n        supported.\n\n        This can route on a number of different parameters, please see the\n        web site of the\n        `IRIS Federator  <https://service.iris.edu/irisws/fedcatalog/1/>`_\n        for details.\n        \"\"\"\n        bulk_params = [\"network\", \"station\", \"location\", \"channel\",\n                       \"starttime\", \"endtime\"]\n        for _i in bulk_params:\n            if _i in kwargs:\n                raise ValueError(\"`%s` must not be part of the optional \"\n                                 \"parameters in a bulk request.\" % _i)\n\n        params = collections.OrderedDict()\n        for k in self.kwargs_of_interest:\n            if k in kwargs:\n                params[k] = str(kwargs[k])\n        params[\"format\"] = \"request\"\n\n        bulk_str = get_bulk_string(bulk, params)\n        r = self._download(self._url + \"/query\", data=bulk_str)\n        split = self._split_routing_response(\n            r.content.decode() if hasattr(r.content, \"decode\") else r.content,\n            service=\"station\")\n        return self._download_stations(split, **kwargs)\n\n    @staticmethod\n    def _split_routing_response(data, service):\n        \"\"\"\n        Splits the routing responses per data center for the federator output.\n\n        Returns a dictionary with the keys being the root URLs of the fdsnws\n        endpoints and the values the data payloads for that endpoint.\n\n        :param data: The return value from the EIDAWS routing service.\n        \"\"\"\n        if service.lower() == \"dataselect\":\n            key = \"DATASELECTSERVICE\"\n        elif service.lower() == \"station\":\n            key = \"STATIONSERVICE\"\n        else:\n            raise ValueError(\"Service must be 'dataselect' or 'station'.\")\n\n        split = collections.defaultdict(list)\n        current_key = None\n        for line in data.splitlines():\n            line = line.strip()\n            if not line:\n                continue\n            if \"http://\" in line or \"https://\" in line:\n                if key not in line:\n                    continue\n                current_key = line[len(key) + 1:line.rfind(\"/fdsnws\")]\n                continue\n            # Anything before the first data center can be ignored.\n            if current_key is None:\n                continue\n            split[current_key].append(line)\n\n        return {k: \"\\n\".join(v) for k, v in split.items()}\n", "path": "obspy/clients/fdsn/routing/federator_routing_client.py"}]}