From 350e134f6b8d39c06809ded55b5d51de0a1cf4c4 Mon Sep 17 00:00:00 2001 From: Peter Kerpedjiev Date: Sat, 25 Jan 2025 09:13:44 -0800 Subject: [PATCH] fix: Use deepcopy instead of model_dump to copy view --- CHANGELOG.md | 1 + src/higlass/_utils.py | 2 +- test/test_api.py | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3fd295..4d3ae11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## [v1.0.2](https://github.com/higlass/higlass-python/compare/v1.0.2...v1.0.1) - Calculate file pointer hash for track uids for tileset tracks +- Fix view copy behavior to preserve specific plugin track class vars ## [v1.0.1](https://github.com/higlass/higlass-python/compare/v1.0.1...v1.0.0) diff --git a/src/higlass/_utils.py b/src/higlass/_utils.py index e4b02fb..abeee89 100644 --- a/src/higlass/_utils.py +++ b/src/higlass/_utils.py @@ -75,7 +75,7 @@ def ensure_list(x: T | list[T] | None) -> list[T]: def copy_unique(model: ModelT) -> ModelT: """Creates a deep copy of a pydantic BaseModel with new UID.""" - copy = model.__class__(**model.model_dump()) + copy = model.model_copy(deep=True) if hasattr(copy, "uid"): setattr(copy, "uid", uid()) return copy diff --git a/test/test_api.py b/test/test_api.py index 6950ac0..e385f2c 100644 --- a/test/test_api.py +++ b/test/test_api.py @@ -1,5 +1,7 @@ from __future__ import annotations +from typing import ClassVar, Literal + import pytest import higlass as hg @@ -205,3 +207,37 @@ def test_options_mixin(): assert track is other assert track.uid == other.uid assert track.options and track.options["foo"] == "bar" + + +def test_plugin_track(): + """Test that plugin track attributes are maintained after a copy.""" + some_url = "https://some_url" + + # Here we'll create a custom plugin track. + class PileupTrack(hg.PluginTrack): + type: Literal["pileup"] = "pileup" + plugin_url: ClassVar[str] = some_url + + # Specify the track-specific data + pileup_data = { + "type": "bam", + "url": "https://some_url/sorted.bam", + "chromSizesUrl": "https://some_url/sorted.chromsizes.bam", + "options": {"maxTileWidth": 30000}, + } + + # Create and use the custom track + pileup_track = PileupTrack(data=pileup_data) + + view = hg.view((pileup_track, "top")) + uid1 = view.uid + assert view.tracks.top[0].plugin_url == some_url + + # The .domain() function creates a copy of the view. We want to make sure + # that the plugin_url attribute of the PluginTrack is maintained + view = view.domain(x=[0, 10]) + uid2 = view.uid + assert view.tracks.top[0].plugin_url == some_url + + # Check to make sure the copy behavior changed the uid as expected + assert uid1 != uid2