@@ -294,7 +294,7 @@ def _has_valid_positional_setitem_indexer(self, indexer):
294
294
295
295
return True
296
296
297
- def _setitem_with_indexer (self , indexer , value ):
297
+ def _setitem_with_indexer (self , indexer , value , columns = None ):
298
298
self ._has_valid_setitem_indexer (indexer )
299
299
300
300
# also has the side effect of consolidating in-place
@@ -304,6 +304,11 @@ def _setitem_with_indexer(self, indexer, value):
304
304
# maybe partial set
305
305
take_split_path = self .obj ._is_mixed_type
306
306
307
+ # if not all columns are present
308
+ if (columns is not None and
309
+ any (k not in self .obj .columns for k in columns )):
310
+ take_split_path = True
311
+
307
312
# if there is only one block/type, still have to take split path
308
313
# unless the block is one-dimensional or it can hold the value
309
314
if not take_split_path and self .obj ._data .blocks :
@@ -466,10 +471,13 @@ def _setitem_with_indexer(self, indexer, value):
466
471
if isinstance (value , ABCSeries ):
467
472
value = self ._align_series (indexer , value )
468
473
469
- info_idx = indexer [info_axis ]
470
- if is_integer (info_idx ):
471
- info_idx = [info_idx ]
472
- labels = item_labels [info_idx ]
474
+ if columns is None :
475
+ info_idx = indexer [info_axis ]
476
+ if is_integer (info_idx ):
477
+ info_idx = [info_idx ]
478
+ labels = item_labels [info_idx ]
479
+ else :
480
+ labels = columns
473
481
474
482
# if we have a partial multiindex, then need to adjust the plane
475
483
# indexer here
@@ -517,6 +525,9 @@ def _setitem_with_indexer(self, indexer, value):
517
525
lplane_indexer = 0
518
526
519
527
def setter (item , v ):
528
+ if item not in self .obj .columns :
529
+ self .obj [item ] = v
530
+ return
520
531
s = self .obj [item ]
521
532
pi = plane_indexer [0 ] if lplane_indexer == 1 else plane_indexer
522
533
@@ -1109,7 +1120,8 @@ def _getitem_axis(self, key, axis=None):
1109
1120
1110
1121
return self ._get_label (key , axis = axis )
1111
1122
1112
- def _get_listlike_indexer (self , key , axis , raise_missing = False ):
1123
+ def _get_listlike_indexer (self , key , axis , is_setter = False ,
1124
+ raise_missing = False ):
1113
1125
"""
1114
1126
Transform a list-like of keys into a new index and an indexer.
1115
1127
@@ -1162,6 +1174,7 @@ def _get_listlike_indexer(self, key, axis, raise_missing=False):
1162
1174
1163
1175
self ._validate_read_indexer (keyarr , indexer ,
1164
1176
o ._get_axis_number (axis ),
1177
+ is_setter = is_setter ,
1165
1178
raise_missing = raise_missing )
1166
1179
return keyarr , indexer
1167
1180
@@ -1210,7 +1223,8 @@ def _getitem_iterable(self, key, axis=None):
1210
1223
return self .obj ._reindex_with_indexers ({axis : [keyarr , indexer ]},
1211
1224
copy = True , allow_dups = True )
1212
1225
1213
- def _validate_read_indexer (self , key , indexer , axis , raise_missing = False ):
1226
+ def _validate_read_indexer (self , key , indexer , axis , is_setter = False ,
1227
+ raise_missing = False ):
1214
1228
"""
1215
1229
Check that indexer can be used to return a result (e.g. at least one
1216
1230
element was found, unless the list of keys was actually empty).
@@ -1244,7 +1258,8 @@ def _validate_read_indexer(self, key, indexer, axis, raise_missing=False):
1244
1258
missing = (indexer < 0 ).sum ()
1245
1259
1246
1260
if missing :
1247
- if missing == len (indexer ):
1261
+ if (not (self .name == 'loc' and is_setter ) and
1262
+ missing == len (indexer )):
1248
1263
raise KeyError (
1249
1264
"None of [{key}] are in the [{axis}]" .format (
1250
1265
key = key , axis = self .obj ._get_axis_name (axis )))
@@ -1268,7 +1283,7 @@ def _validate_read_indexer(self, key, indexer, axis, raise_missing=False):
1268
1283
See the documentation here:
1269
1284
https://pandas.pydata.org/pandas-docs/stable/indexing.html#deprecate-loc-reindex-listlike""" ) # noqa
1270
1285
1271
- if not (ax .is_categorical () or ax .is_interval ()):
1286
+ if not is_setter and not (ax .is_categorical () or ax .is_interval ()):
1272
1287
warnings .warn (_missing_key_warning ,
1273
1288
FutureWarning , stacklevel = 6 )
1274
1289
@@ -1353,8 +1368,8 @@ def _convert_to_indexer(self, obj, axis=None, is_setter=False,
1353
1368
return inds
1354
1369
else :
1355
1370
# When setting, missing keys are not allowed, even with .loc:
1356
- kwargs = {'raise_missing ' : True if is_setter else
1357
- raise_missing }
1371
+ kwargs = {'is_setter ' : is_setter ,
1372
+ 'raise_missing' : raise_missing }
1358
1373
return self ._get_listlike_indexer (obj , axis , ** kwargs )[1 ]
1359
1374
else :
1360
1375
try :
0 commit comments