metafold 0.13.1.dev1__tar.gz → 0.13.2.dev0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/PKG-INFO +1 -1
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/metafold/simulation/compression_simulation.py +11 -2
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/metafold.egg-info/PKG-INFO +1 -1
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/pyproject.toml +1 -1
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/tests/test_compression_simulation.py +71 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/LICENSE +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/README.md +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/metafold/__init__.py +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/metafold/api.py +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/metafold/assets.py +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/metafold/auth.py +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/metafold/client.py +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/metafold/exceptions.py +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/metafold/jobs.py +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/metafold/materials.py +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/metafold/projects.py +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/metafold/simulation/__init__.py +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/metafold/simulation/compression_experiment.py +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/metafold/simulation/run_experiment.py +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/metafold/utils.py +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/metafold/workflows.py +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/metafold.egg-info/SOURCES.txt +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/metafold.egg-info/dependency_links.txt +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/metafold.egg-info/requires.txt +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/metafold.egg-info/top_level.txt +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/setup.cfg +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/tests/test_assets.py +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/tests/test_compession_experiment.py +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/tests/test_jobs.py +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/tests/test_materials.py +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/tests/test_projects.py +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/tests/test_run_experiment.py +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/tests/test_shear_simulation.py +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/tests/test_utils.py +0 -0
- {metafold-0.13.1.dev1 → metafold-0.13.2.dev0}/tests/test_workflows.py +0 -0
|
@@ -656,6 +656,7 @@ class CompressionSimulation:
|
|
|
656
656
|
base_url: str = "https://api.metafold3d.com/",
|
|
657
657
|
cancel_existing_workflows: bool = True,
|
|
658
658
|
project_access: Access = Access.PRIVATE,
|
|
659
|
+
user: Optional[str] = None,
|
|
659
660
|
) -> str:
|
|
660
661
|
"""Find an existing project by name or create a new one.
|
|
661
662
|
|
|
@@ -663,6 +664,10 @@ class CompressionSimulation:
|
|
|
663
664
|
client_id + client_secret (local/programmable use, reads from env via
|
|
664
665
|
setup_client). base_url must match the audience the token was issued for.
|
|
665
666
|
|
|
667
|
+
When user is given, only the caller's own projects are reused; a
|
|
668
|
+
same-named project owned by someone else (visible under org access) is
|
|
669
|
+
ignored so it can't be overwritten.
|
|
670
|
+
|
|
666
671
|
When cancel_existing_workflows is True and an existing project is
|
|
667
672
|
reused, its running workflows are cancelled first.
|
|
668
673
|
|
|
@@ -675,10 +680,14 @@ class CompressionSimulation:
|
|
|
675
680
|
auth_domain=auth_domain,
|
|
676
681
|
base_url=base_url,
|
|
677
682
|
)
|
|
678
|
-
# Quote the
|
|
683
|
+
# Quote the values so multi-word names stay a single search term.
|
|
684
|
+
q = f'name:"{project_name}"'
|
|
685
|
+
if user is not None:
|
|
686
|
+
q = f'{q} AND user:"{user}"'
|
|
679
687
|
existing = [
|
|
680
|
-
p for p in client.projects.list(q=
|
|
688
|
+
p for p in client.projects.list(q=q)
|
|
681
689
|
if p.name == project_name # ensure full match
|
|
690
|
+
and (user is None or p.user == user)
|
|
682
691
|
]
|
|
683
692
|
if existing:
|
|
684
693
|
project_id = existing[0].id
|
|
@@ -1439,3 +1439,74 @@ class TestFindOrCreateProjectCancel:
|
|
|
1439
1439
|
|
|
1440
1440
|
assert pid == "new-pid"
|
|
1441
1441
|
client.workflows.cancel.assert_not_called()
|
|
1442
|
+
|
|
1443
|
+
|
|
1444
|
+
class TestFindOrCreateProjectUserScope:
|
|
1445
|
+
"""With user set, only the caller's own project is reused; a same-named
|
|
1446
|
+
project owned by someone else (visible under org access) is ignored."""
|
|
1447
|
+
|
|
1448
|
+
@pytest.fixture
|
|
1449
|
+
def patched_client_class(self, monkeypatch):
|
|
1450
|
+
from metafold.simulation import compression_simulation
|
|
1451
|
+
fake_class = MagicMock()
|
|
1452
|
+
monkeypatch.setattr(compression_simulation, "MetafoldClient", fake_class)
|
|
1453
|
+
return fake_class
|
|
1454
|
+
|
|
1455
|
+
def _project(self, pid, name, user):
|
|
1456
|
+
p = MagicMock()
|
|
1457
|
+
p.id = pid
|
|
1458
|
+
p.name = name
|
|
1459
|
+
p.user = user
|
|
1460
|
+
return p
|
|
1461
|
+
|
|
1462
|
+
def test_ignores_same_name_owned_by_other_user(self, patched_client_class):
|
|
1463
|
+
client = patched_client_class.return_value
|
|
1464
|
+
# A defensive belt-and-suspenders case: even if the API returned another
|
|
1465
|
+
# user's project, the Python filter drops it and we create a new one.
|
|
1466
|
+
client.projects.list.return_value = [self._project("other-pid", "shared", "userB")]
|
|
1467
|
+
client.projects.create.return_value = self._project("new-pid", "shared", "userA")
|
|
1468
|
+
|
|
1469
|
+
pid = CompressionSimulation.find_or_create_project(
|
|
1470
|
+
"shared", access_token="tok", base_url="http://x/", user="userA",
|
|
1471
|
+
)
|
|
1472
|
+
|
|
1473
|
+
assert pid == "new-pid"
|
|
1474
|
+
client.projects.create.assert_called_once()
|
|
1475
|
+
|
|
1476
|
+
def test_reuses_callers_own_project(self, patched_client_class):
|
|
1477
|
+
client = patched_client_class.return_value
|
|
1478
|
+
client.projects.list.return_value = [self._project("mine", "shared", "userA")]
|
|
1479
|
+
|
|
1480
|
+
pid = CompressionSimulation.find_or_create_project(
|
|
1481
|
+
"shared", access_token="tok", base_url="http://x/", user="userA",
|
|
1482
|
+
cancel_existing_workflows=False,
|
|
1483
|
+
)
|
|
1484
|
+
|
|
1485
|
+
assert pid == "mine"
|
|
1486
|
+
client.projects.create.assert_not_called()
|
|
1487
|
+
|
|
1488
|
+
def test_scopes_query_to_user(self, patched_client_class):
|
|
1489
|
+
client = patched_client_class.return_value
|
|
1490
|
+
client.projects.list.return_value = []
|
|
1491
|
+
client.projects.create.return_value = self._project("new-pid", "shared", "userA")
|
|
1492
|
+
|
|
1493
|
+
CompressionSimulation.find_or_create_project(
|
|
1494
|
+
"shared", access_token="tok", base_url="http://x/", user="userA",
|
|
1495
|
+
)
|
|
1496
|
+
|
|
1497
|
+
q = client.projects.list.call_args.kwargs["q"]
|
|
1498
|
+
assert 'name:"shared"' in q
|
|
1499
|
+
assert 'user:"userA"' in q
|
|
1500
|
+
|
|
1501
|
+
def test_no_user_keeps_unscoped_behavior(self, patched_client_class):
|
|
1502
|
+
client = patched_client_class.return_value
|
|
1503
|
+
client.projects.list.return_value = [self._project("any-pid", "shared", "userB")]
|
|
1504
|
+
|
|
1505
|
+
pid = CompressionSimulation.find_or_create_project(
|
|
1506
|
+
"shared", access_token="tok", base_url="http://x/",
|
|
1507
|
+
cancel_existing_workflows=False,
|
|
1508
|
+
)
|
|
1509
|
+
|
|
1510
|
+
assert pid == "any-pid"
|
|
1511
|
+
q = client.projects.list.call_args.kwargs["q"]
|
|
1512
|
+
assert "user:" not in q
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|