From f810894dcc6015b5af06acd3f23ecd8262524579 Mon Sep 17 00:00:00 2001
From: Bert Palm <bert.palm@ufz.de>
Date: Sun, 16 Feb 2020 03:37:39 +0100
Subject: [PATCH] getitem fine

---
 dios/dios.py | 160 +++++++++++++++++++++++----------------------------
 1 file changed, 72 insertions(+), 88 deletions(-)

diff --git a/dios/dios.py b/dios/dios.py
index 10a1873..a3fb535 100644
--- a/dios/dios.py
+++ b/dios/dios.py
@@ -5,6 +5,7 @@ from dios.errors import *
 import pandas as pd
 import numpy as np
 import operator as op
+from functools import partialmethod
 
 from functools import wraps
 from collections import OrderedDict
@@ -186,45 +187,27 @@ class DictOfSeries:
           - ``dios['a']``      -> return a pd.Series
           - ``dios[iterable]`` -> return a DictOfSeries of all given columns [1]
           - ``dios[slice]``    -> return a sliced DictOfSeries of all(!) columns in the dios
-
         Notes:
           - [1] If ``iterable`` contains any(!) label that does not exist, a KeyError is raised.
         """
-
-        # prepare
-        if is_iterator(key):
-            key = list(key)
-
+        # special case single label
         if isinstance(key, str):
-            self._check_keys([key])
-            return self._get_item(key)
-
-        if isinstance(key, slice):
-            return self._slice(self.columns, key)
-
-        if is_list_like(key) and not is_nested_list_like(key):
-            self._check_keys(key)
-            return self._getitem_listlike(key)
-
-        raise KeyError(f"{key}")
+            if key in self.columns:
+                new = self._get_item(key)
+            else:
+                raise KeyError(key)
+        else:
+            keys, ixs = self._get_keys_and_indexer(key)
+            new = self.copy_empty()
+            for i, _ in enumerate(keys):
+                key, ix = keys[i], ixs[i]
+                new._data[key] = self._get_item(key)[ix]
+        return new
 
     def _get_item(self, key):
         # return always a pd.Series
         return self._data[key]
 
-    def _getitem_listlike(self, keys):
-        new = self.copy_empty()
-        for k in keys:
-            new._data[k] = self._get_item(k)
-        return new
-
-    def _slice(self, keys, slicer):
-        """ Return a slice of self"""
-        new = self.copy_empty()
-        for k in keys:
-            new._data[k] = self._get_item(k)[slicer]
-        return new
-
     def __setitem__(self, key, value):
         """
         Set items:
@@ -253,6 +236,52 @@ class DictOfSeries:
         for tup in gen:
             self._set_item(*tup)
 
