Repository: pyjanitor-devs/pyjanitor

Issue:
complete fails for a dictionary with only one entry
# Brief Description

`complete` fails if only a dictionary is provided, and the values is a pandas Index.

# System Information

<!-- System information helps us. To keep things simple, just let us know the OS and Python version first.
You can provide the optional information later. -->

- Operating system: linux
- OS details (optional):  fedora
- Python version (required): 3.9

# Minimally Reproducible Code

```py
import pandas as pd
import janitor

temp = [{'a': Timestamp('2015-04-01 00:00:00'), 'b': 1},
 {'a': Timestamp('2015-04-01 00:00:00'), 'b': 14},
 {'a': Timestamp('2015-04-02 00:00:00'), 'b': 14},
 {'a': Timestamp('2015-04-03 00:00:00'), 'b': 11},
 {'a': Timestamp('2015-04-04 00:00:00'), 'b': 12},
 {'a': Timestamp('2015-04-05 00:00:00'), 'b': 13},
 {'a': Timestamp('2015-04-08 00:00:00'), 'b': 14}]

temp = pd.DataFrame(temp)
temp

           a   b
0 2015-04-01   1
1 2015-04-01  14
2 2015-04-02  14
3 2015-04-03  11
4 2015-04-04  12
5 2015-04-05  13
6 2015-04-08  14

mapp = {'a' : pd.date_range(temp['a'].min(), temp['a'].max(), freq='1D')}


```
-->

# Error Messages

<!-- If you get an error message, please paste it between the backticks here. -->

```
temp.complete(mapp)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-505-e50fc10d27e8> in <module>
----> 1 temp.complete(mapp)

~/.local/lib/python3.9/site-packages/pandas_flavor/register.py in __call__(self, *args, **kwargs)
     27             @wraps(method)
     28             def __call__(self, *args, **kwargs):
---> 29                 return method(self._obj, *args, **kwargs)
     30 
     31         register_dataframe_accessor(method.__name__)(AccessorMethod)

~/miniforge3/envs/dev/lib/python3.9/site-packages/janitor/functions.py in complete(df, sort, by, *columns)
   5499     df = df.copy()
   5500 
-> 5501     return _computations_complete(df, columns, sort, by)
   5502 
   5503 

~/miniforge3/envs/dev/lib/python3.9/site-packages/janitor/utils.py in _computations_complete(df, columns, sort, by)
    700     if by is None:
    701         uniques = _generic_complete(df, columns, all_strings)
--> 702         return df.merge(uniques, how="outer", on=column_checker, sort=sort)
    703 
    704     uniques = df.groupby(by)

~/.local/lib/python3.9/site-packages/pandas/core/frame.py in merge(self, right, how, on, left_on, right_on, left_index, right_index, sort, suffixes, copy, indicator, validate)
   9184         from pandas.core.reshape.merge import merge
   9185 
-> 9186         return merge(
   9187             self,
   9188             right,

~/.local/lib/python3.9/site-packages/pandas/core/reshape/merge.py in merge(left, right, how, on, left_on, right_on, left_index, right_index, sort, suffixes, copy, indicator, validate)
    105     validate: str | None = None,
    106 ) -> DataFrame:
--> 107     op = _MergeOperation(
    108         left,
    109         right,

~/.local/lib/python3.9/site-packages/pandas/core/reshape/merge.py in __init__(self, left, right, how, on, left_on, right_on, axis, left_index, right_index, sort, suffixes, copy, indicator, validate)
    698             self.right_join_keys,
    699             self.join_names,
--> 700         ) = self._get_merge_keys()
    701 
    702         # validate the merge keys dtypes. We may need to coerce

~/.local/lib/python3.9/site-packages/pandas/core/reshape/merge.py in _get_merge_keys(self)
   1090                     if not is_rkey(rk):
   1091                         if rk is not None:
-> 1092                             right_keys.append(right._get_label_or_level_values(rk))
   1093                         else:
   1094                             # work-around for merge_asof(right_index=True)

~/.local/lib/python3.9/site-packages/pandas/core/generic.py in _get_label_or_level_values(self, key, axis)
   1772 
   1773         if self._is_label_reference(key, axis=axis):
-> 1774             self._check_label_or_level_ambiguity(key, axis=axis)
   1775             values = self.xs(key, axis=other_axes[0])._values
   1776         elif self._is_level_reference(key, axis=axis):

~/.local/lib/python3.9/site-packages/pandas/core/generic.py in _check_label_or_level_ambiguity(self, key, axis)
   1731                 f"{label_article} {label_type} label, which is ambiguous."
   1732             )
-> 1733             raise ValueError(msg)
   1734 
   1735     @final

ValueError: 'a' is both an index level and a column label, which is ambiguous.
```


Discussion:

Resolving patch:
diff --git a/janitor/utils.py b/janitor/utils.py
--- a/janitor/utils.py
+++ b/janitor/utils.py
@@ -812,8 +812,13 @@ def _sub_complete_column(column, df):  # noqa: F811
         if not hasattr(arr, "shape"):
             arr = pd.Series([*arr], name=key)
 
-        if (not isinstance(arr, pd.Series)) and is_extension_array_dtype(arr):
-            arr = pd.Series(arr)
+        if not arr.size > 0:
+            raise ValueError(
+                f"""
+                Kindly ensure the provided array for {key}
+                has at least one value.
+                """
+            )
 
         if isinstance(arr, pd.Index):
             arr_ndim = arr.nlevels
@@ -827,22 +832,13 @@ def _sub_complete_column(column, df):  # noqa: F811
                 """
             )
 
-        if not (arr.size > 0):
-            raise ValueError(
-                f"""
-                Kindly ensure the provided array for {key}
-                has at least one value.
-                """
-            )
-
-        if isinstance(arr, np.ndarray):
+        if not isinstance(arr, pd.Series):
             arr = pd.Series(arr)
 
         if not arr.is_unique:
             arr = arr.drop_duplicates()
 
-        if arr.name is None:
-            arr.name = key
+        arr.name = key
 
         collection[key] = arr
 


Test patch: