Find out if my code runs inside a notebook or jupyter lab?

Is there a way to find out if my code is running inside a jupyter notebook or jupyter lab?

More specifically, is it possible to find out if wherever my code runs it is possible to get HTML rendered or not?

I want to implement a function to display an object. The way how the object is displayed should be configurable so I need to invoke a function like myobject.show(options...) instead of just doing display(myobject).

But I want this function to work well both when displaying HTM is possible, like in a notebook or lab, and e.g. within IPython or the qtconsole or just a plain python interpreter, where this is not possible and I would fall back to some kind of pretty printing instead.

Update: I read that as “Is there a way to find out if my code is running inside a jupyter notebook vs. jupyter lab?” Sorry. After you posted a valid solution for a notebook vs. a script, I then posted & linked below what I should have posted here. But I’m leaving my original response here addressing detecting if running in the classic notebook vs. JupyterLab because how to determine that has been raised as a question a few times.

I haven’t found the answer to that yet; however, to encourage one, I’ll point out by listing the examples I found that this question (or very similar variants) has been raised on StackOverflow & on this discourse in the past a few times with no clear answer. We should then update these to maybe point to such an answer:

1 Like

I found something that works well enough for me:

try:
    from IPython import get_ipython
    ip = get_ipython()
    if ip is None:
            # we have IPython installed but not running from IPython
            return False
        else:
            from IPython.core.interactiveshell import InteractiveShell
            format = InteractiveShell.instance().display_formatter.format
            if len(format(_checkhtml, include="text/html")[0]):
                # TODO: need to check for qtconsole here!
                return True
            else:
                return False
    except:
        # We do not even have IPython installed
        return False

I think this incorrectly returns true if we are running in a qtconsole, but qtconsole can NOT show HTML, so we should check for that separately.
I ignored this for now, cause, how is really using qtconsole? :slight_smile:
Otherwise I think it does what I need.
Feedback welcome!

1 Like

Oops, I totally misread your point. You were looking to find out if it was running in a Jupyter notebook vs. a script /other. For that, in the past I had used a variant of what you have posted now from here (Indeed, I make a comment below that one under my ‘Wayne’ Stackoverflow user name). The StackOverflow question that was in response to is How can I check if code is executed in the IPython notebook?. (This question I misread as well while researching is also asking that but in relation to a particular package, tqdm, that gets imported differently depending, or at least did at that time.)

I thought you were trying to answer the question posed at the links I posted earlier for detecting which specific front-end is being used, Jupyter classic vs. JupyterLab. I still would like to know the answer to that question as others asked it and I have collected the occurrences of that in my response earlier in this thread.

UPDATE:
Later I also came across this related StackOverflow post entitled ‘How to detect whether in Jupyter Notebook or Lab’ that I don’t think I had linked from here.

1 Like

I can see how my question is ambiguous, sorry.
What I basically need to know if wherever my script is running, an object can be rendered as HTML or not.
I thought that actually letting the backend give me the HTML rendered representation of a small object should work, but strangely I still get a text/html representation even if I am in the qtconsole which is not able to render it.

1 Like

I believe the recommended way is like this:

try:
    __IPYTHON__
    _in_ipython_session = True
except NameError:
    _in_ipython_session = False

The name __IPYTHON__ is defined in Jupyter or IPython but not a basic Python interpreter.

As to the HTML rendering, look at how Pandas dataframes work. Did you ever notice how when you are using the IPython console and print a Pandas dataframe, it prints a nicely formatted text table, but the identical code in a Jupyter notebok displays a nice HTML table? That’s because the dataframe has a special method _repr_html_ that the Jupyter Notebooks for. Only Jupyter looks for it, and only when the front-end is capable of displaying HTML. So the front end decides if it can display HTML, and if so, calls _repr_html_().

Here is what it looks like in the console:

n [6]: foo = pd.DataFrame()                                                                                                                

In [7]: foo                                                                                                                                 
Out[7]: 
Empty DataFrame
Columns: []
Index: []

In [8]: foo._repr_html_()                                                                                                                   
Out[8]: '<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border="1" class="dataframe">\n  <thead>\n    <tr style="text-align: right;">\n      <th></th>\n    </tr>\n  </thead>\n  <tbody>\n  </tbody>\n</table>\n</div>'

Bottom line, what you need to do is create a method called _repr_html_ and let Jupyter decide for you to display HTML or not. I don’t think your code needs to figure out if it is actually in Jupyter.

1 Like

Quick clarification - it is not that smart. Using the IPython display method to show such an object will always generate the HTML, regardless of what frontend is being used. In general, the kernel does not know what frontends will be displaying the information, so it cannot make such decisions.

Thanks for the clarification. It’s been a while since I looked at that part of the Jupyter code.

Doesn’t the display method return a JSON object with the thing in multiple mime types, and let the client decide which one to use?

That’s essentially correct. And in general, it gets all mimetypes available and sends all of those to the client, then the client decides which to show the user.

