BUG: read_msgpack raise an error when passed an non existent path in Python 2
State: closed

 - [ ] closes #15296
 - [x] 11 tests added / passed
 - [x] passes ``git diff upstream/master --name-only -- '*.py' | flake8 --diff``
 - [x] whatsnew entry

This PR adds tests to check that a suitable error is raised when a non existent path is passed to `pd.read_xxxxx()`.

A fix is also included for `read_msgpack` with python 2 which works by checking that the first byte of the passed string is `>= 0x80`. So far as I can tell these are [reserved and unused by pandas](https://github.com/msgpack/msgpack/blob/master/spec.md#types-extension-type) so I think this shouldn't break any existing functionality.

Labels:
name: IO Data
description: IO issues that don't fit into a more specific label

Comments:
# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/16523?src=pr&el=h1) Report
> Merging [#16523](https://codecov.io/gh/pandas-dev/pandas/pull/16523?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/ef487d9e474e8052c0f7c6260de5802a950defad?src=pr&el=desc) will **increase** coverage by `<.01%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/pandas-dev/pandas/pull/16523/graphs/tree.svg?token=eZ4WkYLtcO&src=pr&height=150&width=650)](https://codecov.io/gh/pandas-dev/pandas/pull/16523?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master   #16523      +/-   ##
==========================================
+ Coverage   90.79%    90.8%   +<.01%     
==========================================
  Files         161      161              
  Lines       51063    51064       +1     
==========================================
+ Hits        46365    46367       +2     
+ Misses       4698     4697       -1
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `88.64% <100%> (ø)` | :arrow_up: |
| #single | `40.15% <0%> (-0.01%)` | :arrow_down: |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/16523?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/io/packers.py](https://codecov.io/gh/pandas-dev/pandas/pull/16523?src=pr&el=tree#diff-cGFuZGFzL2lvL3BhY2tlcnMucHk=) | `88.58% <100%> (+0.34%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/16523?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/16523?src=pr&el=footer). Last update [ef487d9...f4b6892](https://codecov.io/gh/pandas-dev/pandas/pull/16523?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/16523?src=pr&el=h1) Report
> Merging [#16523](https://codecov.io/gh/pandas-dev/pandas/pull/16523?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/44893893db479894a156dccb28c56f7087b32e14?src=pr&el=desc) will **decrease** coverage by `0.01%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/pandas-dev/pandas/pull/16523/graphs/tree.svg?width=650&height=150&src=pr&token=eZ4WkYLtcO)](https://codecov.io/gh/pandas-dev/pandas/pull/16523?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master   #16523      +/-   ##
==========================================
- Coverage   91.24%   91.23%   -0.02%     
==========================================
  Files         163      163              
  Lines       50168    50169       +1     
==========================================
- Hits        45777    45770       -7     
- Misses       4391     4399       +8
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `89.04% <100%> (ø)` | :arrow_up: |
| #single | `40.27% <0%> (-0.07%)` | :arrow_down: |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/16523?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/io/packers.py](https://codecov.io/gh/pandas-dev/pandas/pull/16523?src=pr&el=tree#diff-cGFuZGFzL2lvL3BhY2tlcnMucHk=) | `88.65% <100%> (+0.34%)` | :arrow_up: |
| [pandas/io/gbq.py](https://codecov.io/gh/pandas-dev/pandas/pull/16523?src=pr&el=tree#diff-cGFuZGFzL2lvL2dicS5weQ==) | `25% <0%> (-58.34%)` | :arrow_down: |
| [pandas/core/frame.py](https://codecov.io/gh/pandas-dev/pandas/pull/16523?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZnJhbWUucHk=) | `97.75% <0%> (-0.1%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/16523?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/16523?src=pr&el=footer). Last update [4489389...9d0f3b6](https://codecov.io/gh/pandas-dev/pandas/pull/16523?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

@jreback I'm putting this here as it is relevant to both of your comments.

Unfortunately I can't use `os.path.isfile` as the API allows `path_or_buf` to be either a path, or a buffer containing data to be read. This bug can also be triggered using `read_json` as follows:

```python
df = pd.DataFrame({'a': np.random.random(5)})
print('Before = ', pd.read_json('[]'), end='\n\n')
df.to_json('[]')
print('After = ', pd.read_json('[]'))
```
which results in this output:
```
Before =  Empty DataFrame
Columns: []
Index: []

After =            a
0  0.637333
1  0.337618
2  0.331358
3  0.073023
4  0.595739
```

Any examples that trigger this using json are somewhat contrived, however with msgpack almost any path has a valid decoded object associated with it.

This also explains why `to_json` and `to_msgpack` raise `ValueError` as in most cases it's not possible to distinguish between a non-existent path and malformed data.

The only place that this is clearly defined is for Python 3 where you can infer if it should be a path from the object type and all the solutions for the other cases that I can think of result in breaking changes to the `read_json` and `read_msgpack` API.
I am not familiar with the msg code, so a basic question @jreback : is there a reason this cannot use the common machinery to deal with path_or_buf as the other readers?
>  am not familiar with the msg code, so a basic question @jreback : is there a reason this cannot use the common machinery to deal with path_or_buf as the other readers?

we are talking about ``pandas.io.common.get_filepath_or_buffer``

we need a modified version for msgpack/json that checks for file existance, but does not open the file or decode the bytes. These are handled by the unpackers. So this could be generalized a bit.
@TomAugspurger thoughts?
can you move the release note to 0.21.0

I think this was ok, will review again after rebase.
@jreback Branch rebased and release notes moved
can you rebase and move note to 0.22.0
@jreback Done
lgtm. @TomAugspurger if you can have a look.
Thanks for your patience @chrisburr!