Repository: deppen8/pandas-vet

Issue:
Check for pd.read_table
Check for `pd.read_table` function call. [See flashcard here](https://deppen8.github.io/pandas-bw/reading-data/). Give error message:

> 'pd.read_table' is deprecated. Use 'pd.read_csv' for all delimited files.

Comments:

Patch:
diff --git a/pandas_vet/__init__.py b/pandas_vet/__init__.py
index b675fd8..3e5e351 100644
--- a/pandas_vet/__init__.py
+++ b/pandas_vet/__init__.py
@@ -33,6 +33,7 @@ class Visitor(ast.NodeVisitor):
         self.errors.extend(check_for_unstack(node))
         self.errors.extend(check_for_arithmetic_methods(node))
         self.errors.extend(check_for_comparison_methods(node))
+        self.errors.extend(check_for_read_table(node))
 
     def visit_Subscript(self, node):
         self.generic_visit(node)  # continue checking children
@@ -136,19 +137,19 @@ def check_for_comparison_methods(node: ast.Call) -> List:
 
 
 def check_for_ix(node: ast.Subscript) -> List:
-    if node.value.attr == "ix":
+    if isinstance(node.value, ast.Attribute) and node.value.attr == "ix":
         return [PD007(node.lineno, node.col_offset)]
     return []
 
 
-def check_for_at(node: ast.Call) -> List:
-    if node.value.attr == "at":
+def check_for_at(node: ast.Subscript) -> List:
+    if isinstance(node.value, ast.Attribute) and node.value.attr == "at":
         return [PD008(node.lineno, node.col_offset)]
     return []
 
 
-def check_for_iat(node: ast.Call) -> List:
-    if node.value.attr == "iat":
+def check_for_iat(node: ast.Subscript) -> List:
+    if isinstance(node.value, ast.Attribute) and node.value.attr == "iat":
         return [PD009(node.lineno, node.col_offset)]
     return []
 
@@ -177,6 +178,17 @@ def check_for_unstack(node: ast.Call) -> List:
     return []
 
 
+def check_for_read_table(node: ast.Call) -> List:
+    """
+    Check AST for occurence of the `.read_table()` method on the pandas object.
+
+    Error/warning message to recommend use of `.read_csv()` method instead.
+    """
+    if isinstance(node.func, ast.Attribute) and node.func.attr == "read_table":
+        return [PD012(node.lineno, node.col_offset)]
+    return []
+
+
 error = namedtuple("Error", ["lineno", "col", "message", "type"])
 VetError = partial(partial, error, type=VetPlugin)
 
@@ -210,3 +222,6 @@ PD009 = VetError(
 PD010 = VetError(
     message="PD010 '.pivot_table' is preferred to '.pivot' or '.unstack'; provides same functionality"
 )
+PD012 = VetError(
+    message="PDO12 '.read_csv' is preferred to '.read_table'; provides same functionality"
+)


Test patch:
diff --git a/tests/test_PD012.py b/tests/test_PD012.py
new file mode 100644
index 0000000..ee45e2e
--- /dev/null
+++ b/tests/test_PD012.py
@@ -0,0 +1,41 @@
+"""
+Test to check for use of the pandas soon-to-be-deprecated `.read_table()`
+method. 
+"""
+import ast
+
+from pandas_vet import VetPlugin
+from pandas_vet import PD012
+
+
+def test_PD012_pass_read_csv():
+    """
+    Test that using .read_csv() explicitly does not result in an error.
+    """
+    statement = "df = pd.read_csv(input_file)"
+    tree = ast.parse(statement)
+    actual = list(VetPlugin(tree).run())
+    expected = []
+    assert actual == expected
+
+
+def test_PD012_fail_read_table():
+    """
+    Test that using .read_table() method results in an error.
+    """
+    statement = "df = pd.read_table(input_file)"
+    tree = ast.parse(statement)
+    actual = list(VetPlugin(tree).run())
+    expected = [PD012(1, 5)]
+    assert actual == expected
+
+
+def test_PD012_node_Name_pass():
+    """
+    Test that where 'read_table' is a Name does NOT raise an error
+    """
+    statement = "df = read_table"
+    tree = ast.parse(statement)
+    actual = list(VetPlugin(tree).run())
+    expected = []
+    assert actual == expected