ENH: Implement EA unary ops
State: closed

- [x] closes #23087
- [x] tests added / passed
    - [x] Array
    - [x] Series
    - [x] DataFrame
    - [x] Panel
    - [x] Sparse
    - [x] Extension (Decimal)
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [x] whatsnew entry

Changed to apply unary funcs per blocks. As a result, unexpected dtype changes are also fixed (as below).
```
# Current master
(-pd.DataFrame({'a': [1], 'b': [1.1]})).dtypes
# a    float64
# b    float64
# dtype: object

# After the PR
(-pd.DataFrame({'a': [1], 'b': [1.1]})).dtypes
# a      int64
# b    float64
# dtype: object
```

Labels:
name: Numeric Operations
description: Arithmetic, Comparison, and Logical operations
name: ExtensionArray
description: Extending pandas with custom dtypes or arrays.

Comments:
Hello @sinhrks! Thanks for updating this PR. We checked the lines you've touched for [PEP 8](https://www.python.org/dev/peps/pep-0008) issues, and found:

























* In the file [`pandas/tests/extension/base/__init__.py`](https://github.com/pandas-dev/pandas/blob/536d002ec1975cdcc5efd62baf16a72d2a0dab6f/pandas/tests/extension/base/__init__.py):

> [Line 53:80](https://github.com/pandas-dev/pandas/blob/536d002ec1975cdcc5efd62baf16a72d2a0dab6f/pandas/tests/extension/base/__init__.py#L53): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (83 > 79 characters)

















##### Comment last updated at 2019-06-30 19:12:01 UTC
@sinhrks can you rebase and will see where this PR is.
can you merge master and upate
# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/23313?src=pr&el=h1) Report
> Merging [#23313](https://codecov.io/gh/pandas-dev/pandas/pull/23313?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/d46d2a5ea900c59439dff58942e79ea8b39e918d?src=pr&el=desc) will **decrease** coverage by `0.17%`.
> The diff coverage is `98.7%`.

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

```diff
@@            Coverage Diff             @@
##           master   #23313      +/-   ##
==========================================
- Coverage   92.38%    92.2%   -0.18%     
==========================================
  Files         166      162       -4     
  Lines       52321    51738     -583     
==========================================
- Hits        48337    47706     -631     
- Misses       3984     4032      +48
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `90.6% <98.7%> (-0.21%)` | :arrow_down: |
| #single | `43.05% <57.14%> (-0.02%)` | :arrow_down: |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/23313?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/arrays/base.py](https://codecov.io/gh/pandas-dev/pandas/pull/23313/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvYXJyYXlzL2Jhc2UucHk=) | `97.04% <100%> (-1.22%)` | :arrow_down: |
| [pandas/core/frame.py](https://codecov.io/gh/pandas-dev/pandas/pull/23313/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZnJhbWUucHk=) | `96.91% <100%> (-0.02%)` | :arrow_down: |
| [pandas/core/generic.py](https://codecov.io/gh/pandas-dev/pandas/pull/23313/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZ2VuZXJpYy5weQ==) | `96.57% <100%> (-0.06%)` | :arrow_down: |
| [pandas/core/arrays/integer.py](https://codecov.io/gh/pandas-dev/pandas/pull/23313/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvYXJyYXlzL2ludGVnZXIucHk=) | `95.66% <100%> (-0.66%)` | :arrow_down: |
| [pandas/core/arrays/sparse.py](https://codecov.io/gh/pandas-dev/pandas/pull/23313/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvYXJyYXlzL3NwYXJzZS5weQ==) | `91.84% <100%> (-0.33%)` | :arrow_down: |
| [pandas/core/ops.py](https://codecov.io/gh/pandas-dev/pandas/pull/23313/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvb3BzLnB5) | `94.4% <97.29%> (+0.11%)` | :arrow_up: |
| [pandas/io/s3.py](https://codecov.io/gh/pandas-dev/pandas/pull/23313/diff?src=pr&el=tree#diff-cGFuZGFzL2lvL3MzLnB5) | `0% <0%> (-86.37%)` | :arrow_down: |
| [pandas/io/sas/sasreader.py](https://codecov.io/gh/pandas-dev/pandas/pull/23313/diff?src=pr&el=tree#diff-cGFuZGFzL2lvL3Nhcy9zYXNyZWFkZXIucHk=) | `86.2% <0%> (-9.95%)` | :arrow_down: |
| [pandas/io/parquet.py](https://codecov.io/gh/pandas-dev/pandas/pull/23313/diff?src=pr&el=tree#diff-cGFuZGFzL2lvL3BhcnF1ZXQucHk=) | `76.92% <0%> (-7.7%)` | :arrow_down: |
| ... and [77 more](https://codecov.io/gh/pandas-dev/pandas/pull/23313/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/23313?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/23313?src=pr&el=footer). Last update [d46d2a5...15fef47](https://codecov.io/gh/pandas-dev/pandas/pull/23313?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/23313?src=pr&el=h1) Report
> :exclamation: No coverage uploaded for pull request base (`master@734b6d1`). [Click here to learn what that means](https://docs.codecov.io/docs/error-reference#section-missing-base-commit).
> The diff coverage is `98.73%`.

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

```diff
@@            Coverage Diff            @@
##             master   #23313   +/-   ##
=========================================
  Coverage          ?   91.73%           
=========================================
  Files             ?      178           
  Lines             ?    50810           
  Branches          ?        0           
=========================================
  Hits              ?    46609           
  Misses            ?     4201           
  Partials          ?        0
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `90.32% <98.73%> (?)` | |
| #single | `41.25% <60.75%> (?)` | |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/23313?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/arrays/base.py](https://codecov.io/gh/pandas-dev/pandas/pull/23313/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvYXJyYXlzL2Jhc2UucHk=) | `99.47% <100%> (ø)` | |
| [pandas/core/arrays/timedeltas.py](https://codecov.io/gh/pandas-dev/pandas/pull/23313/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvYXJyYXlzL3RpbWVkZWx0YXMucHk=) | `88.86% <100%> (ø)` | |
| [pandas/core/frame.py](https://codecov.io/gh/pandas-dev/pandas/pull/23313/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZnJhbWUucHk=) | `96.88% <100%> (ø)` | |
| [pandas/core/arrays/datetimes.py](https://codecov.io/gh/pandas-dev/pandas/pull/23313/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvYXJyYXlzL2RhdGV0aW1lcy5weQ==) | `97.8% <100%> (ø)` | |
| [pandas/core/generic.py](https://codecov.io/gh/pandas-dev/pandas/pull/23313/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZ2VuZXJpYy5weQ==) | `93.98% <100%> (ø)` | |
| [pandas/core/arrays/integer.py](https://codecov.io/gh/pandas-dev/pandas/pull/23313/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvYXJyYXlzL2ludGVnZXIucHk=) | `96.4% <100%> (ø)` | |
| [pandas/core/arrays/sparse.py](https://codecov.io/gh/pandas-dev/pandas/pull/23313/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvYXJyYXlzL3NwYXJzZS5weQ==) | `93.48% <100%> (ø)` | |
| [pandas/core/ops.py](https://codecov.io/gh/pandas-dev/pandas/pull/23313/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvb3BzLnB5) | `94.8% <97.14%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/23313?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/23313?src=pr&el=footer). Last update [734b6d1...536d002](https://codecov.io/gh/pandas-dev/pandas/pull/23313?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

Sorry to take a long. Updated tests to meet NumPy changes. 

One remaining error in Azure is caused by network connection which looks unrelated to the change.
@sinhrks also CI is failing
@sinhrks can you update
Seems to be a datetime failure: https://travis-ci.org/pandas-dev/pandas/jobs/482209044#L2539
This is spitting out, but *only* on the comparison on the expected result. I think these tests prob need if its a datetimelike type, coerce to i8, do the op, coerce back.

```
___ TestSeriesUnary.test_datetime_pos_raises[op0-datetime64[ns, US/Eastern]] ___
2019-01-22T03:04:55.6144005Z [gw0] linux -- Python 3.7.2 /home/vsts/miniconda3/envs/pandas-dev/bin/python
2019-01-22T03:04:55.6144263Z 
2019-01-22T03:04:55.6144496Z self = <pandas.tests.series.test_arithmetic.TestSeriesUnary object at 0x7f7c2482af60>
2019-01-22T03:04:55.6145081Z typ = 'datetime64[ns, US/Eastern]', op = <built-in function pos>
2019-01-22T03:04:55.6145309Z 
2019-01-22T03:04:55.6145805Z     @pytest.mark.parametrize('typ', ['datetime64[ns]', 'datetime64[ns, GMT]',
2019-01-22T03:04:55.6146313Z                                      'datetime64[ns, US/Eastern]'])
2019-01-22T03:04:55.6154775Z     @pytest.mark.parametrize('op', [operator.pos])
2019-01-22T03:04:55.6155197Z     def test_datetime_pos_raises(self, typ, op):
2019-01-22T03:04:55.6155359Z         # GH#23087
2019-01-22T03:04:55.6155887Z         ser = Series([pd.Timestamp('2011-01-01'), pd.Timestamp('2011-01-02'),
2019-01-22T03:04:55.6156481Z                       pd.Timestamp('2011-01-03')], index=range(3), dtype=typ)
2019-01-22T03:04:55.6156689Z         # pandas all raises
2019-01-22T03:04:55.6156870Z         with pytest.raises(TypeError):
2019-01-22T03:04:55.6157018Z             op(ser)
2019-01-22T03:04:55.6157179Z     
2019-01-22T03:04:55.6157330Z         # inconsistent with NumPy
2019-01-22T03:04:55.6157488Z >       tm.assert_numpy_array_equal(ser.values, op(ser.values))
2019-01-22T03:04:55.6158181Z E       DeprecationWarning: Applying '+' to a non-numerical array is ill-defined. Returning a copy, but in the future this will error.
2019-01-22T03:04:55.6158377Z 
```
@TomAugspurger if this is blocking can defer as well.
@sinhrks if you can move the whatsnew to 0.25.0
can you merge master and update
@pandas-dev/pandas-core if anyone would like to rebase this, very close to being ready
@sinhrks can you rebase
Nice PR but I think has gone stale so closing for now - ping if you'd like to pick this back up