From a25fa99c49554940e1e3ce98a888b4b2737ecddd Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 23 Feb 2026 09:47:15 +0000 Subject: [PATCH 1/4] Fix init() to create repos under specified org instead of current user When dagshub.init(repo_owner='org', repo_name='repo') is called and the repo doesn't exist, it now compares repo_owner against the current user's username. If they differ, the repo is created under the org via the org API endpoint. Previously it always created repos under the calling user, ignoring the repo_owner parameter entirely. Also forwards the host parameter to create_repo() for correctness. https://claude.ai/code/session_01DaAdy77PhB4KNXRzuQ3FhD --- dagshub/common/init.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/dagshub/common/init.py b/dagshub/common/init.py index 84db8d7f..632e5f1f 100644 --- a/dagshub/common/init.py +++ b/dagshub/common/init.py @@ -87,8 +87,15 @@ def init( try: repo_api.get_repo_info() except RepoNotFoundError: - log_message(f"Repository {repo_name} doesn't exist, creating it under current user.") - create_repo(repo_name) + current_user = UserAPI.get_current_user(host=host) + if repo_owner and repo_owner != current_user.username: + log_message( + f'Repository {repo_name} doesn\'t exist, creating it under organization "{repo_owner}".' + ) + create_repo(repo_name, org_name=repo_owner, host=host) + else: + log_message(f"Repository {repo_name} doesn't exist, creating it under current user.") + create_repo(repo_name, host=host) # Get the token for the configs token = get_token(host=host) From c81d50d1a1bc92024735090172a3d55045a28d35 Mon Sep 17 00:00:00 2001 From: Guy Smoilovsky Date: Mon, 23 Feb 2026 13:21:35 +0200 Subject: [PATCH 2/4] Review fixes --- .gitignore | 1 + dagshub/common/init.py | 16 +++++---- tests/common/test_init.py | 70 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 tests/common/test_init.py diff --git a/.gitignore b/.gitignore index 14b6b327..502aa60e 100644 --- a/.gitignore +++ b/.gitignore @@ -126,6 +126,7 @@ dmypy.json # IntelliJ .idea/ +*.iml # VSCode .vscode/ diff --git a/dagshub/common/init.py b/dagshub/common/init.py index 632e5f1f..72c6380d 100644 --- a/dagshub/common/init.py +++ b/dagshub/common/init.py @@ -87,12 +87,16 @@ def init( try: repo_api.get_repo_info() except RepoNotFoundError: - current_user = UserAPI.get_current_user(host=host) - if repo_owner and repo_owner != current_user.username: - log_message( - f'Repository {repo_name} doesn\'t exist, creating it under organization "{repo_owner}".' - ) - create_repo(repo_name, org_name=repo_owner, host=host) + if repo_owner: + current_user = UserAPI.get_current_user(host=host) + if repo_owner != current_user.username: + log_message( + f'Repository {repo_name} doesn\'t exist, creating it under organization "{repo_owner}".' + ) + create_repo(repo_name, org_name=repo_owner, host=host) + else: + log_message(f"Repository {repo_name} doesn't exist, creating it under current user.") + create_repo(repo_name, host=host) else: log_message(f"Repository {repo_name} doesn't exist, creating it under current user.") create_repo(repo_name, host=host) diff --git a/tests/common/test_init.py b/tests/common/test_init.py new file mode 100644 index 00000000..e02172e3 --- /dev/null +++ b/tests/common/test_init.py @@ -0,0 +1,70 @@ +from unittest.mock import MagicMock + +import pytest + +import dagshub +from dagshub.common.api.repo import RepoNotFoundError + + +@pytest.fixture +def mock_repo_api(mocker): + mock = mocker.patch("dagshub.common.init.RepoAPI") + mock.return_value.get_repo_info.side_effect = RepoNotFoundError() + return mock + + +@pytest.fixture +def mock_user_api(mocker): + user = MagicMock() + user.username = "testuser" + mock = mocker.patch("dagshub.common.init.UserAPI") + mock.get_current_user.return_value = user + mock.get_user_from_token.return_value = user + return mock + + +@pytest.fixture +def mock_create_repo(mocker): + return mocker.patch("dagshub.common.init.create_repo") + + +@pytest.fixture +def mock_get_token(mocker): + return mocker.patch("dagshub.common.init.get_token", return_value="fake-token") + + +@pytest.fixture +def mock_log_message(mocker): + return mocker.patch("dagshub.common.init.log_message") + + +def test_init_creates_repo_under_org_when_owner_differs( + mock_repo_api, mock_user_api, mock_create_repo, mock_get_token, mock_log_message +): + dagshub.init(repo_owner="my-org", repo_name="my-repo", mlflow=False, dvc=False) + + mock_user_api.get_current_user.assert_called_once() + mock_create_repo.assert_called_once_with("my-repo", org_name="my-org", host="https://dagshub.com") + mock_log_message.assert_any_call( + 'Repository my-repo doesn\'t exist, creating it under organization "my-org".' + ) + + +def test_init_creates_repo_under_current_user_when_owner_matches( + mock_repo_api, mock_user_api, mock_create_repo, mock_get_token, mock_log_message +): + dagshub.init(repo_owner="testuser", repo_name="my-repo", mlflow=False, dvc=False) + + mock_user_api.get_current_user.assert_called_once() + mock_create_repo.assert_called_once_with("my-repo", host="https://dagshub.com") + mock_log_message.assert_any_call( + "Repository my-repo doesn't exist, creating it under current user." + ) + + +def test_init_creates_repo_under_current_user_from_url( + mock_repo_api, mock_user_api, mock_create_repo, mock_get_token, mock_log_message +): + dagshub.init(url="https://dagshub.com/testuser/my-repo", mlflow=False, dvc=False) + + mock_create_repo.assert_called_once_with("my-repo", host="https://dagshub.com") From 41f6ab2442362dfd81e5e4d9f70991a7760633c0 Mon Sep 17 00:00:00 2001 From: Guy Smoilovsky Date: Mon, 23 Feb 2026 13:28:37 +0200 Subject: [PATCH 3/4] Add host=host to get_user_from_token call --- dagshub/common/init.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dagshub/common/init.py b/dagshub/common/init.py index 72c6380d..3e52a9f6 100644 --- a/dagshub/common/init.py +++ b/dagshub/common/init.py @@ -107,7 +107,7 @@ def init( # Configure MLFlow if mlflow: os.environ["MLFLOW_TRACKING_URI"] = f"{url}.mlflow" - os.environ["MLFLOW_TRACKING_USERNAME"] = UserAPI.get_user_from_token(token).username + os.environ["MLFLOW_TRACKING_USERNAME"] = UserAPI.get_user_from_token(token, host=host).username os.environ["MLFLOW_TRACKING_PASSWORD"] = token log_message(f'Initialized MLflow to track repo "{repo_owner}/{repo_name}"') From 1eb946c853a726241f821d5e335e04feb59632c5 Mon Sep 17 00:00:00 2001 From: Guy Smoilovsky Date: Mon, 23 Feb 2026 13:45:36 +0200 Subject: [PATCH 4/4] More review fixes --- dagshub/common/init.py | 16 ++++++++-------- tests/common/test_init.py | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/dagshub/common/init.py b/dagshub/common/init.py index 3e52a9f6..86fad2d4 100644 --- a/dagshub/common/init.py +++ b/dagshub/common/init.py @@ -87,16 +87,16 @@ def init( try: repo_api.get_repo_info() except RepoNotFoundError: + should_create_under_org = False if repo_owner: current_user = UserAPI.get_current_user(host=host) - if repo_owner != current_user.username: - log_message( - f'Repository {repo_name} doesn\'t exist, creating it under organization "{repo_owner}".' - ) - create_repo(repo_name, org_name=repo_owner, host=host) - else: - log_message(f"Repository {repo_name} doesn't exist, creating it under current user.") - create_repo(repo_name, host=host) + should_create_under_org = repo_owner != current_user.username + + if should_create_under_org: + log_message( + f'Repository {repo_name} doesn\'t exist, creating it under organization "{repo_owner}".' + ) + create_repo(repo_name, org_name=repo_owner, host=host) else: log_message(f"Repository {repo_name} doesn't exist, creating it under current user.") create_repo(repo_name, host=host) diff --git a/tests/common/test_init.py b/tests/common/test_init.py index e02172e3..226d9a71 100644 --- a/tests/common/test_init.py +++ b/tests/common/test_init.py @@ -67,4 +67,20 @@ def test_init_creates_repo_under_current_user_from_url( ): dagshub.init(url="https://dagshub.com/testuser/my-repo", mlflow=False, dvc=False) + mock_user_api.get_current_user.assert_called_once() mock_create_repo.assert_called_once_with("my-repo", host="https://dagshub.com") + mock_log_message.assert_any_call( + "Repository my-repo doesn't exist, creating it under current user." + ) + + +def test_init_creates_repo_under_org_from_url( + mock_repo_api, mock_user_api, mock_create_repo, mock_get_token, mock_log_message +): + dagshub.init(url="https://dagshub.com/my-org/my-repo", mlflow=False, dvc=False) + + mock_user_api.get_current_user.assert_called_once() + mock_create_repo.assert_called_once_with("my-repo", org_name="my-org", host="https://dagshub.com") + mock_log_message.assert_any_call( + 'Repository my-repo doesn\'t exist, creating it under organization "my-org".' + )