Repository: spyder-ide/spyder

Issue:
AttributeError when pasting list in collectionseditor.py
While trying to copy a column from libreoffice calc and paste this happened. That would be a nice feature to have. 


`
  File "/opt/anaconda3/lib/python3.6/site-packages/spyder/widgets/variableexplorer/collectionseditor.py", line 880, in keyPressEvent
    self.paste()
  File "/opt/anaconda3/lib/python3.6/site-packages/spyder/widgets/variableexplorer/collectionseditor.py", line 1158, in paste
    self.import_from_string(cliptext, title=_("Import from clipboard"))
  File "/opt/anaconda3/lib/python3.6/site-packages/spyder/widgets/variableexplorer/collectionseditor.py", line 1145, in import_from_string
    blacklist=list(data.keys())))
AttributeError: 'list' object has no attribute 'keys'

`



Discussion:
Please describe step by step how you got this error so we can reproduce it in our side. If you fail to do that, we'll close this issue in a week from now.

Also, please read our

https://github.com/spyder-ide/spyder/wiki/Troubleshooting-Guide-and-FAQ

to see if you are able to fix this problem by following it.
@matheusfillipe Thanks for following up. I was not able to reproduce this on Spyder 3.2.8, Python 3.6.4, Qt/PyQt 5.6 and Windows 8.1 x64, after copying and pasting the column

```
TestName
1
2
3
4
5
6
```

from a fresh spreadsheet, as well as one with other columns, by selecting just the entered data, selecting beyond it, or selecting the whole column from the top, and trying it in LibreOffice Calc 5.4.4.2 x64 as well as MS Excel 2013.

We should be able to fix this if its a bug in Spyder, but we'll need a little more information from you first. Therefore, please let us know your full versions of Spyder, Python, and Qt/PyQt (you can find all of this under the ``Help > About`` dialog box in Spyder), your OS and LibreOffice version, and, most importantly, a simple as possible example of some data you tried to copy that triggered the problem, and the exact, step by step procedure for doing so; all of this was requested by the issue template you should have seen when posting, and apparently removed. Thanks!

I've restarted again and tested again. Steps to reproduce:
On the Ipython shell:
`test=[1,2,3,4]`

Then on the variable explorer double click on the test's list value, select the first cell an hit ctrl+V. Then the errors shows up. 

This is what im trying to pate: 

2
3
4
5


Spyder 3.2.8, Python 3.6.5 64bits, Qt 5.9.4, PyQt5 5.9.2 on Linux Ubuntu 18.04.
Libreoffice Calc: Version: 6.0.3.2; Build ID: 1:6.0.3-0ubuntu1
I think this happens because you're trying to paste an entire list in a single cell. We'll try to fix it in a future release.
@matheusfillipe Oh, thanks. I can reproduce the behavior if I do what you describe. 

However, pasting doesn't currently work that way; you can instead just paste directly into the Variable Explorer proper, rather than into an existing object. That will open the ``Import from clipboard`` dialog, which will allow you to choose a number of options for how to import your data (with sensible defaults), and allow you to store the data as a Python list, Numpy array, or Pandas DataFrame.

@ccordoba12 The proximate cause here is that when pasting into any CollectionEditor (including the global NamespaceEditor, and arbitrary ObjectEditors), Spyder's trying to open a new Import from Clipboard dialog, but it assumes the active Editor contains something (i.e. a dict or namespace) with ``keys()`` to check against, presumably for the user entering a duplicate name to an existing key when pasting (Ctrl-V).

This is a valid assumption for the root ``NamespaceEditor``, presumably the original intention of this feature, and actually works just fine adding the data (as a list, array, or df) as a new value in a dictionary. However, it produces the above error (with the appropriate object type name) with lists, tuples, or sets, and raises the nearly ``AttributeError: 'ProxyObject' object has no attribute 'keys'`` for objecteditors, i.e. arbitrary objects, functions, classes, modules, etc. Meanwhile, for Numpy arrays (``ArrayEditor``) and Pandas Index/Series/DF (``DataFrameEditor``), nothing happens when trying to paste because they don't have that keypress hook collecitoneditors do, which is the expected behavior (at least until we implement something really fancy to handle that).

Also, it doesn't seem to respect the ``readonly`` attribute set on many of those (immutable) collections/objects, since even if this error didn't occur (i.e. the object had a ``keys()`` attribute), it shouldn't be possible to save new data in a readonly/immutable object.  

So, I propose checking for ``readonly`` before trying the ``import_from_string`` call, and then either 

