Repository: modin-project/modin
Pull request: FIX-#4593: Ensure Modin warns when setting columns via attributes
Signed-off-by: Hazem Elmeleegy <hazem@ponder.io>

<!--
Thank you for your contribution!
Please review the contributing docs: https://modin.readthedocs.io/en/latest/development/contributing.html
if you have questions about contributing.
-->

## What do these changes do?

<!-- Please give a short brief about these changes. -->

- [x] commit message follows format outlined [here](https://modin.readthedocs.io/en/latest/development/contributing.html#commit-message-formatting)
- [x] passes `flake8 modin/ asv_bench/benchmarks scripts/doc_checker.py`
- [x] passes `black --check modin/ asv_bench/benchmarks scripts/doc_checker.py`
- [x] signed commit with `git commit -s` <!-- you can amend your commit with a signature via `git commit -amend -s` -->
- [x] Resolves #4593 <!-- issue must be created for each patch -->
- [x] tests added and passing
- [x] module layout described at `docs/development/architecture.rst` is up-to-date <!-- if you have added, renamed or removed files or directories please update the documentation accordingly -->
- [x] added (Issue Number: PR title (PR Number)) and github username to release notes for next major release <!-- e.g. DOCS-#4077: Add release notes template to docs folder (#4078) -->


Problem statement:
Modin should match pandas UserWarning for assigning columns via attributes
### System information
- **OS Platform and Distribution (e.g., Linux Ubuntu 16.04)**: macOS 12.2.1
- **Modin version** (`modin.__version__`): 0.15.0+16.g4574746c
- **Python version**: 3.9.12
- **Code we can use to reproduce**:

```python
import modin.pandas as pd
import pandas

pandas_df = pandas.DataFrame({"a": [1, 2, 3]})
modin_df = pd.DataFrame({"a": [1, 2, 3]})

# This throws a user warning
pandas_df.b = [1,2,3]

# This does not throw a user warning
modin_df.b = [1,2,3]
```

### Describe the problem
Modin doesn't throw a user warning for trying to assign new columns by setting an attribute. This isn't a super pressing issue, but we should at least mimic pandas behavior here. 

### Source code / logs
<!-- Include any logs or source code that would be helpful to diagnose the problem. If including tracebacks, please include the full traceback. Large logs and files should be attached. Try to provide a reproducible test case that is the bare minimum necessary to generate the problem. -->

Hints from issue discussion:

Commit message: FIX-#4593: Ensure Modin warns when setting columns via attributes

Signed-off-by: Hazem Elmeleegy <hazem@ponder.io>

Patch to review:
diff --git a/modin/pandas/dataframe.py b/modin/pandas/dataframe.py
index fa3bcb07026..94ff69b6fea 100644
--- a/modin/pandas/dataframe.py
+++ b/modin/pandas/dataframe.py
@@ -2496,18 +2496,18 @@ def __setattr__(self, key, value):
         # - `_siblings`, which Modin initializes before it appears in __dict__
         if key in ["_query_compiler", "_siblings"] or key in self.__dict__:
             pass
-        elif key in self and key not in dir(self):
+        elif key not in dir(self):
+            if key not in self:
+                warnings.warn(
+                    "Modin doesn't allow columns to be created via a new attribute name - see "
+                    + "https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute-access",
+                    UserWarning,
+                )
             self.__setitem__(key, value)
             # Note: return immediately so we don't keep this `key` as dataframe state.
             # `__getattr__` will return the columns not present in `dir(self)`, so we do not need
             # to manually track this state in the `dir`.
             return
-        elif isinstance(value, pandas.Series):
-            warnings.warn(
-                "Modin doesn't allow columns to be created via a new attribute name - see "
-                + "https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute-access",
-                UserWarning,
-            )
         object.__setattr__(self, key, value)
 
     def __setitem__(self, key, value):


Code review comments:
diff_hunk: @@ -2496,18 +2496,18 @@ def __setattr__(self, key, value):
         # - `_siblings`, which Modin initializes before it appears in __dict__
         if key in ["_query_compiler", "_siblings"] or key in self.__dict__:
             pass
-        elif key in self and key not in dir(self):
+        elif key not in dir(self):
+            if key not in self:
+                warnings.warn(
+                    "Modin doesn't allow columns to be created via a new attribute name - see "
+                    + "https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute-access",
+                    UserWarning,
+                )
path: modin/pandas/dataframe.py
text: @user1:
I was thinking that we could keep the existing check as is, but make an extra check to see if `value` was "list-like". Take a look at this snippet: https://github.com/pandas-dev/pandas/blob/main/pandas/core/generic.py#L5640-L5648. Our goal here is to match pandas behavior.

@author:
Thanks for the comments! The logic is updated now, and it checks for `is_list_like`, which I believe is more general the pre-existing check for `pandas.Series`, and hence that old check is now removed.

Also, tests are added and `docs/release_notes` is updated. PTAL when you get a chance.