Repository: pandas-dev/pandas

Issue:
Replace bare excepts by explicit excepts in pandas/tests/
(superseeds #18419, same task for different files: #22873, #22874, #22875, #22877)

In several parts of the code, we have bare excepts in the form of:
```python
try:
    my_value = my_dict[my_key]
except:  # we are capturing all the exceptions, when we want to capture only KeyError
    my_value = None
```

This is a bad practice, and we want to avoid having this in the code. What we want instead is:
```python
try:
    my_value = my_dict[my_key]
except KeyError:
    my_value = None
```
Of course in every case, the exception can be different (not always `KeyError`), and some research is needed to see which is the right exception (or exceptions, it can be a tuple) that needs to be captured. In some cases, every exception needs to be captured and we'll use `except Exception:`, but this should be avoided unless we really need to capture all exceptions.

This issue is to fix all the bare excepts in testing files `pandas/tests/`. At the moment they are (note that the list can change as code evolves):
```
pandas/tests/test_multilevel.py:1378:9: E722 do not use bare except'
pandas/tests/test_nanops.py:144:9: E722 do not use bare except'
pandas/tests/test_nanops.py:149:9: E722 do not use bare except'
pandas/tests/test_nanops.py:170:21: E722 do not use bare except'
pandas/tests/test_nanops.py:174:21: E722 do not use bare except'
pandas/tests/test_panel.py:338:13: E722 do not use bare except'
pandas/tests/test_panel.py:344:13: E722 do not use bare except'
pandas/tests/test_strings.py:2663:13: E722 do not use bare except'
pandas/tests/indexing/common.py:154:13: E722 do not use bare except'
pandas/tests/indexing/common.py:217:17: E722 do not use bare except'
pandas/tests/io/test_pytables.py:54:9: E722 do not use bare except'
pandas/tests/io/test_pytables.py:62:5: E722 do not use bare except'
pandas/tests/io/test_pytables.py:120:5: E722 do not use bare except'
pandas/tests/io/test_pytables.py:4624:21: E722 do not use bare except'
pandas/tests/io/test_sql.py:1793:9: E722 do not use bare except'
pandas/tests/io/test_sql.py:2378:9: E722 do not use bare except'
pandas/tests/io/test_sql.py:2405:9: E722 do not use bare except'
pandas/tests/io/formats/test_format.py:73:5: E722 do not use bare except'
pandas/tests/io/formats/test_format.py:455:13: E722 do not use bare except'
```
An updated list can be obtained by running: `flake8 --select=E722 --config=none pandas/tests/`


Discussion:
On it!
This issue seems not fixed after some time. It has been a month and I'm not sure if Harald will be finishing this as he didn't respond if he will be fixing the requested changes on his pull request. Could I take over and try to work on this? @datapythonista @jreback 
we would accept multiple PRs for this 
This is the updated list. I will start working on this as soon as possible.

```
pandas/tests/test_panel.py:338:13: E722 do not use bare 'except'
pandas/tests/test_panel.py:344:13: E722 do not use bare 'except'
pandas/tests/test_nanops.py:144:9: E722 do not use bare 'except'
pandas/tests/test_nanops.py:149:9: E722 do not use bare 'except'
pandas/tests/test_nanops.py:170:21: E722 do not use bare 'except'
pandas/tests/test_nanops.py:174:21: E722 do not use bare 'except'
pandas/tests/test_multilevel.py:1381:9: E722 do not use bare 'except'
pandas/tests/test_strings.py:2632:13: E722 do not use bare 'except'
pandas/tests/io/test_pytables.py:54:9: E722 do not use bare 'except'
pandas/tests/io/test_pytables.py:62:5: E722 do not use bare 'except'
pandas/tests/io/test_pytables.py:120:5: E722 do not use bare 'except'
pandas/tests/io/test_pytables.py:4624:21: E722 do not use bare 'except'
pandas/tests/io/test_sql.py:1793:9: E722 do not use bare 'except'
pandas/tests/io/test_sql.py:2378:9: E722 do not use bare 'except'
pandas/tests/io/test_sql.py:2405:9: E722 do not use bare 'except'
pandas/tests/io/formats/test_format.py:73:5: E722 do not use bare 'except'
pandas/tests/io/formats/test_format.py:455:13: E722 do not use bare 'except'
pandas/tests/indexing/common.py:154:13: E722 do not use bare 'except'
pandas/tests/indexing/common.py:217:17: E722 do not use bare 'except'
```

Resolving patch:
diff --git a/doc/source/conf.py b/doc/source/conf.py
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -586,7 +586,7 @@ def linkcode_resolve(domain, info):
     for part in fullname.split('.'):
         try:
             obj = getattr(obj, part)
-        except:
+        except AttributeError:
             return None
 
     try:
@@ -595,14 +595,14 @@ def linkcode_resolve(domain, info):
             fn = inspect.getsourcefile(inspect.unwrap(obj))
         else:
             fn = inspect.getsourcefile(obj)
-    except:
+    except TypeError:
         fn = None
     if not fn:
         return None
 
     try:
         source, lineno = inspect.getsourcelines(obj)
-    except:
+    except OSError:
         lineno = None
 
     if lineno:


Test patch:
diff --git a/pandas/tests/indexing/common.py b/pandas/tests/indexing/common.py
--- a/pandas/tests/indexing/common.py
+++ b/pandas/tests/indexing/common.py
@@ -156,7 +156,7 @@ def get_result(self, obj, method, key, axis):
         with catch_warnings(record=True):
             try:
                 xp = getattr(obj, method).__getitem__(_axify(obj, key, axis))
-            except:
+            except AttributeError:
                 xp = getattr(obj, method).__getitem__(key)
 
         return xp
@@ -219,7 +219,7 @@ def _print(result, error=None):
 
                 try:
                     xp = self.get_result(obj, method2, k2, a)
-                except:
+                except Exception:
                     result = 'no comp'
                     _print(result)
                     return
diff --git a/pandas/tests/io/formats/test_format.py b/pandas/tests/io/formats/test_format.py
--- a/pandas/tests/io/formats/test_format.py
+++ b/pandas/tests/io/formats/test_format.py
@@ -70,7 +70,7 @@ def has_horizontally_truncated_repr(df):
     try:  # Check header row
         fst_line = np.array(repr(df).splitlines()[0].split())
         cand_col = np.where(fst_line == '...')[0][0]
-    except:
+    except IndexError:
         return False
     # Make sure each row has this ... in the same place
     r = repr(df)
@@ -459,7 +459,7 @@ def test_to_string_repr_unicode(self):
         for line in rs[1:]:
             try:
                 line = line.decode(get_option("display.encoding"))
-            except:
+            except AttributeError:
                 pass
             if not line.startswith('dtype:'):
                 assert len(line) == line_len
diff --git a/pandas/tests/io/test_pytables.py b/pandas/tests/io/test_pytables.py
--- a/pandas/tests/io/test_pytables.py
+++ b/pandas/tests/io/test_pytables.py
@@ -51,7 +51,7 @@ def safe_remove(path):
     if path is not None:
         try:
             os.remove(path)
-        except:
+        except OSError:
             pass
 
 
@@ -59,7 +59,7 @@ def safe_close(store):
     try:
         if store is not None:
             store.close()
-    except:
+    except IOError:
         pass
 
 
@@ -117,7 +117,7 @@ def _maybe_remove(store, key):
     no content from previous tests using the same table name."""
     try:
         store.remove(key)
-    except:
+    except (ValueError, KeyError):
         pass
 
 
@@ -4601,7 +4601,7 @@ def do_copy(f, new_f=None, keys=None,
                     safe_close(tstore)
                     try:
                         os.close(fd)
-                    except:
+                    except (OSError, ValueError):
                         pass
                     safe_remove(new_f)
 
diff --git a/pandas/tests/io/test_sql.py b/pandas/tests/io/test_sql.py
--- a/pandas/tests/io/test_sql.py
+++ b/pandas/tests/io/test_sql.py
@@ -1815,6 +1815,7 @@ def test_default_type_conversion(self):
         assert issubclass(df.BoolColWithNull.dtype.type, np.floating)
 
     def test_read_procedure(self):
+        import pymysql
         # see GH7324. Although it is more an api test, it is added to the
         # mysql tests as sqlite does not have stored procedures
         df = DataFrame({'a': [1, 2, 3], 'b': [0.1, 0.2, 0.3]})
@@ -1833,7 +1834,7 @@ def test_read_procedure(self):
         try:
             r1 = connection.execute(proc)  # noqa
             trans.commit()
-        except:
+        except pymysql.Error:
             trans.rollback()
             raise
 
@@ -2418,7 +2419,7 @@ def setup_class(cls):
             # No real user should allow root access with a blank password.
             pymysql.connect(host='localhost', user='root', passwd='',
                             db='pandas_nosetest')
-        except:
+        except pymysql.Error:
             pass
         else:
             return
@@ -2445,7 +2446,7 @@ def setup_method(self, request, datapath):
             # No real user should allow root access with a blank password.
             self.conn = pymysql.connect(host='localhost', user='root',
                                         passwd='', db='pandas_nosetest')
-        except:
+        except pymysql.Error:
             pass
         else:
             return
diff --git a/pandas/tests/test_multilevel.py b/pandas/tests/test_multilevel.py
--- a/pandas/tests/test_multilevel.py
+++ b/pandas/tests/test_multilevel.py
@@ -1376,7 +1376,7 @@ def f():
 
         try:
             df = f()
-        except:
+        except ValueError:
             pass
         assert (df['foo', 'one'] == 0).all()
 
diff --git a/pandas/tests/test_nanops.py b/pandas/tests/test_nanops.py
--- a/pandas/tests/test_nanops.py
+++ b/pandas/tests/test_nanops.py
@@ -141,12 +141,12 @@ def _coerce_tds(targ, res):
             if axis != 0 and hasattr(
                     targ, 'shape') and targ.ndim and targ.shape != res.shape:
                 res = np.split(res, [targ.shape[0]], axis=0)[0]
-        except:
+        except (ValueError, IndexError):
             targ, res = _coerce_tds(targ, res)
 
         try:
             tm.assert_almost_equal(targ, res, check_dtype=check_dtype)
-        except:
+        except AssertionError:
 
             # handle timedelta dtypes
             if hasattr(targ, 'dtype') and targ.dtype == 'm8[ns]':
@@ -167,11 +167,11 @@ def _coerce_tds(targ, res):
                 else:
                     try:
                         res = res.astype('c16')
-                    except:
+                    except RuntimeError:
                         res = res.astype('f8')
                     try:
                         targ = targ.astype('c16')
-                    except:
+                    except RuntimeError:
                         targ = targ.astype('f8')
             # there should never be a case where numpy returns an object
             # but nanops doesn't, so make that an exception
diff --git a/pandas/tests/test_panel.py b/pandas/tests/test_panel.py
--- a/pandas/tests/test_panel.py
+++ b/pandas/tests/test_panel.py
@@ -335,13 +335,13 @@ def check_op(op, name):
         for op in ops:
             try:
                 check_op(getattr(operator, op), op)
-            except:
+            except AttributeError:
                 pprint_thing("Failing operation: %r" % op)
                 raise
         if compat.PY3:
             try:
                 check_op(operator.truediv, 'div')
-            except:
+            except AttributeError:
                 pprint_thing("Failing operation: %r" % 'div')
                 raise
 
diff --git a/pandas/tests/test_strings.py b/pandas/tests/test_strings.py
--- a/pandas/tests/test_strings.py
+++ b/pandas/tests/test_strings.py
@@ -2637,7 +2637,7 @@ def test_slice(self):
                 expected = Series([s[start:stop:step] if not isna(s) else NA
                                    for s in values])
                 tm.assert_series_equal(result, expected)
-            except:
+            except IndexError:
                 print('failed on %s:%s:%s' % (start, stop, step))
                 raise