Repository: pandas-dev/pandas
Pull request: TST: Add tests for fixed issues
- [x] closes #5647
- [x] closes #5586
- [x] closes #5286
- [x] tests added / passed
- [x] passes `black pandas`
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`


Problem statement:
Phantom Index when NaN in MultiIndex
Using the following:

```
csv_str = """u1,u2,u3,d1,d2,d3,d4
Good Things,C,,1,1,1,1
Good Things,R,,1,1,1,1
Bad Things,C,,1,1,1,1
Bad Things,T,,1,1,1,1
Okay Things,N,B,1,1,1,1
Okay Things,N,D,1,1,1,1
Okay Things,B,,1,1,1,1
Okay Things,D,,1,1,1,1"""
d_nan = pd.read_csv(StringIO.StringIO(csv_str), na_filter=False,index_col=[0,1,2])
d_no_nan = pd.read_csv(StringIO.StringIO(csv_str), na_filter=False,index_col=[0,1,2],na_values=[], keep_default_na=False)
```

If I have the following DataFrame:

```
In [63]: d_nan
Out[63]: 
                    d1  d2  d3  d4
u1          u2 u3                 
Good Things C  NaN   1   1   1   1
            R  NaN   1   1   1   1
Bad Things  C  NaN   1   1   1   1
            T  NaN   1   1   1   1
Okay Things N  B     1   1   1   1
               D     1   1   1   1
            B  NaN   1   1   1   1
            D  NaN   1   1   1   1
```

and then I try to use `loc` on the index:

```
In [64]: d_nan.loc["Good Things"]
Out[64]: 
        d1  d2  d3  d4
u2 u3                 
C  NaN   1   1   1   1
R  NaN   1   1   1   1
```

When I try to `loc` the last level, a mysterious D appears:

```
In [65]: d_nan.loc["Good Things"].loc['C']
Out[65]: 
    d1  d2  d3  d4
u3                
D    1   1   1   1
```

if d instead looks like (no NaNs):

```
In [67]: d_no_nan
Out[67]: 
                   d1  d2  d3  d4
u1          u2 u3                
Good Things C       1   1   1   1
            R       1   1   1   1
Bad Things  C       1   1   1   1
            T       1   1   1   1
Okay Things N  B    1   1   1   1
               D    1   1   1   1
            B       1   1   1   1
            D       1   1   1   1
```

then I have no problems:

```
In [68]: d_no_nan.loc["Good Things"].loc['C']
Out[68]: 
    d1  d2  d3  d4
u3                
     1   1   1   1
```


resample with numpy.product gives unexpected results
```
import datetime
import numpy
import pandas

index = pandas.DatetimeIndex(start=datetime.date(2012, 1, 31), freq='M', periods=12)

ts = pandas.Series(range(12), index=index)
df = pandas.DataFrame(dict(A=ts, B=ts+2))

print df

# Correct
print df.resample('M', how=numpy.sum)
# Incorrect
print df.resample('M', how=numpy.product)
# Correct
print df.resample('Q', how=numpy.sum)
# Incorrect
print df.resample('Q', how=numpy.product)
```

for print df.resample('Q', how=numpy.product), was expecting:

```
2012-03-31   2*1*0   4*3*2
2012-06-30   5*4*3   7*6*5
2012-09-30   8*7*6  10*9*8
2012-12-31  11*10*9  13*12*11
```


0.12: join with on= fails with TimeStamp and Int64 MultiIndex
I encountered a very strange problem in 0.12 when a straightforward join fails while it works just fine in 0.11.

```
df1
```

> <class 'pandas.core.frame.DataFrame'>
> Int64Index: 71958 entries, 0 to 104014
> Data columns (total 3 columns):
> FactorDate         71958  non-null values
> FundSecNo          71958  non-null values
> SourceFundSecNo    71958  non-null values
> dtypes: datetime64[ns](1), int64(2)

```
df1.dtypes
```

> FactorDate         datetime64[ns]
> FundSecNo                   int64
> SourceFundSecNo             int64
> dtype: object

```
df2
```

> <class 'pandas.core.frame.DataFrame'>
> MultiIndex: 94868 entries, (2011-10-18 00:00:00, 283) to (2011-10-19 00:00:00, 127419)
> Data columns (total 2 columns):
> DemeanGroupId           94868  non-null values
> NormalizationGroupId    94868  non-null values
> dtypes: float64(1), int64(1)

```
for ind in df2.index.levels:
    print(type(ind))
