Repository: IAMconsortium/pyam
Pull request #459 (2020-11-17 08:42:57)

Add get_variable_components() function incl doc and tests
# Please confirm that this PR has done the following:

- [x] Tests Added
- [x] Documentation Added
- [x] Description in RELEASE_NOTES.md Added

## Adding to RELEASE_NOTES.md (remove section after adding to RELEASE_NOTES.md)

Please add a single line in the release notes similar to the following:

```
- (#XX)[http://link-to-pr.com] Added feature which does something
```

# Description of PR

This pull request adds a new function 'get_variable_components()' to utils.py. It returns (or merges and returns) the variable component(s) in regard to the hierarchy (indicated by ``|``) of x to the specified level(s).

mabudz: Since there seem to be no merge conflicts between branches, do you mean to merge the commits into one? 
danielhuppmann: My guess is that there will be a merge conflict after you add the line to the release notes, so you can either:
1. rebase (or squash & rebase, ie what you suggest), then add a new commit with the release note
2. add a new commit, then resolve the merge conflict manually

Patch:
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 47aa1a1..aa8c7b7 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -2,6 +2,7 @@
 
 ## Individual updates
 
+- [#459](https://github.com/IAMconsortium/pyam/pull/459) Add a `get_variable_components()` function to retrieve or join variable components
 - [#458](https://github.com/IAMconsortium/pyam/pull/458) Enable `Path` for IamDataFrame initialization 
 - [#454](https://github.com/IAMconsortium/pyam/pull/454) Enable dimensionless units and fix `info()` if IamDataFrame is empty
 - [#451](https://github.com/IAMconsortium/pyam/pull/451) Fix unit conversions from C to CO2eq
diff --git a/doc/source/api/variables.rst b/doc/source/api/variables.rst
index 1e15648..200d659 100644
--- a/doc/source/api/variables.rst
+++ b/doc/source/api/variables.rst
@@ -17,3 +17,5 @@ The package provides several functions to work with such strings.
 .. autofunction:: find_depth
 
 .. autofunction:: reduce_hierarchy
+
+.. autofunction:: get_variable_components
diff --git a/pyam/utils.py b/pyam/utils.py
index edcbafa..d4728e1 100644
--- a/pyam/utils.py
+++ b/pyam/utils.py
@@ -588,3 +588,24 @@ def reduce_hierarchy(x, depth):
     _x = x.split('|')
     depth = len(_x) + depth - 1 if depth < 0 else depth
     return '|'.join(_x[0:(depth + 1)])
+
+
+def get_variable_components(x, level, join=False):
+    """Return components for requested level in a list or join these in a str.
+
+    Parameters
+    ----------
+    x : str
+        Uses ``|`` to separate the components of the variable.
+    level : int or list of int
+        Position of the component.
+    join : bool or str, optional
+        If True, IAMC-style (``|``) is used as separator for joined components.
+    """
+    _x = x.split('|')
+    if join is False:
+        return [_x[i] for i in level] if islistable(level) else _x[level]
+    else:
+        level = [level] if type(level) == int else level
+        join = '|' if join is True else join
+        return join.join([_x[i] for i in level])


Test patch:
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 1c72294..5a0df42 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -213,3 +213,27 @@ def test_merge_meta():
 
     obs = utils.merge_meta(left, right, ignore_meta_conflict=True)
     pdt.assert_frame_equal(exp, obs)
+
+
+def test_get_variable_components_int():
+    assert utils.get_variable_components('foo|bar|baz', 1) == 'bar'
+
+
+def test_get_variable_components_list():
+    assert utils.get_variable_components('foo|bar|baz',
+                                         [1, 2]) == ['bar', 'baz']
+
+
+def test_get_variable_components_indexError():
+    with pytest.raises(IndexError):
+        utils.get_variable_components('foo|bar|baz', 3)
+
+
+def test_get_variable_components_joinTRUE():
+    assert utils.get_variable_components('foo|bar|baz', [0, 2],
+                                         join=True) == 'foo|baz'
+
+
+def test_get_variable_components_joinstr():
+    assert utils.get_variable_components('foo|bar|baz', [2, 1],
+                                         join='_') == 'baz_bar'