Jupyter (formerly IPython Notebook) is an open-source project that lets you easily combine Markdown text and executable Python source code on one canvas called a notebook. Visual Studio Code supports working with Jupyter Notebooks natively, as well as through Python code files. This topic covers the support offered through Python code files and demonstrates how to:
Python debug configurations in Visual Studio Code The Python extension supports debugging of a number of types of Python applications. For a short walkthrough of basic debugging, see Tutorial - Configure and run the debugger. Also see the Flask tutorial. Connect Visual Studio Code to Git and GitHub to share your code with the world We assume you are familiar with Python development and already have some form of Python installed on your system (Python 2.7, Python 3.6/3.7, Anaconda, or others).
- Work with Jupyter-like code cells
- Run code in the Python Interactive Window
- View, inspect, and filter variables using the Variable explorer and data viewer
- Connect to a remote Jupyter server
- Debug a Jupyter notebook
- Export a Jupyter notebook
To work with Jupyter notebooks, you must activate an Anaconda environment in VS Code, or another Python environment in which you've installed the Jupyter package. To select an environment, use the Python: Select Interpreter command from the Command Palette (⇧⌘P (Windows, Linux Ctrl+Shift+P)).
Once the appropriate environment is activated, you can create and run Jupyter-like code cells, connect to a remote Jupyter server for running code cells, and export Python files as Jupyter notebooks.
Jupyter code cells
You define Jupyter-like code cells within Python code using a # %%
comment:
Note: Make sure to save the code shown above in a file with a .py extension.
When the Python extension detects a code cell, it adds Run Cell and Debug Cell CodeLens adornments. The first cell also includes Run Below and all subsequent cells include Run Above:
Note: By default, Debug Cell just steps into user code. If you want to step into non-user code, you need to uncheck Data Science: Debug Just My Code in the Python extension settings (⌘, (Windows, Linux Ctrl+,)).
Run Cell applies to only the one code cell. Run Below, which appears on the first cell, runs all the code in the file. Run Above applies to all the code cells up to, but not including, the cell with the adornment. You would use Run Above, for example, to initialize the state of the runtime environment before running that specific cell.
Selecting a command starts Jupyter (if necessary, which might take a minute), then runs the appropriate cell(s) in the Python Interactive window:
You can also run code cells using (Ctrl+Enter) or the Python: Run Selection/Line in Python Terminal command (Shift+Enter). After using this command, the Python extension automatically moves the cursor to the next cell. If you're in the last cell in the file, the extension automatically inserts another # %%
delimiter for a new cell, mimicking the behavior of a Jupyter notebook.
You can also click in the margin to the left of line numbers to set breakpoints. Then you can use Debug Cell to start a debugging session for that code cell. The debugger stops execution at breakpoints and allows you to step through code one line at a time and inspect variables (see Debugging for details).
Additional commands and keyboard shortcuts
The following table lists additional commands and keyboard shortcuts supported when working with code cells.
Command | Keyboard shortcut |
---|---|
Python: Go to Next Cell | Ctrl+Alt+] |
Python: Go to Previous Cell | Ctrl+Alt+[ |
Python: Extend Selection by Cell Above | Ctrl+Shift+Alt+[ |
Python: Extend Selection by Cell Below | Ctrl+Shift+Alt+] |
Python: Move Selected Cells Up | Ctrl+; U |
Python: Move Selected Cells Down | Ctrl+; D |
Python: Insert Cell Above | Ctrl+; A |
Python: Insert Cell Below | Ctrl+; B |
Python: Insert Cell Below Position | Ctrl+; S |
Python: Delete Selected Cells | Ctrl+; X |
Python: Change Cell to Code | Ctrl+; C |
Python: Change Cell to Markdown | Ctrl+; M |
Python Interactive window
The Python Interactive window, mentioned in the previous section, can be used as a standalone console with arbitrary code (with or without code cells). To use the window as a console, open it with the Jupyter: Create Interactive Window command from the Command Palette. You can then type in code, using Enter to go to a new line and Shift+Enter to run the code.
To use the window with a file, use the Jupyter: Run Current File in Python Interactive Window command from the Command Palette.
IntelliSense
The Python Interactive window has full IntelliSense – code completions, member lists, quick info for methods, and parameter hints. You can be just as productive typing in the Python Interactive window as you are in the code editor.
Plot Viewer
The Plot Viewer gives you the ability to work more deeply with your plots. In the viewer you can pan, zoom, and navigate plots in the current session. You can also export plots to PDF, SVG, and PNG formats.
Within the Python Interactive window, double-click any plot to open it in the viewer, or select the expand button on the upper left corner of the plot.
Note: The Python Interactive window supports rendering plots created with matplotlib and Altair.
Live Share for Python Interactive
The Python Interactive window also supports Visual Studio Live Share for real-time collaboration. Live Share lets you co-edit and co-debug while sharing audio, servers, terminals, diffs, comments, and more.
This feature requires the Live Share extensions to be installed on both host and guest machines.
Variable explorer and data viewer
Within the Python Interactive window, it's possible to view, inspect, and filter the variables within your current Jupyter session. By expanding the Variables section after running code and cells, you'll see a list of the current variables, which will automatically update as variables are used in code.
For additional information about your variables, you can also double-click on a row or use the Show variable in data viewer button to see a more detailed view of a variable in the Data Viewer. Once open, you can filter the values by searching over the rows.
Note: Variable explorer is enabled by default, but can be turned off in settings (Python > Data Science: Show Jupyter Variable Explorer).
Connect to a remote Jupyter server
You can offload intensive computation in a Jupyter notebook to other computers by connecting to a remote Jupyter server. Once connected, code cells run on the remote server rather than the local computer.
To connect to a remote Jupyter server:
Run the Jupyter: Specify local or remote Jupyter server for connections command from the Command Palette (⇧⌘P (Windows, Linux Ctrl+Shift+P)).
Select how you would like to connect to a Jupyter server.
If working remotely, provide the server's URI (hostname) with the authentication token included with a
?token=
URL parameter when prompted. (If you start the server in the VS Code terminal with an authentication token enabled, the URL with the token typically appears in the terminal output from where you can copy it.) Alternatively, you can specify a username and password after providing the URI.The Python Interactive window indicates where code is run by displaying the URI (which is blurred out in the image below):
Note: For added security, Microsoft recommends configuring your Jupyter server with security precautions such as SSL and token support. This helps ensure that requests sent to the Jupyter server are authenticated and connections to the remoter server are encrypted. For guidance about securing a notebook server, see the Jupyter docs.
Convert Jupyter notebooks to Python code file
When you've activated an environment with Jupyter installed, you can open a Jupyter notebook file (.ipynb
) in VS Code and then convert it to Python code. Once you've converted the file, you can run the code as you would with any other Python file and also use the VS Code debugger. Opening and debugging notebooks in VS Code is a convenient way to find and resolve code bugs, which is difficult to do directly in a Jupyter notebook.
When you open a notebook file, Visual Studio Code will open it in the Notebook Editor automatically. Use the convert icon on the toolbar to convert the Notebook (.ipynb) file to a Python file (.py).
Select the convert icon followed by 'Python Script', wait a few seconds, and then VS Code opens the converted notebook in an untitled file. The notebook's cells are delimited in the Python file with # %%
comments; Markdown cells are converted wholly to comments preceded with # %% [markdown]
, and render as HTML in the interactive window alongside code and output such as graphs:
Note: The first time you run code cells in a Python file, the Python extension starts a Jupyter server. It may take some time for the server to start up and for the Python Interactive window to appear with the results of the code.
Debug a Jupyter notebook
The Visual Studio Code debugger lets you step through your code, set breakpoints, examine state, and analyze problems. Using the debugger is a helpful way to find and correct issues in notebook code.
In VS Code, activate a Python environment in which Jupyter is installed, as described at the beginning of this article.
Import the notebook's
.ipynb
file into VS Code as described in the previous section. (Download the file first if you're using a cloud-based Jupyter environment such as Azure Notebooks.)To start the debugger, use one of the following options:
- For the whole notebook, open the Command Palette (⇧⌘P (Windows, Linux Ctrl+Shift+P)) and run the Jupyter: Debug Current File in Python Interactive Window command.
- For an individual cell, use the Debug Cell adornment that appears above the cell. The debugger specifically starts on the code in that cell. By default, Debug Cell just steps into user code. If you want to step into non-user code, you need to uncheck Data Science: Debug Just My Code in the Python extension settings (⌘, (Windows, Linux Ctrl+,)).
To familiarize yourself with the general debugging features of VS Code, such as inspecting variables, setting breakpoints, and other activities, review VS Code debugging.
As you find issues, stop the debugger, correct your code, save the file, and start the debugger again.
When you're satisfied that all your code is correct. Save the file, then export the notebook as described in the following section. You can then upload the notebook to your normal Jupyter environment.
Export a Jupyter notebook
In addition to opening a Jupyter notebook, you can also use one of the following commands from the Command Palette (⇧⌘P (Windows, Linux Ctrl+Shift+P)) to export content from a Python file in VS Code to a Jupyter notebook (with the .ipynb
extension).
- Jupyter: Export Current Python File as Jupyter Notebook: creates a Jupyter notebook from the contents of the current file, using the
# %%
and# %% [markdown]
delimiters to specify their respective cell types. - Jupyter: Export Current Python File and Output as Jupyter Notebook: creates a Jupyter notebook from the contents of the current file and includes output from code cells.
- Jupyter: Export Interactive Window as Jupyter Notebook: creates a Jupyter notebook from the contents of the Python Interactive window.
After exporting the contents, VS Code displays a prompt through which you can open the notebook in a browser.
-->Modules written in C++ (or C) are commonly used to extend the capabilities of a Python interpreter as well as to enable access to low-level operating system capabilities. There are three primary types of modules:
- Accelerator modules: because Python is an interpreted language, certain pieces of code can be written in C++ for higher performance.
- Wrapper modules: expose existing C/C++ interfaces to Python code or expose a more 'Pythonic' API that's easy to use from Python.
- Low-level system access modules: created to access lower-level features of the CPython runtime, the operating system, or the underlying hardware.
This article walks through building a C++ extension module for CPython that computes a hyperbolic tangent and calls it from Python code. The routine is implemented first in Python to demonstrate the relative performance gain of implementing the same routine in C++.
Python Visual Studio Code Venv
This article also demonstrates two ways to make the C++ available to Python:
- The standard CPython extensions as described in the Python documentation
- PyBind11, which is recommended for C++ 11 because of its simplicity.
A comparison between these and other means is found under alternative approaches at the end of this article.
The completed sample from this walkthrough can be found on python-samples-vs-cpp-extension (GitHub).
Prerequisites
Visual Studio 2017 or later with both the Desktop Development with C++ and Python Development workloads installed with default options.
In the Python Development workload, also select the box on the right for Python native development tools. This option sets up most of the configuration described in this article. (This option also includes the C++ workload automatically.)
Tip
Installing the Data science and analytical applications workload also includes Python and the Python native development tools option by default.
For more information, see Install Python support for Visual Studio, including using other versions of Visual Studio. If you install Python separately, be sure to select Download debugging symbols and Download debug binaries under Advanced Options in the installer. This option ensures that you have the necessary debug libraries available if you choose to do a debug build.
Create the Python application
Create a new Python project in Visual Studio by selecting File > New > Project. Search for 'Python', select the Python Application template, give it a suitable name and location, and select OK.
Working with C++ requires that you use a 32-bit Python interpreter (Python 3.6 or above recommended). In the Solution Explorer window of Visual Studio, expand the project node, then expand the Python Environments node. If you don't see a 32-bit environment as the default (either in bold, or labeled with global default), then follow the instructions on Select a Python environment for a project. If you don't have a 32-bit interpreter installed, see Install Python interpreters.
In the project's .py file, paste the following code that benchmarks the computation of a hyperbolic tangent (implemented without using the math library for easier comparison). Feel free to enter the code manually to experience some of the Python editing features.
Run the program using Debug > Start without Debugging (Ctrl+F5) to see the results. You can adjust the
COUNT
variable to change how long the benchmark takes to run. For the purposes of this walkthrough, set the count so that the benchmark take around two seconds.
Tip
When running benchmarks, always use Debug > Start without Debugging to avoid the overhead incurred when running code within the Visual Studio debugger.
Create the core C++ projects
Follow the instructions in this section to create two identical C++ projects named 'superfastcode' and 'superfastcode2'. Later you'll use different means in each project to expose the C++ code to Python.
Make sure the
PYTHONHOME
environment variable is set to the Python interpreter you want to use. The C++ projects in Visual Studio rely on this variable to locate files such as python.h, which are used when creating a Python extension.Right-click the solution in Solution Explorer and select Add > New Project. A Visual Studio solution can contain both Python and C++ projects together (which is one of the advantages of using Visual Studio for Python).
Search on 'C++', select Empty project, specify the name 'superfastcode' ('superfastcode2' for the second project), and select OK.
Tip
With the Python native development tools installed in Visual Studio, you can start with the Python Extension Module template instead, which has much of what's described below already in place. For this walkthrough, though, starting with an empty project demonstrates building the extension module step by step. Once you understand the process, the template saves you time when writing your own extensions.
Create a C++ file in the new project by right-clicking the Source Files node, then select Add > New Item, select C++ File, name it
module.cpp
, and select OK.Important
A file with the .cpp extension is necessary to turn on the C++ property pages in the steps that follow.
Right-click the C++ project in Solution Explorer, select Properties.
At the top of the Property Pages dialog that appears, set Configuration to All Configurations and Platform to Win32.
Set the specific properties as described in the following table, then select OK.
Tab Property Value General General > Target Name Specify the name of the module as you want to refer to it from Python in from...import
statements. You use this same name in the C++ when defining the module for Python. If you want to use the name of the project as the module name, leave the default value of $(ProjectName).General > Target Extension .pyd Project Defaults > Configuration Type Dynamic Library (.dll) C/C++ > General Additional Include Directories Add the Python include folder as appropriate for your installation, for example, c:Python36include
.C/C++ > Preprocessor Preprocessor Definitions CPython only: add Py_LIMITED_API;
to the beginning of the string (including the semicolon). This definition restricts some of the functions you can call from Python and makes the code more portable between different versions of Python. If you're working with PyBind11, don't add this definition, otherwise you'll see build errors.C/C++ > Code Generation Runtime Library Multi-threaded DLL (/MD) (see Warning below) Linker > General Additional Library Directories Add the Python libs folder containing .lib files as appropriate for your installation, for example, c:Python36libs
. (Be sure to point to the libs folder that contains .lib files, and not the Lib folder that contains .py files.)Tip
If you don't see the C/C++ tab in the project properties, it's because the project doesn't contain any files that it identifies as C/C++ source files. This condition can occur if you create a source file without a .c or .cpp extension. For example, if you accidentally entered
module.coo
instead ofmodule.cpp
in the new item dialog earlier, then Visual Studio creates the file but doesn't set the file type to 'C/C+ Code,' which is what activates the C/C++ properties tab. Such misidentification remains the case even if you rename the file with.cpp
. To set the file type properly, right-click the file in Solution Explorer, select Properties, then set File Type to C/C++ Code.Warning
Always set the C/C++ > Code Generation > Runtime Library option to Multi-threaded DLL (/MD), even for a debug configuration, because this setting is what the non-debug Python binaries are built with. With CPython, if you happen to set the Multi-threaded Debug DLL (/MDd) option, building a Debug configuration produces error C1189: Py_LIMITED_API is incompatible with Py_DEBUG, Py_TRACE_REFS, and Py_REF_DEBUG. Furthermore, if you remove
Py_LIMITED_API
(which is required with CPython, but not PyBind11) to avoid the build error, Python crashes when attempting to import the module. (The crash happens within the DLL's call toPyModule_Create
as described later, with the output message of Fatal Python error: PyThreadState_Get: no current thread.)The /MDd option is used to build the Python debug binaries (such as python_d.exe), but selecting it for an extension DLL still causes the build error with
Py_LIMITED_API
.Right-click the C++ project and select Build to test your configurations (both Debug and Release). The .pyd files are located in the solution folder under Debug and Release, not the C++ project folder itself.
Add the following code to the C++ project's module.cpp file:
Build the C++ project again to confirm that your code is correct.
If you haven't already done so, repeat the steps above to create a second project named 'superfastcode2' with identical contents.
Convert the C++ projects to extensions for Python
To make the C++ DLL into an extension for Python, you first modify the exported methods to interact with Python types. You then add a function that exports the module, along with definitions of the module's methods.
The sections that follow explain how to perform these steps using both the CPython extensions and PyBind11.
CPython extensions
For background on what's shown in this section for Python 3.x, refer to the Python/C API Reference Manual and especially Module Objects on python.org (remember to select your version of Python from the drop-down control on the upper right to view the correct documentation).
If you're working with Python 2.7, refer instead to Extending Python 2.7 with C or C++ and Porting Extension Modules to Python 3 (python.org).
At the top of module.cpp, include Python.h:
Modify the
tanh_impl
method to accept and return Python types (aPyObject*
, that is):Add a structure that defines how the C++
tanh_impl
function is presented to Python:Add a structure that defines the module as you want to refer to it in your Python code, specifically when using the
from...import
statement. (Make this match the value in the project properties under Configuration Properties > General > Target Name.) In the following example, the 'superfastcode' module name means you can usefrom superfastcode import fast_tanh
in Python, becausefast_tanh
is defined withinsuperfastcode_methods
. (Filenames internal to the C++ project, like module.cpp, are inconsequential.)Add a method that Python calls when it loads the module, which must be named
PyInit_<module-name>
, where <module-name> exactly matches the C++ project's General > Target Name property (that is, it matches the filename of the .pyd built by the project).Set the target configuration to Release and build the C++ project again to verify your code. If you encounter errors, see the Troubleshooting section below.
PyBind11
If you completed the steps in the previous section, you certainly noticed that you used lots of boilerplate code to create the necessary module structures for the C++ code. PyBind11 simplifies the process through macros in a C++ header file that accomplish the same result with much less code. For background on what's shown in this section, see PyBind11 basics (github.com).
Install PyBind11 using pip:
pip install pybind11
orpy -m pip install pybind11
.At the top of module.cpp, include pybind11.h:
At the bottom of module.cpp, use the
PYBIND11_MODULE
macro to define the entrypoint to the C++ function:Set the target configuration to Release and build the C++ project to verify your code. If you encounter errors, see the next section on troubleshooting.
Troubleshooting
The C++ module may fail to compile for the following reasons:
Unable to locate Python.h (E1696: cannot open source file 'Python.h' and/or C1083: Cannot open include file: 'Python.h': No such file or directory): verify that the path in C/C++ > General > Additional Include Directories in the project properties points to your Python installation's include folder. See step 6 under Create the core C++ project.
Unable to locate Python libraries: verify that the path in Linker > General > Additional Library Directories in the project properties points to your Python installation's libs folder. See step 6 under Create the core C++ project.
Linker errors related to target architecture: change the C++ target's project architecture to match that of your Python installation. For example, if you're targeting x64 with the C++ project but your Python installation is x86, change the C++ project to target x86.
Test the code and compare the results
Now that you have the DLLs structured as Python extensions, you can refer to them from the Python project, import the modules, and use their methods.
Make the DLL available to Python
There are two ways to make the DLL available to Python.
The first method works if the Python project and the C++ project are in the same solution. Go to Solution Explorer, right-click the References node in your Python project, and then select Add Reference. In the dialog that appears, select the Projects tab, select both the superfastcode and superfastcode2 projects, and then select OK.
The alternate method, described in the following steps, installs the module in the global Python environment, making it available to other Python projects as well. (Doing so typically requires that you refresh the IntelliSense completion database for that environment in Visual Studio 2017 version 15.5 and earlier. Refreshing is also necessary when removing the module from the environment.)
If you're using Visual Studio 2017 or later, run the Visual Studio installer, select Modify, select Individual Components > Compilers, build tools, and runtimes > Visual C++ 2015.3 v140 toolset. This step is necessary because Python (for Windows) is itself built with Visual Studio 2015 (version 14.0) and expects that those tools are available when building an extension through the method described here. (Note that you may need to install a 32-bit version of Python and target the DLL to Win32 and not x64.)
Create a file named setup.py in the C++ project by right-clicking the project and selecting Add > New Item. Then select C++ File (.cpp), name the file
setup.py
, and select OK (naming the file with the .py extension makes Visual Studio recognize it as Python despite using the C++ file template). When the file appears in the editor, paste the following code into it as appropriate to the extension method:CPython extensions (superfastcode project):
See Building C and C++ extensions (python.org) for documentation on this script.
PyBind11 (superfastcode2 project):
The setup.py code instructs Python to build the extension using the Visual Studio 2015 C++ toolset when used from the command line. Open an elevated command prompt, navigate to the folder containing the C++ project (that is, the folder that contains setup.py), and enter the following command:
or:
Call the DLL from Python
After you've made the DLL available to Python as described in the previous section, you can now call the superfastcode.fast_tanh
and superfastcode2.fast_tanh2
functions from Python code and compare their performance to the Python implementation:
Add the following lines in your .py file to call methods exported from the DLLs and display their outputs:
Run the Python program (Debug > Start without Debugging or Ctrl+F5) and observe that the C++ routines run approximately five to twenty times faster than the Python implementation. Typical output appears as follows:
If the Start Without Debugging command is disabled, right-click the Python project in Solution Explorer and select Set as Startup Project.
Try increasing the
COUNT
variable so that the differences are more pronounced. A Debug build of the C++ module also runs slower than a Release build because the Debug build is less optimized and contains various error checks. Feel free to switch between those configurations for comparison.
Note
In the output, you can see that the PyBind11 extension isn't as fast as the CPython extension, though it's still significantly faster than the straight Python implementation. The difference is due to a small amount of per-call overhead that PyBind11 introduces in order to make its C++ interface dramatically simpler. This per-call difference is actually quite negligible: because the test code calls the extension functions 500,000 times, the results you see here greatly amplify that overhead! Typically, a C++ function does much more work than the trivial fast_tanh[2]
methods used here, in which case the overhead is unimportant. However, if you're implementing methods that might be called thousands of times per second, using the CPython approach can result in better performance than PyBind11.
Debug the C++ code
Visual Studio supports debugging Python and C++ code together. This section walks through the process using the superfastcode project; the steps are the same for the superfastcode2 project.
Right-click the Python project in Solution Explorer, select Properties, select the Debug tab, and then select the Debug > Enable native code debugging option.
Tip
When you enable native code debugging, the Python output window may disappear immediately when the program has completed without giving you the usual Press any key to continue pause. To force a pause, add the
-i
option to the Run > Interpreter Arguments field on the Debug tab when you enable native code debugging. This argument puts the Python interpreter into interactive mode after the code finishes, at which point it waits for you to press Ctrl+Z > Enter to exit. (Alternately, if you don't mind modifying your Python code, you can addimport os
andos.system('pause')
statements at the end of your program. This code duplicates the original pause prompt.)Select File > Save to save the property changes.
Set the build configuration to Debug in the Visual Studio toolbar.
Because code generally takes longer to run in the debugger, you may want to change the
COUNT
variable in your .py file to a value that's about five times smaller (for example, change it from500000
to100000
).In your C++ code, set a breakpoint on the first line of the
tanh_impl
method, then start the debugger (F5 or Debug > Start Debugging). The debugger stops when that code is called. If the breakpoint is not hit, check that the configuration is set to Debug and that you've saved the project (which does not happen automatically when starting the debugger).At this point you can step through the C++ code, examine variables, and so on. These features are detailed in Debug C++ and Python together.
Alternative approaches
There are a variety of means to create Python extensions as described in the following table. The first two entries for CPython and PyBind11 are what has been discussed in this article already.
Approach | Vintage | Representative user(s) |
---|---|---|
C/C++ extension modules for CPython | 1991 | Standard Library |
PyBind11 (Recommended for C++) | 2015 | |
Cython (Recommended for C) | 2007 | gevent, kivy |
Boost.Python | 2002 | |
ctypes | 2003 | oscrypto |
SWIG | 1996 | crfsuite |
cffi | 2013 | cryptography, pypy |
cppyy | 2017 |
See also
Python On Visual Studio Code
The completed sample from this walkthrough can be found on python-samples-vs-cpp-extension (GitHub).