```

> <class 'pandas.tseries.index.DatetimeIndex'>
> <class 'pandas.core.index.Int64Index'>

```
test = df1.join(df2, on=['FactorDate', 'SourceFundSecNo'])
test
```

> <class 'pandas.core.frame.DataFrame'>
> Int64Index: 71958 entries, 0 to 104014
> Data columns (total 5 columns):
> FactorDate              71958  non-null values
> FundSecNo               71958  non-null values
> SourceFundSecNo         71958  non-null values
> DemeanGroupId           0  non-null values
> NormalizationGroupId    0  non-null values
> dtypes: datetime64[ns](1), float64(2), int64(2)

```
date = datetime.datetime(2011, 10, 18)
sfsn = 283
test.loc[(test.FactorDate == date) & (test.SourceFundSecNo == sfsn)]
```

> ```
>           FactorDate  FundSecNo  SourceFundSecNo  DemeanGroupId  NormalizationGroupId
> ```
> 
> 1     2011-10-18 00:00:00        283              283            NaN                   NaN
> 17933 2011-10-18 00:00:00      65213              283            NaN                   NaN

```
df2.loc[(date, sfsn)]
```

> DemeanGroupId           350171
> NormalizationGroupId        35
> Name: (2011-10-18 00:00:00, 283), dtype: float64

I can attach the frames, but I forgot how to do it :-)

Hints from issue discussion:
pls post the creation code when u posts a problem so that it can be copy-pasted to reproduce 

it makes it much easier to see if their is actually a bug 

pls post it in a format which is easily copy pasted

iow, put this in a string and use StringIO to read it in (via csv)

gr8

pls also edit the question, so its a simple copy paste within ipython. you will get much faster responses this way.

 its best to make it easy as possible for readers of this thread. no one wants to wade thru many answers/responses just to see what the problem is.

I had spent some time on trying to get this work (previously, not related to this issue).

The basic problem is since the prescent of more than one nan makes the indes non-unique and quite hard to deal with. This should probably throw an error (not actually constructing it, but selecting from it). It IS useful to be able to have the nan's there during reshaping operations), e.g. imagine that you have nans in a column and you set_index, then reset, you'd expect it to work.

So'll i'll mark this as a bug for 0.14, but prob just to raise an error. that said their are some specific cases that DO work, e.g.

```
In [9]: df = DataFrame({"a":['R1', 'R2', np.nan, 'R4'], 'b':["C1", "C2", "C3" , "C4"], "c":[10, 15, np.nan , 20]})

In [10]: df_nan = df.set_index(['a','b'],drop=False)

In [11]: df_nan
Out[11]: 
          a   b   c
a   b              
R1  C1   R1  C1  10
R2  C2   R2  C2  15
NaN C3  NaN  C3 NaN
R4  C4   R4  C4  20

In [12]: df_nan.loc[(np.nan,'C3')]
Out[12]: 
a    NaN
b     C3
c    NaN
Name: (nan, C3), dtype: object
```

This raises an error (in theory I can get this to work, but once you add another nan its very problematic)

```
In [13]: df_nan.loc[np.nan]
ValueError: cannot use label indexing with a null key
```

The problem that I am trying to deal with is data that has a ragged hierarchy. By that I mean it is hierarchical data, but not all hierarchies have the same depth.

An example can be seen looking at an income statement. 
One data might be revenue/cost->division->subdivision.
Other would be shares outstanding->basic/diluted. The first has 3 levels, the second only two. You could argue that these should be stored in separate frames, which might be right, but initially they are all coming from one source (CSV, Excel, HTML, XBRL, etc).

I would just always fill the index labels with a string to avoid ambiguity. Indexes having NaN are by definition pretty ambiguous.

It might be easier to work with if you put the data in the Index as columns
rather than an MI, probably more straightforward + you could use the new
query methods in 0.13

IMHO you are also better off served NOT using a single frame and trying to shove everything into it. Yes it can work, but most often you need specific behavior. I find that creating an object and have an included DataFrame (an has-a) is a very nice idiom for holding data.

Just because data comes from a single source does not mean that the storage is the right medium. I often serialize in a very flat way because its more efficient/easier; but that does not mean that that is the most 'natural' way.

Which raises another question. Let's say I do have the table called d_nan above.

How do I replace the NaNs in the index with another value (in this case I would imagine some monotonic int or string would be ideal).

```
In [5]: d_nan
Out[5]: 
                    d1  d2  d3  d4
u1          u2 u3                 
Good Things C  NaN   1   1   1   1
            R  NaN   1   1   1   1
