From 13265ddd9ab0b15ce5791fa31d02d7a424edd413 Mon Sep 17 00:00:00 2001 From: Charles Turner Date: Wed, 9 Oct 2024 17:00:51 +1100 Subject: [PATCH 1/2] Added a _display module with a singleton to configure the display options. --- src/intake_dataframe_catalog/_display.py | 63 ++++++++++++++++++++++++ src/intake_dataframe_catalog/core.py | 13 ++--- tests/test_display.py | 11 +++++ 3 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 src/intake_dataframe_catalog/_display.py create mode 100644 tests/test_display.py diff --git a/src/intake_dataframe_catalog/_display.py b/src/intake_dataframe_catalog/_display.py new file mode 100644 index 0000000..95fac5e --- /dev/null +++ b/src/intake_dataframe_catalog/_display.py @@ -0,0 +1,63 @@ +from enum import Enum + +class _DisplayType(Enum): + JUPYTER_NOTEBOOK = 0 + IPYTHON_REPL = 1 + REGULAR_REPL = 2 + + + +class _DisplayOptions: + """ + Singleton class to set display options for Pandas DataFrames. + """ + _instance = None + + def __new__(clf, *args, **kwargs): + if not clf._instance: + clf._instance = super(_DisplayOptions, clf).__new__(clf) + return clf._instance + + def __init__(self): + if hasattr(self, 'initialized'): + return None + self.set_pd_options() + self.initialized = True + + + def __str__(self): + return f"DisplayOptions(display_type={self.display_type})" + + def __repr__(self): + return str(self) + + def set_pd_options(self) -> None: + """ + Set display.max_colwidth to 200 and max_rows to None - but only if we are + in a Jupyter Notebook. Otherwise, leave the defaults. + """ + + if self.display_type == _DisplayType.JUPYTER_NOTEBOOK: + import pandas as pd + pd.set_option('display.max_colwidth', 200) + pd.set_option('display.max_rows', None) + + return None + + @property + def display_type(self) -> _DisplayType: + try: + # Check for Jupyter Notebook + ipy = get_ipython() + if hasattr(ipy, 'kernel'): + return _DisplayType.JUPYTER_NOTEBOOK + elif hasattr(ipy, 'config'): + return _DisplayType.IPYTHON_REPL + except NameError: + return _DisplayType.REGULAR_REPL + + @property + def is_notebook(self) -> bool: + return self.display_type == _DisplayType.JUPYTER_NOTEBOOK + +display_options = _DisplayOptions() \ No newline at end of file diff --git a/src/intake_dataframe_catalog/core.py b/src/intake_dataframe_catalog/core.py index c9a0e32..0875ecf 100644 --- a/src/intake_dataframe_catalog/core.py +++ b/src/intake_dataframe_catalog/core.py @@ -16,9 +16,7 @@ from . import __version__ from ._search import search - -pd.set_option("display.max_colwidth", 200) -pd.set_option("display.max_rows", None) +from ._display import display_options as _display_opts class DfFileCatalogError(Exception): @@ -194,10 +192,13 @@ def _ipython_display_(self): """ Display the dataframe catalog object as a rich object in an IPython session. """ - from IPython.display import HTML, display + if _display_opts.is_notebook: + from IPython.display import HTML, display - contents = self._repr_html_() - display(HTML(contents)) + contents = self._repr_html_() + display(HTML(contents)) + else: + print(self) def keys(self) -> list[str]: """ diff --git a/tests/test_display.py b/tests/test_display.py new file mode 100644 index 0000000..b141a94 --- /dev/null +++ b/tests/test_display.py @@ -0,0 +1,11 @@ +from intake_dataframe_catalog._display import _DisplayOptions, _DisplayType +import pytest + +def test_display_opts_singleton(): + opts1 = _DisplayOptions() + opts2 = _DisplayOptions() + assert opts1 is opts2 + +# Create a test that checks if get_ipython() has a kernel attribute, then the display_type should be JUPYTER_NOTEBOOK +# If get_ipython() has a config attribute, then the display_type should be IPYTHON_REPL +# If get_ipython() raises a NameError, then the display_type should be REGULAR_REPL \ No newline at end of file From 2d2e14a9b912d680ee13f85e6eb6c7308995c7cf Mon Sep 17 00:00:00 2001 From: Charles Turner Date: Wed, 16 Oct 2024 15:11:46 +0800 Subject: [PATCH 2/2] Fixed formatting (pre-commit) --- src/intake_dataframe_catalog/_display.py | 28 +++++++++++++----------- src/intake_dataframe_catalog/core.py | 2 +- tests/test_display.py | 7 +++--- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/intake_dataframe_catalog/_display.py b/src/intake_dataframe_catalog/_display.py index 95fac5e..5ae776d 100644 --- a/src/intake_dataframe_catalog/_display.py +++ b/src/intake_dataframe_catalog/_display.py @@ -1,30 +1,30 @@ from enum import Enum + class _DisplayType(Enum): JUPYTER_NOTEBOOK = 0 IPYTHON_REPL = 1 REGULAR_REPL = 2 - class _DisplayOptions: """ Singleton class to set display options for Pandas DataFrames. """ + _instance = None - def __new__(clf, *args, **kwargs): - if not clf._instance: - clf._instance = super(_DisplayOptions, clf).__new__(clf) - return clf._instance + def __new__(cls, *args, **kwargs): + if not cls._instance: + cls._instance = super().__new__(cls) + return cls._instance def __init__(self): - if hasattr(self, 'initialized'): + if hasattr(self, "initialized"): return None self.set_pd_options() self.initialized = True - def __str__(self): return f"DisplayOptions(display_type={self.display_type})" @@ -39,9 +39,10 @@ def set_pd_options(self) -> None: if self.display_type == _DisplayType.JUPYTER_NOTEBOOK: import pandas as pd - pd.set_option('display.max_colwidth', 200) - pd.set_option('display.max_rows', None) - + + pd.set_option("display.max_colwidth", 200) + pd.set_option("display.max_rows", None) + return None @property @@ -49,9 +50,9 @@ def display_type(self) -> _DisplayType: try: # Check for Jupyter Notebook ipy = get_ipython() - if hasattr(ipy, 'kernel'): + if hasattr(ipy, "kernel"): return _DisplayType.JUPYTER_NOTEBOOK - elif hasattr(ipy, 'config'): + elif hasattr(ipy, "config"): return _DisplayType.IPYTHON_REPL except NameError: return _DisplayType.REGULAR_REPL @@ -60,4 +61,5 @@ def display_type(self) -> _DisplayType: def is_notebook(self) -> bool: return self.display_type == _DisplayType.JUPYTER_NOTEBOOK -display_options = _DisplayOptions() \ No newline at end of file + +display_options = _DisplayOptions() diff --git a/src/intake_dataframe_catalog/core.py b/src/intake_dataframe_catalog/core.py index 0875ecf..e2dab1a 100644 --- a/src/intake_dataframe_catalog/core.py +++ b/src/intake_dataframe_catalog/core.py @@ -15,8 +15,8 @@ from intake.catalog.local import LocalCatalogEntry from . import __version__ -from ._search import search from ._display import display_options as _display_opts +from ._search import search class DfFileCatalogError(Exception): diff --git a/tests/test_display.py b/tests/test_display.py index b141a94..fd89067 100644 --- a/tests/test_display.py +++ b/tests/test_display.py @@ -1,11 +1,12 @@ -from intake_dataframe_catalog._display import _DisplayOptions, _DisplayType -import pytest +from intake_dataframe_catalog._display import _DisplayOptions + def test_display_opts_singleton(): opts1 = _DisplayOptions() opts2 = _DisplayOptions() assert opts1 is opts2 + # Create a test that checks if get_ipython() has a kernel attribute, then the display_type should be JUPYTER_NOTEBOOK # If get_ipython() has a config attribute, then the display_type should be IPYTHON_REPL -# If get_ipython() raises a NameError, then the display_type should be REGULAR_REPL \ No newline at end of file +# If get_ipython() raises a NameError, then the display_type should be REGULAR_REPL