scverse / scverse/spatialdata

Reduce import time

Open
#456 2 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

needs: triage priority: low
Dominant language
Python
Stars
394
Forks
95
Avg merge
4d 3h
Merged PRs (30d)
7

Description

The time to import spatialdata is significant, and can impact some usage scenarios.

(This issue is only for tracking. I don't consider it priority at the current stage of the project. Once the API and code structure stabilize and become cleaner, it might be worth to introduce some techniques to tackle this.)

Example

I am working on a project that takes about 4-5 seconds to import. Partially this is due to other libraries as well, but the biggest chunk is SpatialData.

$ python -m timeit -n 1 -r 1 -c "import spatialdata"
1 loop, best of 1: 2.28 sec per loop

For comparison, numpy takes 81ms.

Use cases

It may not have a big impact for datascience in a Jupyter notebook where you import once and work all day with the same session.

  • CLI tools: my-tool --help should respond immediately. This can be mitigated by removing my CLI tool's __main__ top-level imports and use local imports only in those command functions that actually use the imported modules. This way, only when the user issues a command that does processing with SpatialData, it is imported, whereas other commands respond immediately.

  • Napari plugins: With NPE2, plugins are imported when invoking them in the GUI (for example clicking the menu). When a user invokes a menu item that opens a plugin's widget which uses SpatialData, the user interface remains unresponsive for multiple seconds. For a moment, users think nothing happened.

Workarounds

As a user of SpatialData, we can:

  • Use if TYPE_CHECKING if we just import datastructures for type hinting.
  • Import submodules instead of top-level imports, e.g. from spatialdata.transformations import Affine instead of import spatialdata. The major cause is that many libraries want to expose much of their API at a higher-level module (spatialdata.__init__), which is also recommended since it allows to make deeper module paths private and change them when needed. I believe that when doing a submodule import, Python does not skip the top-level module, so this may not work.
  • Use local imports in functions. I would avoid this where ever possible, because it makes code less organized and readable, and is a source of bugs (some refactoring tools don't catch all local imports and you would only notice at run time, if the bugged function is executed at all).

We can not do anything when:

  • When we implement a class that inherits from a spatialdata class, we must import the real parent class.
  • When we implement a Pydantic model with a field of type SpatialData (validation cannot work with just a forward reference)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the reported baseline with python -m timeit -n 1 -r 1 -c "import spatialdata" and inspect the imports exposed by the top-level spatialdata module. The issue provides no target time, named files, or agreed approach, so completion would require defining a measurable import-time improvement and validating that the documented CLI and plugin use cases remain functional.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
performance
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.