{"payload":{"feedbackUrl":"https://github.com/orgs/community/discussions/53140","repo":{"id":42757577,"defaultBranch":"main","name":"altair","ownerLogin":"vega","currentUserCanPush":false,"isFork":false,"isEmpty":false,"createdAt":"2015-09-19T03:14:04.000Z","ownerAvatar":"https://avatars.githubusercontent.com/u/11796929?v=4","public":true,"private":false,"isOrgOwned":true},"refInfo":{"name":"","listCacheKey":"v0:1718775942.0","currentOid":""},"activityList":{"items":[{"before":"91a1de17f97d0b1de20724f3cfa771f07741dcc7","after":"403f1fad6db13a3053046340789163ececcf754c","ref":"refs/heads/main","pushedAt":"2024-07-03T15:11:02.000Z","pushType":"pr_merge","commitsCount":1,"pusher":{"login":"binste","name":"Stefan Binder","path":"/binste","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/23366411?s=80&v=4"},"commit":{"message":"feat(typing): Ban `typing.Optional` import using `ruff` (#3460)\n\n* feat(typing): Ban `typing.Optional` import using `ruff`\r\n\r\nThe user will see this message ```\r\naltair\\utils\\data.py:17:5: TID251 `typing.Optional` is banned: Use `Union[T, None]` instead. `typing.Optional` is likely to be confused with `altair.Optional`, which have similar but different semantic meaning. See https://github.com/vega/altair/pull/3449 Found 1 error.\r\n```\r\n\r\nPartial fix for https://github.com/vega/altair/pull/3452#discussion_r1663857513\r\n\r\n* fix: typo in message","shortMessageHtmlLink":"feat(typing): Ban typing.Optional import using ruff (#3460)"}},{"before":"7f05ecbf999766ae1398dcbeb6144c128413026c","after":"91a1de17f97d0b1de20724f3cfa771f07741dcc7","ref":"refs/heads/main","pushedAt":"2024-07-02T18:09:20.000Z","pushType":"pr_merge","commitsCount":1,"pusher":{"login":"binste","name":"Stefan Binder","path":"/binste","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/23366411?s=80&v=4"},"commit":{"message":"feat(typing): adds `Map` alias for `Mapping[str, Any]` and uses it in `Chart.encode` (#3458)\n\nThis allows a `TypedDict` to be used, where `mypy` previously would have required exactly a `dict`.\r\n\r\nThe name is not used anywhere currently in `altair` and has the benefit of being short like `dict`, but more permissive.\r\n\r\nI have only added this to `Chart.encode` as I know this does not require the mutability of `dict`, which I cannot confidently say for elsewhere in `altair`.\r\n\r\nFixes https://github.com/vega/altair/pull/3427#discussion_r1662542866","shortMessageHtmlLink":"feat(typing): adds Map alias for Mapping[str, Any] and uses it in…"}},{"before":"3bea54357d0ea1a108a15d2cf255b8469414ca96","after":"7f05ecbf999766ae1398dcbeb6144c128413026c","ref":"refs/heads/main","pushedAt":"2024-06-30T19:50:25.000Z","pushType":"pr_merge","commitsCount":1,"pusher":{"login":"mattijn","name":"Mattijn van Hoek","path":"/mattijn","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/5186265?s=80&v=4"},"commit":{"message":"docs: Fix `use_signature` formatting issue (#3450)","shortMessageHtmlLink":"docs: Fix use_signature formatting issue (#3450)"}},{"before":"54a68a310f48ba9d2201da1820c4abaf459154aa","after":"3bea54357d0ea1a108a15d2cf255b8469414ca96","ref":"refs/heads/main","pushedAt":"2024-06-30T18:58:17.000Z","pushType":"pr_merge","commitsCount":1,"pusher":{"login":"mattijn","name":"Mattijn van Hoek","path":"/mattijn","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/5186265?s=80&v=4"},"commit":{"message":"fix: remove remapped `ruff` rule `PLR1701` (#3453)","shortMessageHtmlLink":"fix: remove remapped ruff rule PLR1701 (#3453)"}},{"before":"c82f8c270e8d4692a2287482ac78155cea1a35dd","after":"54a68a310f48ba9d2201da1820c4abaf459154aa","ref":"refs/heads/main","pushedAt":"2024-06-28T12:59:15.000Z","pushType":"pr_merge","commitsCount":1,"pusher":{"login":"mattijn","name":"Mattijn van Hoek","path":"/mattijn","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/5186265?s=80&v=4"},"commit":{"message":"Add examples of how to create polar bar charts (#3428)","shortMessageHtmlLink":"Add examples of how to create polar bar charts (#3428)"}},{"before":"79783ef8c482cd62f8132b45ce1c2fae446b38d5","after":"c82f8c270e8d4692a2287482ac78155cea1a35dd","ref":"refs/heads/main","pushedAt":"2024-06-28T12:57:21.000Z","pushType":"pr_merge","commitsCount":1,"pusher":{"login":"mattijn","name":"Mattijn van Hoek","path":"/mattijn","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/5186265?s=80&v=4"},"commit":{"message":"perf: Fix issues with `Chart|LayerChart.encode`, 1.32x speedup to `infer_encoding_types` (#3444)\n\n* fix, doc, perf: Fix issues with `Chart|LayerChart.encode`, 1.33x speedup to `infer_encoding_types`\r\n\r\nFixes:\r\n- [Sphinx warning](https://altair-viz.github.io/user_guide/generated/toplevel/altair.Chart.html#altair.Chart) on `Chart.encode`. Also incorrectly under `Attributes` section\r\n- Preserve static typing previously found in `_encode_signature` but lost after `_EncodingMixin.encode`\r\n - Re-running `mypy` output 'Found 63 errors in 47 files (checked 360 source files)', tests/examples\r\n\r\nPerf:\r\n- This was a response to the `TODO` left at the top of `infer_encoding_types`\r\n- Will be adding the benchmark to the PR description\r\n\r\n* fix(typing): Resolve assignment type errors revealed\r\n\r\nIncompatible types in assignment (expression has type \"Chart\", variable has type \"DataFrame\")\r\n\r\n* fix(typing): Resolve direct arg-type errors revealed\r\n\r\n`Color` -> `Fill` when passed to `fill` channel\r\n\r\n* fix(typing): Resolve `alt.condition` overload-related arg-type errors revealed\r\n\r\n'error: Argument \"color\" to \"encode\" of \"_EncodingMixin\" has incompatible type \"dict[Any, Any] | SchemaBase\"; expected \"str | Color | dict[Any, Any] | ColorDatum | ColorValue | UndefinedType\" [arg-type]'\r\n\r\n* test: update `infer_encoding_types` tests\r\n\r\n- New implementation does not use `**kwargs`, which eliminates an entire class of tests based on `.encode(invalidChannel=...)` as these now trigger a runtime error\r\n\r\n* test: Rename `invalidChannel` to `invalidArgument`\r\n\r\nFixes https://github.com/vega/altair/pull/3444/files/e4ab7052e9a1e62ff1fd80379864489c69a1e020#r1657008627\r\n\r\n* chore: remove PR note comment\r\n\r\nFixes https://github.com/vega/altair/pull/3444#discussion_r1657014594\r\n\r\n* docs: fix typo\r\n\r\n* Exclude LookupData export from core.py to fix issue with mypy where it assumes that altair.LookupData comes from core.py instead of api.py\r\n\r\n* Remove 'pd' and 'jsonschema' from __init__.py __all__. Unclear why they show up only now...\r\n\r\n* Format code\r\n\r\n---------\r\n\r\nCo-authored-by: Stefan Binder \r\nCo-authored-by: Mattijn van Hoek ","shortMessageHtmlLink":"perf: Fix issues with Chart|LayerChart.encode, 1.32x speedup to `in…"}},{"before":"c9106f0f8511a18551a9346f6587ce9799e1532a","after":"79783ef8c482cd62f8132b45ce1c2fae446b38d5","ref":"refs/heads/main","pushedAt":"2024-06-28T11:57:01.000Z","pushType":"pr_merge","commitsCount":1,"pusher":{"login":"binste","name":"Stefan Binder","path":"/binste","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/23366411?s=80&v=4"},"commit":{"message":"docs: Fix and improve `alt.Optional` doc (#3449)","shortMessageHtmlLink":"docs: Fix and improve alt.Optional doc (#3449)"}},{"before":"485eae5d6695645241a35e5f5aa6ef06bdd479d4","after":"c9106f0f8511a18551a9346f6587ce9799e1532a","ref":"refs/heads/main","pushedAt":"2024-06-27T19:19:01.000Z","pushType":"pr_merge","commitsCount":1,"pusher":{"login":"binste","name":"Stefan Binder","path":"/binste","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/23366411?s=80&v=4"},"commit":{"message":"style: Remove outdated comments about the use of the former _Parameter protocol (#3448)","shortMessageHtmlLink":"style: Remove outdated comments about the use of the former _Paramete…"}},{"before":"374a07f0aa7605b1d5ef96f9bfd32d73723f3ca9","after":"485eae5d6695645241a35e5f5aa6ef06bdd479d4","ref":"refs/heads/main","pushedAt":"2024-06-27T15:48:34.000Z","pushType":"pr_merge","commitsCount":1,"pusher":{"login":"binste","name":"Stefan Binder","path":"/binste","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/23366411?s=80&v=4"},"commit":{"message":"refactor: Add `ruff` rules, improve type annotations, improve ci performance (#3431)\n\n* ci: Add additional `ruff` rules to `pyproject.toml`\r\n\r\nOnly highly autofixable groups from [#3430](https://github.com/vega/altair/issues/3430).\r\nAiming to refine further, depending on how much manual fixing this generates.\r\n\r\n* fix: add item to `pyproject.toml` to silence import errors for `pylance|pyright`\r\n\r\n* ci: add subset of `SIM` to `extend-safe-fixes`\r\n\r\n* ci: add unfixable `RUF` rules to `ignore`\r\n\r\n[RUF002](https://docs.astral.sh/ruff/rules/ambiguous-unicode-character-docstring/) may be avoidable during schema generation, so I'm not doing any manual fixes right now.\r\n\r\n* refactor: apply new `ruff` rules, fix and reformat\r\n\r\n* test: Skip tests on Win that require a tz database\r\n\r\nSee https://github.com/apache/arrow/pull/36996\r\n\r\n* ci: enable `tool.ruff.lint.preview`\r\n\r\nTesting the effect this has with existing rules, prior to adding `pylint`, `refurb`\r\n\r\n* fix: replace [F841](https://docs.astral.sh/ruff/rules/unused-variable/) violations with dummy variable\r\n\r\n* ci: add additional `preview` fixes to `extend-safe-fixes`\r\n\r\n* refactor: apply `preview` fixes for existing `ruff` rules, reformat\r\n\r\n* ci: add `preview` category `FURB` rules\r\n\r\nAlmost all have autofixes, splitting out from [pylint](https://docs.astral.sh/ruff/rules/#pylint-pl) which is much larger in scope + fewer fixes\r\n\r\n* refactor: apply `FURB` rule fixes, manually fix `FURB101/3`\r\n\r\n* fix: Revert newer fstring syntax, not available to `sphinx`\r\n\r\n* ci: add fixable `pylint` rules\r\n\r\nAcross the 4 `PL.` categories, there are over 50 rules, with a mix of fixable, preview.\r\nTried to be picky with what is added, because adding even 1 of the groups would generate a lot of manual fixes.\r\n\r\n* ci: add `pylint` fixes to `extend-safe-fixes`\r\n\r\n* refactor: apply `pylint` rule fixes, add an inline optimization for `_selection`\r\n\r\n`param_kwds` in `_selection` triggered `PLR6201`. Instead rewrote as a dictcomp.\r\n\r\n* fix: Recover comments lost during linting\r\n\r\nhttps://github.com/vega/altair/pull/3431#discussion_r1628051704\r\n\r\n* fix: Replace sources of `RUF002` violations\r\n\r\n* fix: manual fix `RUF002` in `api`\r\n\r\n* ci: add `PTH` rules\r\n\r\n`flake8-use-pathlib` rules all require manual fixes.\r\n> Found 70 errors.\r\n\r\n
\r\nDetails\r\n\r\n```md\r\n20 PTH118 `os.path.join()` should be replaced by `Path` with `/` operator\r\n12 PTH120 `os.path.dirname()` should be replaced by `Path.parent`\r\n11 PTH100 `os.path.abspath()` should be replaced by `Path.resolve()`\r\n11 PTH123 `open()` should be replaced by `Path.open()`\r\n 7 PTH110 `os.path.exists()` should be replaced by `Path.exists()`\r\n 6 PTH107 `os.remove()` should be replaced by `Path.unlink()`\r\n 3 PTH103 `os.makedirs()` should be replaced by `Path.mkdir(parents=True)`\r\n```\r\n\r\n* refactor: Manually fix `PTH` rule violations\r\n\r\n* fix: Use safer `inspect.getattr_static` in `update_init_file`\r\n\r\nAvoids [triggering](https://docs.python.org/3/library/inspect.html#inspect.getattr_static) on objects like `datum`, `expr`\r\n\r\n* fix: Use correct f-string `!s` modifier\r\n\r\n* fix: Resolve `doc:build-html` error\r\n\r\n```log\r\nExtension error (sphinxext.altairgallery): Handler for event 'builder-inited' threw an exception (exception: unsupported operand type(s) for +: 'PosixPath' and 'str')\r\n```\r\n\r\n* fix: Resolve utf-8 error for [emoji example](https://altair-viz.github.io/gallery/isotype_emoji.html)\r\n\r\n* Update sphinxext/altairgallery.py\r\n\r\nCo-authored-by: Stefan Binder \r\n\r\n* build: bump `docbuild.yml` python `3.10` -> `3.12`\r\n\r\nSee @binste [comment](https://github.com/vega/altair/pull/3431#discussion_r1629789905)\r\n\r\n* style: Simplify `PluginRegistry` repr\r\n\r\nhttps://github.com/vega/altair/pull/3431#discussion_r1629815064\r\n\r\n* revert: ignore `suppressible-exception` rule in `pyproject.toml`\r\n\r\nhttps://github.com/vega/altair/pull/3431#discussion_r1629808660\r\n\r\n* refactor: remove need for exception handling in `utils._vegafusion_data.get_inline_tables`\r\n\r\nI'm happy to revert back to the original `try-catch`, but think it was less both less efficient and understandable.\r\n\r\nIf I've understood correctly:\r\n- Every time this was called, all tables would be iterated over\r\n- On the first call, tables processed by the `vegafusion_data_transformer` would popped and returned\r\n- On all calls, other tables would be ignored but always trigger exceptions\r\n- On any call other than the first, every table triggers an exception\r\n\r\nThis behaviour is easily reduced using [set methods](https://docs.python.org/3/library/stdtypes.html#set) directly, as an empty `set` would produce an empty `dict` during the `dictcomp`.\r\n\r\nhttps://github.com/vega/altair/pull/3431#discussion_r1629808660\r\n\r\n* refactor: remove `python<3.3` compat code in `utils.core.use_signature`\r\n\r\nWas replaced with `contextlib.suppress` in a3fd77ab32f927fd37068e18028ac0cc4192c5a2 but targets long-unsupported python versions.\r\n\r\nFor future reference, there are also related `stdlib` functions that may have not been available when this was written:\r\n- [inspect.getdoc](https://docs.python.org/3/library/inspect.html#inspect.getdoc)\r\n- [functools.wraps](https://docs.python.org/3/library/functools.html#functools.wraps)\r\n\r\nWouldn't cover everything there, but may replace the need for some parts.\r\n\r\nhttps://github.com/vega/altair/pull/3431#discussion_r1629808660\r\n\r\n* revert: replace `PLW1514` fixes with \"utf-8\"\r\n\r\nThe rule remains in `pyproject.toml`, but is no longer autofixed with undesirable `locale.getprefferedencoding(False)`.\r\n\r\nhttps://github.com/vega/altair/pull/3431#discussion_r1629811197\r\n\r\n* refactor: minor simplify and sort `__all__` from `generate_schema_wrapper`\r\n\r\n* docs: `FA100` on most of `tools/`*`\r\n\r\nThe start of a cautious introduction of `from __future__ import annotations`.\r\nExcludes `schemaapi.schemaapi.py` for now, but I think that would be safe as well.\r\n\r\n* docs: `FA100` on `sphinxext/*`\r\n\r\n* docs: `FA100` on `alt.jupyter`\r\n\r\n* docs: `FA100` on `alt.expr`\r\n\r\n* docs: `FA100` on `alt.vegalite`, excluding `v5.api`, `v5.schema/*`\r\n\r\n- Covers non-autogenerated code.\r\n- `api` is being special-cased for now.\r\n - Will be a great candidate for these fixes, but there are many simpler modules in `alt.utils` that I'm priotizing in case they highlight issues\r\n\r\n* docs: `FA100` on private `alt.utils` modules\r\n\r\n* docs(typing): Add annotations for `sphinxext`\r\n\r\n- Making use of `FA100` enabled syntax\r\n- Eventually would like to improve the performance of this, since `sphinxext` is by far the longest build step\r\n- Towards that end, the annotations give a contextual starting point\r\n\r\n* docs: `FA100` on public `alt.utils` modules, excluding `schemapi`\r\n\r\n- Also did made some improvements to annotations more broadly, now that the newer syntax is allowed\r\n\r\n* ci: update `pyproject.toml`, add new granular `tool.ruff.lint.per-file-ignores` setting\r\n\r\n- So far been making the changes one file at a time, followed by tests\r\n- Not encountered any runtime issues\r\n- `mypy` has complained occasionally, but has been resolvable\r\n\r\n* revert: Change `write_file_or_filename` default `encoding` to `None`\r\n\r\n* docs: `FA100` on `tools.schemapi.schemapi`\r\n\r\nAlso adds some annotations that are now possible without circular import concerns\r\n\r\n* feat(typing): add `from __future__ import annotations` for each file in `generate_schema_wrapper`\r\n\r\nAlso:\r\n- ensure `annotations` excluded from `__all__`\r\n- minor standardizing import order\r\n- adjust `ruff` rules to correct schemagen\r\n\r\n* ci(typing): adds `generate-schema-wrapper` script to `hatch`\r\n\r\nRewrites and reformats all annotations in `altair/vegalite/v?/schema`\r\n- Meaning that the original code stays the same:\r\n\r\n```\r\n>>> ruff check altair/vegalite/v?/schema --fix --exit-zero\r\nFound 13006 errors (13006 fixed, 0 remaining).\r\n>>> ruff format altair/vegalite/v?/schema\r\n4 files reformatted\r\n>>> ruff check altair/vegalite/v?/schema --statistics\r\n```\r\n\r\n* refactor(typing): Improve annotations and narrowing in `schemapi`\r\n\r\n- Changes are mainly on `_FromDict.from_dict`\r\n - Avoids type errors due to multiple reassignments\r\n - Adds a range of overloads that preserve the `SchemaBase` subclass\r\n - Not possible in all cases\r\n - replacing `cls` with `tp` - when used in an instance method\r\n - The former is quite strange to see outside of a `@classmethod`\r\n - Especially in a class that has a `@classmethod`\r\n- updated `_default_wrapper_classes` to match `_subclasses` return type in `generate_schema_wrapper`\r\n\r\n* build: run `generate-schema-wrapper`\r\n\r\nThe cumulative effect of `FA100`, `UP`, `TCH` rules applied to `v5.schema`.\r\n\r\nAll tests pass!\r\n\r\n* revert(typing): Roll back runtime evaluated types not possible on older python\r\n\r\n`from __future__ import annotations` applies in annotation scope, but not in aliases. Until `altair` requires `python>=3.9-10`, some syntax will need to differ - like many of the changes seen in this commit.\r\n\r\n# Note\r\nThe current `ruff` config will only upgrade syntax in annotation scope, until `tool.ruff.target-version` \"unlocks\" new features. These were changes I made manually, not having tested against all versions - which are being reverted.\r\n\r\n* fix(typing): Adds overloads and reduce ignore comments relating to `spec_to_mimebundle`\r\n\r\nThe repetition in `utils.save` is unfortunate, but is required to satisfy mypy. The issues are from overloading `spec_to_mimebundle` with `tuple/dict` as each has different indexing constraints.\r\n\r\nA longer term solution would be to adding an intermediate function to return the nested value. Due to `spec_to_mimebundle`'s use elsewhere operating directly on the full output.\r\n\r\n* revert(typing): Roll back additional runtime evaluated types for `python=3.8`\r\n\r\n* fix(typing): Use `...` for `DataTransformerType`\r\n\r\nOriginal `pass` keyword was equivalent to a `None` return\r\n\r\n* docs(typing): `FA100` on `alt.vegalite.v5.api` and manual annotation rewrites\r\n\r\n### `api`\r\nA unique, but significant, difference to the other commits is the large number of module prefixed annotations that can be shortened.\r\n`TopLevelMixin.project` shows the greatest reduction in combined characters for annotations, but there are small improvements throughout.\r\n\r\nI've made all of these `TYPE_CHECKING`-only imports explicit, to highlight a new path forward this opens up. There are many repeat/similar `Union` types, which can now be declared in another module - without concern for circular import issues.\r\n\r\n### `v5.__init__`\r\nThese changes have also removed the need for both the import of `expr` in `api`, and the `# type: ignore[no-redef]` in `v5.__init__`.\r\n\r\n* test: add pytest rules `PT` and fix `PT001` violations\r\n\r\nhttps://docs.astral.sh/ruff/rules/pytest-fixture-incorrect-parentheses-style/\r\n\r\n* test: add ignores for `PT011` on existing tests\r\n\r\nProbably useful to enforce on new code, https://docs.astral.sh/ruff/rules/pytest-raises-too-broad/\r\n\r\n* test: fix `PT018` violation\r\n\r\nhttps://docs.astral.sh/ruff/rules/pytest-composite-assertion/\r\n\r\n* test: fix `PT006` violations\r\n\r\nhttps://docs.astral.sh/ruff/rules/pytest-parametrize-names-wrong-type/\r\n\r\n* test: add ignore for `PT012` violation\r\n\r\nNot sure how this could be rewritten. https://docs.astral.sh/ruff/rules/pytest-raises-with-multiple-statements/\r\n\r\n* test: add `pytest.mark.xfail` for flaky `scatter_with_layered_histogram` test\r\n\r\nStruggling to find the source of the failure, the `mark` is my best guess but currently can't reproduce the following error:\r\n\r\n```\r\n___________________________________________ test_compound_chart_examples[False-scatter_with_layered_histogram.py-all_rows18-all_cols18] ___________________________________________\r\n[gw2] win32 -- Python 3.8.19 C:\\Users\\*\\AppData\\Local\\hatch\\env\\virtual\\altair\\CXM7NV9I\\hatch-test.py3.8\\Scripts\\python.exe\r\n\r\nfilename = 'scatter_with_layered_histogram.py', all_rows = [2, 17], all_cols = [['gender'], ['__count']], to_reconstruct = False\r\n\r\n @pytest.mark.skipif(vf is None, reason=\"vegafusion not installed\")\r\n # fmt: off\r\n @pytest.mark.parametrize(\"filename,all_rows,all_cols\", [\r\n (\"errorbars_with_std.py\", [10, 10], [[\"upper_yield\"], [\"extent_yield\"]]),\r\n (\"candlestick_chart.py\", [44, 44], [[\"low\"], [\"close\"]]),\r\n (\"co2_concentration.py\", [713, 7, 7], [[\"first_date\"], [\"scaled_date\"], [\"end\"]]),\r\n (\"falkensee.py\", [2, 38, 38], [[\"event\"], [\"population\"], [\"population\"]]),\r\n (\"heat_lane.py\", [10, 10], [[\"bin_count_start\"], [\"y2\"]]),\r\n (\"histogram_responsive.py\", [20, 20], [[\"__count\"], [\"__count\"]]),\r\n (\"histogram_with_a_global_mean_overlay.py\", [9, 1], [[\"__count\"], [\"mean_IMDB_Rating\"]]),\r\n (\"horizon_graph.py\", [20, 20], [[\"x\"], [\"ny\"]]),\r\n (\"interactive_cross_highlight.py\", [64, 64, 13], [[\"__count\"], [\"__count\"], [\"Major_Genre\"]]),\r\n (\"interval_selection.py\", [123, 123], [[\"price_start\"], [\"date\"]]),\r\n (\"layered_chart_with_dual_axis.py\", [12, 12], [[\"month_date\"], [\"average_precipitation\"]]),\r\n (\"layered_heatmap_text.py\", [9, 9], [[\"Cylinders\"], [\"mean_horsepower\"]]),\r\n (\"multiline_highlight.py\", [560, 560], [[\"price\"], [\"date\"]]),\r\n (\"multiline_tooltip.py\", [300, 300, 300, 0, 300], [[\"x\"], [\"y\"], [\"y\"], [\"x\"], [\"x\"]]),\r\n (\"pie_chart_with_labels.py\", [6, 6], [[\"category\"], [\"value\"]]),\r\n (\"radial_chart.py\", [6, 6], [[\"values\"], [\"values_start\"]]),\r\n (\"scatter_linked_table.py\", [392, 14, 14, 14], [[\"Year\"], [\"Year\"], [\"Year\"], [\"Year\"]]),\r\n (\"scatter_marginal_hist.py\", [34, 150, 27], [[\"__count\"], [\"species\"], [\"__count\"]]),\r\n (\"scatter_with_layered_histogram.py\", [2, 17], [[\"gender\"], [\"__count\"]]),\r\n (\"scatter_with_minimap.py\", [1461, 1461], [[\"date\"], [\"date\"]]),\r\n (\"scatter_with_rolling_mean.py\", [1461, 1461], [[\"date\"], [\"rolling_mean\"]]),\r\n (\"seattle_weather_interactive.py\", [1461, 5], [[\"date\"], [\"__count\"]]),\r\n (\"select_detail.py\", [20, 1000], [[\"id\"], [\"x\"]]),\r\n (\"simple_scatter_with_errorbars.py\", [5, 5], [[\"x\"], [\"upper_ymin\"]]),\r\n (\"stacked_bar_chart_with_text.py\", [60, 60], [[\"site\"], [\"site\"]]),\r\n (\"us_employment.py\", [120, 1, 2], [[\"month\"], [\"president\"], [\"president\"]]),\r\n (\"us_population_pyramid_over_time.py\", [19, 38, 19], [[\"gender\"], [\"year\"], [\"gender\"]]),\r\n ])\r\n # fmt: on\r\n @pytest.mark.parametrize(\"to_reconstruct\", [True, False])\r\n def test_compound_chart_examples(filename, all_rows, all_cols, to_reconstruct):\r\n source = pkgutil.get_data(examples_methods_syntax.__name__, filename)\r\n chart = eval_block(source)\r\n if to_reconstruct:\r\n # When reconstructing a Chart, Altair uses different classes\r\n # then what might have been originally used. See\r\n # https://github.com/hex-inc/vegafusion/issues/354 for more info.\r\n chart = alt.Chart.from_dict(chart.to_dict())\r\n dfs = chart.transformed_data()\r\n\r\n if not to_reconstruct:\r\n # Only run assert statements if the chart is not reconstructed. Reason\r\n # is that for some charts, the original chart contained duplicated datasets\r\n # which disappear when reconstructing the chart.\r\n assert len(dfs) == len(all_rows)\r\n for df, rows, cols in zip(dfs, all_rows, all_cols):\r\n> assert len(df) == rows\r\nE assert 19 == 17\r\nE + where 19 = len( bin_step_5_age bin_step_5_age_end gender __count\\n0 45.0 50.0 M 247\\n1 ... 11\\n17\r\n 30.0 35.0 F 5\\n18 70.0 75.0 F 1)\r\n\r\ntests\\test_transformed_data.py:132: AssertionError\r\n```\r\n\r\n* ci: tidy up `ruff` section of `pyproject.toml`\r\n\r\n- removed `SIM` rules from `extend-safe-fixes`, only 1 required it and manual fixes should be fine for new code\r\n- Provided links for new config groups/settings\r\n\r\nhttps://github.com/vega/altair/pull/3431#discussion_r1629824002\r\n\r\n* perf: adds config `pyproject.toml` for faster build, test runs\r\n\r\n- `pip` -> `uv`\r\n- `pytest` single-core -> logical max\r\n\r\nhttps://hatch.pypa.io/latest/how-to/environment/select-installer/#enabling-uv\r\nhttps://pytest-xdist.readthedocs.io/en/latest/distribution.html#running-tests-across-multiple-cpus\r\n\r\nShould speed up CI, although GitHub Actions only runs on 4 cores iirc\r\n\r\n* ci: adds `update-init-file` hatch script\r\n\r\n* ci: adds newer-style `hatch` test config\r\n\r\nI've attempted to recreate the existing `test` scripts, but haven't quite worked out the `coverage` parts.\r\n\r\nThis provides: matrix python version testing, parallel tests (within a python version), and slightly shorter commands:\r\n```bash\r\n>>> hatch run test\r\n>>> hatch test\r\n\r\n>>> hatch run test-coverage\r\n>>> hatch test --cover\r\n```\r\n\r\n* feat(typing): Use `TYPE_CHECKING` block for `schema` modules\r\n\r\n- Removes the need for `_Parameter` protocol\r\n- Reduce lines of code by more than 5000, by removing prefix for `SchemaBase`, `Parameter`\r\n\r\n* test: use a more reliable `xfail` condition for flaky test\r\n\r\nThe difficulty in reproducing came from the python debugger disabling `xdist`.\r\n\r\n* build: Embed extra `ruff` calls in `generate-schema-wrapper` into the python script\r\n\r\nHopefully solves: https://github.com/vega/altair/actions/runs/9456437889/job/26048327764?pr=3431\r\n\r\n* build: Manually rewrite certain exceptions with flaky autofix\r\n\r\nThese were previously fixed by `EM` rules, but seem to not always occur - leading to CI fail\r\n\r\nhttps://github.com/vega/altair/actions/runs/9466550650/job/26078482982#step:8:60\r\n\r\n* refactor: remove now-unneeded `PARAMETER_PROTOCOL`\r\n\r\n* refactor: replace existing references to `typing.Optional`\r\n\r\n* refactor(typing): rename `T` TypeVar to `TSchemaBase`\r\n\r\n* feat(typing): Adds dedicated `Optional` alias for `Union[..., UndefinedType]`\r\n\r\n`typing.Optional` is deprecated and is no longer needed in `altair`. The new alias improves the readability of generated signatures, by reducing noise (repeating `UndefinedType`) and clearly grouping together the options for an argument.\r\n\r\n* refactor(typing): Remove `UndefinedType` dependency in `api`\r\n\r\n* refactor(typing): Remove `UndefinedType` dependency in `api`\r\n\r\n* refactor(typing): Remove annotation scope `UndefinedType` dependency in `api`\r\n\r\nAligns `api` with `schema` changes in fbc02e2d577a46509436ae6f40b9b56035e996c8\r\n\r\n* ci: add `W291` to ensure trailing whitespace is autofixed\r\n\r\n* refactor: define non-relevant attributes closer to imports in `update_init_file`\r\n\r\nWill make it easier to keep the two in sync, and now they can be copy/pasted - rather than adding an `or attr is _` expression\r\n\r\n* feat(typing): Adds `_TypeAliasTracer` and reorders `generate_schema_wrapper` to collect unique `Literal` types\r\n\r\nThe next commit will show the changes from build\r\n\r\n* build: run `generate-schema-wrapper` using `_TypeAliasTracer`\r\n\r\nThis commit reduces the length of each module in `schema` by ~50-70% and provides the each alias in the new `_typing` module.\r\n\r\n## Existing art\r\n[`pandas`](https://github.com/pandas-dev/pandas/blob/main/pandas/core/frame.py#L199) and [`polars`](https://github.com/pola-rs/polars/blob/faf0f061eead985a8b29e4584b619fb5d8647e31/py-polars/polars/dataframe/frame.py#L105) similarly define a large number of `TypeAlias`, `Union`, `Literal` types in a single file. These definitions can be imported anywhere in the project - without concern for circular dependencies. It helps keep signatures consistent, and in many cases, simplifies those signatures such that the user can quickly understand what they represent.\r\n\r\n## Future config\r\nThe generated names are currently:\r\n```py\r\nf\"{SchemaInfo.title}_T\"\r\n```\r\nso as to not conflict with the names defined in `core`/`channels`.\r\nI have left this configurable via:\r\n```py\r\n_TypeAliasTracer(fmt=...)\r\n```\r\n\r\nPersonally don't mind what the aliases are called, so if anyone has any ideas please feel free to change.\r\n\r\n* fix: Add missing `LiteralString` import\r\n\r\n* test: add `pytest.mark.filterwarnings` for tests that cannot avoid them\r\n\r\n- `pandas` warnings cannot trivially be avoided, as they need to be compatible with `pandas~=0.25` and are used in examples.\r\n- I have been unable to track down what specific calls are triggering the `traitlets` warnings. There seems to be multiple levels of indirection, but the stacklevel reported is external to `altair`.\r\n\r\n* refactor(typing): Replace `Literal[None]` -> `None`\r\n\r\nCame across [Literal[None] conversion](https://typing.readthedocs.io/en/latest/spec/literal.html#legal-parameters-for-literal-at-type-check-time) during https://github.com/vega/altair/pull/3426#discussion_r1638279005\r\n\r\n* test: Change `skipif` -> `xfail` for `test_sanitize_pyarrow_table_columns` on `win32`\r\n\r\nSeems to be a better fit, considering this would fail for `win32` devs not using `pyarrow` but have it installed.\r\nThis could be removed in the future if installing/confirming install `tzdata` to the correct location was handled during environment activation.\r\n\r\nPossibly resolves: https://github.com/vega/altair/pull/3431#discussion_r1631904170\r\n\r\n* ci: bump `actions/setup-python`, `python-version`, use `uv` in `lint.yml`\r\n\r\nI've made quite a few improvements to performance locally like fd20f00ec4e990cf8255751942a14f97084e05b1, but only `docbuild.yml` uses `hatch` so they haven't reduced CI run time.\r\n\r\nThis is more of a test run on the simplest workflow to identify any issues.\r\n\r\n* ci: create venv before uv pip install\r\n\r\n* ci: ensure venv is activated after install\r\n\r\n* ci: use environment provided by `hatch`\r\n\r\n* ci: testing `pytest-xdist` in `build` workflow\r\n\r\nWould be faster if using `uv`/`hatch` instead of `pip` - but I'm not sure how to untangle `pip` from this yet.\r\n\r\n* test(perf): adds significant parallelism for slow `test_examples`\r\n\r\nhttps://github.com/vega/altair/pull/3431#issuecomment-2168508048\r\n\r\n* refactor, perf: reduce `sys.path` usage, use dictcomp in `update_init_file`\r\n\r\n# `sys.path`\r\nMainly modules in `tools`, but also `tests`, `sphinxext` repeat the same pattern of manipulating `sys.path` to find imports.\r\nIn some cases, I think this wasn't need at all - but others were resolves by adding `tools.__init__.py`.\r\n\r\n- Aligns with many of the other sub/packages\r\n- Removes need for ignoring `E402`\r\n- Makes many of the imports in these modules explicit, and therefore easier to follow.\r\n\r\n# `update_init_file`\r\nWhile rewriting the imports here, I saw an opportunity to simplify gathering relevant attributes.\r\n\r\n- `attr = getattr(alt, attr_name)` using the keys of `__dict__`, was a slow equivalent of a dictionary comprehension.\r\n- `str(Path(alt.__file__).parent)` is a verbose `str(Path.cwd())`\r\n - An earlier commit of mine used this instead of `os.path`\r\n - This version is much shorter and obvious in what it does\r\n\r\n* build: adding debug message to help with build failure\r\n\r\nThe previous run worked locally due to `hatch` managing `sys.path` - but not in CI, which doesn't use hatch yet\r\n\r\n https://github.com/vega/altair/actions/runs/9527747043/job/26264700374\r\n\r\n* build: add cwd to debug message\r\n\r\n* fix: possibly fix cwd not on path\r\n\r\n* ci: testing invoking script with `-m` for cwd\r\n\r\n* fix: remove debug code\r\n\r\n* fix: resolve lint, format, type conflicts following rebase\r\n\r\nFixes https://github.com/vega/altair/actions/runs/9581196541/job/26417448238?pr=3431\r\n\r\n* DO NOT MERGE - TESTING DOC PERF\r\n\r\n* revert: undo last commit\r\n\r\nIntended to discard the changes, but accidentally pushed\r\n\r\n* refactor: Remove commented out dead code\r\n\r\nFixes https://github.com/vega/altair/pull/3431#discussion_r1657104259\r\n\r\n* ci: Remove extra whitespace in `build.yml`\r\n\r\nFixes https://github.com/vega/altair/pull/3431#discussion_r1657095337\r\n\r\n---------\r\n\r\nCo-authored-by: Stefan Binder ","shortMessageHtmlLink":"refactor: Add ruff rules, improve type annotations, improve ci perf…"}},{"before":"6b5a867983c3f8fb0407bc44778e0b9c1ee21d76","after":"374a07f0aa7605b1d5ef96f9bfd32d73723f3ca9","ref":"refs/heads/main","pushedAt":"2024-06-27T14:25:20.000Z","pushType":"pr_merge","commitsCount":1,"pusher":{"login":"binste","name":"Stefan Binder","path":"/binste","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/23366411?s=80&v=4"},"commit":{"message":"chore: avoid pandas warning for freq='H' in test_utils.py","shortMessageHtmlLink":"chore: avoid pandas warning for freq='H' in test_utils.py"}},{"before":"76a9ce1e27a21359e7b0ef9e6cb865f8d95fc298","after":"6b5a867983c3f8fb0407bc44778e0b9c1ee21d76","ref":"refs/heads/main","pushedAt":"2024-06-26T20:52:15.000Z","pushType":"pr_merge","commitsCount":1,"pusher":{"login":"mattijn","name":"Mattijn van Hoek","path":"/mattijn","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/5186265?s=80&v=4"},"commit":{"message":"docs: Add example of cumulative line chart with facet (#3440)","shortMessageHtmlLink":"docs: Add example of cumulative line chart with facet (#3440)"}},{"before":"9e2762c6ac9636fd9a3f9e919d33863cf0ce5a18","after":"76a9ce1e27a21359e7b0ef9e6cb865f8d95fc298","ref":"refs/heads/main","pushedAt":"2024-06-19T08:54:24.000Z","pushType":"pr_merge","commitsCount":1,"pusher":{"login":"mattijn","name":"Mattijn van Hoek","path":"/mattijn","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/5186265?s=80&v=4"},"commit":{"message":"refactor: Remove `toolz` dependency (#3426)","shortMessageHtmlLink":"refactor: Remove toolz dependency (#3426)"}},{"before":"f99282bb9f98cb39d73e207159b18d6eba4a645d","after":null,"ref":"refs/heads/dependabot/github_actions/github-actions-f039b2dc45","pushedAt":"2024-06-19T05:45:42.000Z","pushType":"branch_deletion","commitsCount":0,"pusher":{"login":"dependabot[bot]","name":null,"path":"/apps/dependabot","primaryAvatarUrl":"https://avatars.githubusercontent.com/in/29110?s=80&v=4"}},{"before":"22dcfeaf20a2dd33f60d7c33bf67be77e81b37a6","after":"9e2762c6ac9636fd9a3f9e919d33863cf0ce5a18","ref":"refs/heads/main","pushedAt":"2024-06-19T05:45:34.000Z","pushType":"pr_merge","commitsCount":1,"pusher":{"login":"mattijn","name":"Mattijn van Hoek","path":"/mattijn","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/5186265?s=80&v=4"},"commit":{"message":"Bump the github-actions group with 2 updates (#3439)\n\nBumps the github-actions group with 2 updates: [actions/checkout](https://github.com/actions/checkout) and [actions/setup-python](https://github.com/actions/setup-python).\r\n\r\n\r\nUpdates `actions/checkout` from 3 to 4\r\n- [Release notes](https://github.com/actions/checkout/releases)\r\n- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)\r\n- [Commits](https://github.com/actions/checkout/compare/v3...v4)\r\n\r\nUpdates `actions/setup-python` from 4 to 5\r\n- [Release notes](https://github.com/actions/setup-python/releases)\r\n- [Commits](https://github.com/actions/setup-python/compare/v4...v5)\r\n\r\n---\r\nupdated-dependencies:\r\n- dependency-name: actions/checkout\r\n dependency-type: direct:production\r\n update-type: version-update:semver-major\r\n dependency-group: github-actions\r\n- dependency-name: actions/setup-python\r\n dependency-type: direct:production\r\n update-type: version-update:semver-major\r\n dependency-group: github-actions\r\n...\r\n\r\nSigned-off-by: dependabot[bot] \r\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>","shortMessageHtmlLink":"Bump the github-actions group with 2 updates (#3439)"}},{"before":"44b8feba755a65b49a4d3e8603e359b8bf20c50c","after":"f99282bb9f98cb39d73e207159b18d6eba4a645d","ref":"refs/heads/dependabot/github_actions/github-actions-f039b2dc45","pushedAt":"2024-06-19T05:35:27.000Z","pushType":"force_push","commitsCount":0,"pusher":{"login":"dependabot[bot]","name":null,"path":"/apps/dependabot","primaryAvatarUrl":"https://avatars.githubusercontent.com/in/29110?s=80&v=4"},"commit":{"message":"Bump the github-actions group with 2 updates\n\nBumps the github-actions group with 2 updates: [actions/checkout](https://github.com/actions/checkout) and [actions/setup-python](https://github.com/actions/setup-python).\n\n\nUpdates `actions/checkout` from 3 to 4\n- [Release notes](https://github.com/actions/checkout/releases)\n- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/actions/checkout/compare/v3...v4)\n\nUpdates `actions/setup-python` from 4 to 5\n- [Release notes](https://github.com/actions/setup-python/releases)\n- [Commits](https://github.com/actions/setup-python/compare/v4...v5)\n\n---\nupdated-dependencies:\n- dependency-name: actions/checkout\n dependency-type: direct:production\n update-type: version-update:semver-major\n dependency-group: github-actions\n- dependency-name: actions/setup-python\n dependency-type: direct:production\n update-type: version-update:semver-major\n dependency-group: github-actions\n...\n\nSigned-off-by: dependabot[bot] ","shortMessageHtmlLink":"Bump the github-actions group with 2 updates"}},{"before":"596b28224b36a72b7f32808d2c00e85ba5446533","after":"22dcfeaf20a2dd33f60d7c33bf67be77e81b37a6","ref":"refs/heads/main","pushedAt":"2024-06-19T05:34:55.000Z","pushType":"pr_merge","commitsCount":1,"pusher":{"login":"mattijn","name":"Mattijn van Hoek","path":"/mattijn","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/5186265?s=80&v=4"},"commit":{"message":"Update dependabot.yaml (#3442)","shortMessageHtmlLink":"Update dependabot.yaml (#3442)"}},{"before":null,"after":"672fd6689b38f26812d84293af110f38cb7178c1","ref":"refs/heads/add-prefix-to-dependabot","pushedAt":"2024-06-19T05:15:39.000Z","pushType":"branch_creation","commitsCount":0,"pusher":{"login":"mattijn","name":"Mattijn van Hoek","path":"/mattijn","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/5186265?s=80&v=4"},"commit":{"message":"Update dependabot.yaml","shortMessageHtmlLink":"Update dependabot.yaml"}},{"before":null,"after":"44b8feba755a65b49a4d3e8603e359b8bf20c50c","ref":"refs/heads/dependabot/github_actions/github-actions-f039b2dc45","pushedAt":"2024-06-18T15:46:53.000Z","pushType":"branch_creation","commitsCount":0,"pusher":{"login":"dependabot[bot]","name":null,"path":"/apps/dependabot","primaryAvatarUrl":"https://avatars.githubusercontent.com/in/29110?s=80&v=4"},"commit":{"message":"Bump the github-actions group with 2 updates\n\nBumps the github-actions group with 2 updates: [actions/checkout](https://github.com/actions/checkout) and [actions/setup-python](https://github.com/actions/setup-python).\n\n\nUpdates `actions/checkout` from 3 to 4\n- [Release notes](https://github.com/actions/checkout/releases)\n- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/actions/checkout/compare/v3...v4)\n\nUpdates `actions/setup-python` from 4 to 5\n- [Release notes](https://github.com/actions/setup-python/releases)\n- [Commits](https://github.com/actions/setup-python/compare/v4...v5)\n\n---\nupdated-dependencies:\n- dependency-name: actions/checkout\n dependency-type: direct:production\n update-type: version-update:semver-major\n dependency-group: github-actions\n- dependency-name: actions/setup-python\n dependency-type: direct:production\n update-type: version-update:semver-major\n dependency-group: github-actions\n...\n\nSigned-off-by: dependabot[bot] ","shortMessageHtmlLink":"Bump the github-actions group with 2 updates"}},{"before":"e8817a8ded3df9341c8109d9b978bc7ebedde679","after":"596b28224b36a72b7f32808d2c00e85ba5446533","ref":"refs/heads/main","pushedAt":"2024-06-18T15:46:26.000Z","pushType":"pr_merge","commitsCount":1,"pusher":{"login":"mattijn","name":"Mattijn van Hoek","path":"/mattijn","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/5186265?s=80&v=4"},"commit":{"message":"ci: Add a Dependabot config to auto-update GitHub action versions (#3437)","shortMessageHtmlLink":"ci: Add a Dependabot config to auto-update GitHub action versions (#3437"}},{"before":"18a2c3c237014591d172284560546a2f0ac1a883","after":"e8817a8ded3df9341c8109d9b978bc7ebedde679","ref":"refs/heads/main","pushedAt":"2024-06-18T09:11:55.000Z","pushType":"pr_merge","commitsCount":1,"pusher":{"login":"mattijn","name":"Mattijn van Hoek","path":"/mattijn","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/5186265?s=80&v=4"},"commit":{"message":"ci: pin `numpy<2.0.0` (#3438)","shortMessageHtmlLink":"ci: pin numpy<2.0.0 (#3438)"}},{"before":null,"after":"96028dd2ed425750840a71e4706afd5df97b0b0f","ref":"refs/heads/polar-bar-chart","pushedAt":"2024-05-30T10:19:10.000Z","pushType":"branch_creation","commitsCount":0,"pusher":{"login":"joelostblom","name":"Joel Ostblom","path":"/joelostblom","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/4560057?s=80&v=4"},"commit":{"message":"Add examples of how to create polar bar charts","shortMessageHtmlLink":"Add examples of how to create polar bar charts"}},{"before":"81de7c4d96014721a4389fe46fe8c237637034d5","after":"18a2c3c237014591d172284560546a2f0ac1a883","ref":"refs/heads/main","pushedAt":"2024-05-23T19:17:20.000Z","pushType":"pr_merge","commitsCount":1,"pusher":{"login":"binste","name":"Stefan Binder","path":"/binste","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/23366411?s=80&v=4"},"commit":{"message":"feat: Adds `ChartType` type and type guard `is_chart_type`. Change PurePath to Path type hints (#3420)\n\n* feat: Type hints: Adds `ChartType` and guard `is_chart_type`\r\n\r\nI'm working on a library that uses `altair`, and looking to make it an optional dependency. During this process, I thought `ChartType` and `is_chart_type` might be a good fit in `altair` itself.\r\n\r\nI don't believe any existing `altair` code would directly benefit from these additions - but you could likely reduce some `isinstance` checks with [type narrowing](https://typing.readthedocs.io/en/latest/spec/narrowing.html) functions like `is_chart_type`.\r\nFor example `altair/vegalite/v5/api.py` has **63** occurrences of `isinstance`.\r\n\r\n---\r\n\r\nper [CONTRIBUTING.md](https://github.com/vega/altair/blob/main/CONTRIBUTING.md)\r\n> In particular, we welcome companion efforts from other visualization libraries to render the Vega-Lite specifications output by Altair. We see this portion of the effort as much bigger than Altair itself\r\n\r\nTowards this aim, it could be beneficial to provide `typing` constructs/tools for downstream use.\r\n\r\nRegarding my specfic use case, the below [Protocol](https://typing.readthedocs.io/en/latest/spec/protocol.html#runtime-checkable-decorator-and-narrowing-types-by-isinstance) - I believe - describes the concept of a `_/Chart`, for the purposes of writing to file:\r\n\r\n```py\r\nfrom typing import Any, Protocol, runtime_checkable\r\n\r\n@runtime_checkable\r\nclass AltairChart(Protocol):\r\n data: Any\r\n\r\n def copy(self, *args: Any, **kwargs: Any) -> Any: ...\r\n def save(self, *args: Any, **kwargs: Any) -> None: ...\r\n def to_dict(self, *args: Any, **kwargs: Any) -> dict[Any, Any]: ...\r\n def to_html(self, *args: Any, **kwargs: Any) -> str: ...\r\n```\r\n\r\nDue to the number of symbols in `altair` and heavy use of mixins, coming to this conclusion can be a stumbling block.\r\n\r\nHowever, exporting things like `ChartType`, `is_chart_type`, `AltairChart` could be a way to expose these shared behaviours - without requiring any changes to the core API.\r\n\r\n* fix: Type hints: Add missing `pathlib.Path` in `save` method annotation\r\n\r\n`TopLevelMixin.save` calls a function accepting `pathlib` objects, but the two didn't share the same `Union` for `fp`.\r\nWhen using `pyright`, the following warning is presented:\r\n\r\n> Argument of type \"Path\" cannot be assigned to parameter \"fp\" of type \"str | IO[Unknown]\" in function \"save\"\r\n> Type \"Path\" is incompatible with type \"str | IO[Unknown]\"\r\n> \"Path\" is incompatible with \"str\"\r\n> \"Path\" is incompatible with \"IO[Unknown]\"\r\n\r\nThis fix avoids the need to use type ignores on the public facing API, as a user.\r\n\r\n* refactor: Simplify `save.py` path handling\r\n\r\nBy normalizing `fp` in `save`, it simplifies the signatures of two other functions and removes the need for `str` specific suffix handling.\r\n\r\n* refactor: Replace duplicated `save` get encoding with a single expression\r\n\r\nAlthough there are branches it isn't needed, I think this is easier to read and maintain.\r\n\r\nVery low priority change, just something I noticed while reading.\r\n\r\n* docs: Add docstring for `is_chart_type`\r\n\r\n* fix: Removed unused `type: ignore` comment\r\n\r\n* build: Mark `TypeIs` as not a relevant attribute\r\n\r\n* build: Make new additions to `api` private\r\n\r\nBelieve these should be public, but it seems like the issue at build-time is that I'd be extending the public API.\r\n\r\n* Bump version of typing_extensions so it includes TypeIs\r\n\r\n* Make ChartType and is_chart_type public. Use typing.get_args to reduce duplication of list of charts\r\n\r\n* Update API docs\r\n\r\n* refactor: Adds ruff `SIM101` and apply fixes\r\n\r\nAs [requested](https://github.com/vega/altair/pull/3420/files/a4de6d1feb6f3f17c7f6d4c7738eb008ff33d17e#r1606780541).\r\nSeems to only occur in a few places, but all were autofix-able.\r\n\r\n* revert: Change `set` back to `list` for `format`\r\n\r\nAs [requested](https://github.com/vega/altair/pull/3420/commits/99b4f81d456b2b05c97919e751152dcec1cbf00b#r1606785466)\r\n\r\n* style: Re-run ruff format\r\n\r\n* revert: Add `str` support back for \"private\" `save` functions\r\n\r\nAn earlier commit assumed a minor optimization would be possible, by normalizing a `Union` early and reuse the narrowed type in \"private\" functions.\r\n\r\n@binste [comment](https://github.com/vega/altair/pull/3420/files#r1610440552)\r\n\r\n---------\r\n\r\nCo-authored-by: Stefan Binder ","shortMessageHtmlLink":"feat: Adds ChartType type and type guard is_chart_type. Change Pu…"}},{"before":"82cc0d7297045739babf35aa8803bf47fdeb39c9","after":"8077467000155c22b8304fd49c551fb9070bd8a9","ref":"refs/heads/remote-upperlimit-pin-geopandas","pushedAt":"2024-05-22T22:32:25.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"mattijn","name":"Mattijn van Hoek","path":"/mattijn","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/5186265?s=80&v=4"},"commit":{"message":"single quotes","shortMessageHtmlLink":"single quotes"}},{"before":"87791050ef4837f0e378016db3bf41dc87f88ecc","after":"82cc0d7297045739babf35aa8803bf47fdeb39c9","ref":"refs/heads/remote-upperlimit-pin-geopandas","pushedAt":"2024-05-22T22:27:21.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"mattijn","name":"Mattijn van Hoek","path":"/mattijn","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/5186265?s=80&v=4"},"commit":{"message":"use fiona engine for the test geopandas check","shortMessageHtmlLink":"use fiona engine for the test geopandas check"}},{"before":"4b721d4d2e94c3969e22711e21138f5dc482b09e","after":"87791050ef4837f0e378016db3bf41dc87f88ecc","ref":"refs/heads/remote-upperlimit-pin-geopandas","pushedAt":"2024-05-22T22:24:02.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"mattijn","name":"Mattijn van Hoek","path":"/mattijn","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/5186265?s=80&v=4"},"commit":{"message":"comment forced fiona test","shortMessageHtmlLink":"comment forced fiona test"}},{"before":"0f471f387301f2808f31b6a7d63103bab43c39bb","after":"4b721d4d2e94c3969e22711e21138f5dc482b09e","ref":"refs/heads/remote-upperlimit-pin-geopandas","pushedAt":"2024-05-22T22:21:03.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"mattijn","name":"Mattijn van Hoek","path":"/mattijn","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/5186265?s=80&v=4"},"commit":{"message":"force usage fiona","shortMessageHtmlLink":"force usage fiona"}},{"before":"6152af50aab833d0a6440805b4c3f8deec91ba91","after":"0f471f387301f2808f31b6a7d63103bab43c39bb","ref":"refs/heads/remote-upperlimit-pin-geopandas","pushedAt":"2024-05-22T21:33:30.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"mattijn","name":"Mattijn van Hoek","path":"/mattijn","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/5186265?s=80&v=4"},"commit":{"message":"try patched geopandas","shortMessageHtmlLink":"try patched geopandas"}},{"before":"21377923937f360dcf06757a1eb7a911f6ad2b6f","after":"6152af50aab833d0a6440805b4c3f8deec91ba91","ref":"refs/heads/remote-upperlimit-pin-geopandas","pushedAt":"2024-05-21T22:57:33.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"mattijn","name":"Mattijn van Hoek","path":"/mattijn","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/5186265?s=80&v=4"},"commit":{"message":"add content-length test","shortMessageHtmlLink":"add content-length test"}},{"before":"8bb1efac94115c4c41d17dab95c902c9888f265e","after":"21377923937f360dcf06757a1eb7a911f6ad2b6f","ref":"refs/heads/remote-upperlimit-pin-geopandas","pushedAt":"2024-05-21T22:48:40.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"mattijn","name":"Mattijn van Hoek","path":"/mattijn","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/5186265?s=80&v=4"},"commit":{"message":"logging module required","shortMessageHtmlLink":"logging module required"}},{"before":"325d0fa97a709c723b15d216fe25f3b0d56fb531","after":"8bb1efac94115c4c41d17dab95c902c9888f265e","ref":"refs/heads/remote-upperlimit-pin-geopandas","pushedAt":"2024-05-21T22:47:25.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"mattijn","name":"Mattijn van Hoek","path":"/mattijn","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/5186265?s=80&v=4"},"commit":{"message":"no need for logging module","shortMessageHtmlLink":"no need for logging module"}}],"hasNextPage":true,"hasPreviousPage":false,"activityType":"all","actor":null,"timePeriod":"all","sort":"DESC","perPage":30,"cursor":"djE6ks8AAAAEdgeTIAA","startCursor":null,"endCursor":null}},"title":"Activity · vega/altair"}