Repository: IAMconsortium/pyam
Pull request #622 (2022-02-02 21:56:32)

Support numpy.int in `interpolate()`
# Please confirm that this PR has done the following:

- [x] Tests Added
- ~Documentation Added~
- [x] Name of contributors Added to AUTHORS.rst
- ~Description in RELEASE_NOTES.md Added~

# Description of PR

This PR cherry-picks the changes made by @coroa in #520 to avoid merge conflicts as part of the refactoring to support a mixed time domain, containing year and datetime.


codecov[bot]: # [Codecov](https://codecov.io/gh/IAMconsortium/pyam/pull/622?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=IAMconsortium) Report
> Merging [#622](https://codecov.io/gh/IAMconsortium/pyam/pull/622?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=IAMconsortium) (88727b7) into [feature/year-and-datetime](https://codecov.io/gh/IAMconsortium/pyam/commit/6b3ff79fe9a764f01bfce24dfecf780acde699b0?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=IAMconsortium) (6b3ff79) will **increase** coverage by `0.0%`.
> The diff coverage is `100.0%`.

[![Impacted file tree graph](https://codecov.io/gh/IAMconsortium/pyam/pull/622/graphs/tree.svg?width=650&height=150&src=pr&token=ThxWlNkonJ&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=IAMconsortium)](https://codecov.io/gh/IAMconsortium/pyam/pull/622?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=IAMconsortium)

```diff
@@                    Coverage Diff                    @@
##           feature/year-and-datetime    #622   +/-   ##
=========================================================
  Coverage                       94.4%   94.4%           
=========================================================
  Files                             56      56           
  Lines                           5512    5517    +5     
=========================================================
+ Hits                            5205    5210    +5     
  Misses                           307     307           
```


| [Impacted Files](https://codecov.io/gh/IAMconsortium/pyam/pull/622?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=IAMconsortium) | Coverage Δ | |
|---|---|---|
| [pyam/core.py](https://codecov.io/gh/IAMconsortium/pyam/pull/622/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=IAMconsortium#diff-cHlhbS9jb3JlLnB5) | `94.6% <100.0%> (+<0.1%)` | :arrow_up: |
| [tests/test\_core.py](https://codecov.io/gh/IAMconsortium/pyam/pull/622/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=IAMconsortium#diff-dGVzdHMvdGVzdF9jb3JlLnB5) | `100.0% <100.0%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/IAMconsortium/pyam/pull/622?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=IAMconsortium).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=IAMconsortium)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/IAMconsortium/pyam/pull/622?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=IAMconsortium). Last update [6b3ff79...88727b7](https://codecov.io/gh/IAMconsortium/pyam/pull/622?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=IAMconsortium). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=IAMconsortium).


Patch:
diff --git a/.stickler.yml b/.stickler.yml
index 0207b65..1917317 100644
--- a/.stickler.yml
+++ b/.stickler.yml
@@ -3,6 +3,6 @@ linters:
     black:
     flake8:
         python: 3
-        ignore: I002, F403, E402, E731, W503, W605
+        ignore: I002, F403, E203, E402, E731, W503, W605
         max-line-length: 88
         max-complexity: 20
diff --git a/pyam/core.py b/pyam/core.py
index 7eb4977..e120411 100755
--- a/pyam/core.py
+++ b/pyam/core.py
@@ -7,6 +7,7 @@ import sys
 
 import numpy as np
 import pandas as pd
+from pandas.api.types import is_integer
 
 from pathlib import Path
 from tempfile import TemporaryDirectory
@@ -38,6 +39,7 @@ from pyam.utils import (
     merge_meta,
     find_depth,
     pattern_match,
+    to_list,
     isstr,
     islistable,
     print_list,
@@ -636,16 +638,16 @@ class IamDataFrame(object):
         ret = self.copy() if not inplace else self
         interp_kwargs = dict(method="slinear", axis=1)
         interp_kwargs.update(kwargs)
-        time = list(time) if islistable(time) else [time]
+        time = to_list(time)
         # TODO - have to explicitly cast to numpy datetime to sort later,
         # could enforce as we do for year below
         if self.time_col == "time":
             time = list(map(np.datetime64, time))
-        elif not all(isinstance(x, int) for x in time):
+        elif not all(is_integer(x) for x in time):
             raise ValueError(f"The `time` argument {time} contains non-integers")
 
         old_cols = list(ret[ret.time_col].unique())
-        columns = np.sort(np.unique(old_cols + time))
+        columns = np.unique(np.concatenate([old_cols, time]))
 
         # calculate a separate dataframe with full interpolation
         df = ret.timeseries()


Test patch:
diff --git a/tests/test_core.py b/tests/test_core.py
index 63c9173..58915b2 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -500,6 +500,12 @@ def test_interpolate_with_list(test_df_year):
     npt.assert_allclose(obs, [3, 4, 1.5, 2, 4, 5])
 
 
+def test_interpolate_with_numpy_list(test_df_year):
+    test_df_year.interpolate(np.r_[2007 : 2008 + 1], inplace=True)
+    obs = test_df_year.filter(year=[2007, 2008])._data.values
+    npt.assert_allclose(obs, [3, 4, 1.5, 2, 4, 5])
+
+
 def test_interpolate_full_example():
     cols = ["model_a", "scen_a", "World"]
     df = IamDataFrame(