Repository: globality-corp/flake8-logging-format

Issue:
False positive using argparse's ArgumentParser.error() metho
Code like this using the error method of argparse's ArgumentParser class will trigger “G004 Logging statement uses f-string”:

```python
     if not args.target_directory.is_dir():
         parser.error(f"Target directory {args.target_directory} does not exist")
```

This makes sense since that method looks very similar to logging.error but it doesn't use logging:

https://github.com/python/cpython/blob/main/Lib/argparse.py#L2608-L2619

I don't know whether the best path is to attempt some kind of whitelisting for this or simply document that you might want to ignore this for argparse usage but this is a fairly common part of the stdlib so I'd imagine it comes up periodically on many projects.

Discussion:

Patch:
diff --git a/logging_format/visitor.py b/logging_format/visitor.py
index 4f5a867..9bb2ce8 100644
--- a/logging_format/visitor.py
+++ b/logging_format/visitor.py
@@ -206,7 +206,7 @@ class LoggingVisitor(NodeVisitor):
 
         """
         try:
-            if self.get_id_attr(node.func.value) == "warnings":
+            if self.get_id_attr(node.func.value) in ["parser", "warnings"]:
                 return None
             # NB: We could also look at the argument signature or the target attribute
             if node.func.attr in LOGGING_LEVELS:


Test patch:
diff --git a/logging_format/tests/test_visitor.py b/logging_format/tests/test_visitor.py
index 025fb5b..689dfc1 100644
--- a/logging_format/tests/test_visitor.py
+++ b/logging_format/tests/test_visitor.py
@@ -680,3 +680,20 @@ def test_app_log():
 
     assert_that(visitor.violations, has_length(1))
     assert_that(visitor.violations[0][1], is_(equal_to(FSTRING_VIOLATION)))
+
+
+def test_argparse_parser_error():
+    """
+    argparse.ArgumentParser.error method should not be detected.
+    """
+    tree = parse(dedent("""\
+        import argparse
+        parser = argparse.ArgumentParser()
+        parser.add_argument("target_dir", type=Path)
+        args = parser.parse_args()
+        parser.error(f"Target directory {args.target_dir} does not exist")
+    """))
+    visitor = LoggingVisitor()
+    visitor.visit(tree)
+
+    assert_that(visitor.violations, is_(empty()))