Repository: pandas-dev/pandas
Pull request: Fix for issue #57268 - ENH: Preserve input start/end type in interval…
…_range

- [ ] closes #57268 
- [ ] [Tests added and passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#writing-tests) if fixing a bug or adding a new feature
- [ ] All [code checks passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#pre-commit).
- [ ] Added [type annotations](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#type-hints) to new arguments/methods/functions.
- [ ] Added an entry in the latest `doc/source/whatsnew/vX.X.X.rst` file if fixing a bug or adding a new feature.


Problem statement:
ENH: Preserve input `start`/`end` type in `interval_range`
```python
In [1]: import pandas as pd

In [2]: import numpy as np

In [3]: pd.interval_range(start=np.int8(1), end=np.int8(10))
Out[3]: 
IntervalIndex([(1, 2], (2, 3], (3, 4], (4, 5], (5, 6], (6, 7], (7, 8], (8, 9],
               (9, 10]],
              dtype='interval[int64, right]')
```

It would be ideal if the resulting dtype was `'interval[int8, right]'`

Hints from issue discussion:
In the interval.py, I made it retain the same datatype if both start and end has same datatype

```python
dtype = start.dtype if start.dtype == end.dtype else np.dtype("int64")
breaks = maybe_downcast_numeric(
    breaks,  # type: ignore[arg-type]
    dtype,
)
return IntervalIndex.from_breaks(breaks, name=name, closed=closed, dtype=IntervalDtype(subtype=dtype, closed=closed))
```
And I am getting the desired results

![image](https://github.com/pandas-dev/pandas/assets/16797137/11331b2e-1702-48ee-987d-93f41868afd4)

Commit message: Ruff - Pre-commit issue fix

Patch to review:
diff --git a/pandas/core/indexes/interval.py b/pandas/core/indexes/interval.py
index 46d1ee49c22a0..6e58aeb34da75 100644
--- a/pandas/core/indexes/interval.py
+++ b/pandas/core/indexes/interval.py
@@ -1120,9 +1120,19 @@ def interval_range(
             # error: Argument 1 to "maybe_downcast_numeric" has incompatible type
             # "Union[ndarray[Any, Any], TimedeltaIndex, DatetimeIndex]";
             # expected "ndarray[Any, Any]"  [
+            if isinstance(start, int) or isinstance(end, int):
+                dtype = np.dtype("int64")
+            else:
+                dtype = start.dtype if start.dtype == end.dtype else np.dtype("int64")
             breaks = maybe_downcast_numeric(
                 breaks,  # type: ignore[arg-type]
-                np.dtype("int64"),
+                dtype,
+            )
+            return IntervalIndex.from_breaks(
+                breaks,
+                name=name,
+                closed=closed,
+                dtype=IntervalDtype(subtype=breaks.dtype, closed=closed),
             )
     else:
         # delegate to the appropriate range function


Code review comments:
diff_hunk: @@ -1120,9 +1120,19 @@ def interval_range(
             # error: Argument 1 to "maybe_downcast_numeric" has incompatible type
             # "Union[ndarray[Any, Any], TimedeltaIndex, DatetimeIndex]";
             # expected "ndarray[Any, Any]"  [
+            if isinstance(start, int) or isinstance(end, int):
+                dtype = np.dtype("int64")
+            else:
+                dtype = start.dtype if start.dtype == end.dtype else np.dtype("int64")
             breaks = maybe_downcast_numeric(
                 breaks,  # type: ignore[arg-type]
-                np.dtype("int64"),
+                dtype,
+            )
+            return IntervalIndex.from_breaks(
+                breaks,
+                name=name,
+                closed=closed,
+                dtype=IntervalDtype(subtype=breaks.dtype, closed=closed),
path: pandas/core/indexes/interval.py
text: @user1:
Can you just pass a `dtype` to the `IntervalIndex.from_breaks` below?

@author:
Yes, I can do that!

@author:
All changes have been implemented and tests are passed. Unit test is added as well!