Repository: altair-viz/altair
Pull request #1480 (2019-05-07 02:57:54)

MAINT: fix spelling of several new encoding channels


Patch:
diff --git a/CHANGES.md b/CHANGES.md
index 7d0b226c..c2b7487a 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -27,6 +27,17 @@
 
    In each case, the new invocations are compatible back to Altair 2.X.
 
+- Several of the encoding channels added in 3.0 have had their capitalization
+  corrected to better match the names used in the schema:
+
+  - ``alt.Fillopacity`` -> ``alt.FillOpacity``
+  - ``alt.Strokeopacity`` -> ``alt.StrokeOpacity``
+  - ``alt.Strokewidth`` -> ``alt.StrokeWidth``
+  - ``alt.Xerror`` -> ``alt.XError``
+  - ``alt.Xerror2`` -> ``alt.XError2``
+  - ``alt.Yerror`` -> ``alt.YError``
+  - ``alt.Yerror2`` -> ``alt.YError2``
+
 ## Version 3.0.1
 
 Fix version info bug for HTML output and Colab & Kaggle renderers.
diff --git a/altair/utils/__init__.py b/altair/utils/__init__.py
index 786c9ad2..f1257622 100644
--- a/altair/utils/__init__.py
+++ b/altair/utils/__init__.py
@@ -11,6 +11,7 @@ from .core import (
 )
 from .html import spec_to_html
 from .plugin_registry import PluginRegistry
