Skip to main content

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

Project description

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

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

$ 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

$ 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

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

$ 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. The test suite needs nothing installed:

$ 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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

slowimports-0.1.0.tar.gz (33.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

slowimports-0.1.0-py3-none-any.whl (29.2 kB view details)

Uploaded Python 3

File details

Details for the file slowimports-0.1.0.tar.gz.

File metadata

  • Download URL: slowimports-0.1.0.tar.gz
  • Upload date:
  • Size: 33.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for slowimports-0.1.0.tar.gz
Algorithm Hash digest
SHA256 a6d1de2d310dc0e15d03f8bcd22cc1bbbbffd2d7bf8a9afb74bfad86438075c4
MD5 add929d228ddbe326536d87a199079cf
BLAKE2b-256 e1e77d4bcd32e9674d431a96d82086a520d51632891cd9c4920d307c3c229502

See more details on using hashes here.

Provenance

The following attestation bundles were made for slowimports-0.1.0.tar.gz:

Publisher: release.yml on TeresaCSR/slowimports

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file slowimports-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: slowimports-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 29.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for slowimports-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4fb861aae999f36cb7a34987a636f635faa5c76b65fe83f696eebd0812d77611
MD5 0eebedc8e0b0f753cb3811d69aa3757c
BLAKE2b-256 eaab6b2e67e4f40a6c13325c872ac5fa1092f39cbc53de0d6a64d9f1314174ce

See more details on using hashes here.

Provenance

The following attestation bundles were made for slowimports-0.1.0-py3-none-any.whl:

Publisher: release.yml on TeresaCSR/slowimports

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page