quantumlib / Cirq

A Python framework for creating, editing, and invoking Noisy Intermediate Scale Quantum (NISQ) circuits.
Apache License 2.0
4.3k stars 1.02k forks source link

Example code for installing Cirq is not portable outside of notebook environments #5345

Open mhucka opened 2 years ago

mhucka commented 2 years ago

Description of the issue

One of the first things in the Cirq documentation is the nice Getting Started section. The section begins with the following block of Python code for installing cirq:

try:
    import cirq
except ImportError:
    print("installing cirq...")
    !pip install --quiet cirq
    import cirq
    print("installed cirq.")

This code (sometimes with slight variations) also appears in other places in the cirq documentation. Although I understand the expectation is that most people will run the code in Google Colab or a Jupyter notebook environment, some people may not do that, and may instead (1) use the copy button for the code block, (2) copy-paste the code into a file on their computer, and (3) attempt to run the code as straight Python. This will lead to a syntax error because of the !pip magic command, which may be confusing to people who are novice Python users.

How to reproduce the issue

Put the code above into a file and attempt to run it in a plain Python environment (not a notebook). Python will report a syntax error.

```     import cirq ^ SyntaxError: invalid non-printable character U+00A0 ```

Proposed solution

It's possible to rewrite the code block to make it compatible with both regular Python and Jupyter/Colab notebooks. After some experimentation, I came up with the following, which I'd like to suggest as an alternative:

try:
    import cirq
except ImportError:
    print("installing cirq...")
    if 'get_ipython' in locals():
        get_ipython().run_line_magic('pip', 'install -q cirq')
    else:
        import subprocess, sys
        subprocess.call([sys.executable, '-m', 'pip', 'install', '-q', 'cirq'])
    import cirq
    print("installed cirq.")

This code replaces the !pip ... magic syntax with 5 lines that are safe to execute in both plain python and notebook environments. The basic idea is the following. Both Colab and Jupyter notebooks define the function get_ipython(), so the approach first tests if the function is defined: if it is, then we're in a notebook environment, and if it's not, then we assume it's a regular Python environment. The equivalent of !pip install ... is run_line_magic(...) on the object returned by get_ipython(). If we're in a plain Python environment, then we invoke pip via a subprocess. (The latter is the officially recommended way of running pip from within a regular Python script. Note that sys.executable in the code above is not Bash but rather the Python interpreter executable.)

The following are the environments where I've tested this:

If this proposed replacement code is agreeable to people, I'd be happy to create a PR to change the example wherever it shows up in the docs. (It looks like in some places, the docs say to install cirq using the --pre flag to pip install, so the code above would have to be adjusted appropriately on a case-by-case basis.)

Possible limitation: having to run pip install in the user's environment may not work if the user's account doesn't have permissions for pip to install software. In that case, however, no alternative would work either. The code above could be modified to catch this error and print an explanatory message to help the user figure out why it failed, but that would complicate the code further. Nevertheless, I hope the Cirq developers will comment about whether that would be a desirable approach.

Historical note: it looks like the current form of the import code may have been introduced in PR #3431. An earlier issue #3182 seems to have a comment about adding a simpler variation of the pip installation command (possibly for an earlier version of cirq?).

dstrain115 commented 2 years ago

Discussion in cirq cync: Installing packages in local python environment automatically may not be advisable, but we should definitely add comments to explain what this code snippet is, and link to instructions so people can pip install if they want to.

mhucka commented 2 years ago

Just noticed that issue #3803 is possibly related to this one, specifically the 2nd bullet, which is to clarify "how we are handling python dependencies (colab deps are assumed, e.g. user has to install them in case of jupyter notebook)".