+    def _setitem(self, keys, ixs, val):
+        """Return a generator that yield (key, indexer, value) for all keys"""
+        if is_iterator(val):
+            val = list(val)
+
+        diosl, dfl, nlistl = is_dios_like(val), is_dataframe_like(val), is_nested_list_like(val)
+        if diosl or dfl or nlistl and len(val) != len(keys):
+            raise ValueError(f"could not broadcast input array with length {len(val)}"
+                             f" into dios of length {len(keys)}")
+
+        # now we have everything we need: key, indexer, value
+        # so we just pack it nice and cosy and let setitem
+        # do the dirty work.
+        for i, _ in enumerate(keys):
+            key, ix = keys[i], ixs[i]
+            if dfl or diosl:
+                yield key, ix, val[val.columns[i]]
+            elif nlistl:
+                yield key, ix, val[i]
+            else:
+                yield key, ix, val
+
+    def _set_item(self, key, ix, val):
+        "Set a value (scalar or list or series)"
+        ser = self._data[key]
+        if is_series_like(val):
+            left = ser[ix]
+            index = left.index.intersection(val.index)
+            if not index.empty:
+                left.loc[index] = val.loc[index].copy()
+        else:
+            ser[ix] = val
+
+    def _insert(self, key, val):
+        """"""
+        if isinstance(val, DictOfSeries):
+            val = val.squeeze()
+        elif is_list_like(val) and not is_nested_list_like(val):
+            val = pd.Series(val)
+
+        if not isinstance(val, pd.Series):
+            raise ValueError(f"Only pd.Series can be inserted directly")
+
+        val = cast_to_itype(val, self._itype, policy=self._policy)
+        self._data[key] = val.copy(deep=True)
+
     def _get_keys_and_indexer(self, key):
         """ Determine keys and indexer
         Notes:
@@ -330,52 +359,6 @@ class DictOfSeries:
         # now we have a valid indexer (a slice or a bool array) for every series
         return keys, indexers
 
-    def _setitem(self, keys, ixs, val):
-        """Return a generator that yield (key, indexer, value) for all keys"""
-        if is_iterator(val):
-            val = list(val)
-
-        diosl, dfl, nlistl = is_dios_like(val), is_dataframe_like(val), is_nested_list_like(val)
-        if diosl or dfl or nlistl and len(val) != len(keys):
-            raise ValueError(f"could not broadcast input array with length {len(val)}"
-                             f" into dios of length {len(keys)}")
-
-        # now we have everything we need: key, indexer, value
-        # so we just pack it nice and cosy and let setitem
-        # do the dirty work.
-        for i, _ in enumerate(keys):
-            key, ix = keys[i], ixs[i]
-            if dfl or diosl:
-                yield key, ix, val[val.columns[i]]
-            elif nlistl:
-                yield key, ix, val[i]
-            else:
-                yield key, ix, val
-
-    def _insert(self, key, val):
-        """"""
-        if isinstance(val, DictOfSeries):
-            val = val.squeeze()
-        elif is_list_like(val) and not is_nested_list_like(val):
-            val = pd.Series(val)
-
-        if not isinstance(val, pd.Series):
-            raise ValueError(f"Only pd.Series can be inserted directly")
-
-        val = cast_to_itype(val, self._itype, policy=self._policy)
-        self._data[key] = val.copy(deep=True)
-
-    def _set_item(self, key, ix, val):
-        "Set a value (scalar or list or series)"
-        ser = self._data[key]
-        if is_series_like(val):
-            left = ser[ix]
-            index = left.index.intersection(val.index)
-            if not index.empty:
-                left.loc[index] = val.loc[index].copy()
-        else:
-            ser[ix] = val
-
     @property
     def loc(self):
         return _LocIndexer(self)
@@ -411,7 +394,7 @@ class DictOfSeries:
 
     @property
     def empty(self):
-        return all(self._data[c].empty for c in self._data)
+        return len(self) == 0 or all(self._data[c].empty for c in self._data)
 
     def all(self):
         return pd.Series([self._data[c].any() for c in self._data])
@@ -462,19 +445,20 @@ class DictOfSeries:
         new._itype = self.itype
         return new
 
-    def _op1_wrap(op):
-        def anyop(self):
-            with reraise(f"'{OP_MAP[op]}dios' failed: "):
-                new = self.copy_empty()
-                for k in self:
-                    new[k] = op(self._data[k])
-                return new
+    def anyop(self, op, ):
+        new = self.copy_empty()
+        with reraise(f"'{OP_MAP[op]} dios' failed: "):
+            for k in self:
+                new[k] = op(self._data[k])
+        return new
 
-        return anyop
+    def foo(self, x):
+        raise ValueError('dnsjkncsncj')
 
-    __neg__ = _op1_wrap(op.neg)
-    __abs__ = _op1_wrap(op.abs)
-    __invert__ = _op1_wrap(op.inv)
+    __neg__ = partialmethod(anyop, op.neg)
+    __abs__ = partialmethod(anyop, op.abs)
+    # __invert__ = partialmethod(anyop, op.inv)
+    __invert__ = partialmethod(anyop, foo)
 
     def _op2(self, other, op, inplace=False):
         new = self.copy_empty()
-- 
GitLab