Skip to content

Lazy-load heavy dependencies to speed up import huracanpy#188

Draft
stella-bourdin with Copilot wants to merge 3 commits into
mainfrom
copilot/implement-lazy-imports
Draft

Lazy-load heavy dependencies to speed up import huracanpy#188
stella-bourdin with Copilot wants to merge 3 commits into
mainfrom
copilot/implement-lazy-imports

Conversation

Copilot AI commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

import huracanpy was slow (~3–7s) because all submodules were eagerly imported, immediately pulling in geopandas, cartopy, metpy, matplotlib, and seaborn — even when only using huracanpy.load().

Approach

Move heavy imports from module level to inside the functions that need them. No new dependencies added.

_basins.py — new _LazyBasins class

Previously created gpd.GeoDataFrame objects at module level (requiring geopandas + cartopy on import). Now stores raw shapely geometry dicts and defers GeoDataFrame construction until first access:

# Before: module level
B = gpd.GeoDataFrame(index=NH.keys(), geometry=list(NH.values()), crs=Geodetic())
basins = {"WMO-TC": B, ...}

# After: created on demand via _LazyBasins
basins = _LazyBasins(_raw_basins)  # geopandas/cartopy only imported on first basins["WMO-TC"] access

info/_geography.py

  • Removed top-level geopandas, cartopy, metpy imports
  • Changed _natural_earth_feature_cache from an eager dict comprehension over basins.items() to a lazily-populated {}, with basin entries created inside _cache_natural_earth_feature on first request
  • Used lazy @preprocess_and_wrap pattern for metpy-decorated functions (decorator applied inside function body on a nested _impl)

calc/_translation.py

Moved from cartopy.crs import Geodetic, Orthographic inside _latlon_to_xy().

convert/_geopandas.py

Moved geopandas, cartopy, shapely imports inside to_geodataframe().

plot/ — all plot modules

Moved cartopy, matplotlib, seaborn, matplotlib_venn imports inside the functions that use them (tracks, density, fancyline, doughnut, _venn_*, _setup_grid, pressure_wind_relation).

Result

After these changes, geopandas, cartopy, and seaborn are not imported at startup. metpy is still imported via calc (used for unit handling throughout), which also pulls in matplotlib via pint — deferring those would require broader refactoring of core calc functionality.

Original prompt

Problem

import huracanpy is slow because huracanpy/__init__.py eagerly imports all submodules at once:

from . import _accessor, assess, calc, convert, info, plot, tc

This triggers immediate import of heavy dependencies even if the user only needs basic functionality (e.g., huracanpy.load()). The main offenders are:

  • huracanpy/info/_geography.py: imports geopandas, cartopy, and metpy at module level
  • huracanpy/plot/_tracks.py: imports cartopy, matplotlib, and seaborn at module level
  • huracanpy/convert/_geopandas.py: likely imports geopandas at module level

Typical import times for these libraries:

  • geopandas: ~1–3s
  • cartopy: ~0.5–2s
  • metpy: ~0.5–1s
  • matplotlib + seaborn: ~0.5–1s

Goal

