Skip to content

Commit

Permalink
Fix unclear error when missing dependencies (#3511)
Browse files Browse the repository at this point in the history
* Implement MissingOptionalDependenciesError

* Add testing for MissingOptionalDependenciesError

* Raise clearer error when the CLI extra dependencies need to be installed

* Add RELEASE.md for PR

* Make suggested testing improvements

* Update base class

---------

Co-authored-by: Patrick Arminio <patrick.arminio@gmail.com>
  • Loading branch information
parafoxia and patrick91 committed May 25, 2024
1 parent 61f9e3a commit dd4c343
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 8 deletions.
6 changes: 6 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Release type: minor

When calling the CLI without all the necessary dependencies installed,
a `MissingOptionalDependenciesError` will be raised instead of a
`ModuleNotFoundError`. This new exception will provide a more helpful
hint regarding how to fix the problem.
20 changes: 12 additions & 8 deletions strawberry/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
from .commands.codegen import codegen as codegen # noqa
from .commands.export_schema import export_schema as export_schema # noqa
from .commands.server import server as server # noqa
from .commands.upgrade import upgrade as upgrade # noqa
from .commands.schema_codegen import schema_codegen as schema_codegen # noqa
try:
from .app import app
from .commands.codegen import codegen as codegen # noqa
from .commands.export_schema import export_schema as export_schema # noqa
from .commands.schema_codegen import schema_codegen as schema_codegen # noqa
from .commands.server import server as server # noqa
from .commands.upgrade import upgrade as upgrade # noqa

from .app import app
def run() -> None:
app()

except ModuleNotFoundError as exc:
from strawberry.exceptions import MissingOptionalDependenciesError

def run() -> None:
app()
raise MissingOptionalDependenciesError(extras=["cli"]) from exc
2 changes: 2 additions & 0 deletions strawberry/exceptions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from .invalid_argument_type import InvalidArgumentTypeError
from .invalid_union_type import InvalidTypeForUnionMergeError, InvalidUnionTypeError
from .missing_arguments_annotations import MissingArgumentsAnnotationsError
from .missing_dependencies import MissingOptionalDependenciesError
from .missing_field_annotation import MissingFieldAnnotationError
from .missing_return_annotation import MissingReturnAnnotationError
from .not_a_strawberry_enum import NotAStrawberryEnumError
Expand Down Expand Up @@ -186,4 +187,5 @@ class StrawberryGraphQLError(GraphQLError):
"MissingFieldAnnotationError",
"DuplicatedTypeName",
"StrawberryGraphQLError",
"MissingOptionalDependenciesError",
]
20 changes: 20 additions & 0 deletions strawberry/exceptions/missing_dependencies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from __future__ import annotations

from typing import Optional


class MissingOptionalDependenciesError(Exception):
"""Some optional dependencies that are required for a particular
task are missing."""

def __init__(
self,
*,
packages: Optional[list[str]] = None,
extras: Optional[list[str]] = None,
) -> None:
packages = packages or []
if extras:
packages.append(f"'strawberry-graphql[{','.join(extras)}]'")
hint = f" (hint: pip install {' '.join(packages)})" if packages else ""
self.message = f"Some optional dependencies are missing{hint}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import pytest

from strawberry.exceptions import MissingOptionalDependenciesError


def test_missing_optional_dependencies_error():
with pytest.raises(MissingOptionalDependenciesError) as exc_info:
raise MissingOptionalDependenciesError()

assert exc_info.value.message == "Some optional dependencies are missing"


def test_missing_optional_dependencies_error_packages():
with pytest.raises(MissingOptionalDependenciesError) as exc_info:
raise MissingOptionalDependenciesError(packages=["a", "b"])

assert (
exc_info.value.message
== "Some optional dependencies are missing (hint: pip install a b)"
)


def test_missing_optional_dependencies_error_empty_packages():
with pytest.raises(MissingOptionalDependenciesError) as exc_info:
raise MissingOptionalDependenciesError(packages=[])

assert exc_info.value.message == "Some optional dependencies are missing"


def test_missing_optional_dependencies_error_extras():
with pytest.raises(MissingOptionalDependenciesError) as exc_info:
raise MissingOptionalDependenciesError(extras=["dev", "test"])

assert (
exc_info.value.message
== "Some optional dependencies are missing (hint: pip install 'strawberry-graphql[dev,test]')"
)


def test_missing_optional_dependencies_error_empty_extras():
with pytest.raises(MissingOptionalDependenciesError) as exc_info:
raise MissingOptionalDependenciesError(extras=[])

assert exc_info.value.message == "Some optional dependencies are missing"


def test_missing_optional_dependencies_error_packages_and_extras():
with pytest.raises(MissingOptionalDependenciesError) as exc_info:
raise MissingOptionalDependenciesError(
packages=["a", "b"],
extras=["dev", "test"],
)

assert (
exc_info.value.message
== "Some optional dependencies are missing (hint: pip install a b 'strawberry-graphql[dev,test]')"
)

0 comments on commit dd4c343

Please sign in to comment.