From 32414d16111dac9fdfa28c665d8efa946ac2454f Mon Sep 17 00:00:00 2001 From: Stefan Binder Date: Sat, 7 Jan 2023 18:10:57 +0000 Subject: [PATCH 01/12] Hide deprecated callables from code completion suggestions --- altair/__init__.py | 15 +++++++++++++++ altair/utils/deprecation.py | 1 + 2 files changed, 16 insertions(+) diff --git a/altair/__init__.py b/altair/__init__.py index fe7539bfd..77f154de8 100644 --- a/altair/__init__.py +++ b/altair/__init__.py @@ -1,4 +1,6 @@ # flake8: noqa +import sys + __version__ = "4.3.0.dev0" from .vegalite import * @@ -9,3 +11,16 @@ def load_ipython_extension(ipython): ipython.register_magic_function(vega, "cell") ipython.register_magic_function(vegalite, "cell") + + +# Setting __all__ and __dir__ without deprecated attributes tries to hide them +# from code completion suggestions +__all__ = [ + x + for x in dir(sys.modules[__name__]) + if not getattr(getattr(sys.modules[__name__], x), "_deprecated", False) +] + + +def __dir__(): + return __all__ diff --git a/altair/utils/deprecation.py b/altair/utils/deprecation.py index 9deca223b..0230fda9f 100644 --- a/altair/utils/deprecation.py +++ b/altair/utils/deprecation.py @@ -65,6 +65,7 @@ def new_obj(*args, **kwargs): warnings.warn(message, AltairDeprecationWarning) return obj(*args, **kwargs) + new_obj._deprecated = True return new_obj else: raise ValueError("Cannot deprecate object of type {}".format(type(obj))) From 48fd332a502ebb6b08f0c5970b6e3e522ee3c1e7 Mon Sep 17 00:00:00 2001 From: Stefan Binder Date: Sat, 7 Jan 2023 19:40:58 +0000 Subject: [PATCH 02/12] Declare __all__ explicitly --- altair/__init__.py | 615 ++++++++++++++++++++++++++++++++++++++++- tests/test_toplevel.py | 14 + 2 files changed, 616 insertions(+), 13 deletions(-) create mode 100644 tests/test_toplevel.py diff --git a/altair/__init__.py b/altair/__init__.py index 77f154de8..afde60f36 100644 --- a/altair/__init__.py +++ b/altair/__init__.py @@ -3,24 +3,613 @@ __version__ = "4.3.0.dev0" -from .vegalite import * - - -def load_ipython_extension(ipython): - from ._magics import vega, vegalite - - ipython.register_magic_function(vega, "cell") - ipython.register_magic_function(vegalite, "cell") - # Setting __all__ and __dir__ without deprecated attributes tries to hide them -# from code completion suggestions +# from code completion suggestions. There is a test in test_toplevel.py which makes +# sure that this list is being kept up-to-date __all__ = [ - x - for x in dir(sys.modules[__name__]) - if not getattr(getattr(sys.modules[__name__], x), "_deprecated", False) + "Aggregate", + "AggregateOp", + "AggregateTransform", + "AggregatedFieldDef", + "Align", + "AllSortString", + "Angle", + "AngleDatum", + "AngleValue", + "AnyMark", + "AnyMarkConfig", + "AreaConfig", + "ArgmaxDef", + "ArgminDef", + "AutoSizeParams", + "AutosizeType", + "Axis", + "AxisConfig", + "AxisOrient", + "AxisResolveMap", + "BarConfig", + "BaseTitleNoValueRefs", + "Baseline", + "Bin", + "BinExtent", + "BinParams", + "BinTransform", + "BindCheckbox", + "BindDirect", + "BindInput", + "BindRadioSelect", + "BindRange", + "Binding", + "Blend", + "BoxPlot", + "BoxPlotConfig", + "BoxPlotDef", + "BrushConfig", + "CalculateTransform", + "Categorical", + "Chart", + "Color", + "ColorDatum", + "ColorDef", + "ColorName", + "ColorScheme", + "ColorValue", + "Column", + "CompositeMark", + "CompositeMarkDef", + "CompositionConfig", + "ConcatChart", + "ConcatSpecGenericSpec", + "ConditionalAxisColor", + "ConditionalAxisLabelAlign", + "ConditionalAxisLabelBaseline", + "ConditionalAxisLabelFontStyle", + "ConditionalAxisLabelFontWeight", + "ConditionalAxisNumber", + "ConditionalAxisNumberArray", + "ConditionalAxisPropertyAlignnull", + "ConditionalAxisPropertyColornull", + "ConditionalAxisPropertyFontStylenull", + "ConditionalAxisPropertyFontWeightnull", + "ConditionalAxisPropertyTextBaselinenull", + "ConditionalAxisPropertynumberArraynull", + "ConditionalAxisPropertynumbernull", + "ConditionalAxisPropertystringnull", + "ConditionalAxisString", + "ConditionalMarkPropFieldOrDatumDef", + "ConditionalMarkPropFieldOrDatumDefTypeForShape", + "ConditionalParameterMarkPropFieldOrDatumDef", + "ConditionalParameterMarkPropFieldOrDatumDefTypeForShape", + "ConditionalParameterStringFieldDef", + "ConditionalParameterValueDefGradientstringnullExprRef", + "ConditionalParameterValueDefTextExprRef", + "ConditionalParameterValueDefnumber", + "ConditionalParameterValueDefnumberArrayExprRef", + "ConditionalParameterValueDefnumberExprRef", + "ConditionalParameterValueDefstringExprRef", + "ConditionalParameterValueDefstringnullExprRef", + "ConditionalPredicateMarkPropFieldOrDatumDef", + "ConditionalPredicateMarkPropFieldOrDatumDefTypeForShape", + "ConditionalPredicateStringFieldDef", + "ConditionalPredicateValueDefAlignnullExprRef", + "ConditionalPredicateValueDefColornullExprRef", + "ConditionalPredicateValueDefFontStylenullExprRef", + "ConditionalPredicateValueDefFontWeightnullExprRef", + "ConditionalPredicateValueDefGradientstringnullExprRef", + "ConditionalPredicateValueDefTextBaselinenullExprRef", + "ConditionalPredicateValueDefTextExprRef", + "ConditionalPredicateValueDefnumber", + "ConditionalPredicateValueDefnumberArrayExprRef", + "ConditionalPredicateValueDefnumberArraynullExprRef", + "ConditionalPredicateValueDefnumberExprRef", + "ConditionalPredicateValueDefnumbernullExprRef", + "ConditionalPredicateValueDefstringExprRef", + "ConditionalPredicateValueDefstringnullExprRef", + "ConditionalStringFieldDef", + "ConditionalValueDefGradientstringnullExprRef", + "ConditionalValueDefTextExprRef", + "ConditionalValueDefnumber", + "ConditionalValueDefnumberArrayExprRef", + "ConditionalValueDefnumberExprRef", + "ConditionalValueDefstringExprRef", + "ConditionalValueDefstringnullExprRef", + "Config", + "CsvDataFormat", + "Cursor", + "Cyclical", + "Data", + "DataFormat", + "DataSource", + "Datasets", + "DateTime", + "DatumChannelMixin", + "DatumDef", + "Day", + "DensityTransform", + "DerivedStream", + "Description", + "DescriptionValue", + "Detail", + "Dict", + "DictInlineDataset", + "DictSelectionInit", + "DictSelectionInitInterval", + "Diverging", + "DomainUnionWith", + "DsvDataFormat", + "Element", + "Encoding", + "EncodingSortField", + "ErrorBand", + "ErrorBandConfig", + "ErrorBandDef", + "ErrorBar", + "ErrorBarConfig", + "ErrorBarDef", + "ErrorBarExtent", + "EventStream", + "EventType", + "Expr", + "ExprRef", + "Facet", + "FacetChart", + "FacetEncodingFieldDef", + "FacetFieldDef", + "FacetMapping", + "FacetSpec", + "FacetedEncoding", + "FacetedUnitSpec", + "Field", + "FieldChannelMixin", + "FieldDefWithoutScale", + "FieldEqualPredicate", + "FieldGTEPredicate", + "FieldGTPredicate", + "FieldLTEPredicate", + "FieldLTPredicate", + "FieldName", + "FieldOneOfPredicate", + "FieldOrDatumDefWithConditionDatumDefGradientstringnull", + "FieldOrDatumDefWithConditionDatumDefnumber", + "FieldOrDatumDefWithConditionDatumDefnumberArray", + "FieldOrDatumDefWithConditionDatumDefstringnull", + "FieldOrDatumDefWithConditionMarkPropFieldDefGradientstringnull", + "FieldOrDatumDefWithConditionMarkPropFieldDefTypeForShapestringnull", + "FieldOrDatumDefWithConditionMarkPropFieldDefnumber", + "FieldOrDatumDefWithConditionMarkPropFieldDefnumberArray", + "FieldOrDatumDefWithConditionStringDatumDefText", + "FieldOrDatumDefWithConditionStringFieldDefText", + "FieldOrDatumDefWithConditionStringFieldDefstring", + "FieldRange", + "FieldRangePredicate", + "FieldValidPredicate", + "Fill", + "FillDatum", + "FillOpacity", + "FillOpacityDatum", + "FillOpacityValue", + "FillValue", + "FilterTransform", + "Fit", + "FlattenTransform", + "FoldTransform", + "FontStyle", + "FontWeight", + "Generator", + "GenericUnitSpecEncodingAnyMark", + "GeoJsonFeature", + "GeoJsonFeatureCollection", + "Gradient", + "GradientStop", + "GraticuleGenerator", + "GraticuleParams", + "HConcatChart", + "HConcatSpecGenericSpec", + "Header", + "HeaderConfig", + "HexColor", + "Href", + "HrefValue", + "Impute", + "ImputeMethod", + "ImputeParams", + "ImputeSequence", + "ImputeTransform", + "InlineData", + "InlineDataset", + "Interpolate", + "IntervalSelectionConfig", + "IntervalSelectionConfigWithoutType", + "JoinAggregateFieldDef", + "JoinAggregateTransform", + "JsonDataFormat", + "Key", + "LabelOverlap", + "LatLongDef", + "LatLongFieldDef", + "Latitude", + "Latitude2", + "Latitude2Datum", + "Latitude2Value", + "LatitudeDatum", + "LayerChart", + "LayerRepeatMapping", + "LayerRepeatSpec", + "LayerSpec", + "LayoutAlign", + "Legend", + "LegendBinding", + "LegendConfig", + "LegendOrient", + "LegendResolveMap", + "LegendStreamBinding", + "LineConfig", + "LinearGradient", + "LocalMultiTimeUnit", + "LocalSingleTimeUnit", + "Locale", + "LoessTransform", + "LogicalAndPredicate", + "LogicalNotPredicate", + "LogicalOrPredicate", + "Longitude", + "Longitude2", + "Longitude2Datum", + "Longitude2Value", + "LongitudeDatum", + "LookupData", + "LookupSelection", + "LookupTransform", + "Mark", + "MarkConfig", + "MarkDef", + "MarkPropDefGradientstringnull", + "MarkPropDefnumber", + "MarkPropDefnumberArray", + "MarkPropDefstringnullTypeForShape", + "MarkType", + "MaxRowsError", + "MergedStream", + "Month", + "MultiTimeUnit", + "NamedData", + "NonArgAggregateOp", + "NonLayerRepeatSpec", + "NonNormalizedSpec", + "NumberLocale", + "NumericArrayMarkPropDef", + "NumericMarkPropDef", + "OffsetDef", + "Opacity", + "OpacityDatum", + "OpacityValue", + "Order", + "OrderFieldDef", + "OrderValue", + "OrderValueDef", + "Orient", + "Orientation", + "OverlayMarkDef", + "Padding", + "Parameter", + "ParameterExpression", + "ParameterExtent", + "ParameterName", + "ParameterPredicate", + "Parse", + "ParseValue", + "PivotTransform", + "PointSelectionConfig", + "PointSelectionConfigWithoutType", + "PolarDef", + "Position2Def", + "PositionDatumDef", + "PositionDatumDefBase", + "PositionDef", + "PositionFieldDef", + "PositionFieldDefBase", + "PositionValueDef", + "Predicate", + "PredicateComposition", + "PrimitiveValue", + "Projection", + "ProjectionConfig", + "ProjectionType", + "QuantileTransform", + "RadialGradient", + "Radius", + "Radius2", + "Radius2Datum", + "Radius2Value", + "RadiusDatum", + "RadiusValue", + "RangeConfig", + "RangeEnum", + "RangeRaw", + "RangeRawArray", + "RangeScheme", + "RectConfig", + "RegressionTransform", + "RelativeBandSize", + "RepeatChart", + "RepeatMapping", + "RepeatRef", + "RepeatSpec", + "Resolve", + "ResolveMode", + "Root", + "Row", + "RowColLayoutAlign", + "RowColboolean", + "RowColnumber", + "RowColumnEncodingFieldDef", + "SCHEMA_URL", + "SCHEMA_VERSION", + "SampleTransform", + "Scale", + "ScaleBinParams", + "ScaleBins", + "ScaleConfig", + "ScaleDatumDef", + "ScaleFieldDef", + "ScaleInterpolateEnum", + "ScaleInterpolateParams", + "ScaleResolveMap", + "ScaleType", + "SchemaBase", + "SchemeParams", + "SecondaryFieldDef", + "SelectionConfig", + "SelectionExpression", + "SelectionInit", + "SelectionInitInterval", + "SelectionInitIntervalMapping", + "SelectionInitMapping", + "SelectionParameter", + "SelectionPredicateComposition", + "SelectionResolution", + "SelectionType", + "SequenceGenerator", + "SequenceParams", + "SequentialMultiHue", + "SequentialSingleHue", + "Shape", + "ShapeDatum", + "ShapeDef", + "ShapeValue", + "SharedEncoding", + "SingleDefUnitChannel", + "SingleTimeUnit", + "Size", + "SizeDatum", + "SizeValue", + "Sort", + "SortArray", + "SortByChannel", + "SortByChannelDesc", + "SortByEncoding", + "SortField", + "SortOrder", + "Spec", + "SphereGenerator", + "StackOffset", + "StackTransform", + "StandardType", + "Step", + "StepFor", + "Stream", + "StringFieldDef", + "StringFieldDefWithCondition", + "StringValueDefWithCondition", + "Stroke", + "StrokeCap", + "StrokeDash", + "StrokeDashDatum", + "StrokeDashValue", + "StrokeDatum", + "StrokeJoin", + "StrokeOpacity", + "StrokeOpacityDatum", + "StrokeOpacityValue", + "StrokeValue", + "StrokeWidth", + "StrokeWidthDatum", + "StrokeWidthValue", + "StyleConfigIndex", + "SymbolShape", + "TOPLEVEL_ONLY_KEYS", + "Text", + "TextBaseline", + "TextDatum", + "TextDef", + "TextDirection", + "TextValue", + "Theta", + "Theta2", + "Theta2Datum", + "Theta2Value", + "ThetaDatum", + "ThetaValue", + "TickConfig", + "TickCount", + "TimeInterval", + "TimeIntervalStep", + "TimeLocale", + "TimeUnit", + "TimeUnitParams", + "TimeUnitTransform", + "Title", + "TitleAnchor", + "TitleConfig", + "TitleFrame", + "TitleOrient", + "TitleParams", + "Tooltip", + "TooltipContent", + "TooltipValue", + "TopLevelConcatSpec", + "TopLevelFacetSpec", + "TopLevelHConcatSpec", + "TopLevelLayerSpec", + "TopLevelMixin", + "TopLevelRepeatSpec", + "TopLevelSelectionParameter", + "TopLevelSpec", + "TopLevelUnitSpec", + "TopLevelVConcatSpec", + "TopoDataFormat", + "Transform", + "Type", + "TypeForShape", + "TypedFieldDef", + "URI", + "Undefined", + "UnitSpec", + "UnitSpecWithFrame", + "Url", + "UrlData", + "UrlValue", + "UtcMultiTimeUnit", + "UtcSingleTimeUnit", + "VConcatChart", + "VConcatSpecGenericSpec", + "VEGAEMBED_VERSION", + "VEGALITE_VERSION", + "VEGA_VERSION", + "ValueChannelMixin", + "ValueDefWithConditionMarkPropFieldOrDatumDefGradientstringnull", + "ValueDefWithConditionMarkPropFieldOrDatumDefTypeForShapestringnull", + "ValueDefWithConditionMarkPropFieldOrDatumDefnumber", + "ValueDefWithConditionMarkPropFieldOrDatumDefnumberArray", + "ValueDefWithConditionMarkPropFieldOrDatumDefstringnull", + "ValueDefWithConditionStringFieldDefText", + "ValueDefnumber", + "ValueDefnumberwidthheightExprRef", + "VariableParameter", + "Vector10string", + "Vector12string", + "Vector2DateTime", + "Vector2Vector2number", + "Vector2boolean", + "Vector2number", + "Vector2string", + "Vector3number", + "Vector7string", + "VegaLite", + "VegaLiteSchema", + "ViewBackground", + "ViewConfig", + "WindowEventType", + "WindowFieldDef", + "WindowOnlyOp", + "WindowTransform", + "X", + "X2", + "X2Datum", + "X2Value", + "XDatum", + "XError", + "XError2", + "XError2Value", + "XErrorValue", + "XOffset", + "XOffsetDatum", + "XOffsetValue", + "XValue", + "Y", + "Y2", + "Y2Datum", + "Y2Value", + "YDatum", + "YError", + "YError2", + "YError2Value", + "YErrorValue", + "YOffset", + "YOffsetDatum", + "YOffsetValue", + "YValue", + "__builtins__", + "__cached__", + "__doc__", + "__file__", + "__loader__", + "__name__", + "__package__", + "__path__", + "__spec__", + "__version__", + "api", + "binding", + "binding_checkbox", + "binding_radio", + "binding_range", + "binding_select", + "channels", + "check_fields_and_encodings", + "concat", + "condition", + "core", + "curry", + "data", + "data_transformers", + "datasets", + "default_data_transformer", + "display", + "expr", + "graticule", + "hashlib", + "hconcat", + "io", + "itertools", + "json", + "jsonschema", + "layer", + "limit_rows", + "load_ipython_extension", + "load_schema", + "mixins", + "overload", + "param", + "parse_shorthand", + "pd", + "pipe", + "pkgutil", + "renderers", + "repeat", + "sample", + "schema", + "selection", + "selection_interval", + "selection_point", + "sequence", + "sphere", + "sys", + "theme", + "themes", + "to_csv", + "to_json", + "to_values", + "topo_feature", + "utils", + "v5", + "value", + "vconcat", + "vegalite", + "with_property_setters", ] def __dir__(): return __all__ + + +from .vegalite import * + + +def load_ipython_extension(ipython): + from ._magics import vega, vegalite + + ipython.register_magic_function(vega, "cell") + ipython.register_magic_function(vegalite, "cell") diff --git a/tests/test_toplevel.py b/tests/test_toplevel.py new file mode 100644 index 000000000..af05bcede --- /dev/null +++ b/tests/test_toplevel.py @@ -0,0 +1,14 @@ +import altair as alt + + +def test_completeness_of_all(): + expected = [ + x for x in dir(alt) if not getattr(getattr(alt, x), "_deprecated", False) + ] + + # If the assert statement fails below, there are probably either new objects + # in the top-level Altair namespace or some were removed. + # This can for example happen if Altair is updated to a new version of Vega-Lite. + # In that case, replace the list __all__ in altair/__init__.py with what is + # present in `expected` in this test + assert getattr(alt, "__all__") == expected From 760bd0fa03546ca61a575cac11204418a5590ae2 Mon Sep 17 00:00:00 2001 From: Stefan Binder Date: Sun, 8 Jan 2023 16:12:05 +0000 Subject: [PATCH 03/12] Remove sys import --- altair/__init__.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/altair/__init__.py b/altair/__init__.py index afde60f36..0935fe0aa 100644 --- a/altair/__init__.py +++ b/altair/__init__.py @@ -1,6 +1,4 @@ # flake8: noqa -import sys - __version__ = "4.3.0.dev0" @@ -585,7 +583,6 @@ "selection_point", "sequence", "sphere", - "sys", "theme", "themes", "to_csv", From ade9d7135948d4b2a646b4ec04de6ffdffca22ed Mon Sep 17 00:00:00 2001 From: Stefan Binder Date: Sat, 4 Feb 2023 07:33:56 +0000 Subject: [PATCH 04/12] Remove dunder attributes from __all__ --- altair/__init__.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/altair/__init__.py b/altair/__init__.py index f7eae8414..542867301 100644 --- a/altair/__init__.py +++ b/altair/__init__.py @@ -528,16 +528,6 @@ "YOffsetDatum", "YOffsetValue", "YValue", - "__builtins__", - "__cached__", - "__doc__", - "__file__", - "__loader__", - "__name__", - "__package__", - "__path__", - "__spec__", - "__version__", "api", "binding", "binding_checkbox", From eb1810372597fe2a17bcc57e76cf588704bf0e6d Mon Sep 17 00:00:00 2001 From: Stefan Binder Date: Sat, 4 Feb 2023 07:35:15 +0000 Subject: [PATCH 05/12] Fix self-referencing test which never failed as it used __dir__ which is defined as __all__ --- tests/test_toplevel.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/test_toplevel.py b/tests/test_toplevel.py index af05bcede..c6fd8909d 100644 --- a/tests/test_toplevel.py +++ b/tests/test_toplevel.py @@ -2,9 +2,14 @@ def test_completeness_of_all(): - expected = [ - x for x in dir(alt) if not getattr(getattr(alt, x), "_deprecated", False) - ] + expected = sorted( + [ + x + for x in alt.__dict__.keys() + if not getattr(getattr(alt, x), "_deprecated", False) + and not x.startswith("__") + ] + ) # If the assert statement fails below, there are probably either new objects # in the top-level Altair namespace or some were removed. From 30b98d23b187745dc8a9e5eadbadcb16182c6937 Mon Sep 17 00:00:00 2001 From: Stefan Binder Date: Sat, 4 Feb 2023 07:52:20 +0000 Subject: [PATCH 06/12] Also ignore attributes with single '_' --- tests/test_toplevel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_toplevel.py b/tests/test_toplevel.py index c6fd8909d..4df0e9a24 100644 --- a/tests/test_toplevel.py +++ b/tests/test_toplevel.py @@ -5,9 +5,9 @@ def test_completeness_of_all(): expected = sorted( [ x - for x in alt.__dict__.keys() + for x in alt.__dict__ if not getattr(getattr(alt, x), "_deprecated", False) - and not x.startswith("__") + and not x.startswith("_") ] ) From 056eda546bd43e95616a426e21994d504ff9cb20 Mon Sep 17 00:00:00 2001 From: Stefan Binder Date: Sun, 5 Feb 2023 06:57:51 +0000 Subject: [PATCH 07/12] Remove standard and third-party libraries --- altair/__init__.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/altair/__init__.py b/altair/__init__.py index 542867301..6d6dfa586 100644 --- a/altair/__init__.py +++ b/altair/__init__.py @@ -547,12 +547,7 @@ "display", "expr", "graticule", - "hashlib", "hconcat", - "io", - "itertools", - "json", - "jsonschema", "layer", "limit_rows", "load_ipython_extension", @@ -561,9 +556,7 @@ "overload", "param", "parse_shorthand", - "pd", "pipe", - "pkgutil", "renderers", "repeat", "sample", From c5c3d1f28445cb059b7ea78374b284d7cb07a948 Mon Sep 17 00:00:00 2001 From: Stefan Binder Date: Sun, 5 Feb 2023 07:07:04 +0000 Subject: [PATCH 08/12] Automate updating of __all__ --- altair/__init__.py | 5 +- tools/generate_schema_wrapper.py | 6 ++- tools/update_init_file.py | 78 ++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 5 deletions(-) create mode 100644 tools/update_init_file.py diff --git a/altair/__init__.py b/altair/__init__.py index 6d6dfa586..8485b10e1 100644 --- a/altair/__init__.py +++ b/altair/__init__.py @@ -2,9 +2,8 @@ __version__ = "4.3.0.dev0" -# Setting __all__ and __dir__ without deprecated attributes tries to hide them -# from code completion suggestions. There is a test in test_toplevel.py which makes -# sure that this list is being kept up-to-date +# The content of __all__ is automatically written by +# tools/update_init_file.py. Do not modify directly. __all__ = [ "Aggregate", "AggregateOp", diff --git a/tools/generate_schema_wrapper.py b/tools/generate_schema_wrapper.py index 542e7d2c1..e0eac6def 100644 --- a/tools/generate_schema_wrapper.py +++ b/tools/generate_schema_wrapper.py @@ -631,11 +631,13 @@ def main(): copy_schemapi_util() vegalite_main(args.skip_download) - # Altair is imported after the generation of the new schema files so that - # the API docs reflect the newest changes + # The modules below are imported after the generation of the new schema files + # as these modules import Altair. This allows them to use the new changes import generate_api_docs # noqa: E402 + import update_init_file # noqa: E402 generate_api_docs.write_api_file() + update_init_file.update__all__variable() if __name__ == "__main__": diff --git a/tools/update_init_file.py b/tools/update_init_file.py new file mode 100644 index 000000000..879c0f813 --- /dev/null +++ b/tools/update_init_file.py @@ -0,0 +1,78 @@ +""" +This script updates the attribute __all__ in altair/__init__.py +based on the updated Altair schema. +""" +import inspect +import sys +from pathlib import Path +from os.path import abspath, dirname, join + +import black + +# Import Altair from head +ROOT_DIR = abspath(join(dirname(__file__), "..")) +sys.path.insert(0, ROOT_DIR) +import altair as alt # noqa: E402 + + +def update__all__variable(): + """Updates the __all__ variable to all relevant attributes of top-level Altair. + This is for example useful to hide deprecated attributes from code completion in + Jupyter. + """ + # Read existing file content + init_path = alt.__file__ + with open(init_path, "r") as f: + lines = f.readlines() + lines = [l.strip("\n") for l in lines] + + # Find first and last line of the definition of __all__ + first_definition_line = None + last_definition_line = None + for idx, line in enumerate(lines): + if line.startswith("__all__ ="): + first_definition_line = idx + elif first_definition_line is not None and line.startswith("]"): + last_definition_line = idx + break + assert first_definition_line is not None and last_definition_line is not None + + # Figure out which attributes are relevant + relevant_attributes = sorted( + [x for x in alt.__dict__ if _is_relevant_attribute(x)] + ) + relevant_attributes_str = f"__all__ = {relevant_attributes}" + + # Put file back together, replacing old definition of __all__ with new one, keeping + # the rest of the file as is + new_lines = ( + lines[:first_definition_line] + + [relevant_attributes_str] + + lines[last_definition_line + 1 :] + ) + # Format file content with black + new_file_content = black.format_str("\n".join(new_lines), mode=black.Mode()) + + # Write new version of altair/__init__.py + with open(init_path, "w") as f: + f.write(new_file_content) + + +def _is_relevant_attribute(attr_name): + attr = getattr(alt, attr_name) + if getattr(attr, "_deprecated", False) or attr_name.startswith("_"): + return False + else: + if inspect.ismodule(attr): + # Only include modules which are part of Altair. This excludes built-in + # modules (they do not have a __file__ attribute), standard library, + # and third-party packages. + return getattr(attr, "__file__", "").startswith( + str(Path(alt.__file__).parent) + ) + else: + return True + + +if __name__ == "__main__": + update__all__variable() From 058cf8b6796192c36c8ff0addd2ab8ca834500cf Mon Sep 17 00:00:00 2001 From: Stefan Binder Date: Sun, 5 Feb 2023 07:08:25 +0000 Subject: [PATCH 09/12] Add missing alt.datum --- altair/__init__.py | 1 + tools/update_init_file.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/altair/__init__.py b/altair/__init__.py index 8485b10e1..caa9ccbe2 100644 --- a/altair/__init__.py +++ b/altair/__init__.py @@ -542,6 +542,7 @@ "data", "data_transformers", "datasets", + "datum", "default_data_transformer", "display", "expr", diff --git a/tools/update_init_file.py b/tools/update_init_file.py index 879c0f813..2ccc11082 100644 --- a/tools/update_init_file.py +++ b/tools/update_init_file.py @@ -60,7 +60,7 @@ def update__all__variable(): def _is_relevant_attribute(attr_name): attr = getattr(alt, attr_name) - if getattr(attr, "_deprecated", False) or attr_name.startswith("_"): + if getattr(attr, "_deprecated", False) is True or attr_name.startswith("_"): return False else: if inspect.ismodule(attr): From ee2bdef18eae710f22b478de071b9c06f7fa3cb6 Mon Sep 17 00:00:00 2001 From: Stefan Binder Date: Sun, 5 Feb 2023 07:10:05 +0000 Subject: [PATCH 10/12] Switch to .sort instead of sorted --- tools/update_init_file.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/update_init_file.py b/tools/update_init_file.py index 2ccc11082..5b3e9678b 100644 --- a/tools/update_init_file.py +++ b/tools/update_init_file.py @@ -38,9 +38,8 @@ def update__all__variable(): assert first_definition_line is not None and last_definition_line is not None # Figure out which attributes are relevant - relevant_attributes = sorted( - [x for x in alt.__dict__ if _is_relevant_attribute(x)] - ) + relevant_attributes = [x for x in alt.__dict__ if _is_relevant_attribute(x)] + relevant_attributes.sort() relevant_attributes_str = f"__all__ = {relevant_attributes}" # Put file back together, replacing old definition of __all__ with new one, keeping From eb700faa77f79fafb04f12caeeed7908681a5216 Mon Sep 17 00:00:00 2001 From: Stefan Binder Date: Sun, 5 Feb 2023 07:16:25 +0000 Subject: [PATCH 11/12] Fix test --- tests/test_toplevel.py | 27 ++++++++++++++------------- tools/update_init_file.py | 2 +- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/tests/test_toplevel.py b/tests/test_toplevel.py index 4df0e9a24..1fe82dca6 100644 --- a/tests/test_toplevel.py +++ b/tests/test_toplevel.py @@ -1,19 +1,20 @@ +import sys +from os.path import abspath, join, dirname + import altair as alt +current_dir = dirname(__file__) +sys.path.insert(0, abspath(join(current_dir, ".."))) +from tools import update_init_file + -def test_completeness_of_all(): - expected = sorted( - [ - x - for x in alt.__dict__ - if not getattr(getattr(alt, x), "_deprecated", False) - and not x.startswith("_") - ] - ) +def test_completeness_of__all__(): + relevant_attributes = [ + x for x in alt.__dict__ if update_init_file._is_relevant_attribute(x) + ] + relevant_attributes.sort() # If the assert statement fails below, there are probably either new objects # in the top-level Altair namespace or some were removed. - # This can for example happen if Altair is updated to a new version of Vega-Lite. - # In that case, replace the list __all__ in altair/__init__.py with what is - # present in `expected` in this test - assert getattr(alt, "__all__") == expected + # In that case, run tools/update_init_file.py to update __all__ + assert getattr(alt, "__all__") == relevant_attributes diff --git a/tools/update_init_file.py b/tools/update_init_file.py index 5b3e9678b..2697b0c43 100644 --- a/tools/update_init_file.py +++ b/tools/update_init_file.py @@ -41,7 +41,7 @@ def update__all__variable(): relevant_attributes = [x for x in alt.__dict__ if _is_relevant_attribute(x)] relevant_attributes.sort() relevant_attributes_str = f"__all__ = {relevant_attributes}" - + # Put file back together, replacing old definition of __all__ with new one, keeping # the rest of the file as is new_lines = ( From 7190200f75f235e893b34c254a79556c917d1b73 Mon Sep 17 00:00:00 2001 From: Stefan Binder Date: Sun, 5 Feb 2023 07:52:17 +0000 Subject: [PATCH 12/12] Fix flake8 linting errors --- tests/test_toplevel.py | 2 +- tools/update_init_file.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_toplevel.py b/tests/test_toplevel.py index 1fe82dca6..0da425ada 100644 --- a/tests/test_toplevel.py +++ b/tests/test_toplevel.py @@ -5,7 +5,7 @@ current_dir = dirname(__file__) sys.path.insert(0, abspath(join(current_dir, ".."))) -from tools import update_init_file +from tools import update_init_file # noqa: E402 def test_completeness_of__all__(): diff --git a/tools/update_init_file.py b/tools/update_init_file.py index 2697b0c43..921715a53 100644 --- a/tools/update_init_file.py +++ b/tools/update_init_file.py @@ -24,7 +24,7 @@ def update__all__variable(): init_path = alt.__file__ with open(init_path, "r") as f: lines = f.readlines() - lines = [l.strip("\n") for l in lines] + lines = [line.strip("\n") for line in lines] # Find first and last line of the definition of __all__ first_definition_line = None