Skip to content

Improve error for contrib when the dependency packages are not installed - #3421

Open
hirosassa wants to merge 7 commits into
spotify:masterfrom
hirosassa:import-error-without-deps
Open

Improve error for contrib when the dependency packages are not installed#3421
hirosassa wants to merge 7 commits into
spotify:masterfrom
hirosassa:import-error-without-deps

Conversation

@hirosassa

Copy link
Copy Markdown
Contributor

Description

This PR improves error behavior when using contrib modules without their required dependencies installed.

Motivation and Context

In the current implementation, when a dependency is missing, only a warning is logged at import time. This means users may not notice the issue until the code is actually executed. Furthermore, since the ImportError is silently swallowed in the except block, runtime errors manifest as NameError or AttributeError instead, making root cause investigation difficult.

In this change, I introduce an availability flag in each contrib module's try/except ImportError block and checks it in the init of the relevant classes. When a required dependency is not installed, a clear ImportError is raised at instantiation time with a message indicating which package to install (e.g., pip install boto3). This allows users to identify the problem earlier and with a more actionable error message.

Have you tested this? If so, how?

Add tests and passed CI successfully.

@hirosassa
hirosassa requested a review from dlstadther as a code owner May 4, 2026 08:24
@hirosassa
hirosassa requested a review from a team May 4, 2026 08:24
@hirosassa
hirosassa force-pushed the import-error-without-deps branch from aea35de to 80900af Compare May 4, 2026 08:36

@dlstadther dlstadther left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I worry a little about the non-dryness between defining the name of the dependent python package(s) as a string in a exception message, when there are a subset of dependency groups defined in the pyproject.toml . A more ideal pattern (IMO) would be to define 1 dependency group per contrib module (where needed) which defines the range of dependent packages and versions it requires. Then the contrib exception can mention something like "missing package dependencies, install with luigi[s3]".


def __init__(self, *args, **kwargs):
if not _avro_enabled:
raise ImportError("avro is required for BigQueryLoadAvro. Install it with: pip install avro-python3")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indirectly related to this PR avro-python3 is deprecated in favor of avro. Something worth addressing separately.

Comment thread luigi/contrib/dataproc.py Outdated
Comment thread luigi/contrib/ftp.py
import pysftp
except ImportError:
logger.warning("Please install pysftp to use SFTP.")
raise ImportError("pysftp is required for SFTP functionality. Install it with: pip install pysftp")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Outside of scope - pysftp hasn't been updated in a very long time. Should probably be replaced with paramiko.

Comment thread luigi/contrib/gcp.py Outdated
Comment thread luigi/contrib/redshift.py
@hirosassa
hirosassa force-pushed the import-error-without-deps branch from 02ae457 to 1501bb6 Compare May 14, 2026 04:08
@hirosassa

hirosassa commented May 14, 2026

Copy link
Copy Markdown
Contributor Author

A more ideal pattern (IMO) would be to define 1 dependency group per contrib module

I agree with this idea.
I think it would be best to first define contrib-specific extras (e.g., s3, gcloud, docker) in [project.optional-dependencies] in a separate PR, and then update the error messages to something like pip install luigi[gcloud].

@hirosassa

Copy link
Copy Markdown
Contributor Author

CI for Azure blob is flaky recently

@dlstadther dlstadther left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why the codecov failure is here.

@dlstadther

Copy link
Copy Markdown
Contributor

@hirosassa , i'm not in a position to override the failing codecov check. It appears the codecov complaint is about the qty of new lines that aren't executed by any test.

@hirosassa

Copy link
Copy Markdown
Contributor Author

@dlstadther Thanks for flagging this. The new lines that codecov is complaining about are the if not _xxx_enabled: raise ImportError(...) checks in each contrib module's init. These paths only execute when the required dependency packages are not installed, but in CI, those dependencies are installed, so these lines are inherently uncoverable under normal test runs.

To cover them, we'd need to mock sys.modules or reload modules with dependencies removed, which adds test complexity without much real value — it would just verify that if not flag: raise works.

Would it be possible to override the codecov check and merge as-is, or is there a preferred way to handle this?

@dlstadther

Copy link
Copy Markdown
Contributor

Would it be possible to override the codecov check and merge as-is, or is there a preferred way to handle this?

Technically, yes. But i don't have the repo permissions to be able to do this. I've historically needed someone like @RRap0so to help in these scenarios.

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