From cc816e9a61047987358dffe7e154d19c2704ce5f Mon Sep 17 00:00:00 2001 From: Marc Wouts Date: Wed, 22 Jun 2022 13:58:34 +0200 Subject: [PATCH] Offline mode (#77) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Implement the offline mode * Import jquery from code.jquery.com and dt from cdn.datatables.net * Update documentation and move the changelog there Co-authored-by: François Wouts --- .github/workflows/continuous-integration.yml | 4 +- .gitignore | 3 + .pre-commit-config.yaml | 4 +- CHANGELOG.md | 147 ------------------ README.md | 17 +- docs/_toc.yml | 1 + docs/changelog.md | 143 +++++++++++++++++ docs/developing.md | 8 +- docs/quick_start.md | 9 +- docs/supported_editors.md | 3 + docs/troubleshooting.md | 10 +- environment.yml | 2 +- itables/datatables_template.html | 46 ------ itables/html/datatables_template.html | 30 ++++ .../html/datatables_template_connected.html | 31 ++++ itables/html/itables_render.html | 14 ++ itables/javascript.py | 91 +++++++++-- itables/require_config.js | 7 - itables/version.py | 2 +- setup.py | 24 ++- tests/test_changelog.py | 37 +++++ tests/test_connected_notebook_is_small.py | 31 ++++ 22 files changed, 435 insertions(+), 229 deletions(-) delete mode 100644 CHANGELOG.md create mode 100644 docs/changelog.md delete mode 100644 itables/datatables_template.html create mode 100644 itables/html/datatables_template.html create mode 100644 itables/html/datatables_template_connected.html create mode 100644 itables/html/itables_render.html delete mode 100644 itables/require_config.js create mode 100644 tests/test_changelog.py create mode 100644 tests/test_connected_notebook_is_small.py diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index c1c23b2d..5c593289 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -57,8 +57,10 @@ jobs: flake8 itables tests # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide flake8 . --count --exit-zero --max-complexity=10 --statistics + - name: Install a development version of 'itables' + run: pip install -e . - name: Install a Jupyter Kernel - run: python -m ipykernel install --name itables-dev --user + run: python -m ipykernel install --name itables --user - name: Test with pytest run: pytest --cov=./ --cov-report=xml - name: Upload coverage diff --git a/.gitignore b/.gitignore index 31c881a3..4c655a5c 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,6 @@ dist # Jupyter Book _build + +# External dependencies +itables/external diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fcfb8b1e..36dbc886 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,7 +10,7 @@ exclude: > repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.1.0 + rev: v4.3.0 hooks: - id: check-json - id: check-yaml @@ -34,7 +34,7 @@ repos: - id: black - repo: https://github.com/asottile/pyupgrade - rev: v2.31.1 + rev: v2.34.0 hooks: - id: pyupgrade args: ["--py36-plus"] diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 4fc490e5..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,147 +0,0 @@ -0.4.7 (2022-04-13) -================== - -Added ------ -- Additional `tags` like e.g. captions are supported (#10). - -0.4.6 (2022-03-29) -================== - -Changed -------- -- We have removed the default column width at 70 pixels (#61, #62, #66) -- We now use `pyupgrade` in our pre-commit hooks - -Fixed -------- -- We have improved the rendering of multiindex columns (#63) - - -0.4.5 (2022-01-25) -================== - -Changed -------- -- The `itables` documentation now uses Jupyter Book (#56) -- We have added a new `style` option in `itables.options` and in `show`, with a default value equal to `max-width:100%`. - - -0.4.4 (2022-01-10) -================== - -Fixed -------- -- Add 'require_config.js' to the pip package (#48) - - -0.4.3 (2022-01-08) -================== - -Changed -------- -- When a JS function is created on the Python side, we export it as-is (without quotes) in the HTML file and don't use JS eval anymore. - - -0.4.2 (2022-01-07) -================== - -Fixed ------ -- Fix the HTML output when `eval_functions=True` -- Display "Loading..." under the table header until the table is displayed with datatables.net -- `init_notebook_mode(all_interactive=False)` restores the original Pandas HTML representation. - -0.4.1 (2022-01-06) -================== - -Fixed -------- -- Long column names don't overlap anymore (#28) - - -0.4.0 (2022-01-06) -================== - -Fixed -------- -- Now `itables` also works in Jupyter Lab, Colab, VS Code and PyCharm (#3, #4, #26, #40), as we load the `datatables.net` library with an ES import when `require.js` is not available. Many thanks to [François Wouts](https://github.com/fwouts) for his precious help! - -Changed -------- -- The `show` function (and `itables.options`) has a new argument `eval_functions`. When set to `True`, the nested strings passed to `datatables.net` that start with `function` are converted to Javascript functions. -- The HTML code for the datatables.net representation of the table is generated with an HTML template. -- We use f-strings and thus require Python >= 3.6 - - -0.3.1 (2021-12-24) -================== - -Fixed ------ -- We fixed an issue (`jquery` not found) with the HTML export when using `nbconvert>=6.0` (#21) -- We documented how to change the default ordering of rows - with the `order` option (#30) -- We documented how to load `require` in Jupyter Lab (#3) - -Changed -------- -- The main branch for the project is `main` rather than `master` -- Updated `datatables` to 1.11.3 and `jquery` to 3.5.1 - - -0.3.0 (2020-12-14) -================== - -Fixed ------ -- `itables` now has an explicit `init_notebook_mode` function, which inserts the datatables.net library in the notebook. Use `init_notebook_mode(all_interactive=True)` to display all the pandas object as interactive tables. This fixes (#6) and (#17). - -Changed -------- -- `itables` uses GitHub Actions for the CI. - -Added ------ -- `itables` is tested with Python 3.9 as well. - - -0.2.2 (2020-10-01) -================== - -Fixed ------ -- Pandas' `display.max_columns` can be `None`, by Arthur Deygin (#14) - - -0.2.1 (2019-11-21) -================== - -Added ------ -- Animated screenshot in README - -Fixed ------ -- Add IPython to setup.py install_requires, by Jon Shao (#9) - - -0.2.0 (2019-11-20) -================== - -Added ------ -- Large tables are downsampled (#2) - -Changed -------- -- Javascript code moved to Javascript files - -Fixed ------ -- Tables with many columns are now well rendered (#5) - - -0.1.0 (2019-04-23) -================== - -Initial release diff --git a/README.md b/README.md index d86b9987..df8b3ccd 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,12 @@ init_notebook_mode(all_interactive=True) ``` or use `itables.show` to show just one Series or DataFrame as an interactive table. -(NB: In Jupyter Notebook, Jupyter NBconvert and Jupyter Book, you need to call `init_notebook_mode()` before using `show`). +Since `itables==1.0.0`, the [jquery](https://jquery.com/) and [datatables.net](https://datatables.net/) libraries and CSS +are injected in the notebook when you execute `init_notebook_mode` with its default argument `connected=False`. +Thanks to this the interactive tables will work even without a connection to the internet. + +If you prefer to load the libraries dynamically (and keep the notebook lighter), use `connected=True` when you +execute `init_notebook_mode`. ## Documentation @@ -47,9 +52,15 @@ You can run our examples notebooks directly on [![Lab](https://img.shields.io/ba If the table just says "Loading...", then maybe - You loaded a notebook that is not trusted (run "Trust Notebook" in View / Activate Command Palette) -- Or you are offline? +- You forgot to run `init_notebook_mode`, or you deleted that cell or its output +- Or you ran `init_notebook_mode(connected=True)` but you are not connected to the internet? + +Please note that if you change the value of the `connected` argument in +the `init_notebook_mode` cell, you will need to re-execute all the cells +that display interactive tables. -At the moment `itables` does not have an [offline mode](https://github.com/mwouts/itables/issues/8). While the table data is embedded in the notebook, the `jquery` and `datatables.net` are loaded from a CDN, see our [require.config](https://github.com/mwouts/itables/blob/main/itables/javascript/load_datatables_connected.js) and our [table template](https://github.com/mwouts/itables/blob/main/itables/datatables_template.html), so an internet connection is required to display the tables. +If the above does not help, please check out the [ChangeLog](docs/changelog.md) +and decide whether you should upgrade `itables`. ## Downsampling diff --git a/docs/_toc.yml b/docs/_toc.yml index 74d4c815..08797813 100644 --- a/docs/_toc.yml +++ b/docs/_toc.yml @@ -8,3 +8,4 @@ chapters: - file: references - file: developing - file: troubleshooting +- file: changelog diff --git a/docs/changelog.md b/docs/changelog.md new file mode 100644 index 00000000..62caf119 --- /dev/null +++ b/docs/changelog.md @@ -0,0 +1,143 @@ +ITables ChangeLog +================= + +1.0.0 (2022-06-22) +------------------ + +**Added** +- ITables works offline! ([#8](https://github.com/mwouts/jupytext/issues/8), [#70](https://github.com/mwouts/jupytext/issues/70)). Marc would like to thank +[Allan Jardine](https://sprymedia.co.uk/), the author of the [datatables](https://datatables.net/) library, +and [François Wouts](https://github.com/fwouts) for their precious help on the subject. + + +**Changed** +- ITables uses the ESM version 1.12.1 of datatables.net + + +0.4.7 (2022-04-13) +------------------ + +**Added** +- Additional `tags` like e.g. captions are supported ([#10](https://github.com/mwouts/jupytext/issues/10)). + + +0.4.6 (2022-03-29) +------------------ + +**Changed** +- We have removed the default column width at 70 pixels ([#61](https://github.com/mwouts/jupytext/issues/61), [#62](https://github.com/mwouts/jupytext/issues/62), [#66](https://github.com/mwouts/jupytext/issues/66)) +- We now use `pyupgrade` in our pre-commit hooks + +**Fixed** +- We have improved the rendering of multiindex columns ([#63](https://github.com/mwouts/jupytext/issues/63)) + + +0.4.5 (2022-01-25) +------------------ + +**Changed** +- The `itables` documentation now uses Jupyter Book ([#56](https://github.com/mwouts/jupytext/issues/56)) +- We have added a new `style` option in `itables.options` and in `show`, with a default value equal to `max-width:100%`. + + +0.4.4 (2022-01-10) +------------------ + +**Fixed** +- Add 'require_config.js' to the pip package ([#48](https://github.com/mwouts/jupytext/issues/48)) + + +0.4.3 (2022-01-08) +------------------ + +**Changed** +- When a JS function is created on the Python side, we export it as-is (without quotes) in the HTML file and don't use JS eval anymore. + + +0.4.2 (2022-01-07) +------------------ + +**Fixed** +- Fix the HTML output when `eval_functions=True` +- Display "Loading..." under the table header until the table is displayed with datatables.net +- `init_notebook_mode(all_interactive=False)` restores the original Pandas HTML representation. + +0.4.1 (2022-01-06) +------------------ + +**Fixed** +- Long column names don't overlap anymore ([#28](https://github.com/mwouts/jupytext/issues/28)) + + +0.4.0 (2022-01-06) +------------------ + +r**Fixed** +- Now `itables` also works in Jupyter Lab, Colab, VS Code and PyCharm ([#3](https://github.com/mwouts/jupytext/issues/3), [#4](https://github.com/mwouts/jupytext/issues/4), [#26](https://github.com/mwouts/jupytext/issues/26), [#40](https://github.com/mwouts/jupytext/issues/40)), as we load the `datatables.net` library with an ES import when `require.js` is not available. Many thanks to [François Wouts](https://github.com/fwouts) for his precious help! + +**Changed** +- The `show` function (and `itables.options`) has a new argument `eval_functions`. When set to `True`, the nested strings passed to `datatables.net` that start with `function` are converted to Javascript functions. +- The HTML code for the datatables.net representation of the table is generated with an HTML template. +- We use f-strings and thus require Python >= 3.6 + + +0.3.1 (2021-12-24) +------------------ + +**Fixed** +- We fixed an issue (`jquery` not found) with the HTML export when using `nbconvert>=6.0` ([#21](https://github.com/mwouts/jupytext/issues/21)) +- We documented how to change the default ordering of rows - with the `order` option ([#30](https://github.com/mwouts/jupytext/issues/30)) +- We documented how to load `require` in Jupyter Lab ([#3](https://github.com/mwouts/jupytext/issues/3)) + +**Changed** +- The main branch for the project is `main` rather than `master` +- Updated `datatables` to 1.11.3 and `jquery` to 3.5.1 + + +0.3.0 (2020-12-14) +------------------ + +**Fixed** +- `itables` now has an explicit `init_notebook_mode` function, which inserts the datatables.net library in the notebook. Use `init_notebook_mode(all_interactive=True)` to display all the pandas object as interactive tables. This fixes ([#6](https://github.com/mwouts/jupytext/issues/6)) and ([#17](https://github.com/mwouts/jupytext/issues/17)). + +**Changed** +- `itables` uses GitHub Actions for the CI. + +**Added** +- `itables` is tested with Python 3.9 as well. + + +0.2.2 (2020-10-01) +------------------ + +**Fixed** +- Pandas' `display.max_columns` can be `None`, by Arthur Deygin ([#14](https://github.com/mwouts/jupytext/issues/14)) + + +0.2.1 (2019-11-21) +------------------ + +**Added** +- Animated screenshot in README + +**Fixed** +- Add IPython to setup.py install_requires, by Jon Shao ([#9](https://github.com/mwouts/jupytext/issues/9)) + + +0.2.0 (2019-11-20) +------------------ + +**Added** +- Large tables are downsampled ([#2](https://github.com/mwouts/jupytext/issues/2)) + +**Changed** +- Javascript code moved to Javascript files + +**Fixed** +- Tables with many columns are now well rendered ([#5](https://github.com/mwouts/jupytext/issues/5)) + + +0.1.0 (2019-04-23) +------------------ + +Initial release diff --git a/docs/developing.md b/docs/developing.md index 334da2a4..3e00e761 100644 --- a/docs/developing.md +++ b/docs/developing.md @@ -13,7 +13,7 @@ mamba env update --file environment.yml Then, activate that environment with ```shell -conda activate itables-dev +conda activate itables ``` Install the pre-commit hooks with @@ -35,7 +35,11 @@ pytest The `itables` documentation uses [Jupyter Book](https://jupyterbook.org/). -To build the documentation locally, use +To build the documentation locally, create a kernel named `itables` with +```shell +python -m ipykernel install --name itables --user +``` +and then build the documentation with ``` jupyter-book build docs ``` diff --git a/docs/quick_start.md b/docs/quick_start.md index d8667983..1a8bbb9d 100644 --- a/docs/quick_start.md +++ b/docs/quick_start.md @@ -59,7 +59,14 @@ x = get_population() show(x) ``` -(NB: In Jupyter Notebook, Jupyter NBconvert and Jupyter Book, you need to call `init_notebook_mode()` before using `show`). +## Offline mode + +Since `itables==1.0.0`, the [jquery](https://jquery.com/) and [datatables.net](https://datatables.net/) libraries and CSS +are injected in the notebook when you execute `init_notebook_mode` with its default argument `connected=False`. +Thanks to this the interactive tables will work even without a connection to the internet. + +If you prefer to load the libraries dynamically (and keep the notebook lighter), use `connected=True` when you +execute `init_notebook_mode`. ## Advanced parameters diff --git a/docs/supported_editors.md b/docs/supported_editors.md index b8b502e3..f6374ed0 100644 --- a/docs/supported_editors.md +++ b/docs/supported_editors.md @@ -38,4 +38,7 @@ In VS Code, `itables` works both for Jupyter Notebooks and Python scripts ## PyCharm +In PyCharm we recommend to call `init_notebook_mode` with the `connected=True` argument, +because otherwise the notebooks do not display the interactive tables when they are reloaded. + ![](images/pycharm.png) diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index b06d8742..97eeb775 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -2,6 +2,12 @@ If the table just says "Loading...", then maybe - You loaded a notebook that is not trusted (run "Trust Notebook" in View / Activate Command Palette) -- Or you are offline? +- You forgot to run `init_notebook_mode`, or you deleted that cell or its output +- Or you ran `init_notebook_mode(connected=True)` but you are not connected to the internet? -At the moment `itables` does not have an [offline mode](https://github.com/mwouts/itables/issues/8). While the table data is embedded in the notebook, the `jquery` and `datatables.net` are loaded from a CDN, see our [require.config](https://github.com/mwouts/itables/blob/main/itables/javascript/load_datatables_connected.js) and our [table template](https://github.com/mwouts/itables/blob/main/itables/datatables_template.html), so an internet connection is required to display the tables. +Please note that if you change the value of the `connected` argument in +the `init_notebook_mode` cell, you will need to re-execute all the cells +that display interactive tables. + +If the above does not help, please check out the [ChangeLog](changelog.md) +and decide whether you should upgrade `itables`. diff --git a/environment.yml b/environment.yml index 320d8b0a..1ba5751d 100644 --- a/environment.yml +++ b/environment.yml @@ -1,4 +1,4 @@ -name: itables-dev +name: itables channels: - defaults - conda-forge diff --git a/itables/datatables_template.html b/itables/datatables_template.html deleted file mode 100644 index 205d7161..00000000 --- a/itables/datatables_template.html +++ /dev/null @@ -1,46 +0,0 @@ -
A
- - - - diff --git a/itables/html/datatables_template.html b/itables/html/datatables_template.html new file mode 100644 index 00000000..f34abf28 --- /dev/null +++ b/itables/html/datatables_template.html @@ -0,0 +1,30 @@ +
A
+ + + diff --git a/itables/html/datatables_template_connected.html b/itables/html/datatables_template_connected.html new file mode 100644 index 00000000..f0671f00 --- /dev/null +++ b/itables/html/datatables_template_connected.html @@ -0,0 +1,31 @@ +
A
+ + + + diff --git a/itables/html/itables_render.html b/itables/html/itables_render.html new file mode 100644 index 00000000..1ef3874f --- /dev/null +++ b/itables/html/itables_render.html @@ -0,0 +1,14 @@ + diff --git a/itables/javascript.py b/itables/javascript.py index 8ea295cd..6da45a79 100644 --- a/itables/javascript.py +++ b/itables/javascript.py @@ -5,11 +5,12 @@ import re import uuid import warnings +from base64 import b64encode import numpy as np import pandas as pd import pandas.io.formats.format as fmt -from IPython.core.display import HTML, Javascript, display +from IPython.display import HTML, Javascript, display import itables.options as opt @@ -20,15 +21,53 @@ logger = logging.getLogger(__name__) _ORIGINAL_DATAFRAME_REPR_HTML = pd.DataFrame._repr_html_ +_CONNECTED = True +try: + import google.colab -def init_notebook_mode(all_interactive=False): - """Load the datatables.net library and the corresponding css, and if desired (all_interactive=True), - activate the datatables representation for all the Pandas DataFrames and Series. + # I can't find out how to suppress the LGTM alert about unused-import + # (Tried with # lgtm[py/unused-import] # noqa: F401) + # So we use the import: + assert google.colab.output - Make sure you don't remove the output of this cell, otherwise the interactive tables won't work when - your notebook is reloaded. + GOOGLE_COLAB = True +except ImportError: + GOOGLE_COLAB = False + + +def init_notebook_mode( + all_interactive=False, connected=GOOGLE_COLAB, warn_if_call_is_superfluous=True +): + """Load the datatables.net library and the corresponding css (if connected=False), + and (if all_interactive=True), activate the datatables representation for all the Pandas DataFrames and Series. + + Warning: make sure you keep the output of this cell when 'connected=False', + otherwise the interactive tables will stop working. """ + global _CONNECTED + if GOOGLE_COLAB and not connected: + warnings.warn( + "The offline mode for itables is not supposed to work in Google Colab. " + "This is because HTML outputs in Google Colab are encapsulated in iframes." + ) + + if ( + all_interactive is False + and pd.DataFrame._repr_html_ == _ORIGINAL_DATAFRAME_REPR_HTML + and connected is True + and _CONNECTED == connected + ): + if warn_if_call_is_superfluous: + warnings.warn( + "Did you know? " + "init_notebook_mode(all_interactive=False, connected=True) does nothing. " + "Feel free to remove this line, or pass warn_if_call_is_superfluous=False." + ) + return + + _CONNECTED = connected + if all_interactive: pd.DataFrame._repr_html_ = _datatables_repr_ pd.Series._repr_html_ = _datatables_repr_ @@ -37,8 +76,29 @@ def init_notebook_mode(all_interactive=False): if hasattr(pd.Series, "_repr_html_"): del pd.Series._repr_html_ - # TODO remove this when require.js is not used any more, see #51 - display(Javascript(read_package_file("require_config.js"))) + if not connected: + display(Javascript(read_package_file("external/jquery.min.js"))) + # We use datatables' ES module version because the non module version + # fails to load as a simple script in the presence of require.js + dt64 = b64encode( + read_package_file("external/jquery.dataTables.mjs").encode("utf-8") + ).decode("ascii") + display( + HTML( + replace_value( + read_package_file("html/itables_render.html"), + "dt_src", + f"data:text/javascript;base64,{dt64}", + ) + ) + ) + display( + HTML( + "" + ) + ) def _formatted_values(df): @@ -105,11 +165,11 @@ def eval_functions_dumps(obj): return json.dumps(obj) -def replace_value(template, pattern, value, count=1): +def replace_value(template, pattern, value): """Set the given pattern to the desired value in the template, after making sure that the pattern is found exactly once.""" assert isinstance(template, str) - assert template.count(pattern) == count + assert template.count(pattern) == 1 return template.replace(pattern, value) @@ -144,7 +204,10 @@ def _datatables_repr_(df=None, tableId=None, **kwargs): kwargs["paging"] = False # Load the HTML template - output = read_package_file("datatables_template.html") + if _CONNECTED: + output = read_package_file("html/datatables_template_connected.html") + else: + output = read_package_file("html/datatables_template.html") tableId = tableId or str(uuid.uuid4()) if isinstance(classes, list): @@ -162,7 +225,7 @@ def _datatables_repr_(df=None, tableId=None, **kwargs): '
A
', table_header, ) - output = replace_value(output, "#table_id", f"#{tableId}", count=2) + output = replace_value(output, "#table_id", f"#{tableId}") # Export the DT args to JSON if eval_functions: @@ -176,9 +239,7 @@ def _datatables_repr_(df=None, tableId=None, **kwargs): "To silence this warning, use 'eval_functions=False'." ) - output = replace_value( - output, "let dt_args = {};", f"let dt_args = {dt_args};", count=2 - ) + output = replace_value(output, "let dt_args = {};", f"let dt_args = {dt_args};") # Export the table data to JSON and include this in the HTML data = _formatted_values(df.reset_index() if showIndex else df) diff --git a/itables/require_config.js b/itables/require_config.js deleted file mode 100644 index 124c8378..00000000 --- a/itables/require_config.js +++ /dev/null @@ -1,7 +0,0 @@ -if (typeof require !== 'undefined') - require.config({ - paths: { - jquery: 'https://code.jquery.com/jquery-3.5.1.min', - datatables: 'https://cdn.datatables.net/1.11.3/js/jquery.dataTables.min', - } - }); diff --git a/itables/version.py b/itables/version.py index 369b7c88..bb0d42a8 100644 --- a/itables/version.py +++ b/itables/version.py @@ -1,3 +1,3 @@ """ITables' version number""" -__version__ = "0.4.7" +__version__ = "1.0.0" diff --git a/setup.py b/setup.py index ed0cf37c..5163e931 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,8 @@ import re from os import path +from pathlib import Path +import requests from setuptools import find_packages, setup this_directory = path.abspath(path.dirname(__file__)) @@ -12,6 +14,22 @@ version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", version_file, re.M) version = version_match.group(1) +external = Path(__file__).parent / "itables" / "external" +external.mkdir(exist_ok=True) +for name, url in [ + ("jquery.min.js", "https://code.jquery.com/jquery-3.6.0.min.js"), + ( + "jquery.dataTables.min.css", + "https://cdn.datatables.net/1.12.1/css/jquery.dataTables.min.css", + ), + ( + "jquery.dataTables.mjs", + "https://cdn.datatables.net/1.12.1/js/jquery.dataTables.mjs", + ), +]: + r = requests.get(url) + (external / name).write_bytes(r.content) + setup( name="itables", version=version, @@ -23,7 +41,11 @@ url="https://github.com/mwouts/itables", packages=find_packages(exclude=["tests"]), package_data={ - "itables": ["require_config.js", "datatables_template.html", "samples/*.csv"] + "itables": [ + "external/*", + "html/*", + "samples/*.csv", + ] }, tests_require=["pytest"], install_requires=["IPython", "pandas"], diff --git a/tests/test_changelog.py b/tests/test_changelog.py new file mode 100644 index 00000000..e6f041bc --- /dev/null +++ b/tests/test_changelog.py @@ -0,0 +1,37 @@ +import re +from pathlib import Path + +import pytest + + +def replace_issue_number_with_links(text): + return re.sub( + r"([^\[])#([0-9]+)", + r"\1[#\2](https://github.com/mwouts/jupytext/issues/\2)", + text, + ) + + +@pytest.mark.parametrize( + "input,output", + [ + ( + "Issue #535", + "Issue [#535](https://github.com/mwouts/jupytext/issues/535)", + ), + ( + "Multiline\ntext (#123)", + "Multiline\ntext ([#123](https://github.com/mwouts/jupytext/issues/123))", + ), + ], +) +def test_replace_issue_numbers_with_links(input, output): + assert replace_issue_number_with_links(input) == output + + +def test_update_changelog(): + changelog_file = Path(__file__).parent.parent / "docs" / "changelog.md" + cur_text = changelog_file.read_text() + new_text = replace_issue_number_with_links(cur_text) + if cur_text != new_text: + changelog_file.write_text(new_text) # pragma: no cover diff --git a/tests/test_connected_notebook_is_small.py b/tests/test_connected_notebook_is_small.py new file mode 100644 index 00000000..cdea50f1 --- /dev/null +++ b/tests/test_connected_notebook_is_small.py @@ -0,0 +1,31 @@ +from jupytext.cli import jupytext + + +def text_notebook(connected): + return f"""# %% +from itables import init_notebook_mode + +init_notebook_mode(all_interactive=True, connected={connected}) + +# %% +import pandas as pd +pd.DataFrame() +""" + + +def test_connected_notebook_is_small(tmp_path): + nb_py = tmp_path / "nb.py" + nb_ipynb = tmp_path / "nb.ipynb" + nb_py.write_text(text_notebook(connected=True)) + jupytext([str(nb_py), "--to", "ipynb", "--set-kernel", "itables", "--execute"]) + assert nb_ipynb.exists() + assert nb_ipynb.stat().st_size < 5_000 + + +def test_offline_notebook_is_not_too_large(tmp_path): + nb_py = tmp_path / "nb.py" + nb_ipynb = tmp_path / "nb.ipynb" + nb_py.write_text(text_notebook(connected=False)) + jupytext([str(nb_py), "--to", "ipynb", "--set-kernel", "itables", "--execute"]) + assert nb_ipynb.exists() + assert 700_000 < nb_ipynb.stat().st_size < 750_000