Metadata-Version: 2.4
Name: slowimports
Version: 0.1.1
Summary: Find out why your Python program is slow to start, and what to do about it.
Project-URL: Homepage, https://github.com/CAOShurong/slowimports
Project-URL: Issues, https://github.com/CAOShurong/slowimports/issues
Project-URL: Changelog, https://github.com/CAOShurong/slowimports/blob/main/CHANGELOG.md
Author-email: Shurong Cao <170531907+CAOShurong@users.noreply.github.com>
License: MIT License
        
        Copyright (c) 2026 Shurong Cao
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: benchmark,cli,import,importtime,lazy-import,optimization,performance,profiler,profiling,startup,terminal
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Debuggers
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: System :: Benchmark
Classifier: Topic :: Utilities
Requires-Python: >=3.9
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Description-Content-Type: text/markdown

# slowimports

**Find out why your Python program is slow to start — and what to do about it.**

Every Python CLI eventually gets slow to launch, and it is almost never the
code that runs. It is an import at the top of a file that is only needed on one
branch, pulling half a dependency tree in before `--help` can print.

`python -X importtime` will tell you where the milliseconds went, in nine
hundred lines of nested output. slowimports reads that, and then reads *your
source*, and tells you which imports you can actually move:

![advice](https://raw.githubusercontent.com/CAOShurong/slowimports/main/docs/advice.png)

That last part is the point. Knowing `unittest.mock` costs 64 ms is trivia;
knowing it is only referenced inside one function, and that moving it there
recovers those 64 ms, is a change you can make in ten seconds.

## Install

```console
$ pip install slowimports
```

**No dependencies.** A tool that measures import cost has no business adding
any of its own — `subprocess` runs the target, `ast` reads the source, and
that is the whole shopping list. Python 3.9+, Linux, macOS and Windows.

## Use

```console
$ slowimports myscript.py            # a script
$ slowimports -m pytest              # a module
$ slowimports mytool                 # an installed command
$ slowimports -c 'import pandas'     # a single import
```

The default view groups by package, because that is the level you act on —
nobody removes `numpy.linalg`, they remove `numpy`:

```
examples/slow_cli.py
  103 ms of import time across 214 modules  (noticeable)

Where the time goes, by package
  asyncio   ██████████████████████████████████████████████████████   13.1 ms 12.7%
  _ssl      ████████████████████████████▏                            6.83 ms  6.7%
  unittest  ███████████████████████                                  5.59 ms  5.4%
  email     ████████████████████▎                                    4.91 ms  4.8%
  _socket   ███████████████▏                                         3.67 ms  3.6%
  encodings █████████▍                                               2.27 ms  2.2%
  re        █████████                                                2.20 ms  2.1%
  ssl       ████████▊                                                2.15 ms  2.1%
```

![packages](https://raw.githubusercontent.com/CAOShurong/slowimports/main/docs/packages.png)

Add `--advice` for the analysis, `--modules` to rank individual modules,
`--tree` for an icicle chart of the import graph, or `--all` for everything.

## How the advice works

It reads your file with `ast` and reports an import only when **every** use of
the bound name is inside a function body. Anything touched while the module is
being imported is left alone, because moving it would turn a working program
into a `NameError` on some path you did not test.

Disqualifying uses, all of which run at import time:

| | |
|---|---|
| module-level code | assignments, calls, `if` tests, loops |
| class bodies | they execute during import |
| decorators | `@functools.cache` |
| base classes | `class C(enum.Enum)` |
| default arguments | `def f(x=json.dumps({}))` |
| annotations | unless `from __future__ import annotations` makes them strings |
| rebinding | `json = something_else` later in the file |
| `global` declarations | the name may be reassigned |

Star imports are never reported: what `from x import *` binds is not knowable
without importing it, so nothing can be proven about the uses.

The analysis is deliberately one-sided. It will miss safe moves rather than
suggest an unsafe one.

## The saving is not the cumulative time

A module's `cumulative` figure counts everything it imported, and most of that
is shared. Dropping `pandas` does not give you back the `re` and `enum` that
five other things also need.

So the reported saving is what would actually be recovered: the total minus
whatever still gets imported once that module is gone. And the headline figure
for a set of imports is computed for the set, not summed — candidates that
share a dependency each exclude it, so adding the individual numbers
understates, while candidates that contain one another overlap, so it
overstates.

## Before and after

```console
$ slowimports app.py --save before.json
# ... make the changes ...
$ slowimports app.py --compare before.json
```

which reports the difference, plus which packages stopped being imported and
which started.

## Everything else

| | |
|---|---|
| `--json` | the profile as data |
| `-n N` | how many rows |
| `--min-saving MS` | ignore advice worth less than this (default 1 ms) |
| `--ascii` | no block-drawing characters |
| `--light` | colours stepped for a light terminal |
| `--python PATH` | measure a different interpreter |
| `-- ARGS` | everything after `--` goes to the target |

Colour degrades from 24-bit through 256 and 16 to none, and honours
`NO_COLOR`. Output is plain text when redirected, so `slowimports app.py >
report.txt` gives you a clean file.

## About the colours

The icicle chart's eight hues are a documented palette, checked by script for
lightness band, chroma floor, contrast against the background, and separation
under simulated protanopia and deuteranopia. Bars are deliberately a single
colour: a bar's length already encodes its duration, so colouring it by
duration too would spend the identity channel restating what length says.
Past eight packages the tail is drawn in grey rather than given a ninth hue
that would not survive the simulation.

## Contributing

Bug reports and pull requests welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).
The test suite needs nothing installed:

```console
$ python -m unittest discover -s tests
```

If slowimports suggests an import that turns out not to be safe to move, that
is the most valuable bug you can report. Please include the file, or the
smallest version of it that still reproduces.

## License

MIT — see [LICENSE](LICENSE).