Bad Things  C  NaN   1   1   1   1
            T  NaN   1   1   1   1
Okay Things N  B     1   1   1   1
               D     1   1   1   1
            B  NaN   1   1   1   1
            D  NaN   1   1   1   1

In [7]: df = d_nan.reset_index()

In [9]: df['u3'] = df['u3'].fillna('_nan_')

IIn [11]: df.set_index(['u1','u2','u3'],inplace=True)

In [12]: df
Out[12]: 
                      d1  d2  d3  d4
u1          u2 u3                   
Good Things C  _nan_   1   1   1   1
            R  _nan_   1   1   1   1
Bad Things  C  _nan_   1   1   1   1
            T  _nan_   1   1   1   1
Okay Things N  B       1   1   1   1
               D       1   1   1   1
            B  _nan_   1   1   1   1
            D  _nan_   1   1   1   1
```

I think this just needs a mapping like `np.prod` has (which works correcly). These numpy functions are mapped internally to cython functions.

I had just fixed this when I realized there are lots of other numpy functions which will behave in the same way, e.g. 

```
>>> df.groupby("a").agg(np.max)
    b
a    
10  2
20  3
30  5
```

but

```
>>> df.groupby("a").agg(np.nanmax)
     b
a     
10  10
20  20
30  30
```

Is whitelisting them one by one really our best option?

the nan ones are somewhat newer

I think there are only a few more to add
not really sure of a better way l

maybe could try some sort of regex matching on the name of the function?
(and see what comes up and just map them)

FYI since for example nanmean doesn't exist in older numpies have to conditionally add them 

Maybe we could go the other way, and blacklist the ones we haven't done.  Admittedly that wouldn't catch `.agg(lambda x: np.some_new_function(x))`, but it would protect against `.agg(np.some_new_function)` if we hadn't handled it yet.

But couldn't we just catch anything else in numpy and pass it `np.asarray(x)`, though?

First, check to see if it's been special cased. If so, use it.
Next, check to see if it's a numpy function we haven't whitelisted.  If so, call it with np.asarray(x); more likely to give the expected answer.
If not, pass it x.

Vaguely like

```
>>> np_funcs = {f for n, f in inspect.getmembers(np) if callable(f)}
>>> f = np.product
>>> df.groupby("a").agg(np.prod)
     b
a     
10   2
20   3
30  20
>>> df.groupby("a").agg(np.product)
        b
a        
10    200
20     60
30  18000
>>> f = np.product
>>> df.groupby("a").agg(f if f not in np_funcs else (lambda x: f(np.asarray(x))))
     b
a     
10   2
20   3
30  20
```

yes I think that how could definitly be more strict in that you could evaluate on cases:
- if its in our white list map to a pandas fast function and go
- if its on black list raise
- if its a lamba pass thru
- if its a numpy function that is not the above, the use `np.asarray` (and maybe show a warning?)

I like the warning idea, though I'm not sure what the appropriate label would be: SemiImplementedWarning, maybe? :^)

```
SemiImplementedWarning: numpy function {} does not have a fast native pandas
equivalent yet and is not fully supported; coercing the groups to ndarrays
```

Whatever we do, I think the current approach of special-casing a few and letting the rest silently give incorrect results -- even though they're called in exactly the same way the ones which work do -- should be replaced with something noisier.

you can say that you should use `lambda x: np.function_that_we_do_fast` as this will pass thru and just let the warning happen (until we put an explicity put it on the whitelist with either a fast version or a simple passthru)

Looks fixed in master. Could use a test.
@mroeschke what would we be testing?  the `df.resample("M", np.product)` usage from the OP is no longer supported
`df.resample('M').apply(np.product)` produces the correct result IIRC.
can you put up a small reproducible example if possible.

I tried quickly but couldn't come up with one that exhibits the same behavior. Can I put the frames into an HDF5 file and somehow ship it to you guys? This would be the easiest way.

sure....show complete code to get them out...and put on dropbox like service and post the link

https://www.dropbox.com/s/c0hq6uqn8y5vkbk/issue5647.h5

```
store = pd.HDFStore('issue5647.h5', mode='r')
df1 = store.select('df1')
df2 = store.select('df2')
store.close()
```

I think you want something like this
The problem is it doesn't know how to match up the 'SourceFundSecNo' with 'FundSecNo'.

```
In [72]: x = df2.reset_index()

In [73]: x['SourceFundSecNo'] = x['FundSecNo']

