znicholls: Oh nice then keep it as is, I was just doing what seemed to  read more
easily to me but consistency with the wider community is a better choice

On Sat, 30 Nov 2019 at 6:07 pm, Daniel Huppmann <notifications@github.com>
wrote:

> *@danielhuppmann* commented on this pull request.
> ------------------------------
>
> In pyam/core.py
> <https://github.com/IAMconsortium/pyam/pull/297#discussion_r352270626>:
>
> > @@ -148,6 +148,11 @@ def tail(self, *args, **kwargs):
>          """Identical to pd.DataFrame.tail() operating on data"""
>          return self.data.tail(*args, **kwargs)
>
> +    @property
> +    def empty(self):
> +        """Indicator whether ``IamDataFrame`` is empty"""
>
> I was using the pandas docstring as a template, see
> https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.empty.html
>
> —
> You are receiving this because your review was requested.
> Reply to this email directly, view it on GitHub
> <https://github.com/IAMconsortium/pyam/pull/297?email_source=notifications&email_token=AFUH5GZ6BLHMECEZHCRL6STQWIGJHA5CNFSM4JRZ44AKYY3PNVWWK3TUL52HS4DFWFIHK3DMKJSXC5LFON2FEZLWNFSXPKTDN5WW2ZLOORPWSZGOCNOUQBA#discussion_r352270626>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AFUH5GYTR357ETI4TKEYSOTQWIGJHANCNFSM4JRZ44AA>
> .
>

danielhuppmann: thanks @znicholls for the review!
danielhuppmann: Merging as approved by @znicholls
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index c868d77..c43a18f 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,6 +1,7 @@
 
 # Next Release
 
