From 50bd25e7b2feff520f4d780e44230ac5646ac670 Mon Sep 17 00:00:00 2001 From: Nathan McDougall Date: Fri, 31 Oct 2025 07:58:46 +1300 Subject: [PATCH] Implement filename-based default pin titles for `.pin_upload` --- pins/boards.py | 24 +++++++++++++++++++++ pins/tests/test_boards.py | 44 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/pins/boards.py b/pins/boards.py index c1eeb2f2..d5927659 100644 --- a/pins/boards.py +++ b/pins/boards.py @@ -491,6 +491,30 @@ def pin_upload( if not Path(path).is_file(): raise PinsError(f"Path is not a valid file: {path}") + if title is None: + # Use the filename/s as the name. + # Otherwise, the title ends up being something like '...: a pinned str object' + # https://github.com/rstudio/pins-python/issues/346 + if len(paths) == 1: + filename = Path(paths[0]).name + title = f"'{filename}': a pinned file" + else: + # Don't let the string get too long; if the number of characters is + # excessive, then just use ... to represent the rest of them + file_list_str = "" + for p in paths: + filename = Path(p).name + + if len(file_list_str) > 30: + file_list_str += ", ..." + break + + if file_list_str: + file_list_str += ", " + file_list_str += f"'{filename}'" + + title = f"{file_list_str}: {len(paths)} pinned files" + return self._pin_store( paths, name, diff --git a/pins/tests/test_boards.py b/pins/tests/test_boards.py index ee22bd3d..4f4ed9a1 100644 --- a/pins/tests/test_boards.py +++ b/pins/tests/test_boards.py @@ -281,6 +281,50 @@ def test_board_pin_upload_path_list(board_with_cache, tmp_path): (pin_path,) = board_with_cache.pin_download("cool_pin") +@skip_if_dbc +def test_board_pin_upload_name(board_with_cache, tmp_path): + # create and save data + df = pd.DataFrame({"x": [1, 2, 3]}) + + path = tmp_path / "data.csv" + df.to_csv(path, index=False) + + meta = board_with_cache.pin_upload([path], "cool_pin") + + assert meta.title == "'data.csv': a pinned file" + + +@skip_if_dbc +def test_board_pin_upload_name_multiple_paths(board_with_cache, tmp_path): + # create and save data + df = pd.DataFrame({"x": [1, 2, 3]}) + + path1 = tmp_path / "data1.csv" + path2 = tmp_path / "data2.csv" + df.to_csv(path1, index=False) + df.to_csv(path2, index=False) + + meta = board_with_cache.pin_upload([path1, path2], "cool_pin") + + assert meta.title == "'data1.csv', 'data2.csv': 2 pinned files" + + +@skip_if_dbc +def test_board_pin_upload_name_many_paths(board_with_cache, tmp_path): + # create and save data + df = pd.DataFrame({"x": [1, 2, 3]}) + + paths = [] + for i in range(1, 4 + 1): + path = tmp_path / f"data{i}.csv" + df.to_csv(path, index=False) + paths.append(path) + + meta = board_with_cache.pin_upload(paths, "cool_pin") + + assert meta.title == "'data1.csv', 'data2.csv', 'data3.csv', ...: 4 pinned files" + + @skip_if_dbc def test_board_pin_download_filename_multifile(board_with_cache, tmp_path): # create and save data