In [74]: x.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 94868 entries, 0 to 94867
Data columns (total 5 columns):
FactorDate              94868  non-null values
FundSecNo               94868  non-null values
DemeanGroupId           94868  non-null values
NormalizationGroupId    94868  non-null values
SourceFundSecNo         94868  non-null values
dtypes: datetime64[ns](1), float64(1), int64(3)
In [75]: df1.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 71958 entries, 0 to 104014
Data columns (total 3 columns):
FactorDate         71958  non-null values
FundSecNo          71958  non-null values
SourceFundSecNo    71958  non-null values
dtypes: datetime64[ns](1), int64(2)
```

inner join

```
In [76]: pd.merge(df1,x,on=['FactorDate','SourceFundSecNo']).info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 71958 entries, 0 to 71957
Data columns (total 6 columns):
FactorDate              71958  non-null values
FundSecNo_x             71958  non-null values
SourceFundSecNo         71958  non-null values
FundSecNo_y             71958  non-null values
DemeanGroupId           71958  non-null values
NormalizationGroupId    71958  non-null values
dtypes: datetime64[ns](1), float64(1), int64(4)
```

outer join I think is what you want (e.g. many-many)

```
In [77]: pd.merge(df1,x,on=['FactorDate','SourceFundSecNo'],how='outer').info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 103922 entries, 0 to 103921
Data columns (total 6 columns):
FactorDate              103922  non-null values
FundSecNo_x             71958  non-null values
SourceFundSecNo         103922  non-null values
FundSecNo_y             103922  non-null values
DemeanGroupId           103922  non-null values
NormalizationGroupId    103922  non-null values
dtypes: datetime64[ns](1), float64(3), int64(2)
```

Well, as you can see, the index in df2 is unique (at least it's supposed to be; by the way, is there a function that checks for that, similar to is_lexsorted?). So, the idea is to propagate unique values by (FactorDate, FundSecNo) from df2 into each (FactorDate, SourceFundSecNo) in df1. In other words, many-to-one. This is a pretty standard idea.

I can work around that, sure, but it looks ugly and wastes CPU and memory. The problem is that it worked perfectly in 0.11 while it doesn't work in 0.12. Do you observe the same behavior? If so, why? Was 0.11 behavior wrong? join() is just syntactic sugar for merge(), right? Any toy example I tried to come up with in 0.12 worked as expected.

join default is 'left', I think you just need 'outer' here. Not sure whyy its different in 0.11; I don't think it changed.

you can do

df2.index.is_unique
(which is True here)

```
In [84]: df1.join(df2,on=['FactorDate','SourceFundSecNo'],how='outer')
Out[84]: 
               FactorDate  FundSecNo  SourceFundSecNo  DemeanGroupId  NormalizationGroupId
0     2011-10-18 00:00:00        280            12432        1520161                   152
1883  2011-10-18 00:00:00      12432            12432        1520161                   152
1     2011-10-18 00:00:00        283              283         350171                    35
17933 2011-10-18 00:00:00      65213              283         350171                    35
2     2011-10-18 00:00:00        285              285        1510157                   151
3     2011-10-18 00:00:00        286              286        1510157                   151
4     2011-10-18 00:00:00        287              287         350161                    35
5     2011-10-18 00:00:00        294              294         350175                    35
6     2011-10-18 00:00:00        300              300         350174                    35
```

At the risk of beating the dead horse here, but I do want 'left'! The fact that 'left' returns no joins at all while 'outer' returns all of them just doesn't make sense. 0.11 behavior did make sense. How can we make sense of test2 below given test3?

```
test2 = pd.merge(df1, df2, how='left', left_on=['FactorDate', 'SourceFundSecNo'], right_index=True)
test2.info()
```

> <class 'pandas.core.frame.DataFrame'>
> Int64Index: 71958 entries, 0 to 104014
> Data columns (total 5 columns):
> FactorDate              71958  non-null values
> FundSecNo               71958  non-null values
> SourceFundSecNo         71958  non-null values
> DemeanGroupId           0  non-null values
> NormalizationGroupId    0  non-null values
> dtypes: datetime64[ns](1), float64(2), int64(2)

```
test3 = pd.merge(df1, df2, how='outer', left_on=['FactorDate', 'SourceFundSecNo'], right_index=True)
test3.info()
```

> <class 'pandas.core.frame.DataFrame'>
> Int64Index: 103922 entries, 0 to 104014
> Data columns (total 5 columns):
> FactorDate              103922  non-null values
> FundSecNo               71958  non-null values
> SourceFundSecNo         103922  non-null values
> DemeanGroupId           103922  non-null values
> NormalizationGroupId    103922  non-null values
> dtypes: datetime64[ns](1), float64(3), int64(1)

not sure...maybe andy can chime in @hayd  ?

So I think we can see this from the head of df1 and df2, the left doesn't look right (it has only NaNs):

```
In [11]: pd.merge(df1.head(), df2.head(), how='outer', left_on=['FactorDate', 'SourceFundSecNo'], right_index=True)
Out[11]: 
           FactorDate  FundSecNo  SourceFundSecNo  DemeanGroupId  NormalizationGroupId
