Repository: pandas-dev/pandas
Pull request: Fixes SparseSeries initiated with dictionary raising AttributeError
-  [x] closes #16905
 - [x] tests added / passed
 - [x] whatsnew entry


Problem statement:
BUG: SparseSeries from dict inconsistency
#### Code Sample, a copy-pastable example if possible
Two (somewhat related) issues:
```python
>>> pd.Series({1: 1})
1    1
dtype: int64

>>> pd.SparseSeries({1: 1})
---------------------------------------------------------------------------
AttributeError: 'dict' object has no attribute 'index'
```

```py
>>> pd.Series({1: 1}, index=[0, 1, 2])
0    NaN
1    1.0
2    NaN
dtype: float64

>>> pd.SparseSeries({1: 1.}, index=[0, 1, 2])
0    1.0
1     
2     
dtype: float64
BlockIndex
Block locations: array([0], dtype=int32)
Block lengths: array([1], dtype=int32)
```
#### Problem description
SparseSeries initialization from dict acts too differently from Series'.

#### Expected Output
```py
>>> pd.SparseSeries({1: 1})
1    1.0
dtype: float64
BlockIndex
Block locations: array([0], dtype=int32)
Block lengths: array([1], dtype=int32)

>>> pd.SparseSeries({1: 1.}, index=[0, 1, 2])
0    NaN 
1    1.0 
2    NaN
dtype: float64
BlockIndex
Block locations: array([1], dtype=int32)
Block lengths: array([1], dtype=int32)
```

#### Output of ``pd.show_versions()``

<details>
pandas 0.21.0.dev+223.ga9421af1a
</details>

Hints from issue discussion:
yep looks like a bug
I think I have a fix for this. I'm testing it now.

Commit message: Refactors test for SparseSeries construction

Patch to review:
diff --git a/doc/source/whatsnew/v0.21.0.txt b/doc/source/whatsnew/v0.21.0.txt
index 6ddf6029b99bb..e6a14d4bb1c85 100644
--- a/doc/source/whatsnew/v0.21.0.txt
+++ b/doc/source/whatsnew/v0.21.0.txt
@@ -180,7 +180,7 @@ Groupby/Resample/Rolling
 
 Sparse
 ^^^^^^
-
+- Bug in SparseSeries raises AttributeError when a dictionary is passed in as data (:issue:`16777`)
 
 
 Reshaping
diff --git a/pandas/core/sparse/series.py b/pandas/core/sparse/series.py
index 9dd061e26ba06..be54bb57fd927 100644
--- a/pandas/core/sparse/series.py
+++ b/pandas/core/sparse/series.py
@@ -146,10 +146,10 @@ def __init__(self, data=None, index=None, sparse_index=None, kind='block',
                 data = data._data
 
             elif isinstance(data, (Series, dict)):
+                data = Series(data)
                 if index is None:
                     index = data.index.view()
 
-                data = Series(data)
                 res = make_sparse(data, kind=kind, fill_value=fill_value)
                 data, sparse_index, fill_value = res
 
diff --git a/pandas/tests/sparse/test_series.py b/pandas/tests/sparse/test_series.py
index b524d6bfab418..ea1566e76eee1 100644
--- a/pandas/tests/sparse/test_series.py
+++ b/pandas/tests/sparse/test_series.py
@@ -88,6 +88,18 @@ def setup_method(self, method):
         self.ziseries2 = SparseSeries(arr, index=index, kind='integer',
                                       fill_value=0)
 
+    def test_constructor_data_input(self):
+        # see gh-16905
+        test_dict = {1: 1}
+        test_index = [0, 1, 2]
+        test_series = pd.Series({1: 1}, index=test_index)
+
+        arr = SparseSeries(test_dict)
+        assert arr.count() == len(test_dict)
+
+        arr = SparseSeries(test_series, index=test_index))
+        assert arr.count() == test_series.count()
+
     def test_constructor_dtype(self):
         arr = SparseSeries([np.nan, 1, 2, np.nan])
         assert arr.dtype == np.float64
@@ -109,6 +121,9 @@ def test_constructor_dtype(self):
         assert arr.dtype == np.int64
         assert arr.fill_value == 0
 
+        arr = SparseSeries({1: 1})
+        assert arr.dtype == np.int64
+
     def test_iteration_and_str(self):
         [x for x in self.bseries]
         str(self.bseries)


Code review comments:
diff_hunk: @@ -88,6 +88,18 @@ def setup_method(self, method):
         self.ziseries2 = SparseSeries(arr, index=index, kind='integer',
                                       fill_value=0)
 
+    def test_constructor_data_input(self):
+        # see gh-16905
+        test_dict = {1: 1}
+        test_index = [0, 1, 2]
+        test_series = pd.Series({1: 1}, index=test_index)
path: pandas/tests/sparse/test_series.py
text: @user1:
Replace the `{1: 1}` with `test_dict`.

diff_hunk: @@ -88,6 +88,18 @@ def setup_method(self, method):
         self.ziseries2 = SparseSeries(arr, index=index, kind='integer',
                                       fill_value=0)
 
+    def test_constructor_data_input(self):
+        # see gh-16905
+        test_dict = {1: 1}
+        test_index = [0, 1, 2]
+        test_series = pd.Series({1: 1}, index=test_index)
+
+        arr = SparseSeries(test_dict)
+        assert arr.count() == len(test_dict)
+
+        arr = SparseSeries(test_series, index=test_index))
path: pandas/tests/sparse/test_series.py
text: @user1:
Oops: got an extra right parenthesis there