Repository: obspy/obspy

Issue:
GCF read fails on windows (recent python + numpy 1.22)
https://tests.obspy.org/115141/ & https://tests.obspy.org/115136/ on two independent machines show the error

I suspect it's numpy-dtype related:

```
Traceback (most recent call last):
File "C:\Miniconda3\envs\test\lib\site-packages\numpy\core\fromnumeric.py", line 57, in _wrapfunc
return bound(*args, **kwds)
TypeError: the resolved dtypes are not compatible with add.accumulate. Resolved (dtype('int32'), dtype('int32'), dtype('int32'))
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "D:\a\obspy\obspy\obspy\io\gcf\tests\test_core.py", line 72, in test_read_via_module
st = _read_gcf(filename)
File "D:\a\obspy\obspy\obspy\io\gcf\core.py", line 89, in _read_gcf
hd = libgcf.read(f, **kwargs)
File "D:\a\obspy\obspy\obspy\io\gcf\libgcf.py", line 167, in read
return read_data_block(f, headonly=False, **kwargs)
File "D:\a\obspy\obspy\obspy\io\gcf\libgcf.py", line 144, in read_data_block
data = (fic + np.cumsum(data)).astype('i4')
File "<__array_function__ internals>", line 180, in cumsum
File "C:\Miniconda3\envs\test\lib\site-packages\numpy\core\fromnumeric.py", line 2569, in cumsum
return _wrapfunc(a, 'cumsum', axis=axis, dtype=dtype, out=out)
File "C:\Miniconda3\envs\test\lib\site-packages\numpy\core\fromnumeric.py", line 66, in _wrapfunc
return _wrapit(obj, method, *args, **kwds)
File "C:\Miniconda3\envs\test\lib\site-packages\numpy\core\fromnumeric.py", line 43, in _wrapit
result = getattr(asarray(obj), method)(*args, **kwds)
TypeError: the resolved dtypes are not compatible with add.accumulate. Resolved (dtype('int32'), dtype('int32'), dtype('int32'))
```



Discussion:
note to self: temporarily fixed numpy<1.22 for github actions testing!

![image](https://user-images.githubusercontent.com/916937/148120794-007c26e6-3b60-4e41-b9a7-7c39dcec6fc5.png)
 and it's OK like this! 
should be solved by https://github.com/numpy/numpy/pull/20722 ; so waiting now that numpy releases 1.22.1 and we can relax the "numpy<1.22" condition
Nominally, the `.. versionchanged::` tag says 1.23.0. I'm checking on the PR thread to verify
Looks like it won't be backported. `numpy!=1.22` might be a better option.

Resolving patch:
diff --git a/obspy/io/gcf/libgcf.py b/obspy/io/gcf/libgcf.py
--- a/obspy/io/gcf/libgcf.py
+++ b/obspy/io/gcf/libgcf.py
@@ -5,6 +5,8 @@
 # Based on Guralp's GCF reference (GCF-RFC-GCFR, Issue C, 2011-01-05)
 # more details available from: http://www.guralp.com/apps/ok?doc=GCF_Intro
 # last access: June, 2016
+import struct
+
 import numpy as np
 
 from obspy import UTCDateTime
@@ -27,9 +29,10 @@
     179: 8.,
     181: 16.}
 COMPRESSION_D = {  # Table 3.2: format field to data type
-    1: '>i4',
-    2: '>i2',
-    4: '>i1'}
+    1: 'i',  # 4 bytes
+    2: 'h',  # 2 bytes
+    4: 'b',  # 1 byte
+}
 
 
 def is_gcf(f):
@@ -86,29 +89,20 @@ def read_data_block(f, headonly=False, channel_prefix="HH", **kwargs):
     sysid = f.read(4)
     if not sysid:
         raise EOFError  # got to EOF
-    sysid = np.frombuffer(sysid, count=1, dtype='>u4')
+    sysid, = struct.unpack('>I', sysid)
     if sysid >> 31 & 0b1 > 0:
         sysid = (sysid << 6) >> 6
