Skip to content

Commit ca0622c

Browse files
committed
Nicer import failure
1 parent bb58289 commit ca0622c

File tree

3 files changed

+47
-3
lines changed

3 files changed

+47
-3
lines changed

pandas/io/api.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,20 @@
2020
try:
2121
from pandas.formats.style import Styler
2222
except:
23-
pass
23+
from pandas.compat import add_metaclass as _add_metaclass
24+
from pandas.util.importing import _UnSubclassable
25+
26+
# We want to *not* raise an ImportError upon importing this module
27+
# We *do* want to raise an ImportError with a custom message
28+
# when the class is instantiated or subclassed.
29+
@_add_metaclass(_UnSubclassable)
30+
class Styler(object):
31+
msg = ("pandas.io.api.Styler requires jinja2. "
32+
"Please install with `conda install Jinja2` "
33+
"or `pip install Jinaj2`")
34+
def __init__(self, *args, **kargs):
35+
raise ImportError(self.msg)
36+
2437

2538
# deprecation, xref #13790
2639
def Term(*args, **kwargs):

pandas/tests/api/test_api.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class TestPDApi(Base, tm.TestCase):
2727

2828
# these are optionally imported based on testing
2929
# & need to be ignored
30-
ignored = ['tests', 'locale', 'conftest', 'Styler']
30+
ignored = ['tests', 'locale', 'conftest']
3131

3232
# top-level sub-packages
3333
lib = ['api', 'compat', 'computation', 'core',
@@ -48,7 +48,7 @@ class TestPDApi(Base, tm.TestCase):
4848
'Grouper', 'HDFStore', 'Index', 'Int64Index', 'MultiIndex',
4949
'Period', 'PeriodIndex', 'RangeIndex', 'UInt64Index',
5050
'Series', 'SparseArray', 'SparseDataFrame',
51-
'SparseSeries', 'TimeGrouper', 'Timedelta',
51+
'SparseSeries', 'Styler', 'TimeGrouper', 'Timedelta',
5252
'TimedeltaIndex', 'Timestamp']
5353

5454
# these are already deprecated; awaiting removal
@@ -121,6 +121,27 @@ def test_styler(self):
121121
pytest.importorskip('jinja2')
122122
from pandas.io.api import Styler # noqa
123123

124+
def test_import_styler_no_jinja(self):
125+
try:
126+
import jinja2 # noqa
127+
has_jinja = True
128+
except ImportError:
129+
has_jinja = False
130+
else:
131+
if has_jinja:
132+
pytest.skip("Skipping since jinja is installed")
133+
134+
# ensure we can access it
135+
Styler = pd.io.api.Styler
136+
# but can't instantiate or subclass
137+
with pytest.raises(ImportError) as excinfo:
138+
Styler()
139+
assert excinfo.match("jinja2")
140+
141+
with pytest.raises(ImportError) as excinfo:
142+
class MyStyler(Styler):
143+
pass
144+
assert excinfo.match("jinja2")
124145

125146
class TestApi(Base, tm.TestCase):
126147

pandas/util/importing.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
class _UnSubclassable(type):
2+
"""
3+
Metaclass to raise an ImportError when subclassed
4+
"""
5+
msg = ""
6+
7+
def __init__(cls, name, bases, clsdict):
8+
if len(cls.mro()) > 2:
9+
raise ImportError(cls.msg)
10+
super(_UnSubclassable, cls).__init__(name, bases, clsdict)

0 commit comments

Comments
 (0)