# How to allow sensitive data to be displayed on screen but not saved to file?

**URL:** <https://discourse.jupyter.org/t/how-to-allow-sensitive-data-to-be-displayed-on-screen-but-not-saved-to-file/11627>\
**Category:** JupyterLab\
**Tags:** jupyterlab, how-to, help-wanted\
**Created:** [November 10, 2021, 8:52pm UTC](https://discourse.jupyter.org/t/how-to-allow-sensitive-data-to-be-displayed-on-screen-but-not-saved-to-file/11627 "2021-11-10T20:52:27Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![hikemtshasta](https://avatars.discourse-cdn.com/v4/letter/h/c5a1d2/32.png) [@hikemtshasta](https://discourse.jupyter.org/u/hikemtshasta)\
**Post date:** [November 10, 2021, 8:52pm UTC](https://discourse.jupyter.org/t/how-to-allow-sensitive-data-to-be-displayed-on-screen-but-not-saved-to-file/11627/1 "2021-11-10T20:52:27Z")

</div>

Is there any way to allow (sensitive) data to be displayed in Jupyter on screen, but not saved to the .ipynb (when checkpoint or save)? If there is no such way at present, what is the best/easier way to implement this function? Pointers are greatly appreciated!

Here is a use case for discussion purpose: say there are sensitive data in some data source (e.g. PAI data like zipcode stored in a database), and there is a special API that a user can call to retrieve the PAI data. After retrieving the PAI data in memory, the user may inspect the data and do some aggregation. We would like the user to be able to see the data, but not to save to the .ipynb notebook.

The current notebook behavior is that the displayed data on screen is also saved in the .ipynb (in the output section of a cell in the ,ipynb json file). Thus PAI data will be stored in file, which is what we want to avoid.

For simplicity, we can assume this not-allowed-to-save-to-file behavior is at a cell level (i.e. can be controlled by some %%magic to be written). I can further assume that this cell can be cell-tagged to identify that this is a special cell.

I have taken a look at %%capture which works at a cell level. It seems to be pretty close, but I couldn’t figure how to use it to allow me to do what I need to do.

I am wondering if there is an extension hook for saving the .ipynb: upon checkpoint/saving, jupyter can call this hook to remove the output section of a cell tagged with certain cell-tag?

Any ideas are appreciated. Thanks in advance!

---

<div class="post-metadata">

**Author:** ![manics](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/manics/32/85_2.png) [@manics](https://discourse.jupyter.org/u/manics)\
**Post date:** [November 10, 2021, 11:22pm UTC](https://discourse.jupyter.org/t/how-to-allow-sensitive-data-to-be-displayed-on-screen-but-not-saved-to-file/11627/2 "2021-11-10T23:22:15Z")

</div>

I found a related idea in:

> [@Exit/abort Save from pre\_save\_hook?](https://discourse.jupyter.org/t/exit-abort-save-from-pre-save-hook/8410/2):
>
> Currently, all errors in pre\_save\_hooks are [caught and logged](https://github.com/jupyter-server/jupyter_server/blob/a6a5d100759587ea0fee45d5b844ef1b8eb13d6b/jupyter_server/services/contents/manager.py#L121), so they cannot cancel the save in progress. [This patch](https://github.com/jupyter-server/jupyter_server/pull/456) will allow you to raise HTTPErrors to cancel saves with a message that will be shown to the user. Until you can require that, though, you need to implement the quota enforcement by overriding ContentsManager.save instead of a hook: from tornado.web import HTTPError from jupyter\_server.services.contents.largefilemanager import LargeFileManager class QuotaFileManager(LargeFileMa…

You could try overriding the ContentsManager which handles saving/loading notebooks:  
[https://jupyter-server.readthedocs.io/en/latest/developers/contents.html#writing-a-custom-contentsmanager](https://jupyter-server.readthedocs.io/en/latest/developers/contents.html#writing-a-custom-contentsmanager)

---

<div class="post-metadata">

**Author:** ![bollwyvl](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/bollwyvl/32/904_2.png) [@bollwyvl](https://discourse.jupyter.org/u/bollwyvl)\
**Post date:** [November 10, 2021, 11:48pm UTC](https://discourse.jupyter.org/t/how-to-allow-sensitive-data-to-be-displayed-on-screen-but-not-saved-to-file/11627/3 "2021-11-10T23:48:20Z")

</div>

Of course all of this goes out the window if the end user can decide what packages/extensions to use!

- The `ContentsManager` on both the backend _and_ [frontend](https://github.com/jupyterlab/jupyterlab/blob/6830a1c7526e1dae40e9187030c587f8de392560/packages/services/src/contents/index.ts#L822) could be patched to clobber the offending data.
- Inside a kernel, one could have, say, a context manager that patched `output/*/metadata`, e.g. `with some_metadata_thing(pai=True):`
  - setting _cell_ metadata is rather harder from the kernel itself

---

<div class="post-metadata">

**Author:** ![hikemtshasta](https://avatars.discourse-cdn.com/v4/letter/h/c5a1d2/32.png) [@hikemtshasta](https://discourse.jupyter.org/u/hikemtshasta)\
**Post date:** [November 11, 2021, 7:24am UTC](https://discourse.jupyter.org/t/how-to-allow-sensitive-data-to-be-displayed-on-screen-but-not-saved-to-file/11627/4 "2021-11-11T07:24:40Z")

</div>

> [@manics](#):
>
> ContentsManager

Thanks for the tips. Since all of the notebook code and output (except the PAI output) needed to be written out faithfully, I probably cannot use quota to deny the saving/checkpointing of the .ipynb, right?

The ContentsManager looks interesting. I am not familiar with how to work with it though. I’ll need to read through the doc in greater depth… One thing is not clear to me is where the updated code would sit? Is it like defining a new class file in a ts file parallel to manager.ts in jupyberlab/packages/services/src/manager.ts? Or could this be done as a lab extension? Thanks very much!

---

<div class="post-metadata">

**Author:** ![hikemtshasta](https://avatars.discourse-cdn.com/v4/letter/h/c5a1d2/32.png) [@hikemtshasta](https://discourse.jupyter.org/u/hikemtshasta)\
**Post date:** [November 11, 2021, 7:44am UTC](https://discourse.jupyter.org/t/how-to-allow-sensitive-data-to-be-displayed-on-screen-but-not-saved-to-file/11627/5 "2021-11-11T07:44:50Z")

</div>

Oh… By that, you mean both the ContentsManager of the jupyterlab (ts code) and the backend Jupyter Server need to be updated to support this function? That would be bad news for me, as I have hard enough time to worry about either one of them…

BTW, your first line of the comment is right on, but in our specific case, we do provision a specific jupyterlab for the user and that this cannot be overridden in our env (but the user can create their own conda env to use in conjunction with this specific jlab). What we have in mind is to create a specific cell template (such that parameter tagging can be done) for user to copy to use; or with some scaffolding code to do something similar.

The ideal packaging for us is not to come up with our own patch of jupyterlab, but simply an extension (or additional code somewhere) we can install on the top of standard juypyterlab from conda forge…

If we can keep the cell tag as a guide/marker, it looks to me to be real easy to write a python prog to simply parse the .ipynb to remove the output section of the particular cells with matching cell tag. This amount to a post-processing step after the generation/saving of .ipynb. To folks like me with very limited working experience with jlab source code, if there is an invocation hook at this level (i.e. based on file level), that would be very attractive…

Thanks very much again for your comments.

---

<div class="post-metadata">

**Author:** ![manics](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.jupyter.org/manics/32/85_2.png) [@manics](https://discourse.jupyter.org/u/manics)\
**Post date:** [November 11, 2021, 9:21am UTC](https://discourse.jupyter.org/t/how-to-allow-sensitive-data-to-be-displayed-on-screen-but-not-saved-to-file/11627/6 "2021-11-11T09:21:31Z")

</div>

> [@hikemtshasta](#):
>
> If we can keep the cell tag as a guide/marker, it looks to me to be real easy to write a python prog to simply parse the .ipynb to remove the output section of the particular cells with matching cell tag. This amount to a post-processing step after the generation/saving of .ipynb. To folks like me with very limited working experience with jlab source code, if there is an invocation hook at this level (i.e. based on file level), that would be very attractive…

I think overriding the backend (jupyter-server) `ContentsManager.save(model, path)` in a server extension (written in Python) would do exactly this, except that it would be automatic instead of needing a separate Python program. In your custom ContentsManager you’d take the `model` object, modify it to remove the sensitive data, then write it to `path`. In theory anyway 😃

---

<div class="post-metadata">

**Author:** ![hikemtshasta](https://avatars.discourse-cdn.com/v4/letter/h/c5a1d2/32.png) [@hikemtshasta](https://discourse.jupyter.org/u/hikemtshasta)\
**Post date:** [November 11, 2021, 8:25pm UTC](https://discourse.jupyter.org/t/how-to-allow-sensitive-data-to-be-displayed-on-screen-but-not-saved-to-file/11627/7 "2021-11-11T20:25:00Z")

</div>

Cool! I am more in the alley of python than js/ts. So this is great pointer and points me to the right place where I can start the experimentation. Thanks again!

---

<div class="post-metadata">

**Author:** ![hikemtshasta](https://avatars.discourse-cdn.com/v4/letter/h/c5a1d2/32.png) [@hikemtshasta](https://discourse.jupyter.org/u/hikemtshasta)\
**Post date:** [December 2, 2021, 12:05am UTC](https://discourse.jupyter.org/t/how-to-allow-sensitive-data-to-be-displayed-on-screen-but-not-saved-to-file/11627/8 "2021-12-02T00:05:55Z")

</div>

Just to elaborate the detail of manics’ solution here: one can override the pre-save and post-save handler in jupyter\_notebook\_config.py: c.FileContentsManager.pre\_save\_hook and c.FileContentsManager.post\_save\_hook. For this issue purpose, the pre-save hook would be the more appropriate hook. (Jupyterlab Doc has details in both hooks). Thanks again to manics!