-    if isinstance(sysid, np.ndarray) and sysid.shape == (1,):
-        sysid = sysid[0]
-    else:
-        raise ValueError('sysid should be a single element np.ndarray')
     sysid = decode36(sysid)
     # get Stream ID
-    stid = np.frombuffer(f.read(4), count=1, dtype='>u4')
-    if isinstance(stid, np.ndarray) and stid.shape == (1,):
-        stid = stid[0]
-    else:
-        raise ValueError('stid should be a single element np.ndarray')
+    stid, = struct.unpack('>I', f.read(4))
     stid = decode36(stid)
     # get Date & Time
-    data = np.frombuffer(f.read(4), count=1, dtype='>u4')
+    data, = struct.unpack('>I', f.read(4))
     starttime = decode_date_time(data)
     # get data format
     # get reserved, SPS, data type compression,
     # number of 32bit records (num_records)
-    reserved, sps, compress, num_records = np.frombuffer(f.read(4), count=4,
-                                                         dtype='>u1')
+    reserved, sps, compress, num_records = struct.unpack('>4B', f.read(4))
     compression = compress & 0b00000111  # get compression code
     t_offset = compress >> 4  # get time offset
     if t_offset > 0:
@@ -136,14 +130,14 @@ def read_data_block(f, headonly=False, channel_prefix="HH", **kwargs):
         return header
     else:
         # get FIC
-        fic = np.frombuffer(f.read(4), count=1, dtype='>i4')
+        fic, = struct.unpack('>i', f.read(4))
         # get incremental data
-        data = np.frombuffer(f.read(4 * num_records), count=npts,
-                             dtype=COMPRESSION_D[compression])
+        data = struct.unpack(f'>{npts}{COMPRESSION_D[compression]}',
+                             f.read(4 * num_records))
         # construct time series
         data = (fic + np.cumsum(data)).astype('i4')
         # get RIC
-        ric = np.frombuffer(f.read(4), count=1, dtype='>i4')
+        ric, = struct.unpack('>i', f.read(4))
         # skip to end of block if only partly filled with data
         if 1000 - num_records * 4 > 0:
             f.seek(1000 - num_records * 4, 1)


Test patch:
diff --git a/.github/test_conda_env-3.10.yml b/.github/test_conda_env-3.10.yml
--- a/.github/test_conda_env-3.10.yml
+++ b/.github/test_conda_env-3.10.yml
@@ -13,7 +13,7 @@ dependencies:
   - greenlet
   - kiwisolver
   - lxml
-  - numpy<1.22
+  - numpy
   - pillow
   - pip
   - pyparsing
diff --git a/.github/test_conda_env-3.7.yml b/.github/test_conda_env-3.7.yml
--- a/.github/test_conda_env-3.7.yml
+++ b/.github/test_conda_env-3.7.yml
@@ -3,7 +3,7 @@ channels:
   - conda-forge
   - defaults
 dependencies:
-  - numpy<1.22
+  - numpy
   - scipy
   - matplotlib>3.2.0
   - pip
diff --git a/.github/test_conda_env-3.8.yml b/.github/test_conda_env-3.8.yml
--- a/.github/test_conda_env-3.8.yml
+++ b/.github/test_conda_env-3.8.yml
@@ -3,7 +3,7 @@ channels:
   - conda-forge
   - defaults
 dependencies:
-  - numpy<1.22
+  - numpy
   - scipy
   - matplotlib
   - pip
diff --git a/.github/test_conda_env-3.9.yml b/.github/test_conda_env-3.9.yml
--- a/.github/test_conda_env-3.9.yml
+++ b/.github/test_conda_env-3.9.yml
@@ -13,7 +13,7 @@ dependencies:
   - greenlet
   - kiwisolver
   - lxml
-  - numpy<1.22
+  - numpy
   - pillow
   - pip
   - pyparsing
diff --git a/.github/test_conda_env.yml b/.github/test_conda_env.yml
--- a/.github/test_conda_env.yml
+++ b/.github/test_conda_env.yml
@@ -3,7 +3,7 @@ channels:
   - conda-forge
   - defaults
 dependencies:
-  - numpy<1.22
+  - numpy
   - scipy
   - matplotlib>3.2.0
   - pip