Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Log debug message if import PythonShell and PythonEditor fail in api.py #801

Merged
merged 4 commits into from
Nov 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions pyface/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#
# Thanks for using Enthought open source!

import logging as _logging

from .about_dialog import AboutDialog
from .application import Application
Expand All @@ -28,13 +29,22 @@
from .key_pressed_event import KeyPressedEvent
from .message_dialog import error, information, warning, MessageDialog
from .progress_dialog import ProgressDialog
try:

from .util._optional_dependencies import optional_import as _optional_import

# Excuse pygments dependency (for Qt), otherwise re-raise
with _optional_import(
"pygments",
msg="PythonEditor not available due to missing pygments.",
logger=_logging.getLogger(__name__)):
from .python_editor import PythonEditor

with _optional_import(
"pygments",
msg="PythonShell not available due to missing pygments.",
logger=_logging.getLogger(__name__)):
from .python_shell import PythonShell
except ImportError as _exception:
# Excuse pygments dependency (for Qt), otherwise re-raise
if _exception.name != "pygments":
raise

from .sorter import Sorter
from .single_choice_dialog import choose_one, SingleChoiceDialog
from .splash_screen import SplashScreen
Expand Down
38 changes: 38 additions & 0 deletions pyface/util/_optional_dependencies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@

# (C) Copyright 2005-2020 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only under
# the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
""" Utilities for handling optional import dependencies."""

import contextlib


@contextlib.contextmanager
def optional_import(dependency_name, msg, logger):
""" Context manager for capturing ImportError for a particular optional
dependency. If such an error occurs, it will be silenced and a debug
message will be logged.

Parameters
----------
dependency_name : str
Name of the module that may fail to be imported.
If matched, the ImportError will be silenced
msg : str
Log message to be emitted.
logger : Logger
Logger to use for logging messages.
"""
try:
yield
except ImportError as exception:
if exception.name == dependency_name:
logger.debug(msg, exc_info=True)
else:
raise
38 changes: 38 additions & 0 deletions pyface/util/tests/test__optional_dependencies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# (C) Copyright 2005-2020 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only under
# the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
""" Tests for the _optional_dependencies module """

import logging
import unittest

from pyface.util._optional_dependencies import optional_import


class TestOptionalImport(unittest.TestCase):
""" Test optional import context manager """

def test_optional_import(self):
# Test excusing dependency and the logging behaviour
logger = logging.getLogger(self.id())
with self.assertLogs(logger, level="DEBUG") as log_context:
with optional_import(
"random_missing_lib", "fail to import", logger):
# assume this library is not importable.
import random_missing_lib # noqa: F401

log, = log_context.output
self.assertIn("fail to import", log)

def test_optional_import_reraise(self):
# Test if the import error was about something else, reraise
logger = logging.getLogger(self.id())
with self.assertRaises(ImportError):
with optional_import("some_random_lib", "", logger):
import some_random_missing_lib # noqa: F401