Skip to content

Handle external removes #272

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

Merged
merged 3 commits into from
Mar 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 29 additions & 14 deletions cascade/repos/repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,32 @@ def __init__(
}

if "lines" in kwargs:
raise ValueError(
"lines was removed in 0.14.0, consider using add_line method instead"
)
raise ValueError("lines was removed in 0.14.0, consider using add_line method instead")

self.sync_meta()

def _new_line_name(self):
n = len(self)
index_name = f"{n:0>5d}"
if n == 0:
return index_name

line_names = self.get_line_names()

# Since lines are always sorted
# Latest will be the max
latest_numeric_name = None
for name in line_names[::-1]:
if name.isnumeric():
latest_numeric_name = name
break

if latest_numeric_name:
latest_line_num = int(latest_numeric_name)
return f"{latest_line_num + 1:0>5d}"
else:
return index_name

def add_line(
self,
name: Optional[str] = None,
Expand Down Expand Up @@ -139,14 +159,11 @@ def add_line(
_description_
"""
if name is None:
name = f"{len(self):0>5d}"
if name in self.get_line_names():
# Name can appear in the repo if the user manually
# removed the lines from the middle of the repo

# This will be handled strictly
# until it will become clear that some solution needed
raise RuntimeError(f"Line {name} already exists in {self}")
name = self._new_line_name()
assert name not in self._lines, (
f"Tried creating line name `{name}` that is already in repo."
" This is unexpected, if you see this, please fill a GitHub issue"
)

folder = os.path.join(self._root, name)
if meta_fmt is None:
Expand Down Expand Up @@ -236,9 +253,7 @@ def load_obj_meta(self, obj: str) -> Meta:
continue
else:
return meta
raise FileNotFoundError(
f"Failed to find the object {obj} in the repo at {self._root}"
)
raise FileNotFoundError(f"Failed to find the object {obj} in the repo at {self._root}")

def _update_lines(self) -> None:
for name in sorted(os.listdir(self._root)):
Expand Down
32 changes: 28 additions & 4 deletions cascade/tests/lines/test_model_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
sys.path.append(os.path.dirname(MODULE_PATH))

from cascade.base import MetaHandler, default_meta_format
from cascade.lines import ModelLine
from cascade.models import BasicModel
from cascade.repos import Repo
from cascade.lines import ModelLine
from cascade.tests.conftest import DummyModel


Expand Down Expand Up @@ -63,19 +63,42 @@ def test_change_of_format(tmp_path_str, ext):
assert len(glob.glob(os.path.join(tmp_path_str, "meta.*"))) == 1


def test_same_index_check(model_line):
def test_external_remove_first(model_line):
for _ in range(5):
model_line.save(BasicModel())

shutil.rmtree(os.path.join(model_line.get_root(), "00000"))

model_line = ModelLine(model_line.get_root())
model_line.save(BasicModel())

assert os.path.exists(os.path.join(model_line.get_root(), "00005"))


def test_external_remove_middle(model_line):
for _ in range(5):
model_line.save(BasicModel())

shutil.rmtree(os.path.join(model_line.get_root(), "00001"))
shutil.rmtree(os.path.join(model_line.get_root(), "00002"))
shutil.rmtree(os.path.join(model_line.get_root(), "00003"))

model_line = ModelLine(model_line.get_root())
model_line.save(BasicModel())

assert os.path.exists(os.path.join(model_line.get_root(), "00005"))


def test_external_remove_last(model_line):
for _ in range(5):
model_line.save(BasicModel())

shutil.rmtree(os.path.join(model_line.get_root(), "00004"))

model_line = ModelLine(model_line.get_root())
model_line.save(BasicModel())

assert os.path.exists(os.path.join(model_line.get_root(), "00004"))


# TODO: write tests for exceptions
def test_load_model_meta_slug(model_line, dummy_model):
dummy_model.evaluate()
Expand Down Expand Up @@ -184,6 +207,7 @@ def test_model_names(tmp_path_str):
line = ModelLine(tmp_path_str)
assert line.get_model_names() == ["00000", "00001", "00002"]


# TODO: write test for restoring line from repo


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import glob
import os
import shutil
import sys

import pytest
Expand Down Expand Up @@ -297,13 +298,90 @@ def test_auto_line_name(tmp_path_str, ext):

names = repo.get_line_names()

assert names == ["00000", "test", "00002", "00003"]
assert set(names) == {"00000", "test", "00001", "00002"}

repo = Repo(str(tmp_path_str), meta_fmt=ext)

names = repo.get_line_names()
def test_external_remove_first(tmp_path_str):
repo = Repo(str(tmp_path_str))
repo.add_line()
repo.add_line()
repo.add_line()
repo.add_line()

shutil.rmtree(os.path.join(repo.get_root(), "00000"))

repo = Repo(str(tmp_path_str))
repo.add_line()

assert repo.get_line_names() == [
"00001",
"00002",
"00003",
"00004",
]


def test_external_remove_middle(tmp_path_str):
repo = Repo(str(tmp_path_str))
repo.add_line()
repo.add_line()
repo.add_line()
repo.add_line()

shutil.rmtree(os.path.join(repo.get_root(), "00001"))

repo = Repo(str(tmp_path_str))
repo.add_line()

assert repo.get_line_names() == [
"00000",
"00002",
"00003",
"00004",
]


def test_external_remove_last(tmp_path_str):
repo = Repo(str(tmp_path_str))
repo.add_line()
repo.add_line()
repo.add_line()
repo.add_line()

shutil.rmtree(os.path.join(repo.get_root(), "00003"))

repo = Repo(str(tmp_path_str))
repo.add_line()

assert repo.get_line_names() == [
"00000",
"00001",
"00002",
"00003",
]


def test_mixed_formats(tmp_path_str):
repo = Repo(str(tmp_path_str))
repo.add_line("00000")
repo.add_line("00001")
repo.add_line("a")
repo.add_line("b")
repo.add_line("c")

shutil.rmtree(os.path.join(repo.get_root(), "b"))

repo = Repo(str(tmp_path_str))
repo.add_line()

assert names == ["00000", "00002", "00003", "test"]
# I do not care about order here
assert set(repo.get_line_names()) == {
"00000",
"00001",
"00002",
"a",
"c",
}


@pytest.mark.skip
Expand Down