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

refactor: alt.themes -> alt.theme #3618

Open
wants to merge 52 commits into
base: main
Choose a base branch
from
Open

refactor: alt.themes -> alt.theme #3618

wants to merge 52 commits into from

Conversation

dangotbanned
Copy link
Member

@dangotbanned dangotbanned commented Sep 28, 2024

Need a way to make sense of these and start GH threads:

- 10 total files
- 3 modules named `theme.py`
- 2 modules named `__init__.py`
@dangotbanned dangotbanned added maintenance deprecation Requires a **MINOR** version bump labels Sep 28, 2024
altair/__init__.py Outdated Show resolved Hide resolved
def __getattr__(name: str) -> _Any:
from altair.utils.deprecation import deprecated_warn

if name == "themes":
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solution is fine currently, but as soon as we start deprecating other imports it would make sense to generalize

@@ -93,7 +93,7 @@

class AreaConfigKwds(TypedDict, total=False):
"""
:class:`AreaConfig` ``TypedDict`` wrapper.
:class:`altair.AreaConfig` ``TypedDict`` wrapper.
Copy link
Member Author

@dangotbanned dangotbanned Sep 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously these didn't work as links in the API reference.

Now they do

image

Note

I expect this hasn't come up before since everything has already been in altair.___.

The same will apply for any symbols in altair.(theme|typing)

altair/theme.py Outdated
Comment on lines 264 to 266
enable = themes.enable
get = themes.get
names = themes.names
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

Originally planned for this to be a temporary solution.

Quite surpised at how well aliasing worked:

Docstring

image

API Reference

image

Indistinguishable from an actual function

image

@dangotbanned
Copy link
Member Author

@mattijn just wanted to check if you had any thoughts on 3-5 in #3618 (comment)?

Currently planning to go ahead with 2 and then explore 4 some more today.

Side note

I'm hoping to tackle #3497 once this one is merged, since

>>> ruff check . --config "target-version = 'py39'" --output-format "concise"
Found 86 errors.
[*] 70 fixable with the `--fix` option (2 hidden fixes can be enabled with the `--unsafe-fixes` option).
86 errors

altair\expr\core.py:3:1: UP035 `typing.Dict` is deprecated, use `dict` instead
altair\expr\core.py:240:74: UP006 [*] Use `dict` instead of `Dict` for type annotation
altair\utils\_dfi_types.py:10:1: UP035 [*] Import from `collections.abc` instead: `Iterable`
altair\utils\_show.py:5:1: UP035 [*] Import from `collections.abc` instead: `Iterable`
altair\utils\_transformed_data.py:3:1: UP035 [*] Import from `collections.abc` instead: `Iterable`
altair\utils\_transformed_data.py:3:1: UP035 `typing.Dict` is deprecated, use `dict` instead
altair\utils\_transformed_data.py:3:1: UP035 `typing.Tuple` is deprecated, use `tuple` instead
altair\utils\_transformed_data.py:37:20: UP006 [*] Use `tuple` instead of `Tuple` for type annotation
altair\utils\_transformed_data.py:38:27: UP006 [*] Use `dict` instead of `Dict` for type annotation
altair\utils\_transformed_data.py:38:32: UP006 [*] Use `tuple` instead of `Tuple` for type annotation
altair\utils\_transformed_data.py:38:51: UP006 [*] Use `tuple` instead of `Tuple` for type annotation
altair\utils\_vegafusion_data.py:4:1: UP035 [*] Import from `collections.abc` instead: `MutableMapping`
altair\utils\compiler.py:1:1: UP035 `typing.Dict` is deprecated, use `dict` instead
altair\utils\compiler.py:8:34: UP006 [*] Use `dict` instead of `Dict` for type annotation
altair\utils\compiler.py:8:51: UP006 [*] Use `dict` instead of `Dict` for type annotation
altair\utils\compiler.py:11:69: UP006 [*] Use `dict` instead of `Dict` for type annotation
altair\utils\core.py:15:1: UP035 [*] Import from `collections.abc` instead: `Iterator`
altair\utils\data.py:9:1: UP035 [*] Import from `collections.abc` instead: `MutableMapping`, `Sequence`
altair\utils\data.py:9:1: UP035 `typing.Dict` is deprecated, use `dict` instead
altair\utils\data.py:9:1: UP035 `typing.List` is deprecated, use `list` instead
altair\utils\data.py:57:5: UP006 [*] Use `dict` instead of `Dict` for type annotation
altair\utils\data.py:63:31: UP006 [*] Use `dict` instead of `Dict` for type annotation
altair\utils\data.py:64:21: UP006 [*] Use `dict` instead of `Dict` for type annotation
altair\utils\data.py:64:37: UP006 [*] Use `list` instead of `List` for type annotation
altair\utils\data.py:64:42: UP006 [*] Use `dict` instead of `Dict` for type annotation
altair\utils\data.py:66:33: UP006 [*] Use `dict` instead of `Dict` for type annotation
altair\utils\data.py:66:49: UP006 [*] Use `dict` instead of `Dict` for type annotation
altair\utils\data.py:66:65: UP006 [*] Use `list` instead of `List` for type annotation
altair\utils\data.py:66:70: UP006 [*] Use `dict` instead of `Dict` for type annotation
altair\utils\data.py:67:41: UP006 [*] Use `dict` instead of `Dict` for type annotation
altair\utils\display.py:7:1: UP035 `typing.Dict` is deprecated, use `dict` instead
altair\utils\display.py:7:1: UP035 `typing.Tuple` is deprecated, use `tuple` instead
altair\utils\display.py:21:33: UP006 [*] Use `dict` instead of `Dict` for type annotation
altair\utils\display.py:22:37: UP006 [*] Use `dict` instead of `Dict` for type annotation
altair\utils\display.py:24:25: UP006 [*] Use `tuple` instead of `Tuple` for type annotation
altair\utils\display.py:29:40: UP006 [*] Use `tuple` instead of `Tuple` for type annotation
altair\utils\display.py:30:5: UP006 [*] Use `dict` instead of `Dict` for type annotation
altair\utils\display.py:30:26: UP006 [*] Use `dict` instead of `Dict` for type annotation
altair\utils\display.py:30:44: UP006 [*] Use `dict` instead of `Dict` for type annotation
altair\utils\display.py:30:54: UP006 [*] Use `dict` instead of `Dict` for type annotation
altair\utils\schemapi.py:16:1: UP035 [*] Import from `collections.abc` instead: `Iterable`, `Iterator`, `Mapping`, `Sequence`
altair\utils\schemapi.py:16:1: UP035 `typing.Dict` is deprecated, use `dict` instead
altair\utils\schemapi.py:16:1: UP035 `typing.List` is deprecated, use `list` instead
altair\utils\schemapi.py:70:34: UP006 [*] Use `list` instead of `List` for type annotation
altair\utils\schemapi.py:71:38: UP006 [*] Use `dict` instead of `Dict` for type annotation
altair\utils\schemapi.py:1354:46: UP006 [*] Use `dict` instead of `Dict` for type annotation
altair\utils\schemapi.py:1354:62: UP006 [*] Use `list` instead of `List` for type annotation
altair\utils\selection.py:4:1: UP035 `typing.Dict` is deprecated, use `dict` instead
altair\utils\selection.py:4:1: UP035 `typing.List` is deprecated, use `list` instead
altair\utils\selection.py:8:26: UP006 [*] Use `list` instead of `List` for type annotation
altair\utils\selection.py:8:31: UP006 [*] Use `dict` instead of `Dict` for type annotation
altair\vegalite\v5\api.py:13:1: UP035 [*] Import from `collections.abc` instead: `Sequence`
altair\vegalite\v5\api.py:50:5: UP035 [*] Import from `collections.abc` instead: `Iterable`, `Iterator`
altair\vegalite\v5\api.py:663:26: UP006 [*] Use `list` instead of `t.List` for type annotation
altair\vegalite\v5\schema\_config.py:7:1: UP035 [*] Import from `collections.abc` instead: `Sequence`
altair\vegalite\v5\schema\_typing.py:8:1: UP035 [*] Import from `collections.abc` instead: `Mapping`, `Sequence`
altair\vegalite\v5\schema\_typing.py:35:4: UP036 Version block is outdated for minimum Python version
altair\vegalite\v5\schema\_typing.py:38:5: UP035 [*] Import from `typing` instead: `Annotated`
altair\vegalite\v5\schema\channels.py:14:1: UP035 [*] Import from `collections.abc` instead: `Sequence`
altair\vegalite\v5\schema\core.py:8:1: UP035 [*] Import from `collections.abc` instead: `Iterator`, `Sequence`
altair\vegalite\v5\schema\mixins.py:6:1: UP035 [*] Import from `collections.abc` instead: `Sequence`
sphinxext\code_ref.py:17:5: UP035 [*] Import from `collections.abc` instead: `Iterable`, `Iterator`, `Mapping`, `Sequence`
sphinxext\schematable.py:6:1: UP035 [*] Import from `collections.abc` instead: `Iterator`, `Sequence`
tests\__init__.py:15:5: UP035 [*] Import from `collections.abc` instead: `Collection`, `Iterator`, `Mapping`
tests\expr\test_expr.py:6:1: UP035 [*] Import from `collections.abc` instead: `Iterable`, `Iterator`
tests\utils\test_schemapi.py:13:1: UP035 [*] Import from `collections.abc` instead: `Iterable`, `Sequence`
tools\codemod.py:12:1: UP035 [*] Import from `collections.abc` instead: `Iterable`
tools\codemod.py:25:5: UP035 [*] Import from `collections.abc` instead: `Iterator`
tools\codemod.py:59:4: UP036 Version block is outdated for minimum Python version
tools\generate_api_docs.py:8:1: UP035 [*] Import from `collections.abc` instead: `Iterator`
tools\generate_schema_wrapper.py:15:1: UP035 [*] Import from `collections.abc` instead: `Iterable`, `Iterator`
tools\markup.py:8:1: UP035 [*] Import from `collections.abc` instead: `Iterable`
tools\schemapi\codegen.py:11:1: UP035 [*] Import from `collections.abc` instead: `Iterable`, `Iterator`
tools\schemapi\schemapi.py:14:1: UP035 [*] Import from `collections.abc` instead: `Iterable`, `Iterator`, `Mapping`, `Sequence`
tools\schemapi\schemapi.py:14:1: UP035 `typing.Dict` is deprecated, use `dict` instead
tools\schemapi\schemapi.py:14:1: UP035 `typing.List` is deprecated, use `list` instead
tools\schemapi\schemapi.py:68:34: UP006 [*] Use `list` instead of `List` for type annotation
tools\schemapi\schemapi.py:69:38: UP006 [*] Use `dict` instead of `Dict` for type annotation
tools\schemapi\schemapi.py:1352:46: UP006 [*] Use `dict` instead of `Dict` for type annotation
tools\schemapi\schemapi.py:1352:62: UP006 [*] Use `list` instead of `List` for type annotation
tools\schemapi\utils.py:13:1: UP035 [*] Import from `collections.abc` instead: `Iterable`, `Iterator`, `Mapping`, `Sequence`
tools\update_init_file.py:11:1: UP035 [*] Import from `collections.abc` instead: `Iterable`, `Iterator`
tools\update_init_file.py:21:5: UP006 [*] Use `list` instead of `t.List` for type annotation
tools\update_init_file.py:22:5: UP006 [*] Use `dict` instead of `t.Dict` for type annotation
tools\update_init_file.py:23:5: UP006 [*] Use `tuple` instead of `t.Tuple` for type annotation
tools\vega_expr.py:19:1: UP035 [*] Import from `collections.abc` instead: `Iterable`, `Iterator`, `Mapping`, `Sequence`

>>> ruff check . --config "target-version = 'py39'" --statistics
44      UP035   [ ] deprecated-import
40      UP006   [*] non-pep585-annotation
 2      UP036   [*] outdated-version-block

So it seems like a good time to me to get that ready for 5.5.0 as planned it #3497 (comment)

@mattijn
Copy link
Contributor

mattijn commented Oct 18, 2024

I'm OK with option 5 (from choices 3-5). Option 2 is good as well.

Rather than saying exactly where `name` is **stored**, showing a place it is **used** with an example
- Replaced references to `altair.theme.themes`
- Tried to improve the flow, without entirely removing the term "registry"
@dangotbanned dangotbanned marked this pull request as draft October 18, 2024 15:39
@dangotbanned
Copy link
Member Author

I'm OK with option 5 (from choices 3-5). Option 2 is good as well.

@mattijn thanks for the quick response

I'm having a hard time getting 5 working

There's an example of this in the deprecated package

If I've understood laurent-laporte-pro/deprecated#64 (comment) correctly, this approach doesn't work for action="once"


It isn't a huge job to track (ourselves) if we've served this warning yet.
However, it would require adding some global state - which might not be ideal

@dangotbanned
Copy link
Member Author

@mattijn, as of docs: Add examples to deprecation message, the following message is displayed on first access only to alt.themes:

Warning output

/Temp/ipykernel_9448/3158091034.py:3: AltairDeprecationWarning: Deprecated in `altair=5.5.0`. Use altair.theme instead.
Most cases require only the following change:

    # Deprecated
    alt.themes.enable('quartz')

    # Updated
    alt.theme.enable('quartz')

If your code registers a theme, make the following change:

    # Deprecated
    def custom_theme():
        return {'height': 400, 'width': 700}
    alt.themes.register('theme_name', custom_theme)
    alt.themes.enable('theme_name')

    # Updated
    @alt.theme.register('theme_name', enable=True)
    def custom_theme() -> alt.theme.ThemeConfig:
        return {'height': 400, 'width': 700}

See the updated User Guide for further details:
    https://altair-viz.github.io/user_guide/api.html#theme
    https://altair-viz.github.io/user_guide/customization.html#chart-themes
  alt.themes

Comparing to (#3618 (comment)), the main change was removing:

import altair as alt

It isn't possible to trigger the warning without this import having occurred.
The final line of the warning will point to exactly where accessing the alt namespace happened.


I've got one last thing I'm experimenting with locally, that I hadn't thought of earlier.

Essentially, option 4 from (#3618 (comment)) with two tweaks:

Default visual feedback

image

This would be in addition to the runtime warning for alt.themes.
However, it would mean static-typing users could very clearly see all instances they've used it.

Especially when opting-in to pyright's reportDeprecated rule

[reportDeprecated] feedback

image

Right now I'm working on getting deprecation message to pass through for this case, but still keep the versioning requirement from #3455

If we were to use this, I'd want the message to be more specific than:

The method "register" in class "ThemeRegistry" is deprecated

@mattijn
Copy link
Contributor

mattijn commented Oct 19, 2024

Great! One simple question.
Can we add a new line (\n) to the first line of the warning? Currently the core message is a bit hidden at the end of a very long line.

From current:

/Temp/ipykernel_9448/3158091034.py:3: AltairDeprecationWarning: Deprecated in `altair=5.5.0`. Use altair.theme instead.

To wish:

/Temp/ipykernel_9448/3158091034.py:3: 
AltairDeprecationWarning: Deprecated in `altair=5.5.0`. Use altair.theme instead.

@dangotbanned
Copy link
Member Author

Great! One simple question. Can we add a new line (\n) to the first line of the warning? Currently the core message is a bit hidden at the end of a very long line.

From current:

/Temp/ipykernel_9448/3158091034.py:3: AltairDeprecationWarning: Deprecated in `altair=5.5.0`. Use altair.theme instead.

To wish:

/Temp/ipykernel_9448/3158091034.py:3: 
AltairDeprecationWarning: Deprecated in `altair=5.5.0`. Use altair.theme instead.

@mattijn I would definitely prefer that, but the AltairDeprecationWarning: part is added by warnings.warn itself.

AFAIK, the best we could do is:

/Temp/ipykernel_9448/3158091034.py:3: AltairDeprecationWarning: 
Deprecated in `altair=5.5.0`. Use altair.theme instead.
...

I'm open to changing the format for the part we can control:

def _format_message(
version: LiteralString,
alternative: LiteralString | None,
message: LiteralString | None,
/,
) -> LiteralString:
output = f"Deprecated in `altair={version}`."
if alternative:
output = f"{output} Use {alternative} instead."
return f"{output}\n{message}" if message else output

@mattijn
Copy link
Contributor

mattijn commented Oct 19, 2024

That's also good👍

"` to all deprecation warnings

#3618 (comment), #3618 (comment)
@dangotbanned
Copy link
Member Author

That's also good👍

Fixed in (22d7df2)

Really botched the commit message there, it should be:

docs: Prefix "\n" to all deprecation warnings

@dangotbanned
Copy link
Member Author

dangotbanned commented Oct 19, 2024

Comparison

To reproduce, enable the rule in pyproject.toml:

diff --git a/pyproject.toml b/pyproject.toml
index 2adcd15a..33a89ae3 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -449,6 +449,7 @@ reportTypedDictNotRequiredAccess="none"
 reportIncompatibleMethodOverride="none"
 reportUnusedExpression="none"
 reportUnsupportedDunderAll="none"
+reportDeprecated=true
 include=[
     "./altair/**/*.py",
     "./doc/*.py",

As mentioned in (#3618 (comment)), this is opt-in.

Effectively, just serving this kind of warning to those who want it.
No impact on other users.

Before

See also #3618 (comment)

image

After (25cbdc8)

image

@dangotbanned dangotbanned marked this pull request as ready for review October 19, 2024 17:42
@dangotbanned dangotbanned requested review from mattijn and removed request for mattijn October 19, 2024 18:09
@mattijn
Copy link
Contributor

mattijn commented Oct 19, 2024

Open question, you mention in the deprecation warning: deprecated in v5.5.0, would it make sense to change this into deprecated since v5.5.0?

@dangotbanned
Copy link
Member Author

Open question, you mention in the deprecation warning: deprecated in v5.5.0, would it make sense to change this into deprecated since v5.5.0?

Yeah that makes sense @mattijn

I hadn't noticed the convention before, but you can see it here https://docs.python.org/3/library/importlib.html#module-importlib.machinery

  • Added in ...
  • Changed in ...
  • Deprecated since ...

I'm happy for you to make the change, or I'll update it tomorrow?

@dangotbanned
Copy link
Member Author

@mattijn I've addressed (#3618 (comment)) in (a0497e0)

All of the Unresolved conversations are just to help make the review easier.
You can dismiss once you've seen them to unblock merging

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
deprecation Requires a **MINOR** version bump maintenance
Projects
None yet
2 participants