0 2011-10-18 00:00:00        280            12432            NaN                   NaN
1 2011-10-18 00:00:00        283              283         350171                    35
2 2011-10-18 00:00:00        285              285        1510157                   151
3 2011-10-18 00:00:00        286              286        1510157                   151
4 2011-10-18 00:00:00        287              287            NaN                   NaN
4 2011-10-19 00:00:00        NaN              283         350171                    35
4 2011-10-19 00:00:00        NaN              285        1510157                   151

[7 rows x 5 columns]
```

```
# inner
In [12]: pd.merge(df1.head(), df2.head(), left_on=['FactorDate', 'SourceFundSecNo'], right_index=True)
Out[12]: 
           FactorDate  FundSecNo  SourceFundSecNo  DemeanGroupId  NormalizationGroupId
1 2011-10-18 00:00:00        283              283         350171                    35
2 2011-10-18 00:00:00        285              285        1510157                   151
3 2011-10-18 00:00:00        286              286        1510157                   151 

[3 rows x 5 columns]
```

```
In [13]: pd.merge(df1.head(), df2.head(), how='left', left_on=['FactorDate', 'SourceFundSecNo'], right_index=True)
Out[13]: 
           FactorDate  FundSecNo  SourceFundSecNo  DemeanGroupId  NormalizationGroupId
0 2011-10-18 00:00:00        280            12432            NaN                   NaN
1 2011-10-18 00:00:00        283              283            NaN                   NaN
2 2011-10-18 00:00:00        285              285            NaN                   NaN
3 2011-10-18 00:00:00        286              286            NaN                   NaN
4 2011-10-18 00:00:00        287              287            NaN                   NaN