+- [#297](https://github.com/IAMconsortium/pyam/pull/297) Add `empty` attribute, better error for `timeseries()` on empty dataframe 
 - [#292](https://github.com/IAMconsortium/pyam/pull/292) Add warning message if `data` is empty at initialization (after formatting)
 - [#288](https://github.com/IAMconsortium/pyam/pull/288) Put `pyam` logger in its own namespace (see [here](https://docs.python-guide.org/writing/logging/#logging-in-a-library>))
 
diff --git a/pyam/core.py b/pyam/core.py
index d5787f1..03837dd 100644
--- a/pyam/core.py
+++ b/pyam/core.py
@@ -148,6 +148,11 @@ class IamDataFrame(object):
         """Identical to pd.DataFrame.tail() operating on data"""
         return self.data.tail(*args, **kwargs)
 
+    @property
+    def empty(self):
+        """Indicator whether ``IamDataFrame`` is empty"""
+        return self.data.empty
+
     def models(self):
         """Get a list of models"""
         return pd.Series(self.meta.index.levels[0])
@@ -373,14 +378,24 @@ class IamDataFrame(object):
         return list(cols)
 
     def timeseries(self, iamc_index=False):
-        """Returns a pd.DataFrame in wide format (years or timedate as columns)
+        """Returns a pd.DataFrame in wide format (years or datetime as columns)
 
         Parameters
         ----------
         iamc_index: bool, default False
             if True, use `['model', 'scenario', 'region', 'variable', 'unit']`;
             else, use all `data` columns
+
+        Raises
+        ------
+        ValueError
+            ``IamDataFrame`` is empty
+        ValueError
+            reducing to IAMC-index yields an index with duplicates
         """
+        if self.empty:
+            raise ValueError('this `IamDataFrame` is empty')
+
         index = IAMC_IDX if iamc_index else IAMC_IDX + self.extra_cols
         df = (
             self.data

`timeseries()` on empty `IamDataFrame` fails very loudly
# Description of the issue

When calling `timeseries()` on an empty `IamDataFrame`, the internally used `pandas.DataFrame.pivot_table()` fails with a long, non-intuitive error message (see below). This might be quite intimidating to non-expert users.

## Improved behaviour

Checking whether the `data` table is empty before doing the pivot operation is straightforward. 

Two questions on implementation and expected behaviour, though:

1) Should `pyam` only write a message to the log file (as is done for `filter()`, see [here](https://github.com/IAMconsortium/pyam/blob/103b60f8f2f46fddae4d0325cbc2651cb098030a/pyam/core.py#L1001), or should a (nicer) error be raised?

2) If only a warning is written to the log, should the returned object be `None` or an empty `pandas.DataFrame` (but with the correct index dimensions).

# Error message

```
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-48-36a29f3c3d4a> in <module>
----> 1 df.filter(variable='foo').timeseries()

~/Github/pyam/pyam/core.py in timeseries(self, iamc_index)
    382         df = (
    383             self.data
--> 384             .pivot_table(index=index, columns=self.time_col)
    385             .value  # column name
    386             .rename_axis(None, axis=1)

~/anaconda3/lib/python3.7/site-packages/pandas/core/generic.py in __getattr__(self, name)
   5177             if self._info_axis._can_hold_identifiers_and_holds_name(name):
   5178                 return self[name]
-> 5179             return object.__getattribute__(self, name)
   5180 
   5181     def __setattr__(self, name, value):

AttributeError: 'DataFrame' object has no attribute 'value'
```
diff --git a/tests/test_core.py b/tests/test_core.py
index 58fb1ef..ae3965a 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -152,6 +152,11 @@ def test_init_empty_message(test_pd_df, caplog):
     assert caplog.records[message_idx].levelno == logging.WARNING
 
 
+def test_empty_attribute(test_df_year):
+    assert not test_df_year.empty
+    assert test_df_year.filter(model='foo').empty
+
+
 def test_to_excel(test_df):
     fname = 'foo_testing.xlsx'
     test_df.to_excel(fname)
@@ -491,6 +496,11 @@ def test_timeseries(test_df):
     npt.assert_array_equal(obs, exp)
 
 
+def test_timeseries_raises(test_df_year):
+    _df = test_df_year.filter(model='foo')
+    pytest.raises(ValueError, _df.timeseries)
+
+
 def test_read_pandas():
     df = IamDataFrame(os.path.join(TEST_DATA_DIR, 'testing_data_2.csv'))
     assert list(df.variables()) == ['Primary Energy']
diff --git a/tests/test_tutorials.py b/tests/test_tutorials.py
index 8f4560d..4b4f5c6 100644
--- a/tests/test_tutorials.py
+++ b/tests/test_tutorials.py
@@ -28,7 +28,7 @@ tut_path = os.path.join(here, '..', 'doc', 'source', 'tutorials')
 # https://blog.thedataincubator.com/2016/06/testing-jupyter-notebooks/
 
 
-def _notebook_run(path, kernel=None, capsys=None):
+def _notebook_run(path, kernel=None, timeout=60, capsys=None):
     """Execute a notebook via nbconvert and collect output.
     :returns (parsed nb object, execution errors)
     """
@@ -39,7 +39,7 @@ def _notebook_run(path, kernel=None, capsys=None):
     fname = os.path.join(here, 'test.ipynb')
     args = [
         "jupyter", "nbconvert", "--to", "notebook", "--execute",
-        "--ExecutePreprocessor.timeout=60",
+        "--ExecutePreprocessor.timeout={}".format(timeout),
         "--ExecutePreprocessor.kernel_name={}".format(kernel),
         "--output", fname, path]
     subprocess.check_call(args)
@@ -87,7 +87,7 @@ def test_pyam_logo():
 @pytest.mark.skipif(not pandoc_installed, reason=pandoc_reason)
 def test_iiasa_dbs():
     fname = os.path.join(tut_path, 'iiasa_dbs.ipynb')
-    nb, errors = _notebook_run(fname)
+    nb, errors = _notebook_run(fname, timeout=600)
     assert errors == []
 
 

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-mpl
3.7
ci/environment-conda-default.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
aiofiles==22.1.0
aiosqlite==0.19.0
anyio==3.7.1
argon2-cffi==23.1.0
argon2-cffi-bindings==21.2.0
arrow==1.2.3
attrs==24.2.0
Babel==2.14.0
backcall==0.2.0
beautifulsoup4==4.13.3
bleach==6.0.0
cached-property==1.5.2
certifi @ file:///croot/certifi_1671487769961/work/certifi
cffi==1.15.1
charset-normalizer==3.4.1
comm==0.1.4
cycler==0.11.0
debugpy==1.7.0
decorator==5.1.1
defusedxml==0.7.1
entrypoints==0.4
exceptiongroup==1.2.2
fastjsonschema==2.21.1
fonttools==4.38.0
fqdn==1.5.1
idna==3.10
importlib-metadata==6.7.0
importlib-resources==5.12.0
iniconfig==2.0.0
ipykernel==6.16.2
ipython==7.34.0
ipython-genutils==0.2.0
ipywidgets==8.1.5
isoduration==20.11.0
jedi==0.19.2
Jinja2==3.1.6
json5==0.9.16
jsonpointer==3.0.0
jsonschema==4.17.3
jupyter==1.1.1
jupyter-console==6.6.3
jupyter-events==0.6.3
jupyter-server==1.24.0
jupyter-ydoc==0.2.5
jupyter_client==7.4.9
jupyter_core==4.12.0
jupyter_server_fileid==0.9.3
jupyter_server_ydoc==0.8.0
jupyterlab==3.6.8
jupyterlab-pygments==0.2.2
jupyterlab_server==2.24.0
jupyterlab_widgets==3.0.13
kiwisolver==1.4.5
MarkupSafe==2.1.5
matplotlib==3.0.2
matplotlib-inline==0.1.6
mistune==3.0.2
nbclassic==1.2.0
nbclient==0.7.4
nbconvert==7.6.0
nbformat==5.8.0
nest-asyncio==1.6.0
notebook==6.5.7
notebook_shim==0.2.4
numpy==1.21.6
packaging==24.0
pandas==1.3.5
pandocfilters==1.5.1
parso==0.8.4
pexpect==4.9.0
pickleshare==0.7.5
Pillow==9.5.0
pkgutil_resolve_name==1.3.10
pluggy==1.2.0
prometheus-client==0.17.1
prompt_toolkit==3.0.48
psutil==7.0.0
ptyprocess==0.7.0
-e git+https://github.com/IAMconsortium/pyam.git@16c0ea5714cbb85bbbfebda895b2a853cd1b7dc4#egg=pyam_iamc
pycparser==2.21
Pygments==2.17.2
pyparsing==3.1.4
pyrsistent==0.19.3
pytest==7.4.4
pytest-mpl==0.17.0
python-dateutil==2.9.0.post0
python-json-logger==3.0.1
pytz==2025.2
PyYAML==6.0.1
pyzmq==26.2.1
requests==2.31.0
rfc3339-validator==0.1.4
rfc3986-validator==0.1.1
scipy==1.7.3
seaborn==0.11.2
Send2Trash==1.8.3
six==1.17.0
sniffio==1.3.1
soupsieve==2.4.1
terminado==0.17.1
tinycss2==1.2.1
tomli==2.0.1
tornado==6.2
traitlets==5.9.0
typing_extensions==4.7.1
uri-template==1.3.0
urllib3==2.0.7
wcwidth==0.2.13
webcolors==1.13
webencodings==0.5.1
websocket-client==1.6.1
widgetsnbextension==4.0.13
xlrd==2.0.1
XlsxWriter==3.2.2
y-py==0.6.2
ypy-websocket==0.8.4
zipp==3.15.0

name: pyam
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=22.3.1=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - aiofiles==22.1.0
      - aiosqlite==0.19.0
      - anyio==3.7.1
      - argon2-cffi==23.1.0
      - argon2-cffi-bindings==21.2.0
      - argparse==1.4.0
      - arrow==1.2.3
      - attrs==24.2.0
      - babel==2.14.0
      - backcall==0.2.0
      - beautifulsoup4==4.13.3
      - bleach==6.0.0
      - cached-property==1.5.2
      - cffi==1.15.1
      - charset-normalizer==3.4.1
      - comm==0.1.4
      - cycler==0.11.0
      - debugpy==1.7.0
      - decorator==5.1.1
      - defusedxml==0.7.1
      - entrypoints==0.4
      - exceptiongroup==1.2.2
      - fastjsonschema==2.21.1
      - fonttools==4.38.0
      - fqdn==1.5.1
      - idna==3.10
      - importlib-metadata==6.7.0
      - importlib-resources==5.12.0
      - iniconfig==2.0.0
      - ipykernel==6.16.2
      - ipython==7.34.0
      - ipython-genutils==0.2.0
      - ipywidgets==8.1.5
      - isoduration==20.11.0
      - jedi==0.19.2
      - jinja2==3.1.6
      - json5==0.9.16
      - jsonpointer==3.0.0
      - jsonschema==4.17.3
      - jupyter==1.1.1
      - jupyter-client==7.4.9
      - jupyter-console==6.6.3
      - jupyter-core==4.12.0
      - jupyter-events==0.6.3
      - jupyter-server==1.24.0
      - jupyter-server-fileid==0.9.3
      - jupyter-server-ydoc==0.8.0
      - jupyter-ydoc==0.2.5
      - jupyterlab==3.6.8
      - jupyterlab-pygments==0.2.2
      - jupyterlab-server==2.24.0
      - jupyterlab-widgets==3.0.13
      - kiwisolver==1.4.5
      - markupsafe==2.1.5
      - matplotlib==3.0.2
      - matplotlib-inline==0.1.6
      - mistune==3.0.2
      - nbclassic==1.2.0
      - nbclient==0.7.4
      - nbconvert==7.6.0
      - nbformat==5.8.0
      - nest-asyncio==1.6.0
      - notebook==6.5.7
      - notebook-shim==0.2.4
      - numpy==1.21.6
      - packaging==24.0
      - pandas==1.3.5
      - pandocfilters==1.5.1
      - parso==0.8.4
      - pexpect==4.9.0
      - pickleshare==0.7.5
      - pillow==9.5.0
      - pkgutil-resolve-name==1.3.10
      - pluggy==1.2.0
      - prometheus-client==0.17.1
      - prompt-toolkit==3.0.48
      - psutil==7.0.0
      - ptyprocess==0.7.0
      - pycparser==2.21
      - pygments==2.17.2
      - pyparsing==3.1.4
      - pyrsistent==0.19.3
      - pytest==7.4.4
      - pytest-mpl==0.17.0
      - python-dateutil==2.9.0.post0
      - python-json-logger==3.0.1
      - pytz==2025.2
      - pyyaml==6.0.1
      - pyzmq==26.2.1
      - requests==2.31.0
      - rfc3339-validator==0.1.4
      - rfc3986-validator==0.1.1
      - scipy==1.7.3
      - seaborn==0.11.2
      - send2trash==1.8.3
      - six==1.17.0
      - sniffio==1.3.1
      - soupsieve==2.4.1
      - terminado==0.17.1
      - tinycss2==1.2.1
      - tomli==2.0.1
      - tornado==6.2
      - traitlets==5.9.0
      - typing-extensions==4.7.1
      - uri-template==1.3.0
      - urllib3==2.0.7
      - wcwidth==0.2.13
      - webcolors==1.13
      - webencodings==0.5.1
      - websocket-client==1.6.1
      - widgetsnbextension==4.0.13
      - xlrd==2.0.1
      - xlsxwriter==3.2.2
      - y-py==0.6.2
      - ypy-websocket==0.8.4
      - zipp==3.15.0
prefix: /opt/conda/envs/pyam

tests/test_core.py::test_empty_attribute tests/test_core.py::test_timeseries_raises
tests/test_core.py::test_filter_meta_index[meta_df0] tests/test_core.py::test_filter_meta_index[meta_df1] tests/test_core.py::test_load_metadata[meta_df0] tests/test_core.py::test_load_metadata[meta_df1] tests/test_core.py::test_load_SSP_database_downloaded_file tests/test_core.py::test_load_RCP_database_downloaded_file
tests/test_core.py::test_init_df_with_index tests/test_core.py::test_init_df_with_float_cols_raises tests/test_core.py::test_init_df_with_duplicates_raises[test_df0] tests/test_core.py::test_init_df_with_duplicates_raises[test_df1] tests/test_core.py::test_init_df_with_duplicates_raises[test_df2] tests/test_core.py::test_init_df_with_duplicates_raises[test_df3] tests/test_core.py::test_init_df_with_float_cols tests/test_core.py::test_init_df_from_timeseries[test_df0] tests/test_core.py::test_init_df_from_timeseries[test_df1] tests/test_core.py::test_init_df_from_timeseries[test_df2] tests/test_core.py::test_init_df_from_timeseries[test_df3] tests/test_core.py::test_init_df_with_extra_col tests/test_core.py::test_init_datetime tests/test_core.py::test_init_datetime_subclass_long_timespan tests/test_core.py::test_init_empty_message tests/test_core.py::test_to_excel[test_df0] tests/test_core.py::test_to_excel[test_df1] tests/test_core.py::test_to_excel[test_df2] tests/test_core.py::test_to_excel[test_df3] tests/test_core.py::test_to_csv[test_df0] tests/test_core.py::test_to_csv[test_df1] tests/test_core.py::test_to_csv[test_df2] tests/test_core.py::test_to_csv[test_df3] tests/test_core.py::test_get_item[test_df0] tests/test_core.py::test_get_item[test_df1] tests/test_core.py::test_get_item[test_df2] tests/test_core.py::test_get_item[test_df3] tests/test_core.py::test_model[test_df0] tests/test_core.py::test_model[test_df1] tests/test_core.py::test_model[test_df2] tests/test_core.py::test_model[test_df3] tests/test_core.py::test_scenario[test_df0] tests/test_core.py::test_scenario[test_df1] tests/test_core.py::test_scenario[test_df2] tests/test_core.py::test_scenario[test_df3] tests/test_core.py::test_region[test_df0] tests/test_core.py::test_region[test_df1] tests/test_core.py::test_region[test_df2] tests/test_core.py::test_region[test_df3] tests/test_core.py::test_variable[test_df0] tests/test_core.py::test_variable[test_df1] tests/test_core.py::test_variable[test_df2] tests/test_core.py::test_variable[test_df3] tests/test_core.py::test_variable_unit[test_df0] tests/test_core.py::test_variable_unit[test_df1] tests/test_core.py::test_variable_unit[test_df2] tests/test_core.py::test_variable_unit[test_df3] tests/test_core.py::test_filter_empty_df tests/test_core.py::test_filter_variable_and_depth[test_df0] tests/test_core.py::test_filter_variable_and_depth[test_df1] tests/test_core.py::test_filter_variable_and_depth[test_df2] tests/test_core.py::test_filter_variable_and_depth[test_df3] tests/test_core.py::test_variable_depth_0_keep_false[test_df0] tests/test_core.py::test_variable_depth_0_keep_false[test_df1] tests/test_core.py::test_variable_depth_0_keep_false[test_df2] tests/test_core.py::test_variable_depth_0_keep_false[test_df3] tests/test_core.py::test_variable_depth_raises[test_df0] tests/test_core.py::test_variable_depth_raises[test_df1] tests/test_core.py::test_variable_depth_raises[test_df2] tests/test_core.py::test_variable_depth_raises[test_df3] tests/test_core.py::test_filter_error_illegal_column[test_df0] tests/test_core.py::test_filter_error_illegal_column[test_df1] tests/test_core.py::test_filter_error_illegal_column[test_df2] tests/test_core.py::test_filter_error_illegal_column[test_df3] tests/test_core.py::test_filter_error_keep[test_df0] tests/test_core.py::test_filter_error_keep[test_df1] tests/test_core.py::test_filter_error_keep[test_df2] tests/test_core.py::test_filter_error_keep[test_df3] tests/test_core.py::test_filter_year[test_df0] tests/test_core.py::test_filter_year[test_df1] tests/test_core.py::test_filter_year[test_df2] tests/test_core.py::test_filter_year[test_df3] tests/test_core.py::test_filter_month[test_df0-6] tests/test_core.py::test_filter_month[test_df0-June] tests/test_core.py::test_filter_month[test_df0-Jun] tests/test_core.py::test_filter_month[test_df0-jun] tests/test_core.py::test_filter_month[test_df0-test_month4] tests/test_core.py::test_filter_month[test_df1-6] tests/test_core.py::test_filter_month[test_df1-June] tests/test_core.py::test_filter_month[test_df1-Jun] tests/test_core.py::test_filter_month[test_df1-jun] tests/test_core.py::test_filter_month[test_df1-test_month4] tests/test_core.py::test_filter_month[test_df2-6] tests/test_core.py::test_filter_month[test_df2-June] tests/test_core.py::test_filter_month[test_df2-Jun] tests/test_core.py::test_filter_month[test_df2-jun] tests/test_core.py::test_filter_month[test_df2-test_month4] tests/test_core.py::test_filter_month[test_df3-6] tests/test_core.py::test_filter_month[test_df3-June] tests/test_core.py::test_filter_month[test_df3-Jun] tests/test_core.py::test_filter_month[test_df3-jun] tests/test_core.py::test_filter_month[test_df3-test_month4] tests/test_core.py::test_filter_year_month[test_df0-6] tests/test_core.py::test_filter_year_month[test_df0-Jun] tests/test_core.py::test_filter_year_month[test_df0-jun] tests/test_core.py::test_filter_year_month[test_df0-test_month3] tests/test_core.py::test_filter_year_month[test_df1-6] tests/test_core.py::test_filter_year_month[test_df1-Jun] tests/test_core.py::test_filter_year_month[test_df1-jun] tests/test_core.py::test_filter_year_month[test_df1-test_month3] tests/test_core.py::test_filter_year_month[test_df2-6] tests/test_core.py::test_filter_year_month[test_df2-Jun] tests/test_core.py::test_filter_year_month[test_df2-jun] tests/test_core.py::test_filter_year_month[test_df2-test_month3] tests/test_core.py::test_filter_year_month[test_df3-6] tests/test_core.py::test_filter_year_month[test_df3-Jun] tests/test_core.py::test_filter_year_month[test_df3-jun] tests/test_core.py::test_filter_year_month[test_df3-test_month3] tests/test_core.py::test_filter_day[test_df0-17] tests/test_core.py::test_filter_day[test_df0-Fri] tests/test_core.py::test_filter_day[test_df0-Friday] tests/test_core.py::test_filter_day[test_df0-friday] tests/test_core.py::test_filter_day[test_df0-test_day4] tests/test_core.py::test_filter_day[test_df1-17] tests/test_core.py::test_filter_day[test_df1-Fri] tests/test_core.py::test_filter_day[test_df1-Friday] tests/test_core.py::test_filter_day[test_df1-friday] tests/test_core.py::test_filter_day[test_df1-test_day4] tests/test_core.py::test_filter_day[test_df2-17] tests/test_core.py::test_filter_day[test_df2-Fri] tests/test_core.py::test_filter_day[test_df2-Friday] tests/test_core.py::test_filter_day[test_df2-friday] tests/test_core.py::test_filter_day[test_df2-test_day4] tests/test_core.py::test_filter_day[test_df3-17] tests/test_core.py::test_filter_day[test_df3-Fri] tests/test_core.py::test_filter_day[test_df3-Friday] tests/test_core.py::test_filter_day[test_df3-friday] tests/test_core.py::test_filter_day[test_df3-test_day4] tests/test_core.py::test_filter_hour[test_df0-0] tests/test_core.py::test_filter_hour[test_df0-12] tests/test_core.py::test_filter_hour[test_df0-test_hour2] tests/test_core.py::test_filter_hour[test_df1-0] tests/test_core.py::test_filter_hour[test_df1-12] tests/test_core.py::test_filter_hour[test_df1-test_hour2] tests/test_core.py::test_filter_hour[test_df2-0] tests/test_core.py::test_filter_hour[test_df2-12] tests/test_core.py::test_filter_hour[test_df2-test_hour2] tests/test_core.py::test_filter_hour[test_df3-0] tests/test_core.py::test_filter_hour[test_df3-12] tests/test_core.py::test_filter_hour[test_df3-test_hour2] tests/test_core.py::test_filter_time_exact_match[test_df0] tests/test_core.py::test_filter_time_exact_match[test_df1] tests/test_core.py::test_filter_time_exact_match[test_df2] tests/test_core.py::test_filter_time_exact_match[test_df3] tests/test_core.py::test_filter_time_range[test_df0] tests/test_core.py::test_filter_time_range[test_df1] tests/test_core.py::test_filter_time_range[test_df2] tests/test_core.py::test_filter_time_range[test_df3] tests/test_core.py::test_filter_time_range_year[test_df0] tests/test_core.py::test_filter_time_range_year[test_df1] tests/test_core.py::test_filter_time_range_year[test_df2] tests/test_core.py::test_filter_time_range_year[test_df3] tests/test_core.py::test_filter_time_range_month[test_df0-month_range0] tests/test_core.py::test_filter_time_range_month[test_df0-Mar-Jun] tests/test_core.py::test_filter_time_range_month[test_df1-month_range0] tests/test_core.py::test_filter_time_range_month[test_df1-Mar-Jun] tests/test_core.py::test_filter_time_range_month[test_df2-month_range0] tests/test_core.py::test_filter_time_range_month[test_df2-Mar-Jun] tests/test_core.py::test_filter_time_range_month[test_df3-month_range0] tests/test_core.py::test_filter_time_range_month[test_df3-Mar-Jun] tests/test_core.py::test_filter_time_range_round_the_clock_error[test_df0-month_range0] tests/test_core.py::test_filter_time_range_round_the_clock_error[test_df1-month_range0] tests/test_core.py::test_filter_time_range_round_the_clock_error[test_df2-month_range0] tests/test_core.py::test_filter_time_range_round_the_clock_error[test_df3-month_range0] tests/test_core.py::test_filter_time_range_day[test_df0-day_range0] tests/test_core.py::test_filter_time_range_day[test_df0-Thu-Sat] tests/test_core.py::test_filter_time_range_day[test_df1-day_range0] tests/test_core.py::test_filter_time_range_day[test_df1-Thu-Sat] tests/test_core.py::test_filter_time_range_day[test_df2-day_range0] tests/test_core.py::test_filter_time_range_day[test_df2-Thu-Sat] tests/test_core.py::test_filter_time_range_day[test_df3-day_range0] tests/test_core.py::test_filter_time_range_day[test_df3-Thu-Sat] tests/test_core.py::test_filter_time_range_hour[test_df0-hour_range0] tests/test_core.py::test_filter_time_range_hour[test_df1-hour_range0] tests/test_core.py::test_filter_time_range_hour[test_df2-hour_range0] tests/test_core.py::test_filter_time_range_hour[test_df3-hour_range0] tests/test_core.py::test_filter_time_no_match[test_df0] tests/test_core.py::test_filter_time_no_match[test_df1] tests/test_core.py::test_filter_time_no_match[test_df2] tests/test_core.py::test_filter_time_no_match[test_df3] tests/test_core.py::test_filter_time_not_datetime_error[test_df0] tests/test_core.py::test_filter_time_not_datetime_error[test_df1] tests/test_core.py::test_filter_time_not_datetime_error[test_df2] tests/test_core.py::test_filter_time_not_datetime_error[test_df3] tests/test_core.py::test_filter_time_not_datetime_range_error[test_df0] tests/test_core.py::test_filter_time_not_datetime_range_error[test_df1] tests/test_core.py::test_filter_time_not_datetime_range_error[test_df2] tests/test_core.py::test_filter_time_not_datetime_range_error[test_df3] tests/test_core.py::test_filter_year_with_time_col tests/test_core.py::test_filter_as_kwarg[meta_df0] tests/test_core.py::test_filter_as_kwarg[meta_df1] tests/test_core.py::test_filter_keep_false[meta_df0] tests/test_core.py::test_filter_keep_false[meta_df1] tests/test_core.py::test_filter_by_regexp[meta_df0] tests/test_core.py::test_filter_by_regexp[meta_df1] tests/test_core.py::test_timeseries[test_df0] tests/test_core.py::test_timeseries[test_df1] tests/test_core.py::test_timeseries[test_df2] tests/test_core.py::test_timeseries[test_df3] tests/test_core.py::test_read_pandas tests/test_core.py::test_meta_idx[meta_df0] tests/test_core.py::test_meta_idx[meta_df1] tests/test_core.py::test_require_variable[meta_df0] tests/test_core.py::test_require_variable[meta_df1] tests/test_core.py::test_require_variable_top_level[meta_df0] tests/test_core.py::test_require_variable_top_level[meta_df1] tests/test_core.py::test_validate_all_pass[meta_df0] tests/test_core.py::test_validate_all_pass[meta_df1] tests/test_core.py::test_validate_nonexisting[meta_df0] tests/test_core.py::test_validate_nonexisting[meta_df1] tests/test_core.py::test_validate_up[meta_df0] tests/test_core.py::test_validate_up[meta_df1] tests/test_core.py::test_validate_lo[meta_df0] tests/test_core.py::test_validate_lo[meta_df1] tests/test_core.py::test_validate_both[meta_df0] tests/test_core.py::test_validate_both[meta_df1] tests/test_core.py::test_validate_year[meta_df0] tests/test_core.py::test_validate_year[meta_df1] tests/test_core.py::test_validate_exclude[meta_df0] tests/test_core.py::test_validate_exclude[meta_df1] tests/test_core.py::test_validate_top_level[meta_df0] tests/test_core.py::test_validate_top_level[meta_df1] tests/test_core.py::test_category_none[meta_df0] tests/test_core.py::test_category_none[meta_df1] tests/test_core.py::test_category_pass[meta_df0] tests/test_core.py::test_category_pass[meta_df1] tests/test_core.py::test_category_top_level[meta_df0] tests/test_core.py::test_category_top_level[meta_df1] tests/test_core.py::test_interpolate tests/test_core.py::test_filter_by_bool[meta_df0] tests/test_core.py::test_filter_by_bool[meta_df1] tests/test_core.py::test_filter_by_int[meta_df0] tests/test_core.py::test_filter_by_int[meta_df1] tests/test_core.py::test_map_regions_r5 tests/test_core.py::test_map_regions_r5_region_col tests/test_core.py::test_map_regions_r5_inplace tests/test_core.py::test_map_regions_r5_agg tests/test_core.py::test_48a tests/test_core.py::test_48b tests/test_core.py::test_48c tests/test_core.py::test_pd_filter_by_meta[meta_df0] tests/test_core.py::test_pd_filter_by_meta[meta_df1] tests/test_core.py::test_pd_filter_by_meta_no_index[meta_df0] tests/test_core.py::test_pd_filter_by_meta_no_index[meta_df1] tests/test_core.py::test_pd_filter_by_meta_nonmatching_index[meta_df0] tests/test_core.py::test_pd_filter_by_meta_nonmatching_index[meta_df1] tests/test_core.py::test_pd_join_by_meta_nonmatching_index[meta_df0] tests/test_core.py::test_pd_join_by_meta_nonmatching_index[meta_df1] tests/test_core.py::test_concat_fails_iter tests/test_core.py::test_concat_fails_notdf tests/test_core.py::test_concat[meta_df0] tests/test_core.py::test_concat[meta_df1] tests/test_core.py::test_normalize[meta_df0] tests/test_core.py::test_normalize[meta_df1] tests/test_core.py::test_normalize_not_time[meta_df0] tests/test_core.py::test_normalize_not_time[meta_df1] tests/test_core.py::test_swap_time_to_year[test_df0-True] tests/test_core.py::test_swap_time_to_year[test_df0-False] tests/test_core.py::test_swap_time_to_year[test_df1-True] tests/test_core.py::test_swap_time_to_year[test_df1-False] tests/test_core.py::test_swap_time_to_year[test_df2-True] tests/test_core.py::test_swap_time_to_year[test_df2-False] tests/test_core.py::test_swap_time_to_year[test_df3-True] tests/test_core.py::test_swap_time_to_year[test_df3-False] tests/test_core.py::test_swap_time_to_year_errors[test_df0-True] tests/test_core.py::test_swap_time_to_year_errors[test_df0-False] tests/test_core.py::test_swap_time_to_year_errors[test_df1-True] tests/test_core.py::test_swap_time_to_year_errors[test_df1-False] tests/test_core.py::test_swap_time_to_year_errors[test_df2-True] tests/test_core.py::test_swap_time_to_year_errors[test_df2-False] tests/test_core.py::test_swap_time_to_year_errors[test_df3-True] tests/test_core.py::test_swap_time_to_year_errors[test_df3-False]
pyam/core.py RELEASE_NOTES.md
pyam/core.py RELEASE_NOTES.md