So if we have a fixed number of possible clients, and we know which of the clients is capable of showing html, then the way to figure this out could maybe be to check which client we have?

The method I use so far already distinguishes everything I care about but qtconsole where it thinks HTML can be displayed but it cannot.

So I guess the question that remains is: is there a way to find out that I am running qtconsole and not notebook/lab?

I use this:

def is_lab_notebook():
        import re
        import psutil
        
        return any(re.search('jupyter-lab-script', x)
                   for x in psutil.Process().parent().cmdline())

Thanks!
I have seen a number of answers based on checking the process we are running in but I was hoping for a solution based on just the code of the client or kernel we are running in, especially as this should work on all operating systems.

TBH this is now just curiosity, as the main cases are solved anyways and nobody really uses qtconsole I think. It is just interesting that such a simple task is not something already dealt with in the API in the first place.
I think a client should know what it can and cannot do and tell the module that wants to display something which then can provide the data as needed, rather than the module generating all the diferent versions and the client picking what it can deal with.
There was probably a good reason to do it that way but: still weird.

I don’t think that is universal @CatChenal. To get your function to return True, I needed to change jupyter-lab-script to jupyter-notebook inside a notebook running in JupyterLab that was running via MyBinder, which is a fancy JupyterHub.

Here’s what psutil.Process().parent().cmdline() returns inside my current JupyterLab session with the token anonymized:

['/srv/conda/envs/notebook/bin/python',
 '/srv/conda/envs/notebook/bin/jupyter-notebook',
 '--ip=0.0.0.0',
 '--port=8888',
 '--NotebookApp.base_url=/user/fomightez-hhsuite3-binder-gru3g8n3/',
 '--NotebookApp.token=XXXXXXXXXXXXX',
 '--NotebookApp.trust_xheaders=True',
 '--NotebookApp.allow_origin=*']

For completeness, I should add that I got back the same from psutil.Process().parent().cmdline(), whether I was running in classic notebook or JupyterLab notebook interface on that hub.

I’ve just tested the function inside two kinds of binder environments:

Following your link pasted in #2 and finding what you wrote for #2 is not my experience:

Possible the indentation got messed up in what you pasted in discourse?
Or it matters what MyBinder host it runs from? Here it is running on the gke host.

Your original statement is correct, @fomightez: my “solution” is not universal (actually, I had never tested it for binder bundles).
From your last test, I don’t even think this is the right approach since there is nothing in the psutil command output that can identify a ‘native’ JupyterLab string with ‘lab’ in it (as the user-defined base_url may be totally different than yours).

The function I gave, with the wrong indentation, which you caught, is part of another one which I use as a reminder depending on how I open an existing notebook:

def is_lab_notebook():
    import re
    import psutil

    return any(re.search('jupyter-lab-script', x)
               for x in psutil.Process().parent().cmdline())
                   
def check_notebook():
    """
    Util to check a Jupyter notebook environment:
    a markdown cell in a jupyter lab notebook cannot render
    variables: the cell text needs to be created with
    IPython.display.Markdown.
    """

    if is_lab_notebook():
        # need to use Markdown if referencing variables:
        from IPython.display import Markdown
        msg = "This is a <span style=\"color:red;\">JupyterLab notebook </span>:<br>"
        msg += "* Use `IPython.display.Markdown(F'x = {n}')` if referencing variables. "
        msg += "Using {{n}} directly in a Markdown cell will not work."       
        return Markdown('### {}'.format(msg))
    
check_notebook()
1 Like

Bonus question: does anyone know how to find out if we are running under Google Colab?

It turns out that some of the things I use for loading javascript from within the generated HTML do not work with Google Colab, so I need yet another approach to correctly render the object there, and of course it would be nice for the code to figure out when that is necessary automatically!

To answer my own question here for future reference, this seems to work:

def in_colab():
    from IPython.core import getipython
    return 'google.colab' in str(getipython.get_ipython())
1 Like

This is what I’m using in JupySQL to display user feedback, It’ll take care of displaying HTML if running Jupyter and the text version if running IPython.

from IPython.display import display


class Message:
    def __init__(self, message) -> None:
        self._message = message

    def _repr_html_(self):
        return f"<i>{self._message}</i>"

    def __repr__(self) -> str:
        return self._message


def display_message(message):
    display(Message(message))

This will try to determine the runtime environment.

import __main__
import sys
import os

def get_runtime():
    if "google.colab" in sys.modules:
        return "Google Colab"
    elif "ipykernel" in sys.modules:
        if "jupyter" in sys.modules:
            return "JupyterLab"
        else:
            return "Jupyter Notebook"
    elif "win32" in sys.platform:
        if 'CMDEXTVERSION' in os.environ:
            return "Windows Command Prompt"
        else:
            return "Windows PowerShell"          
    elif "darwin" in sys.platform:
        return "MacOS Terminal"
    else:
        if hasattr(__main__,'__file__'):
            return "Linux Terminal"
        else:
            return "Interactive Python Shell"

print(get_runtime())
1 Like