[5 rows x 5 columns]
```

Clearly these shouldn't all be NaNs...

Commit message: Specify dtype

Patch to review:
diff --git a/pandas/tests/indexing/multiindex/test_loc.py b/pandas/tests/indexing/multiindex/test_loc.py
index b6b9f7f205394..da7d89a15125b 100644
--- a/pandas/tests/indexing/multiindex/test_loc.py
+++ b/pandas/tests/indexing/multiindex/test_loc.py
@@ -411,3 +411,29 @@ def test_loc_setitem_single_column_slice():
     df.loc[:, "B"] = np.arange(4)
     expected.iloc[:, 2] = np.arange(4)
     tm.assert_frame_equal(df, expected)
+
+
+def test_loc_nan_multiindex():
+    # GH 5286
+    tups = [
+        ("Good Things", "C", np.nan),
+        ("Good Things", "R", np.nan),
+        ("Bad Things", "C", np.nan),
+        ("Bad Things", "T", np.nan),
+        ("Okay Things", "N", "B"),
+        ("Okay Things", "N", "D"),
+        ("Okay Things", "B", np.nan),
+        ("Okay Things", "D", np.nan),
+    ]
+    df = DataFrame(
+        np.ones((8, 4)),
+        columns=Index(["d1", "d2", "d3", "d4"]),
+        index=MultiIndex.from_tuples(tups, names=["u1", "u2", "u3"]),
+    )
+    result = df.loc["Good Things"].loc["C"]
+    expected = DataFrame(
+        np.ones((1, 4)),
+        index=Index([np.nan], dtype="object", name="u3"),
+        columns=Index(["d1", "d2", "d3", "d4"], dtype="object"),
+    )
+    tm.assert_frame_equal(result, expected)
diff --git a/pandas/tests/indexing/test_loc.py b/pandas/tests/indexing/test_loc.py
index 6f20ec649b200..dbb2d01e878f3 100644
--- a/pandas/tests/indexing/test_loc.py
+++ b/pandas/tests/indexing/test_loc.py
@@ -968,3 +968,11 @@ def test_loc_getitem_label_list_integer_labels(
     expected = df.iloc[:, expected_columns]
     result = df.loc[["A", "B", "C"], column_key]
     tm.assert_frame_equal(result, expected, check_column_type=check_column_type)
+
+
+def test_loc_upcast_int():
+    # GH 6485
+    result = DataFrame({"a": range(10)}, dtype="i4")
+    result.loc[10] = 99
+    expected = DataFrame({"a": list(range(10)) + [99]})
+    tm.assert_frame_equal(result, expected)
diff --git a/pandas/tests/resample/test_datetime_index.py b/pandas/tests/resample/test_datetime_index.py
index 5837d526e3978..bcd7081d5b1a5 100644
--- a/pandas/tests/resample/test_datetime_index.py
+++ b/pandas/tests/resample/test_datetime_index.py
@@ -1564,3 +1564,20 @@ def test_get_timestamp_range_edges(first, last, offset, exp_first, exp_last):
     result = _get_timestamp_range_edges(first, last, offset)
     expected = (exp_first, exp_last)
     assert result == expected
+
+
+def test_resample_apply_product():
+    # GH 5586
+    index = date_range(start="2012-01-31", freq="M", periods=12)
+
+    ts = Series(range(12), index=index)
+    df = DataFrame(dict(A=ts, B=ts + 2))
+    result = df.resample("Q").apply(np.product)
+    expected = DataFrame(
+        np.array([[0, 24], [60, 210], [336, 720], [990, 1716]], dtype=np.int64),
+        index=DatetimeIndex(
+            ["2012-03-31", "2012-06-30", "2012-09-30", "2012-12-31"], freq="Q-DEC"
+        ),
+        columns=["A", "B"],
+    )
+    tm.assert_frame_equal(result, expected)
diff --git a/pandas/tests/reshape/merge/test_join.py b/pandas/tests/reshape/merge/test_join.py
index e477b7608ab93..141dd4b5e1fa5 100644
--- a/pandas/tests/reshape/merge/test_join.py
+++ b/pandas/tests/reshape/merge/test_join.py
@@ -770,6 +770,35 @@ def test_join_on_tz_aware_datetimeindex(self):
         expected["vals_2"] = pd.Series([np.nan] * 2 + list("tuv"), dtype=object)
         tm.assert_frame_equal(result, expected)
 
+    def test_join_datetime_string(self):
+        # GH 5647
+        dfa = DataFrame(
+            [
+                ["2012-08-02", "L", 10],
+                ["2012-08-02", "J", 15],
+                ["2013-04-06", "L", 20],
+                ["2013-04-06", "J", 25],
+            ],
+            columns=["x", "y", "a"],
+        )
+        dfa["x"] = pd.to_datetime(dfa["x"])
+        dfb = DataFrame(
+            [["2012-08-02", "J", 1], ["2013-04-06", "L", 2]],
+            columns=["x", "y", "z"],
+            index=[2, 4],
+        )
+        dfb["x"] = pd.to_datetime(dfb["x"])
+        result = dfb.join(dfa.set_index(["x", "y"]), on=["x", "y"])
+        expected = DataFrame(
+            [
+                [pd.Timestamp("2012-08-02 00:00:00"), "J", 1, 15],
+                [pd.Timestamp("2013-04-06 00:00:00"), "L", 2, 20],
+            ],
+            index=[2, 4],
+            columns=["x", "y", "z", "a"],
+        )
+        tm.assert_frame_equal(result, expected)
+
 
 def _check_join(left, right, result, join_col, how="left", lsuffix="_x", rsuffix="_y"):
 


Code review comments:
diff_hunk: @@ -968,3 +968,11 @@ def test_loc_getitem_label_list_integer_labels(
     expected = df.iloc[:, expected_columns]
     result = df.loc[["A", "B", "C"], column_key]
     tm.assert_frame_equal(result, expected, check_column_type=check_column_type)
+
+
+def test_loc_upcast_int():
+    # GH 6485
+    result = DataFrame({"a": range(10)}, dtype="i4")
+    result.loc[10] = 99
+    expected = DataFrame({"a": list(range(10)) + [99]})
path: pandas/tests/indexing/test_loc.py
text: @user1:
can you specify the expected dtype here?  im actually not clear on why this is "fixed".  casting to int64 is better than casting to float64 like it did in the OP in #6485, but dont we want the dtype to stay int32?

Also, there is mention in that issue of an empty case that is still broken.  should that issue stay open or new issue for the still-broken case?

@author:
Good point. Ideally we should maintain int32 here. I guess that issue is not totally solved and it leave it open for both cases