Repository: obspy/obspy

Issue:
Station.identifiers[0] should not be URI type
Hello!
Just want to say that obspy continues to be an incredibly useful package!

I'm trying to set the identifiers on an obspy Station instance.
According to FDSN schema 1.1 IdentifierType should be a simple string with "type" attribute:
```
  <xs:complexType name="IdentifierType">
    <xs:annotation>
      <xs:documentation>A type to document persistent identifiers.
        Identifier values should be specified without a URI scheme (prefix),
        instead the identifer type is documented as an attribute.
      </xs:documentation>
    </xs:annotation>
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute name="type" type="xs:string"> </xs:attribute>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>

```
However, obspy (v.1.2.2) seems to have encoded this as xsd:anyURI type instead:

>>> wes.identifiers = ['10.157778/RESIF.FR']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/mth/mth/miniconda3/envs/test_yasmine/lib/python3.8/site-packages/obspy/core/inventory/util.py", line 123, in identifiers
    _warn_on_invalid_uri(identifier)
  File "/Users/mth/mth/miniconda3/envs/test_yasmine/lib/python3.8/site-packages/obspy/core/inventory/util.py", line 1076, in _warn_on_invalid_uri
    msg = "Given string seems to not be a valid URI: ''" % uri
TypeError: not all arguments converted during string formatting

```
>>> wes.identifiers=['http://10.16778/RESIF.FR', 'http://32.2323/RESIF.CR']
>>> print("obspy is happy now!")
```

Tracking it down a bit further:

core/inventory/util.py:
```
    @identifiers.setter
    def identifiers(self, value):
        if not hasattr(value, "__iter__"):
            msg = "identifiers needs to be an iterable, e.g. a list."
            raise ValueError(msg)
        # make sure to unwind actual iterators, or the just might get exhausted
        # at some point
        identifiers = [identifier for identifier in value]
        for identifier in identifiers:
            _warn_on_invalid_uri(identifier)
        self._identifiers = identifiers
```

This calls:

```
def _warn_on_invalid_uri(uri):
    if not _is_valid_uri(uri):
        msg = "Given string seems to not be a valid URI: ''" % uri
        warnings.warn(msg)
```

And that msg seems to be missing the %s format to print uri and that seems to be
the error I'm getting.

So I guess there are 2 things:
1. identifiers - sholudn't be checked as valid_uri, at least not for basenode types
2. the _warn_on_invalid_uri() func has an error in msg.


Thanks!
-Mike


Discussion:
Two things..
- yes, that error needs to be fixed
- stationxml is just storing the URI in two pieces (URI path as the text value and URI scheme attribute "type") whereas we decided to keep it in one piece in obspy internally, just to keep it simple, so checking and warning if not following URI syntax still seems like the right thing to do, also considering how FDSN StationXML xsd is pleading for a valid URI scheme:path syntax in the annotation ;-)

Resolving patch:
diff --git a/obspy/core/inventory/util.py b/obspy/core/inventory/util.py
--- a/obspy/core/inventory/util.py
+++ b/obspy/core/inventory/util.py
@@ -1072,7 +1072,7 @@ def _is_valid_uri(uri):
 
 def _warn_on_invalid_uri(uri):
     if not _is_valid_uri(uri):
-        msg = "Given string seems to not be a valid URI: ''" % uri
+        msg = f"Given string seems to not be a valid URI: '{uri}'"
         warnings.warn(msg)
 
 


Test patch:
diff --git a/obspy/core/tests/test_station.py b/obspy/core/tests/test_station.py
--- a/obspy/core/tests/test_station.py
+++ b/obspy/core/tests/test_station.py
@@ -13,6 +13,8 @@
 import pytest
 
 from obspy import read_inventory, UTCDateTime
+from obspy.core.inventory import Station
+from obspy.core.util import CatchAndAssertWarnings
 from obspy.core.util.testing import WarningsCapture
 
 
@@ -153,3 +155,14 @@ def test_station_select(self):
         assert len(sta.select(
             latitude=47.95, longitude=12.95,
             minradius=0.08, maxradius=0.1)) == 0
+
+    def test_warn_identifier_invalid_uri_syntax(self):
+        """
+        Tests the warning on Identifiers getting set with an invalid URI (not
+        having scheme-colon-path)
+        """
+        sta = Station(code='A', latitude=1, longitude=1, elevation=1)
+        invalid_uri = "this-has-no-URI-scheme-and-no-colon"
+        msg = f"Given string seems to not be a valid URI: '{invalid_uri}'"
+        with CatchAndAssertWarnings(expected=[(UserWarning, msg)]):
+            sta.identifiers = [invalid_uri]