+from .deprecation import AltairDeprecationWarning
 
 
 __all__ = (
@@ -22,6 +23,7 @@ __all__ = (
     'update_subtraits',
     'update_nested',
     'display_traceback',
+    'AltairDeprecationWarning',
     'SchemaBase',
     'Undefined',
     'PluginRegistry'
diff --git a/altair/utils/deprecation.py b/altair/utils/deprecation.py
new file mode 100644
index 00000000..766ab212
--- /dev/null
+++ b/altair/utils/deprecation.py
@@ -0,0 +1,47 @@
+import warnings
+# import functools
+
+
+class AltairDeprecationWarning(UserWarning):
+    pass
+
+
+def _deprecated(obj, name=None, message=None):
+    """Return a version of a class or function that raises a deprecation warning.
+
+    Parameters
+    ----------
+    obj : class or function
+        The object to create a deprecated version of.
+    name : string (optional)
+        The name of the deprecated object
+    message : string (optional)
+        The deprecation message
+
+    Returns
+    -------
+    deprecated_obj :
+        The deprecated version of obj
+
+    Examples
+    --------
+    >>> class Foo(object): pass
+    >>> OldFoo = _deprecated(Foo, "OldFoo")
+    >>> f = OldFoo()  # doctest: +SKIP
+    AltairDeprecationWarning: alt.OldFoo is deprecated. Use alt.Foo instead.
+    """
+    if message is None:
+        message = ("alt.{} is deprecated. Use alt.{} instead."
+                   "".format(name, obj.__name__))
+    if isinstance(obj, type):
+        return type(name, (obj,),
+                    {'__doc__': obj.__doc__,
+                    '__init__': _deprecated(obj.__init__, "__init__", message)})
+    elif callable(obj):
+        # @functools.wraps(obj)  # TODO: use this in Py3 only
+        def new_obj(*args, **kwargs):
+            warnings.warn(message, AltairDeprecationWarning)
+            return obj(*args, **kwargs)
+        return new_obj
+    else:
+        raise ValueError("Cannot deprecate object of type {}".format(type(obj)))
diff --git a/altair/vegalite/v3/__init__.py b/altair/vegalite/v3/__init__.py
index 93575aab..8dcfec55 100644
--- a/altair/vegalite/v3/__init__.py
+++ b/altair/vegalite/v3/__init__.py
@@ -1,6 +1,7 @@
 # flake8: noqa
 from .schema import *
 from .api import *
+from ._deprecated import *
 
 from ...datasets import (
     list_datasets,
diff --git a/altair/vegalite/v3/_deprecated.py b/altair/vegalite/v3/_deprecated.py
new file mode 100644
index 00000000..5241d1ed
--- /dev/null
+++ b/altair/vegalite/v3/_deprecated.py
@@ -0,0 +1,19 @@
+from ...utils.deprecation import _deprecated
+from . import channels
+
+# Deprecated classes (see https://github.com/altair-viz/altair/issues/1474).
+# TODO: Remove these in Altair 3.2.
+Fillopacity = _deprecated(channels.FillOpacity, 'Fillopacity')
+FillopacityValue = _deprecated(channels.FillOpacityValue, 'FillopacityValue')
+Strokeopacity = _deprecated(channels.StrokeOpacity, 'Strokeopacity')
+StrokeopacityValue = _deprecated(channels.StrokeOpacityValue, 'StrokeopacityValue')
+Strokewidth = _deprecated(channels.StrokeWidth, 'Strokewidth')
+StrokewidthValue = _deprecated(channels.StrokeWidthValue, 'StrokewidthValue')
+Xerror = _deprecated(channels.XError, 'Xerror')
+XerrorValue = _deprecated(channels.XErrorValue, 'XerrorValue')
+Xerror2 = _deprecated(channels.XError2, 'Xerror2')
+Xerror2Value = _deprecated(channels.XError2Value, 'Xerror2Value')
+Yerror = _deprecated(channels.YError, 'Yerror')
+YerrorValue = _deprecated(channels.YErrorValue, 'YerrorValue')
+Yerror2 = _deprecated(channels.YError2, 'Yerror2')
+Yerror2Value = _deprecated(channels.YError2Value, 'Yerror2Value')
diff --git a/altair/vegalite/v3/schema/channels.py b/altair/vegalite/v3/schema/channels.py
index 9161bb9f..4848edb3 100644
--- a/altair/vegalite/v3/schema/channels.py
+++ b/altair/vegalite/v3/schema/channels.py
@@ -862,8 +862,8 @@ class FillValue(ValueChannelMixin, core.ColorValueDefWithCondition):
         super(FillValue, self).__init__(value=value, **kwds)
 
 
-class Fillopacity(FieldChannelMixin, core.NumericFieldDefWithCondition):
-    """Fillopacity schema wrapper
+class FillOpacity(FieldChannelMixin, core.NumericFieldDefWithCondition):
+    """FillOpacity schema wrapper
 
     Mapping(required=[shorthand])
     A FieldDef with Condition :raw-html:`<ValueDef>`
@@ -1030,13 +1030,13 @@ class Fillopacity(FieldChannelMixin, core.NumericFieldDefWithCondition):
     def __init__(self, shorthand=Undefined, aggregate=Undefined, bin=Undefined, condition=Undefined,
                  field=Undefined, legend=Undefined, scale=Undefined, sort=Undefined, timeUnit=Undefined,
                  title=Undefined, type=Undefined, **kwds):
-        super(Fillopacity, self).__init__(shorthand=shorthand, aggregate=aggregate, bin=bin,
+        super(FillOpacity, self).__init__(shorthand=shorthand, aggregate=aggregate, bin=bin,
                                           condition=condition, field=field, legend=legend, scale=scale,
                                           sort=sort, timeUnit=timeUnit, title=title, type=type, **kwds)
 
 
-class FillopacityValue(ValueChannelMixin, core.NumericValueDefWithCondition):
-    """FillopacityValue schema wrapper
+class FillOpacityValue(ValueChannelMixin, core.NumericValueDefWithCondition):
+    """FillOpacityValue schema wrapper
 
     anyOf(:class:`ValueDefWithOptionalConditionMarkPropFieldDefnumber`,
     :class:`ConditionOnlyDefMarkPropFieldDef`)
@@ -1046,7 +1046,7 @@ class FillopacityValue(ValueChannelMixin, core.NumericValueDefWithCondition):
     _class_is_valid_at_instantiation = False
 
     def __init__(self, value, **kwds):
-        super(FillopacityValue, self).__init__(value=value, **kwds)
+        super(FillOpacityValue, self).__init__(value=value, **kwds)
 
 
 class Href(FieldChannelMixin, core.TextFieldDefWithCondition):
@@ -2843,8 +2843,8 @@ class StrokeValue(ValueChannelMixin, core.ColorValueDefWithCondition):
         super(StrokeValue, self).__init__(value=value, **kwds)
 
 
-class Strokeopacity(FieldChannelMixin, core.NumericFieldDefWithCondition):
-    """Strokeopacity schema wrapper
+class StrokeOpacity(FieldChannelMixin, core.NumericFieldDefWithCondition):
+    """StrokeOpacity schema wrapper
 
     Mapping(required=[shorthand])
     A FieldDef with Condition :raw-html:`<ValueDef>`
@@ -3011,14 +3011,14 @@ class Strokeopacity(FieldChannelMixin, core.NumericFieldDefWithCondition):
     def __init__(self, shorthand=Undefined, aggregate=Undefined, bin=Undefined, condition=Undefined,
                  field=Undefined, legend=Undefined, scale=Undefined, sort=Undefined, timeUnit=Undefined,
                  title=Undefined, type=Undefined, **kwds):
-        super(Strokeopacity, self).__init__(shorthand=shorthand, aggregate=aggregate, bin=bin,
+        super(StrokeOpacity, self).__init__(shorthand=shorthand, aggregate=aggregate, bin=bin,
                                             condition=condition, field=field, legend=legend,
                                             scale=scale, sort=sort, timeUnit=timeUnit, title=title,
                                             type=type, **kwds)
 
 
-class StrokeopacityValue(ValueChannelMixin, core.NumericValueDefWithCondition):
-    """StrokeopacityValue schema wrapper
+class StrokeOpacityValue(ValueChannelMixin, core.NumericValueDefWithCondition):
+    """StrokeOpacityValue schema wrapper
 
     anyOf(:class:`ValueDefWithOptionalConditionMarkPropFieldDefnumber`,
     :class:`ConditionOnlyDefMarkPropFieldDef`)
@@ -3028,11 +3028,11 @@ class StrokeopacityValue(ValueChannelMixin, core.NumericValueDefWithCondition):
     _class_is_valid_at_instantiation = False
 
     def __init__(self, value, **kwds):
-        super(StrokeopacityValue, self).__init__(value=value, **kwds)
+        super(StrokeOpacityValue, self).__init__(value=value, **kwds)
 
 
-class Strokewidth(FieldChannelMixin, core.NumericFieldDefWithCondition):
-    """Strokewidth schema wrapper
+class StrokeWidth(FieldChannelMixin, core.NumericFieldDefWithCondition):
+    """StrokeWidth schema wrapper
 
     Mapping(required=[shorthand])
     A FieldDef with Condition :raw-html:`<ValueDef>`
@@ -3199,13 +3199,13 @@ class Strokewidth(FieldChannelMixin, core.NumericFieldDefWithCondition):
     def __init__(self, shorthand=Undefined, aggregate=Undefined, bin=Undefined, condition=Undefined,
                  field=Undefined, legend=Undefined, scale=Undefined, sort=Undefined, timeUnit=Undefined,
                  title=Undefined, type=Undefined, **kwds):
-        super(Strokewidth, self).__init__(shorthand=shorthand, aggregate=aggregate, bin=bin,
+        super(StrokeWidth, self).__init__(shorthand=shorthand, aggregate=aggregate, bin=bin,
                                           condition=condition, field=field, legend=legend, scale=scale,
                                           sort=sort, timeUnit=timeUnit, title=title, type=type, **kwds)
 
 
-class StrokewidthValue(ValueChannelMixin, core.NumericValueDefWithCondition):
-    """StrokewidthValue schema wrapper
+class StrokeWidthValue(ValueChannelMixin, core.NumericValueDefWithCondition):
+    """StrokeWidthValue schema wrapper
 
     anyOf(:class:`ValueDefWithOptionalConditionMarkPropFieldDefnumber`,
     :class:`ConditionOnlyDefMarkPropFieldDef`)
@@ -3215,7 +3215,7 @@ class StrokewidthValue(ValueChannelMixin, core.NumericValueDefWithCondition):
     _class_is_valid_at_instantiation = False
 
     def __init__(self, value, **kwds):
-        super(StrokewidthValue, self).__init__(value=value, **kwds)
+        super(StrokeWidthValue, self).__init__(value=value, **kwds)
 
 
 class Text(FieldChannelMixin, core.TextFieldDefWithCondition):
@@ -3874,8 +3874,8 @@ class X2Value(ValueChannelMixin, core.XValueDef):
         super(X2Value, self).__init__(value=value, **kwds)
 
 
-class Xerror(FieldChannelMixin, core.SecondaryFieldDef):
-    """Xerror schema wrapper
+class XError(FieldChannelMixin, core.SecondaryFieldDef):
+    """XError schema wrapper
 
     Mapping(required=[shorthand])
     A field definition of a secondary channel that shares a scale with another primary channel.
@@ -3955,12 +3955,12 @@ class Xerror(FieldChannelMixin, core.SecondaryFieldDef):
 
     def __init__(self, shorthand=Undefined, aggregate=Undefined, bin=Undefined, field=Undefined,
                  timeUnit=Undefined, title=Undefined, **kwds):
-        super(Xerror, self).__init__(shorthand=shorthand, aggregate=aggregate, bin=bin, field=field,
+        super(XError, self).__init__(shorthand=shorthand, aggregate=aggregate, bin=bin, field=field,
                                      timeUnit=timeUnit, title=title, **kwds)
 
 
-class XerrorValue(ValueChannelMixin, core.NumberValueDef):
-    """XerrorValue schema wrapper
+class XErrorValue(ValueChannelMixin, core.NumberValueDef):
+    """XErrorValue schema wrapper
 
     Mapping(required=[value])
     Definition object for a constant value of an encoding channel.
@@ -3975,11 +3975,11 @@ class XerrorValue(ValueChannelMixin, core.NumberValueDef):
     _class_is_valid_at_instantiation = False
 
     def __init__(self, value, **kwds):
-        super(XerrorValue, self).__init__(value=value, **kwds)
+        super(XErrorValue, self).__init__(value=value, **kwds)
 
 
-class Xerror2(FieldChannelMixin, core.SecondaryFieldDef):
-    """Xerror2 schema wrapper
+class XError2(FieldChannelMixin, core.SecondaryFieldDef):
+    """XError2 schema wrapper
 
     Mapping(required=[shorthand])
     A field definition of a secondary channel that shares a scale with another primary channel.
@@ -4059,12 +4059,12 @@ class Xerror2(FieldChannelMixin, core.SecondaryFieldDef):
 
     def __init__(self, shorthand=Undefined, aggregate=Undefined, bin=Undefined, field=Undefined,
                  timeUnit=Undefined, title=Undefined, **kwds):
-        super(Xerror2, self).__init__(shorthand=shorthand, aggregate=aggregate, bin=bin, field=field,
+        super(XError2, self).__init__(shorthand=shorthand, aggregate=aggregate, bin=bin, field=field,
                                       timeUnit=timeUnit, title=title, **kwds)
 
 
-class Xerror2Value(ValueChannelMixin, core.NumberValueDef):
-    """Xerror2Value schema wrapper
+class XError2Value(ValueChannelMixin, core.NumberValueDef):
+    """XError2Value schema wrapper
 
     Mapping(required=[value])
     Definition object for a constant value of an encoding channel.
@@ -4079,7 +4079,7 @@ class Xerror2Value(ValueChannelMixin, core.NumberValueDef):
     _class_is_valid_at_instantiation = False
 
     def __init__(self, value, **kwds):
-        super(Xerror2Value, self).__init__(value=value, **kwds)
+        super(XError2Value, self).__init__(value=value, **kwds)
 
 
 class Y(FieldChannelMixin, core.PositionFieldDef):
@@ -4402,8 +4402,8 @@ class Y2Value(ValueChannelMixin, core.YValueDef):
         super(Y2Value, self).__init__(value=value, **kwds)
 
 
-class Yerror(FieldChannelMixin, core.SecondaryFieldDef):
-    """Yerror schema wrapper
+class YError(FieldChannelMixin, core.SecondaryFieldDef):
+    """YError schema wrapper
 
     Mapping(required=[shorthand])
     A field definition of a secondary channel that shares a scale with another primary channel.
@@ -4483,12 +4483,12 @@ class Yerror(FieldChannelMixin, core.SecondaryFieldDef):
 
     def __init__(self, shorthand=Undefined, aggregate=Undefined, bin=Undefined, field=Undefined,
                  timeUnit=Undefined, title=Undefined, **kwds):
-        super(Yerror, self).__init__(shorthand=shorthand, aggregate=aggregate, bin=bin, field=field,
+        super(YError, self).__init__(shorthand=shorthand, aggregate=aggregate, bin=bin, field=field,
                                      timeUnit=timeUnit, title=title, **kwds)
 
 
-class YerrorValue(ValueChannelMixin, core.NumberValueDef):
-    """YerrorValue schema wrapper
+class YErrorValue(ValueChannelMixin, core.NumberValueDef):
+    """YErrorValue schema wrapper
 
     Mapping(required=[value])
     Definition object for a constant value of an encoding channel.
@@ -4503,11 +4503,11 @@ class YerrorValue(ValueChannelMixin, core.NumberValueDef):
     _class_is_valid_at_instantiation = False
 
     def __init__(self, value, **kwds):
-        super(YerrorValue, self).__init__(value=value, **kwds)
+        super(YErrorValue, self).__init__(value=value, **kwds)
 
 
-class Yerror2(FieldChannelMixin, core.SecondaryFieldDef):
-    """Yerror2 schema wrapper
+class YError2(FieldChannelMixin, core.SecondaryFieldDef):
+    """YError2 schema wrapper
 
     Mapping(required=[shorthand])
     A field definition of a secondary channel that shares a scale with another primary channel.
@@ -4587,12 +4587,12 @@ class Yerror2(FieldChannelMixin, core.SecondaryFieldDef):
 
     def __init__(self, shorthand=Undefined, aggregate=Undefined, bin=Undefined, field=Undefined,
                  timeUnit=Undefined, title=Undefined, **kwds):
-        super(Yerror2, self).__init__(shorthand=shorthand, aggregate=aggregate, bin=bin, field=field,
+        super(YError2, self).__init__(shorthand=shorthand, aggregate=aggregate, bin=bin, field=field,
                                       timeUnit=timeUnit, title=title, **kwds)
 
 
-class Yerror2Value(ValueChannelMixin, core.NumberValueDef):
-    """Yerror2Value schema wrapper
+class YError2Value(ValueChannelMixin, core.NumberValueDef):
+    """YError2Value schema wrapper
 
     Mapping(required=[value])
     Definition object for a constant value of an encoding channel.
@@ -4607,4 +4607,4 @@ class Yerror2Value(ValueChannelMixin, core.NumberValueDef):
     _class_is_valid_at_instantiation = False
 
     def __init__(self, value, **kwds):
-        super(Yerror2Value, self).__init__(value=value, **kwds)
+        super(YError2Value, self).__init__(value=value, **kwds)
diff --git a/doc/user_guide/API.rst b/doc/user_guide/API.rst
index 49d4a981..aef8621b 100644
--- a/doc/user_guide/API.rst
+++ b/doc/user_guide/API.rst
@@ -41,8 +41,8 @@ Encoding Channels
    FieldChannelMixin
    Fill
    FillValue
-   Fillopacity
-   FillopacityValue
+   FillOpacity
+   FillOpacityValue
    Href
    HrefValue
    Key
@@ -65,10 +65,10 @@ Encoding Channels
    SizeValue
    Stroke
    StrokeValue
-   Strokeopacity
-   StrokeopacityValue
-   Strokewidth
-   StrokewidthValue
+   StrokeOpacity
+   StrokeOpacityValue
+   StrokeWidth
+   StrokeWidthValue
    Text
    TextValue
    Tooltip
@@ -79,18 +79,18 @@ Encoding Channels
    X2
    X2Value
    XValue
-   Xerror
-   Xerror2
-   Xerror2Value
-   XerrorValue
+   XError
+   XError2
+   XError2Value
+   XErrorValue
    Y
    Y2
    Y2Value
    YValue
-   Yerror
-   Yerror2
-   Yerror2Value
-   YerrorValue
+   YError
+   YError2
+   YError2Value
+   YErrorValue
 
 API Functions
 -------------
diff --git a/doc/user_guide/encoding.rst b/doc/user_guide/encoding.rst
index 92aae6a2..e68fe18f 100644
--- a/doc/user_guide/encoding.rst
+++ b/doc/user_guide/encoding.rst
@@ -273,8 +273,8 @@ The :class:`Shape` encoding accepts the following options:
 
 .. altair-object-table:: altair.ShapeFieldDefWithCondition
 
-The :class:`Fillopacity`, :class:`Opacity`, :class:`Size`, :class:`StrokeOpacity`,
-and :class:`Strokewidth` encodings accept the following options:
+The :class:`FillOpacity`, :class:`Opacity`, :class:`Size`, :class:`StrokeOpacity`,
+and :class:`StrokeWidth` encodings accept the following options:
 
 .. altair-object-table:: altair.NumericFieldDefWithCondition
 
@@ -286,11 +286,6 @@ The :class:`Text` and :class:`Tooltip` encodings accept the following options:
 
 .. altair-object-table:: altair.TextFieldDefWithCondition
 
-The :class:`Fillopacity`, :class:`Opacity`, :class:`Size`, :class:`Strokeopacity`,
-and :class:`Strokewidth` encodings accept the following options:
-
-.. altair-object-table:: altair.NumericFieldDefWithCondition
-
 The :class:`Detail` and :class:`Key` encodings accept the following options:
 
 .. altair-object-table:: altair.FieldDef
@@ -299,8 +294,8 @@ The :class:`Latitude` and :class:`Longitude` encodings accept the following opti
 
 .. altair-object-table:: altair.LatLongFieldDef
 
-The :class:`Latitude2`, :class:`Longitude2`, :class:`X2`, :class:`Y2`, :class:`Xerror`, :class:`Yerror`,
-:class:`Xerror2`, and :class:`Yerror2` encodings accept the following options:
+The :class:`Latitude2`, :class:`Longitude2`, :class:`X2`, :class:`Y2`, :class:`XError`, :class:`YError`,
+:class:`XError2`, and :class:`YError2` encodings accept the following options:
 
 .. altair-object-table:: altair.SecondaryFieldDef
 
diff --git a/doc/user_guide/interactions.rst b/doc/user_guide/interactions.rst
index eca2b7cd..932dd05e 100644
--- a/doc/user_guide/interactions.rst
+++ b/doc/user_guide/interactions.rst
@@ -325,7 +325,7 @@ create a wide variety of linked interactive chart types.
 
 Binding: Adding Data Driven Inputs
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-With an understanding of the selection types and conditions, you can now add data-driven input elements to the charts using the ``bind`` option. As specified by `Vega-lite binding <https://vega.github.io/vega-lite/docs/bind.html#input-element-binding>`_, selections can be bound two-ways:
+With an understanding of the selection types and conditions, you can now add data-driven input elements to the charts using the  :class:`bind`. As specified by `Vega-lite binding <https://vega.github.io/vega-lite/docs/bind.html#input-element-binding>`_, selections can be bound two-ways:
 
 1. Single selections can be bound directly to an input elements. *For example, a radio button.*
 2. Interval selections which can be bound to scale. *for example, zooming in on a map.*
@@ -395,11 +395,14 @@ Bindings and input elements can also be used to filter data on the client side.
 
 Scale Binding
 ^^^^^^^^^^^^^
-With interval selections, the ``bind`` property can be set to the value of ``"scales"``. In these cases, the binding will automatically respond to the panning and zooming along the chart:
+With interval selections, the bind property can be set to the value of :"scales":. In these cases, the binding will automatically respond to the panning and zooming along the chart:
 
 .. altair-plot::
 
-    selection = alt.selection_interval(bind='scales')
+    selection = alt.selection_interval(bind="scales")
+    color = alt.condition(selection,
+                        alt.Color('Origin:N', legend=None),
+                        alt.value('lightgray'))
 
     alt.Chart(cars).mark_point().encode(
         x='Horsepower:Q',
diff --git a/tools/generate_schema_wrapper.py b/tools/generate_schema_wrapper.py
index f8d4e141..ad19edd4 100644
--- a/tools/generate_schema_wrapper.py
+++ b/tools/generate_schema_wrapper.py
@@ -302,7 +302,7 @@ def generate_vegalite_channel_wrappers(schemafile, version, imports=None):
         for definition in definitions:
             defschema = {'$ref': definition}
             basename = definition.split('/')[-1]
-            classname = prop.title()
+            classname = prop[0].upper() + prop[1:]
 
             if 'Value' in basename:
                 Generator = ValueSchemaGenerator


Test patch:
diff --git a/altair/utils/tests/test_deprecation.py b/altair/utils/tests/test_deprecation.py
new file mode 100644
index 00000000..035d6087
--- /dev/null
+++ b/altair/utils/tests/test_deprecation.py
@@ -0,0 +1,13 @@
+import pytest
+
+import altair as alt
+from altair.utils import AltairDeprecationWarning
+from altair.utils.deprecation import _deprecated
+
+
+def test_deprecated_class():
+    OldChart = _deprecated(alt.Chart, "OldChart")
+    with pytest.warns(AltairDeprecationWarning) as record:
+        OldChart()
+    assert "alt.OldChart" in record[0].message.args[0]
+    assert "alt.Chart" in record[0].message.args[0]
\ No newline at end of file
diff --git a/altair/vegalite/v3/tests/test_api.py b/altair/vegalite/v3/tests/test_api.py
index cb021942..e9f9143d 100644
--- a/altair/vegalite/v3/tests/test_api.py
+++ b/altair/vegalite/v3/tests/test_api.py
@@ -10,6 +10,7 @@ import pytest
 import pandas as pd
 
 import altair.vegalite.v3 as alt
+from altair.utils import AltairDeprecationWarning
 
 try:
     import selenium
@@ -560,3 +561,14 @@ def test_consolidate_InlineData():
     with alt.data_transformers.enable(consolidate_datasets=True):
         dct = chart.to_dict()
     assert dct['data'] == data.to_dict()
+
+
+def test_deprecated_encodings():
+    base = alt.Chart('data.txt').mark_point()
+
+    with pytest.warns(AltairDeprecationWarning) as record:
+        chart1 = base.encode(strokeOpacity=alt.Strokeopacity('x:Q')).to_dict()
+    assert 'alt.StrokeOpacity' in record[0].message.args[0]
+    chart2 = base.encode(strokeOpacity=alt.StrokeOpacity('x:Q')).to_dict()
+
+    assert chart1 == chart2
\ No newline at end of file