Implement lazy imports for the heavy submodules so that their dependencies are only loaded when actually used. The approach should:

  1. Use inline/deferred imports inside functions in the submodules that use heavy dependencies (primarily huracanpy/info/_geography.py, huracanpy/plot/*.py, huracanpy/convert/_geopandas.py), OR use the lazy_loader package at the top-level __init__.py.

  2. The preferred approach is inline imports inside functions (no new dependency needed), since lazy_loader would add a new dependency. Move the heavy top-level imports (geopandas, cartopy, metpy, matplotlib, seaborn) to inside the functions that use them, in these files:

    • huracanpy/info/_geography.py
    • huracanpy/plot/_tracks.py
    • huracanpy/plot/_density.py
    • huracanpy/plot/_fancyline.py
    • huracanpy/plot/_doughnut.py
    • huracanpy/plot/_venn.py
    • huracanpy/plot/_pressure_wind.py
    • huracanpy/convert/_geopandas.py
  3. Make sure all existing tests still pass.

  4. Do not change any public API or function signatures.

  5. Add a brief note in the changelog or a comment in __init__.py explaining the change.

Notes

  • The _accessor.py file also imports from . import calc, info, plot, tc at module level. Since _accessor itself is eagerly imported in __init__.py, the same lazy-import approach should be applied there too, or the accessor import in __init__.py should be deferred.
  • Be careful with @preprocess_and_wrap decorator from metpy in _geography.py — the import of metpy needs to happen before the decorator is applied, so it must be imported at the top of the function or the decorator must be handled differently (e.g., by importing metpy at the top of the module but using importlib lazy loading, or by restructuring the decorated functions).
  • Prioritise the highest-impact changes first: geopandas, cartopy, metpy.

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: I mean, make suggestions for publishing the code associated to this as a python package

Assistant: I'd love to help with suggestions for publishing your code as a Python package! However, I don't have context about which repository or project you're referring to. Could you please share the repository (e.g., owner/repo) or link to the code you have in mind?

User: Here is. description :
This paper presents a proof of concept for a new analogue-based framework for the detection and attribution of hurricane-related hazards. This framework addresses two important limitations of existing analogue-based methodologies: the lack of observed similar events, and the unsuitability of the distance metrics for hurricanes. To do so, we use a track-based metric, and we make use of synthetic tracks catalogues. We show that our method allows for selecting a sufficient number of suitable analogues, and we apply it to nine hurricane cases. Our analysis does not reveal any robust changes in wind hazards, translation speed, seasonality, or frequency over recent decades, consistent with current literature. This framework provides a reliable alternative to traditional analogue-based methods in the case of hurricanes, complementing and potentially enhancing efforts in addressing extreme weather event attribution.

Assistant: Thanks for the description! That's a great research project. However, I still need the GitHub repository link or owner/repo to look at the actual code structure before making specific suggestions.

Could you share the repository? For example: stella-bourdin/my-hurricane-repo

User: there is no repo yet, I'm wondering how to name the repo

Assistant: Based on the description, here are some name suggestions:

Concise & Descriptive

  • pyHATTR – Python Hurricane Attribution via Track-based analogues
  • hurricane-analogues – straightforward and searchable
  • track-analogues – emphasizes the track-based metric

Acronym-based

  • HAAF – Hurricane Analogue Attribution Framework
  • HABITAT – Hurricane Attribution By Iterative Track Analogue Toolkit
  • THAAF – Tra...

This pull request was created from Copilot chat.

Move heavy dependencies (geopandas, cartopy, seaborn) from module-level
imports to inside the functions that use them. This means `import huracanpy`
no longer triggers loading of geopandas, cartopy, or seaborn; these are only
imported on first use.

Files changed:
- huracanpy/_basins.py: add _LazyBasins class; GeoDataFrames created on demand
- huracanpy/info/_geography.py: lazy _natural_earth_feature_cache; defer geopandas/cartopy/metpy
- huracanpy/convert/_geopandas.py: move geopandas/cartopy/shapely imports inside to_geodataframe()
- huracanpy/calc/_translation.py: move cartopy imports inside _latlon_to_xy()
- huracanpy/plot/_tracks.py: move cartopy/matplotlib/seaborn imports inside tracks()
- huracanpy/plot/_density.py: move cartopy/matplotlib imports inside density()
- huracanpy/plot/_fancyline.py: move matplotlib/cartopy imports inside functions
- huracanpy/plot/_doughnut.py: move matplotlib import inside doughnut()
- huracanpy/plot/_venn.py: move matplotlib_venn imports inside helper functions
- huracanpy/plot/_pressure_wind.py: lazy metpy decorator + seaborn import
- huracanpy/__init__.py: add comment explaining lazy-import strategy
Copilot AI changed the title [WIP] Implement lazy imports for heavy submodules in huracanpy Lazy-load heavy dependencies to speed up import huracanpy Jun 5, 2026
Copilot AI requested a review from stella-bourdin June 5, 2026 12:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants