From d5fceb2a971dd1f5acc5e37569d56090fec0a65f Mon Sep 17 00:00:00 2001 From: tomas Date: Mon, 24 Aug 2026 12:04:19 +0000 Subject: [PATCH 1/2] fix(chart): Bump deepnote-vegafusion to 2.1.1 for fractional-second timestamps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Charts over string timestamp columns failed with `Error parsing timestamp from '...' using format '%B %d, %Y %H:%M'` whenever the value had a fractional-second part other than exactly 3 digits. VegaFusion 2.1.0 parsed timezone-naive strings with a `%.3f`-only format list, so microsecond strings — what most database drivers emit — never matched any candidate format and the error named the last one tried. deepnote/vegafusion v2.1.1 widens those formats to `%.f`. The added test covers 0, 1, 3, 6 and 9 fractional digits; the 1, 6 and 9 digit cases fail against 2.1.0 and pass on 2.1.1. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01QSHPq7nj9cJD8XVPesADtA --- poetry.lock | 16 ++++++++-------- pyproject.toml | 2 +- tests/unit/test_chart.py | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/poetry.lock b/poetry.lock index 7befdd1..01c6b4c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1495,18 +1495,18 @@ test = ["pytest", "pytest-cov", "pytest-xdist"] [[package]] name = "deepnote-vegafusion" -version = "2.1.0" +version = "2.1.1" description = "Core tools for using VegaFusion from Python" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "deepnote_vegafusion-2.1.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:3847971dad40d6542b5cf3033379a3f29d7c400dd51adbbba1fe33b5dff152d3"}, - {file = "deepnote_vegafusion-2.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:5278d0e7d98a54835691308ba3853db19607f17b7d1bc7fdc3874984c50cdb52"}, - {file = "deepnote_vegafusion-2.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76577a98005f8180dc60423a40b9b1f330011dfac2ee846880a5b970d2ca9f21"}, - {file = "deepnote_vegafusion-2.1.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:56311d3621a44003725431bbf63ab1446b9bedabcba4705769c44d17ce022168"}, - {file = "deepnote_vegafusion-2.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:45ce94a5fb0b3d3849cd0543ca57cf91416436f35f163c40eb3dd4c91a5c913c"}, - {file = "deepnote_vegafusion-2.1.0.tar.gz", hash = "sha256:357851e7b6e50674c4f91ba07b373f3ec10b5b50e2815574b856da6e1e008725"}, + {file = "deepnote_vegafusion-2.1.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:9a00700ca1cf2b8ea342548ef3a163f20c6d14274f1fcc97a70179121f6dd6c1"}, + {file = "deepnote_vegafusion-2.1.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:6a5273d33e1c507d1ed608fe8566e2de7e9aad74b9ac54875155dbe9872036a4"}, + {file = "deepnote_vegafusion-2.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a70b0d1ab7ad957c7f2f3acadc5c88b5a739150cfb6ee09d8641071debe5256"}, + {file = "deepnote_vegafusion-2.1.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:128706704db43b7d7faa15e5bc0cc8d0f1b309d9913cd00bb421d82c9a7b188c"}, + {file = "deepnote_vegafusion-2.1.1-cp39-abi3-win_amd64.whl", hash = "sha256:2e803653c212e8fc742c4ea5b5d0049240188811cb1ab81020c53cd2fc6b7111"}, + {file = "deepnote_vegafusion-2.1.1.tar.gz", hash = "sha256:9cc74368a22f4248b144d9a96b30cd0fcb85080891dcd2064199bb02ef5f005b"}, ] [package.dependencies] @@ -7449,4 +7449,4 @@ server = ["deepnote-python-lsp-server", "jupyter-resource-usage", "jupyter-serve [metadata] lock-version = "2.1" python-versions = ">=3.10.0,<3.14" -content-hash = "3566e573e09e177f019327ea8df4779daf3f7f3e404f0b5de82eb8453b110ee1" +content-hash = "c774c3f56bb55bf5c3227baed5f6a7b742cc499ac8b5ff17ec286897f81d302e" diff --git a/pyproject.toml b/pyproject.toml index 98eae57..746dde7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -125,7 +125,7 @@ dependencies = [ # NOTE: 1.7.0 is latest version of vl-convert which ships with Vega 5. In webapp we can't update to Vega 6 due to ESM-only issues # so we keep vl-convert version pinned as well "vl-convert-python==1.7.0", - "deepnote-vegafusion>=2.1.0,<3", + "deepnote-vegafusion>=2.1.1,<3", "matplotlib-inline>=0.1.7,<0.2.0; python_version <= '3.10'", # 0.2.0 is not compatible with matplotlib 3.6.3 on Python <=3.10 "matplotlib-inline>=0.2.1,<0.3.0; python_version >= '3.11'", diff --git a/tests/unit/test_chart.py b/tests/unit/test_chart.py index 0e32c76..fbfccc0 100644 --- a/tests/unit/test_chart.py +++ b/tests/unit/test_chart.py @@ -246,6 +246,42 @@ def test_works_with_polars_uuid_object_column(self): spec = {"mark": "bar", "encoding": {"x": {"field": "id"}}} self._assert_chart_is_json_serializable(df, spec) + # Regression test for https://github.com/deepnote/vegafusion/releases/tag/v2.1.1: + # timestamp strings without a timezone were only parseable with exactly 0 or 3 + # fractional digits, so microsecond-precision strings (what most databases emit) + # failed the whole chart with a parse error. + @parameterized.expand( + [ + ("no_fraction", "2024-01-01 10:00:00", "2024-01-01T10:00:00.000"), + ("tenths", "2024-01-01 10:00:00.1", "2024-01-01T10:00:00.100"), + ("milliseconds", "2024-01-01 10:00:00.123", "2024-01-01T10:00:00.123"), + ("microseconds", "2024-01-01 10:00:00.123456", "2024-01-01T10:00:00.123"), + ( + "nanoseconds", + "2024-01-01 10:00:00.123456789", + "2024-01-01T10:00:00.123", + ), + ] + ) + def test_timezone_naive_string_timestamps(self, _name, raw_timestamp, expected): + df = pd.DataFrame({"ts": [raw_timestamp], "value": [1]}) + spec = { + "mark": "line", + "encoding": { + "x": {"field": "ts", "type": "temporal"}, + "y": {"field": "value", "type": "quantitative"}, + }, + } + + chart = DeepnoteChart(df, spec_dict=spec) + + charted_rows = [ + dataset["values"] + for dataset in chart.compiled_vega_spec_dict["data"] + if dataset.get("values") and "ts" in dataset["values"][0] + ] + self.assertEqual(charted_rows, [[{"ts": expected, "value": 1}]]) + class TestDeepnoteSanitizeDataframe(unittest.TestCase): def test_small_dataframe_remains_ordered_the_same(self): From 5dd23fb1167db50774e22f05e47ebf1aa11556a2 Mon Sep 17 00:00:00 2001 From: tomas Date: Mon, 24 Aug 2026 12:53:03 +0000 Subject: [PATCH 2/2] chore(test): Condense the timestamp regression test comment Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01QSHPq7nj9cJD8XVPesADtA --- tests/unit/test_chart.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/unit/test_chart.py b/tests/unit/test_chart.py index fbfccc0..5f4319a 100644 --- a/tests/unit/test_chart.py +++ b/tests/unit/test_chart.py @@ -246,10 +246,7 @@ def test_works_with_polars_uuid_object_column(self): spec = {"mark": "bar", "encoding": {"x": {"field": "id"}}} self._assert_chart_is_json_serializable(df, spec) - # Regression test for https://github.com/deepnote/vegafusion/releases/tag/v2.1.1: - # timestamp strings without a timezone were only parseable with exactly 0 or 3 - # fractional digits, so microsecond-precision strings (what most databases emit) - # failed the whole chart with a parse error. + # Regression test: naive timestamp strings only parsed with 0 or 3 fractional digits. @parameterized.expand( [ ("no_fraction", "2024-01-01 10:00:00", "2024-01-01T10:00:00.000"),