Repository: pandas-dev/pandas

Issue:
read_hdf / store.select modifies the passed columns parameters when multi-indexed
code to reproduce:

``` python
import pandas as pd
import numpy as np

## generate data
df = pd.DataFrame(np.random.rand(4,5), index=list('abcd'), columns=list('ABCDE'))
df.index.name = 'letters'
df = df.set_index(keys='E' , append=True)

## save to hdf5
h5name = 'tst.h5'
key = 'tst_key'
df.to_hdf(h5name, key,
          mode='a', append=True,
          data_columns = df.index.names+df.columns.tolist(),
          index=False, 
          complevel=5, complib='blosc', 
          #expectedrows = expectedrows ,
          )

## load part of df
cols2load = list('BCD')
print 'before loading: \n\t cols2load = {}'.format(cols2load)
df_ = pd.read_hdf(h5name, key, columns= cols2load)
print 'after loading: \n\t cols2load = {}'.format(cols2load)
```

The printed output:

> before loading: 
>    cols2load = ['B', 'C', 'D']
> after loading: 
>    cols2load = ['E', 'letters', 'B', 'C', 'D']

pd.**version** = '0.13.1'



Discussion:
hmm, not sure their any guarantees on this, but makes sense to simply copy this and not modify.

Want to do a pull-request?

my current solution is to pass a copy:

``` python
df_ = pd.read_hdf(h5name, key, columns= list(cols2load))
```

BTW, the same problem holds for the `where` parameter of `read_hdf`.
I do not expect to be able to do the pull-request soon (it'll be my first, so it will take time...).
I mainly thought it is worth posting as I wasted quite some time on finding the "bug" in my code.
Turned out it wast this (I was using `cols2load` for several different purposes in the code).

no problem

take your time

about to release 0.14.0 in any event

@eldad-a if you have a pull-request for this would be great

@jreback unfortunately i do not expect to be able to get into the matter soon.
In case I will, I'll defenitely submit a pull-request.

ok, thanks

working on this


Resolving patch:
diff --git a/pandas/io/pytables.py b/pandas/io/pytables.py
--- a/pandas/io/pytables.py
+++ b/pandas/io/pytables.py
@@ -3453,6 +3453,10 @@ def get_blk_items(mgr, blocks):
     def process_axes(self, obj, columns=None):
         """ process axes filters """
 
+        # make a copy to avoid side effects
+        if columns is not None:
+            columns = list(columns)
+
         # make sure to include levels if we have them
         if columns is not None and self.is_multi_index:
             for n in self.levels:


Test patch:
diff --git a/pandas/io/tests/test_pytables.py b/pandas/io/tests/test_pytables.py
--- a/pandas/io/tests/test_pytables.py
+++ b/pandas/io/tests/test_pytables.py
@@ -4617,6 +4617,29 @@ def test_preserve_timedeltaindex_type(self):
             store['df'] = df
             assert_frame_equal(store['df'], df)
 
+    def test_colums_multiindex_modified(self):
+        # BUG: 7212
+        # read_hdf store.select modified the passed columns parameters
+        # when multi-indexed.
+
+        df = DataFrame(np.random.rand(4, 5),
+                       index=list('abcd'),
+                       columns=list('ABCDE'))
+        df.index.name = 'letters'
+        df = df.set_index(keys='E', append=True)
+
+        data_columns = df.index.names+df.columns.tolist()
+        with ensure_clean_path(self.path) as path:
+            df.to_hdf(path, 'df',
+                      mode='a',
+                      append=True,
+                      data_columns=data_columns,
+                      index=False)
+            cols2load = list('BCD')
+            cols2load_original = list(cols2load)
+            df_loaded = read_hdf(path, 'df', columns=cols2load)
+            self.assertTrue(cols2load_original == cols2load)
+
 
 def _test_sort(obj):
     if isinstance(obj, DataFrame):