Refactor dependencies to make more optional#1548
Conversation
Related to #1224; addresses user feedback asking to handle dependencies in a more elegant manner. Many previously-required dependencies are now optional. Also may speed up "import uxarray" slightly, as now-optional dependencies are moved to no longer be at top of files; instead, they are imported the first time any relevant method gets called. See upcoming associated PR for more notes / reasoning / discussion.
(copilot suggestions hallucinated a strange import, this commit fixes that.)
Missed an import of GeoAxes, while refactoring to remove required dependencies. Added pooch dependency, which is necessary for test/io/test_structure.py tests to run, and previously was not included anywhere in dependencies.
because #1541 was merged!
also clarifies: conda installation automatically includes optional dependencies, not just required dependencies.
|
One thing to flag: anyone doing |
(forgot to remove the comment when moving hvplot dependency during cb8c8a3...)
I definitely agree, we should make sure to discuss more before merging. I am curious to know what people think. One thought I had is: something that might help could be to provide hints during those crashes. Something like: def function_that_uses_holoviews(*args, **kwargs):
try:
import holoviews as hv
except ImportError as err:
raise ImportError('holoviews import failed; to install all plotting dependencies, could do: pip install "uxarray[viz]".') from err
# << code from functionAs opposed to the code presently in the PR, which just does Although, this doesn't match xarray's style. In xarray, if you fail to install optional dependencies you will just see an ImportError crash once you try to use them, there's no hint to pip install xarray[viz] or anything like that. Another slight downside is that this option might get a bit unwieldy due to the need to repeat it inside every relevant method. A partial workaround could be to handle these hints all in one place: # --- inside new file: utils.imports.py --- #
def _import_with_hint_if_error(*modules):
"""import modules, but make nice error if crash, providing hint to pip install "uxarray[...]".
E.g., if 'holoviews' in modules, and import holoviews fails, hint to use: pip install "uxarray[viz]".
"""
if 'holoviews' in modules:
try:
import holoviews as hv
except ImportError as err:
raise ImportError('holoviews import failed; to install all plotting dependencies, could do: pip install "uxarray[viz]".') from err
if 'geoviews' in modules:
# similar
# similar for all other optional dependencies.Then functions with optional dependencies can look like: from uxarray.utils.imports import _import_with_hint_if_error
def function_that_uses_holoviews_and_geoviews(*args, **kwargs):
_import_with_hint_if_error('holoviews', 'geoviews')
import holoviews as hv
import geoviews as gvI actually have a slight personal preference to do something like that; I think user experience is improved when common errors include debugging hints. But, I'm happy to go with whatever we decide together. |
Closes #1224
Waiting for #1541 before asking to merge (in order to move hvplot from required to "viz").Overview
Addresses user feedback asking to handle dependencies in a more elegant manner. Many previously-required dependencies are now optional. Also may speed up "import uxarray" slightly, as now-optional dependencies are moved to no longer be at top-level / top of files; instead, they are imported the first time any relevant method gets called. Imports of some required dependencies were similarly moved, to possibly improve "import uxarray" timing.
Notes about all dependencies which were previously listed as required in pyproject.toml:
antimeridian: important for geometry → keep as required. [EFF] Efficiency note: antimeridian was already never being imported at top-level.cartopy: used only in plotting → vizdask[dataframe]: keep as required for now. But, it is only used in core.aggrecation and core.zonal, so maybe could make optional? [EFF] already never at top-level.datashader: not used explicitly anywhere → removedgeoviews: used only in examples, for plotting → vizholoviews: used only in examples, tests, and HoloviewsBackend for plotting → vizmatplotlib: used only for plotting → vizmatplotlib-inline: not used explicitly anywhere → removednetcdf4: not used explicitly, but everyone is reading .nc files → keep as requirednumba: keep as required, of coursenumpy: keep as required, of coursepandas: important for grid methods, e.g. pd.Series and pd.IntervalIndex used explicitly → keep as requiredpyarrow: not used explicitly, and dask[dataframe] already depends on it → removedrequests: not used explicitly anywhere in uxarray → removedscikit-learn: important for neighbor algorithms, e.g. KDTree → keep as required. [EFF] already not at top-level.scipy: important for delaunay triangulations and some io → keep as required. [EFF] removed from top-level.shapely: important for geometry → keep as required. [EFF] already not at top-level.spatialpandas: just for spatialpandas.GeoDataFrame conversions; should be optional → geogeopandas: just for geopandas.GeoDataFrame conversions; should be optional → geoxarray: keep as required, of coursehvplot: used only for plotting → viz.Didn't move it yet though; waiting for Speed up import and load hvplot lazily #1541 to get mergedhealpix: just for healpix grids; should be optional → geopolars: used explicitly for some internal methods → keep as requiredpyproj: only used in uxarray.cross_sections.sample.sample_geodesic; should be optional → geoMiscellaneous notes:
pathlib; pathlib became a built-in part of the standard library in Python 3.4, and the pyproject.toml requires Python >= 3.10.poochto "dev" dependency group, because pooch was secretly required in order for all tests to pass. Comment in test/io/test_structure.py clarifies why pooch dependency exists despite not being imported explicitly anywhere in uxarray.Expected Usage
Users can now install uxarray with optional dependency groups. Simple examples with pip interface:
Required dependencies only:
Also includes all optional dependencies related to geospatial grids (geopandas, healpix, pyproj, spatialpandas)
Also includes everything related to geospatial grids, plus everything related to visualization (cartopy, geoviews, holoviews, matplotlib)
Includes all required plus all optional dependencies:
Equivalent to above:
pip install "uxarray[all]"PR Checklist
General
Testing
import uxarrayafter doingpip install uxarraywith minimal dependencies? We could maybe add a few more tests for different combinations of dependencies too?