Repository: rasterio/rasterio

Issue:
`dtypes.get_minimum_dtype` doesn't support `int8`
<!--

WELCOME ABOARD!

Hi and welcome to the Rasterio project. We appreciate bug reports, questions
about documentation, and suggestions for new features. This issue template
isn't intended to ward you off; only to intercept and redirect some particular
categories of reports, and to collect a few important facts that issue reporters
often omit.

The primary forum for questions about installation and usage of Rasterio is 
https://rasterio.groups.io/g/main. The authors and other users will answer 
questions when they have expertise to share and time to explain. Please take the
time to craft a clear question and be patient about responses. Please do not
bring these questions to Rasterio's issue tracker, which we want to reserve for
bug reports and other actionable issues.

Questions about development of Rasterio, brainstorming, requests for comment,
and not-yet-actionable proposals are welcome in the project's developers 
discussion group https://rasterio.groups.io/g/dev. Issues opened in Rasterio's
GitHub repo which haven't been socialized there may be perfunctorily closed.

Please note: Rasterio contains extension modules and is thus susceptible to
C library compatibility issues. If you are reporting an installation or module
import issue, please note that this project only accepts reports about problems
with packages downloaded from the Python Package Index. Conda users should take
issues to one of the following trackers:

- https://github.com/ContinuumIO/anaconda-issues/issues
- https://github.com/conda-forge/rasterio-feedstock

You think you've found a bug? We believe you!
-->

## Expected behavior and actual behavior.

`rasterio.dtypes.get_minimum_dtype` doesn't support `int8` even though it's a supported type in `rasterio` (added by #1595). Looking at [the source](https://github.com/rasterio/rasterio/blob/5cf71dc806adc299108543def00647845ab4fc42/rasterio/dtypes.py#L162), there's no check for signed ranges smaller than `int16`. 

Maybe there's a good reason for this, but if it's as simple as just adding a check for the `[-128, 127]` range, I'm happy to make a PR to add that.

## Steps to reproduce the problem.

```python
import rasterio

rasterio.dtypes.get_minimum_dtype([-128, 127]) # int16
```

#### Environment Information
```
rasterio info:
  rasterio: 1.3.2
      GDAL: 3.5.1
      PROJ: 9.0.1
      GEOS: 3.10.2
 PROJ DATA: /home/az/miniconda3/envs/wxee/share/proj
 GDAL DATA: /home/az/miniconda3/envs/wxee/share/gdal

System:
    python: 3.9.6 | packaged by conda-forge | (default, Jul 11 2021, 03:39:48)  [GCC 9.3.0]
executable: /home/az/miniconda3/envs/wxee/bin/python
   machine: Linux-5.18.10-76051810-generic-x86_64-with-glibc2.33

Python deps:
    affine: 2.3.1
     attrs: None
   certifi: 2022.09.24
     click: 8.0.1
     cligj: 0.7.2
    cython: None
     numpy: 1.21.1
    snuggs: 1.4.7
click-plugins: None
setuptools: 49.6.0.post20210108
```
## Installation Method

Installed from PyPI with `pip==21.2.2`.

Thanks!


Discussion:
I think this makes sense to add. Thoughts @sgillies @vincentsarago ?

Resolving patch:
diff --git a/rasterio/dtypes.py b/rasterio/dtypes.py
--- a/rasterio/dtypes.py
+++ b/rasterio/dtypes.py
@@ -159,6 +159,8 @@ def get_minimum_dtype(values):
             if not _GDAL_AT_LEAST_35:
                 raise ValueError("Values out of range for supported dtypes")
             return uint64
+        elif min_value >= -128 and max_value <= 127:
+            return int8
         elif min_value >= -32768 and max_value <= 32767:
             return int16
         elif min_value >= -2147483648 and max_value <= 2147483647:


Test patch:
diff --git a/tests/test_dtypes.py b/tests/test_dtypes.py
--- a/tests/test_dtypes.py
+++ b/tests/test_dtypes.py
@@ -10,6 +10,7 @@
     uint16,
     uint32,
     uint64,
+    int8,
     int16,
     int32,
     int64,
@@ -68,7 +69,8 @@ def test_get_minimum_dtype():
     assert get_minimum_dtype([0, 1]) == uint8
     assert get_minimum_dtype([0, 1000]) == uint16
     assert get_minimum_dtype([0, 100000]) == uint32
-    assert get_minimum_dtype([-1, 0, 1]) == int16
+    assert get_minimum_dtype([-1, 0, 1]) == int8
+    assert get_minimum_dtype([-1, 0, 128]) == int16
     assert get_minimum_dtype([-1, 0, 100000]) == int32
     assert get_minimum_dtype([-1.5, 0, 1.5]) == float32
     assert get_minimum_dtype([-1.5e+100, 0, 1.5e+100]) == float64
@@ -76,7 +78,8 @@ def test_get_minimum_dtype():
     assert get_minimum_dtype(np.array([0, 1], dtype=np.uint)) == uint8
     assert get_minimum_dtype(np.array([0, 1000], dtype=np.uint)) == uint16
     assert get_minimum_dtype(np.array([0, 100000], dtype=np.uint)) == uint32
-    assert get_minimum_dtype(np.array([-1, 0, 1], dtype=int)) == int16
+    assert get_minimum_dtype(np.array([-1, 0, 1], dtype=int)) == int8
+    assert get_minimum_dtype(np.array([-1, 0, 128], dtype=int)) == int16
     assert get_minimum_dtype(np.array([-1, 0, 100000], dtype=int)) == int32
     assert get_minimum_dtype(np.array([-1.5, 0, 1.5], dtype=np.float64)) == float32