Repository: ericmjl/pyjanitor (python)

Issue:
janitor.utils.check_column issue when passed single column
If `check_column` is passed a string instead of an iterable list/tuple/etc of column names, as can happen with `label_encode`, it will iterate through the string's characters, checking whether each is present as a column:

https://github.com/ericmjl/pyjanitor/blob/87ee618d3764a8c0bf9cf5c277b926cbc0f3e14e/janitor/utils.py#L340-L371

There should be some form of type checking here to prevent this from happening:

```python
if isinstance(column_names, str) or not isinstance(column_names, Iterable):
    column_names = [column_names]
```

Will submit PR for this later

Pull request description:
[ENH] Fix check_column to support single inputs


<!-- Thank you for your PR!

BEFORE YOU CONTINUE! Please add the appropriate three-letter abbreviation to your title.

The abbreviations can be:
- [DOC]: Documentation fixes.
- [ENH]: Code contributions and new features.
- [TST]: Test-related contributions.
- [INF]: Infrastructure-related contributions.

Also, do not forget to tag the relevant issue here as well.

Finally, as commits come in, don't forget to regularly rebase!
-->

# PR Description

Please describe the changes proposed in the pull request:

- Fixes #810 which breaks functions like `label_encode`.
- Also: we listed `sklearn` as a pip dep and the proper package is `scikit-learn`.

# PR Checklist

1. [x] PR in from a fork off your branch. Do not PR from `<your_username>`:`dev`, but rather from `<your_username>`:`<feature-branch_name>`.
<!-- Doing this helps us keep the commit history much cleaner than it would otherwise be. -->
2. [x] If you're not on the contributors list, add yourself to `AUTHORS.rst`.
<!-- We'd like to acknowledge your contributions! -->
3. [x] Add a line to `CHANGELOG.md` under the latest version header (i.e. the one that is "on deck") describing the contribution.
    - Do use some discretion here; if there are multiple PRs that are related, keep them in a single line.

# Automatic checks

There will be automatic checks run on the PR. These include:

- Building a preview of the docs on Netlify
- Automatically linting the code
- Making sure the code is documented
- Making sure that all tests are passed
- Making sure that code coverage doesn't go down.

# Relevant Reviewers

- @ericmjl


Patch:
diff --git a/.requirements/base.in b/.requirements/base.in
index cdef080..b793e56 100644
--- a/.requirements/base.in
+++ b/.requirements/base.in
@@ -4,5 +4,5 @@
 natsort
 # seaborn
 pandas_flavor
-sklearn
+scikit-learn
 multipledispatch
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 469ca60..e00378c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,9 +4,7 @@
 
 - [ENH] Add `dropna` parameter to groupby_agg. @samukweku
 - [ENH] `complete` adds a `by` parameter to expose explicit missing values per group, via groupby. @samukweku
-
-- [ENH] Add `dropna` parameter to groupby_agg. @samukweku
-- [ENH] `complete` adds a `by` parameter to expose explicit missing values per group, via groupby. @samukweku
+- [ENH] Fix check_column to support single inputs - fixes `label_encode`. @zbarry
 
 ## [v0.20.13] - 2021-02-25
 
diff --git a/janitor/utils.py b/janitor/utils.py
index f837a13..ed9e602 100644
--- a/janitor/utils.py
+++ b/janitor/utils.py
@@ -42,7 +42,7 @@ def check(varname: str, value, expected_types: list):
 
         check('x', x, [int, float])
 
-    :param varname: The name of the variable.
+    :param varname: The name of the variable (for diagnostic error message).
     :param value: The value of the varname.
     :param expected_types: The types we expect the item to be.
     :raises TypeError: if data is not the expected type.
@@ -360,6 +360,9 @@ def check_column(
         in df.columns.
     :raises ValueError: if data is not the expected type.
     """
+    if isinstance(column_names, str) or not isinstance(column_names, Iterable):
+        column_names = [column_names]
+
     for column_name in column_names:
         if present and column_name not in df.columns:  # skipcq: PYL-R1720
             raise ValueError(


Test patch:
diff --git a/tests/utils/test_check_column.py b/tests/utils/test_check_column.py
index 88e3cdd..2ee2878 100644
--- a/tests/utils/test_check_column.py
+++ b/tests/utils/test_check_column.py
@@ -11,6 +11,27 @@ def test_check_column(dataframe):
     assert check_column(dataframe, ["a"]) is None
 
 
+@pytest.mark.utils
+def test_check_column_single(dataframe):
+    """
+    Check works with a single input
+    """
+
+    assert check_column(dataframe, "a") is None
+
+    with pytest.raises(ValueError):
+        check_column(dataframe, "b")
+
+    # should also work with non-string inputs
+
+    with pytest.raises(ValueError):
+        check_column(dataframe, 2)
+
+    dataframe[2] = "asdf"
+
+    assert check_column(dataframe, 2) is None
+
+
 @pytest.mark.utils
 def test_check_column_absent_column(dataframe):
     """