Not by itself. The IPython %pip magic runs the pip package manager within the current kernel, so it changes that environment, but it does not write a requirements file or lockfile. A scanner that reads manifests will not see packages that exist only in an install cell. Record them in a pinned file.
What the magic does
The IPython documentation describes %pip as running the pip package manager within the current kernel, with usage %pip install [pkgs], and %conda the same way for conda. It also says magics are specific to and provided by the IPython kernel, so availability depends on the kernel.
The practical result is that the notebook can install what it needs on first run. That is handy for exploration. It also means the notebook's dependency list is a line of code in a cell, and any installed version is whatever was newest at the time.
Why this is a security gap
Three issues come up in reviews.
First, nothing pins the version. Two runs a month apart can use different releases, and one may have an advisory the other does not.
Second, tools that inventory dependencies from manifests, such as requirements files, lockfiles and project files, have nothing to read for those packages. Whether a particular scanner reads notebook cells is a question for its documentation, so ask your vendor rather than assume.
Third, the installed environment disappears when the kernel or container does, so the evidence of what ran goes with it.
Turn install cells into a record
- Collect every install line from the notebook.
- Put the package names in a requirements input file for the project, with exact versions for anything that touches production data.
- Replace the install cell with a note that points to the file, and install from it when you build the environment.
- Commit the file next to the notebook.
- Add a short check cell that prints key package versions, so the executed notebook records what ran.
import importlib.metadata as md
for name in ["pandas", "numpy", "requests"]:
print(name, md.version(name))
Review table
| Practice | Why |
|---|---|
| No unpinned install in shared notebooks | Prevents silent version drift |
| Install in the environment build, not at run time | Gives you a reviewable, repeatable step |
| One manifest per project | Gives scanners and reviewers a file to read |
| Print versions in the run | Leaves evidence in the executed output |
Try it yourself
Click through it at your own pace, or open it full screen. Look at how an inventory is built from declared dependencies.
Where Safeguard fits
Safeguard's dependency scanning and SBOM generation work from the manifests in a repository, so a committed requirements file gives them something to inventory. You can try a free scan.
Quick check
Should I use %pip or !pip in a notebook?
The IPython docs describe %pip as running pip within the current kernel. The page does not compare it with a shell call, so check your kernel documentation if the difference matters.
Is one requirements file per notebook too much?
One per project is usually enough, as long as the notebooks in it share an environment.
Sources
Last reviewed: 19 October 2026.