* Catching and passing ``AttributeError`` there (thus doing nothing), 
* Raising an appropriate warning dialog for each one as is currently done there for an empty clipboard,

or, somewhat more ambitiously, we can handle it for lists inside ``import_from_string`` and ``ImportWizard`` by just not worrying about ``keys() and appending the list/array/df as a new object in the list. It shouldn't be that hard...
@ccordoba12 Just saw your new comment after posting mine:

> I think this happens because you're trying to paste an entire list in a single cell.

Actually, that works fine. The problem only occurs when not pasting into a cell but pasting into a CollectionEditor (collection, namespace, object...) itself, because that triggers the import from clipboard dialog which assumes the object has keys() to check against, which in the case of most collection types is not the case.
> So, I propose checking for readonly before trying the import_from_string call, and then either
    * Catching and passing AttributeError there (thus doing nothing),
    * Raising an appropriate warning dialog for each one as is currently done there for an empty clipboard

I agree with this for 3.x.

> or, somewhat more ambitiously, we can handle it for lists inside import_from_string and ImportWizard by just not worrying about ``keys() and appending the list/array/df as a new object in the list. It shouldn't be that hard

This could be done for Spyder 4, but perhaps we would have to deal with several corner cases, so I'd prefer simply to pass.
Okay, cool. So do you prefer the warning dialog Ux like that when pasting an empty object, or the "do nothing" Ux like that when trying to paste in the DFEditor and ArrayEditor? I don't want to annoy the user with extra dialogs, but I figure pasting into a non-dict/namespace collectioneditor is sufficiently rare (considering we haven't seen this one before) that preventing user frustration from not understanding why they couldn't paste (as we indeed saw in this issue) would outweigh that minor annoyance.
> or the "do nothing" UI like that when trying to paste in the DFEditor and ArrayEditor?

Doing nothing is fine. Even better, I think we should deactivate several menu entries when collectionseditor is not used to show the main namespace:

* Paste
* Duplicate
* Show arrays min/max
> Paste

There's no harm in keeping it for ``dict`` (and namespace) since it works just fine, but it definitely should be removed for anything readonly and, at least until we implement a way to paste into lists, anything else as well, which is in scope for this PR. I should also probably catch the error for the keypress earlier, in ``keyPressEvent``.

> Duplicate
> Show arrays min/max

These are both not in scope for this PR, and I also see no reason to disable them in any CollectionsEditor. They both work fine in my testing, and are still quite useful in such a context, duplicate particularly so (perhaps even more so than in the main namespace). Deactivating them just takes up space without offering the fully working and useful functionality, which seems ill advised.
I hope this becomes a feature soon. Importing all sorts of data is a common task to me and just being able to put some column of cells from spreadsheets directly into a variable in a more easy way like this would be really helpful.
@matheusfillipe As mentioned, you can easily do this right now. Aside from importing the spreadsheet directly as a pandas dataframe and manipulating it from there (a much more reliable and reproducible approach in general), you can just paste the columns right into the main Variable Explorer window, and they can be added with two clicks as a list, array, or dataframe. You can then easily use ``pandas.concat`` to join them, in one command, to another dataframe (or multiple), or use ``.at``/``iat`` to  insert them directly.

If you want the ability to directly copy and paste them into a specific part of an existing dataframe, that is probably possible to add but would be much more complicated, involve a lot of edge cases and potential bugs, and overall not be a very robust or sustainable workflow anyway. Of course, you're welcome to submit a PR to add that feature if it doesn't get on the nearterm roadmap, and we'd be glad to point you in the right direction.
Oh ! This way is easier. Thanks for pointing it out, i didn't pay enough attention on what you were talking about before.
Aside from that now the only feature I miss is a better vim editor. Hope that's coming on spyder4 ! 
Check out the spyder-ide/spyder-vim plugin for that and we also should have built in vim hotkey profiles in Spyder 4; support for the addon is currently paused to focus on the Spyder 4 release but will be resumed in full force after.

Resolving patch:
diff --git a/spyder/widgets/variableexplorer/collectionseditor.py b/spyder/widgets/variableexplorer/collectionseditor.py
--- a/spyder/widgets/variableexplorer/collectionseditor.py
+++ b/spyder/widgets/variableexplorer/collectionseditor.py
@@ -1150,6 +1150,9 @@ def copy(self):
     def import_from_string(self, text, title=None):
         """Import data from string"""
         data = self.model.get_data()
+        # Check if data is a dict
+        if not hasattr(data, "keys"):
+            return
         editor = ImportWizard(self, text, title=title,
                               contents_title=_("Clipboard contents"),
                               varname=fix_reference_name("data",


Test patch: