import unittest
import tempfile
import pathlib
import datetime
import warnings

from IPython.testing.globalipapp import start_ipython, get_ipython

import pandas.util.testing as tm
from pandas.core.frame import DataFrame
from pandas.core.series import Series
from pandas import read_excel

import pytest

ip = get_ipython()
ip.magic('load_ext excelify')

class TestMagicExportImport(unittest.TestCase):

    def setUp(self):
        self.tempexcel = tempfile.NamedTemporaryFile(suffix='.xlsx')

    def test_series(self):
        series = Series()
        excel_name = self.tempexcel.name
        ip.run_line_magic('excel', 'series -f {filepath}'.format(filepath=excel_name))
        loaded_series = read_excel(excel_name, squeeze=True, dtype=series.dtype)
        tm.assert_series_equal(series, loaded_series, check_names=False)

    def test_dataframe(self):
        df = DataFrame()
        excel_name = self.tempexcel.name
        ip.run_line_magic('excel', 'df -f {filepath}'.format(filepath=excel_name))
        loaded_df = read_excel(excel_name, dtype=df.dtypes)
        tm.assert_frame_equal(df, loaded_df, check_names=False)

    def test_sheet_name(self):
        series = Series()
        excel_name = self.tempexcel.name
        sheetname = 'test_sheet_name'
        ip.run_line_magic('excel', 'series -f {filepath} -s {sheetname}'.format(filepath=excel_name, sheetname=sheetname))
        loaded_excel = read_excel(excel_name, sheet_name=None)
        assert 'test_sheet_name' in loaded_excel

    def test_all_pandas_objects(self):
        df1 = DataFrame()
        df2 = DataFrame()
        series1 = Series()
        series2 = Series()
        pandas_objects = [(name, obj) for (name, obj) in locals().items()
                          if isinstance(obj, (DataFrame, Series))]
        excel_name = self.tempexcel.name
        ip.run_line_magic('excel_all', '-f {filepath}'.format(filepath=excel_name))
        for (name, obj) in pandas_objects:
            if isinstance(obj, Series):
                loaded_data = read_excel(excel_name, sheet_name=name, squeeze=True, dtype=obj.dtype)
                tm.assert_series_equal(obj, loaded_data, check_names=False)
            elif isinstance(obj, DataFrame):
                loaded_data = read_excel(excel_name, sheet_name=name, dtype=obj.dtypes)
                tm.assert_frame_equal(obj, loaded_data, check_names=False)

    def test_sheet_timestamp(self):
        series = Series()
        excel_name = self.tempexcel.name
        ip.run_line_magic('excel', 'series -f {filepath}'.format(filepath=excel_name))
        loaded_excel = read_excel(excel_name, sheet_name=None)
        sheet_names = list(loaded_excel.keys())
        for sheet in sheet_names:
            _, date_string = sheet.split('_')
            saved_date = datetime.datetime.strptime(date_string, "%Y%m%d-%H%M%S")
            load_to_read = datetime.datetime.now() - saved_date
            # there is probably a better way to test this
            assert load_to_read.seconds < 10

    def test_all_long_name(self):
        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always")
            locals().update({'a' * 33 : Series()})
            excel_name = self.tempexcel.name
            ip.run_line_magic('excel_all', '-f {filepath}'.format(filepath=excel_name))
            assert len(w) == 1
            assert issubclass(w[-1].category, UserWarning)
            assert "truncated" in str(w[-1].message)

    def test_long_name_provided(self):
        with warnings.catch_warnings(record=True) as w:
            series = Series()
            excel_name = self.tempexcel.name
            longsheet = 'a' * 33
            ip.run_line_magic('excel', 'series -f {filepath} -s {longsheet}'.format(filepath=excel_name, longsheet=longsheet))
            assert len(w) == 1
            assert issubclass(w[-1].category, UserWarning)
            assert "truncated" in str(w[-1].message)

    def test_long_name_default(self):
        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always")
            longsheet = 'a' * 33
            locals().update({longsheet : Series()})
            excel_name = self.tempexcel.name
            ip.run_line_magic('excel', '{longsheet} -f {filepath}'.format(longsheet=longsheet, filepath=excel_name))
            assert len(w) == 1
            assert issubclass(w[-1].category, UserWarning)
            assert "truncated" in str(w[-1].message)

    def tearDown(self):
        self.tempexcel.close()


def test_filename():
    series = Series()
    ip.run_line_magic('excel', 'series')
    excel_name = list(pathlib.Path().glob('series_*.xlsx'))[0]
    assert excel_name.exists()
    excel_name.unlink()

def test_all_filename():
    series = Series()
    df = DataFrame()
    ip.run_line_magic('excel_all', '')
    excel_name = list(pathlib.Path().glob('all_data_*.xlsx'))[0]
    assert excel_name.exists()
    excel_name.unlink()


@pytest.fixture
def no_extension_file():
    file = tempfile.NamedTemporaryFile()
    yield file
    file.close()

def test_filepath_append(no_extension_file):
    series = Series()
    excel_name = no_extension_file.name
    ip.run_line_magic('excel', 'series -f {filepath}'.format(filepath=excel_name))
    exported_filepath = pathlib.PurePath(excel_name + '.xlsx')
    assert exported_filepath.suffix == '.xlsx'
    
def test_all_filepath_append(no_extension_file):
    series = Series()
    df = DataFrame()
    excel_name = no_extension_file.name
    ip.run_line_magic('excel_all', '-f {filepath}'.format(filepath=excel_name))
    exported_filepath = pathlib.Path(excel_name + '.xlsx')
    exported_filepath = pathlib.PurePath(excel_name + '.xlsx')
    assert exported_filepath.suffix == '.xlsx'

def test_no_object():
    with pytest.raises(NameError):
        ip.run_line_magic('excel', 'nonexistantobject')

def test_non_pandas_object():
    integer = 3
    with pytest.raises(TypeError):
        ip.run_line_magic('excel', 'integer')

    string = 'string'
    with pytest.raises(TypeError):
        ip.run_line_magic('excel', 'string')

def test_all_no_objects():
    with pytest.raises(RuntimeError):
        ip.run_line_magic('excel_all', '')

def test_all_too_many_objects():
    # this seems like a bad idea...
    for i in range(102):
        locals().update({'series' + str(i) : Series()})
    with pytest.raises(RuntimeError):
        ip.run_line_magic('excel_all', '')


[(16, 'IPython.testing.globalipapp.get_ipython', 'get_ipython', ([], {}), False, 'from IPython.testing.globalipapp import start_ipython, get_ipython\n'), (112, 'pandas.core.series.Series', 'Series', ([], {}), False, 'from pandas.core.series import Series\n'), (119, 'pandas.core.series.Series', 'Series', ([], {}), False, 'from pandas.core.series import Series\n'), (120, 'pandas.core.frame.DataFrame', 'DataFrame', ([], {}), False, 'from pandas.core.frame import DataFrame\n'), (129, 'tempfile.NamedTemporaryFile', 'tempfile.NamedTemporaryFile', ([], {}), False, 'import tempfile\n'), (134, 'pandas.core.series.Series', 'Series', ([], {}), False, 'from pandas.core.series import Series\n'), (137, 'pathlib.PurePath', 'pathlib.PurePath', (["(excel_name + '.xlsx')"], {}), False, 'import pathlib\n'), (141, 'pandas.core.series.Series', 'Series', ([], {}), False, 'from pandas.core.series import Series\n'), (142, 'pandas.core.frame.DataFrame', 'DataFrame', ([], {}), False, 'from pandas.core.frame import DataFrame\n'), (145, 'pathlib.Path', 'pathlib.Path', (["(excel_name + '.xlsx')"], {}), False, 'import pathlib\n'), (146, 'pathlib.PurePath', 'pathlib.PurePath', (["(excel_name + '.xlsx')"], {}), False, 'import pathlib\n'), (22, 'tempfile.NamedTemporaryFile', 'tempfile.NamedTemporaryFile', ([], {'suffix': '""".xlsx"""'}), False, 'import tempfile\n'), (25, 'pandas.core.series.Series', 'Series', ([], {}), False, 'from pandas.core.series import Series\n'), (28, 'pandas.read_excel', 'read_excel', (['excel_name'], {'squeeze': '(True)', 'dtype': 'series.dtype'}), False, 'from pandas import read_excel\n'), (29, 'pandas.util.testing.assert_series_equal', 'tm.assert_series_equal', (['series', 'loaded_series'], {'check_names': '(False)'}), True, 'import pandas.util.testing as tm\n'), (32, 'pandas.core.frame.DataFrame', 'DataFrame', ([], {}), False, 'from pandas.core.frame import DataFrame\n'), (35, 'pandas.read_excel', 'read_excel', (['excel_name'], {'dtype': 'df.dtypes'}), False, 'from pandas import read_excel\n'), (36, 'pandas.util.testing.assert_frame_equal', 'tm.assert_frame_equal', (['df', 'loaded_df'], {'check_names': '(False)'}), True, 'import pandas.util.testing as tm\n'), (39, 'pandas.core.series.Series', 'Series', ([], {}), False, 'from pandas.core.series import Series\n'), (43, 'pandas.read_excel', 'read_excel', (['excel_name'], {'sheet_name': 'None'}), False, 'from pandas import read_excel\n'), (47, 'pandas.core.frame.DataFrame', 'DataFrame', ([], {}), False, 'from pandas.core.frame import DataFrame\n'), (48, 'pandas.core.frame.DataFrame', 'DataFrame', ([], {}), False, 'from pandas.core.frame import DataFrame\n'), (49, 'pandas.core.series.Series', 'Series', ([], {}), False, 'from pandas.core.series import Series\n'), (50, 'pandas.core.series.Series', 'Series', ([], {}), False, 'from pandas.core.series import Series\n'), (64, 'pandas.core.series.Series', 'Series', ([], {}), False, 'from pandas.core.series import Series\n'), (67, 'pandas.read_excel', 'read_excel', (['excel_name'], {'sheet_name': 'None'}), False, 'from pandas import read_excel\n'), (150, 'pytest.raises', 'pytest.raises', (['NameError'], {}), False, 'import pytest\n'), (155, 'pytest.raises', 'pytest.raises', (['TypeError'], {}), False, 'import pytest\n'), (159, 'pytest.raises', 'pytest.raises', (['TypeError'], {}), False, 'import pytest\n'), (163, 'pytest.raises', 'pytest.raises', (['RuntimeError'], {}), False, 'import pytest\n'), (170, 'pytest.raises', 'pytest.raises', (['RuntimeError'], {}), False, 'import pytest\n'), (71, 'datetime.datetime.strptime', 'datetime.datetime.strptime', (['date_string', '"""%Y%m%d-%H%M%S"""'], {}), False, 'import datetime\n'), (77, 'warnings.catch_warnings', 'warnings.catch_warnings', ([], {'record': '(True)'}), False, 'import warnings\n'), (78, 'warnings.simplefilter', 'warnings.simplefilter', (['"""always"""'], {}), False, 'import warnings\n'), (87, 'warnings.catch_warnings', 'warnings.catch_warnings', ([], {'record': '(True)'}), False, 'import warnings\n'), (88, 'pandas.core.series.Series', 'Series', ([], {}), False, 'from pandas.core.series import Series\n'), (97, 'warnings.catch_warnings', 'warnings.catch_warnings', ([], {'record': '(True)'}), False, 'import warnings\n'), (98, 'warnings.simplefilter', 'warnings.simplefilter', (['"""always"""'], {}), False, 'import warnings\n'), (57, 'pandas.read_excel', 'read_excel', (['excel_name'], {'sheet_name': 'name', 'squeeze': '(True)', 'dtype': 'obj.dtype'}), False, 'from pandas import read_excel\n'), (58, 'pandas.util.testing.assert_series_equal', 'tm.assert_series_equal', (['obj', 'loaded_data'], {'check_names': '(False)'}), True, 'import pandas.util.testing as tm\n'), (72, 'datetime.datetime.now', 'datetime.datetime.now', ([], {}), False, 'import datetime\n'), (169, 'pandas.core.series.Series', 'Series', ([], {}), False, 'from pandas.core.series import Series\n'), (60, 'pandas.read_excel', 'read_excel', (['excel_name'], {'sheet_name': 'name', 'dtype': 'obj.dtypes'}), False, 'from pandas import read_excel\n'), (61, 'pandas.util.testing.assert_frame_equal', 'tm.assert_frame_equal', (['obj', 'loaded_data'], {'check_names': '(False)'}), True, 'import pandas.util.testing as tm\n'), (79, 'pandas.core.series.Series', 'Series', ([], {}), False, 'from pandas.core.series import Series\n'), (100, 'pandas.core.series.Series', 'Series', ([], {}), False, 'from pandas.core.series import Series\n'), (114, 'pathlib.Path', 'pathlib.Path', ([], {}), False, 'import pathlib\n'), (122, 'pathlib.Path', 'pathlib.Path', ([], {}), False, 'import pathlib\n')]