Repository: dask/dask
Pull request: Add single quotes around column names if strings
- [ ] Tests added / passed
- [x] Passes `black dask` / `flake8 dask`

Fixes #6470 

Adds explicit single quotes around the column names in `bad_dtypes` so that it's easier to distinguish between `str(int)` column names and `int` column names.

```
Traceback (most recent call last):
  File "metadata_mismatch.py", line 11, in <module>
    df.compute()
  File "/Users/gil/github.com/dask/dask/dask/base.py", line 167, in compute
    (result,) = compute(self, traverse=False, **kwargs)
  File "/Users/gil/github.com/dask/dask/dask/base.py", line 447, in compute
    results = schedule(dsk, keys, **kwargs)
  File "/Users/gil/github.com/dask/dask/dask/threaded.py", line 76, in get
    results = get_async(
  File "/Users/gil/github.com/dask/dask/dask/local.py", line 486, in get_async
    raise_exception(exc, tb)
  File "/Users/gil/github.com/dask/dask/dask/local.py", line 316, in reraise
    raise exc
  File "/Users/gil/github.com/dask/dask/dask/local.py", line 222, in execute_task
    result = _execute_task(task, data)
  File "/Users/gil/github.com/dask/dask/dask/core.py", line 121, in _execute_task
    return func(*(_execute_task(a, cache) for a in args))
  File "/Users/gil/github.com/dask/dask/dask/dataframe/utils.py", line 672, in check_meta
    raise ValueError(
ValueError: Metadata mismatch found in `from_delayed`.

Partition type: `pandas.core.frame.DataFrame`
+--------+-------+----------+
| Column | Found | Expected |
+--------+-------+----------+
| '7'    | int64 | -        |
| '8'    | int64 | -        |
| 7      | -     | int64    |
| 8      | -     | int64    |
+--------+-------+----------+
```

Problem statement:
Metadata mismatch is not clear about why columns are different
Reproducible code

```
import pandas as pd
from dask.delayed import delayed
import dask.dataframe as dd

def df_with_str_columns(): 
    return pd.DataFrame({'7': [1, 2], '8': [3, 4]}) 

# Note in meta columns are ints
meta = {7: 'int', 8: 'int'}
df = dd.from_delayed([delayed(df_with_str_columns)(), delayed(df_with_str_columns)()], meta=meta)
df.compute()
```

Output:
```

ValueError: Metadata mismatch found in `from_delayed`.

Partition type: `pandas.core.frame.DataFrame`
+--------+-------+----------+
| Column | Found | Expected |
+--------+-------+----------+
| 7      | int64 | -        |
| 8      | int64 | -        |
| 7      | -     | int64    |
| 8      | -     | int64    |
+--------+-------+----------+
```

The problem is that the output doesn't make it clear that 2 of the columns are strings, while two are ints. The following would be helpful:

```

ValueError: Metadata mismatch found in `from_delayed`.

Partition type: `pandas.core.frame.DataFrame`
+--------+-------+----------+
| Column | Found | Expected |
+--------+-------+----------+
| '7'      | int64 | -        |
| '8'      | int64 | -        |
| 7      | -     | int64    |
| 8      | -     | int64    |
+--------+-------+----------+
```

Hints from issue discussion:
I can see how this could be moderately infuriating.  Thanks for reporting @birdsarah -- proposed fix incoming.

Commit message: Add single quotes around column names if strings

Patch to review:
diff --git a/dask/dataframe/utils.py b/dask/dataframe/utils.py
index db9e6951eac..649e61c4a2c 100644
--- a/dask/dataframe/utils.py
+++ b/dask/dataframe/utils.py
@@ -647,7 +647,9 @@ def equal_dtypes(a, b):
     elif is_dataframe_like(meta):
         dtypes = pd.concat([x.dtypes, meta.dtypes], axis=1, sort=True)
         bad_dtypes = [
-            (col, a, b)
+            # add single quotes around string variables
+            # to more clearly demarcate column type
+            (f"'{col}'", a, b) if isinstance(col, str) else (col, a, b)
             for col, a, b in dtypes.fillna("-").itertuples()
             if not equal_dtypes(a, b)
         ]


Code review comments:
diff_hunk: @@ -647,7 +647,9 @@ def equal_dtypes(a, b):
     elif is_dataframe_like(meta):
         dtypes = pd.concat([x.dtypes, meta.dtypes], axis=1, sort=True)
         bad_dtypes = [
-            (col, a, b)
+            # add single quotes around string variables
+            # to more clearly demarcate column type
+            (f"'{col}'", a, b) if isinstance(col, str) else (col, a, b)
path: dask/dataframe/utils.py
text: @user1:
Maybe `repr(col)` instead?

@author:
yep, that's a better idea.