codecov-io: # [Codecov](https://codecov.io/gh/repobee/repobee/pull/174?src=pr&el=h1) Report
> Merging [#174](https://codecov.io/gh/repobee/repobee/pull/174?src=pr&el=desc) into [master](https://codecov.io/gh/repobee/repobee/commit/9f90b85a1ff502c64c6dadc8152d792ed95072fa?src=pr&el=desc) will **decrease** coverage by `0.35%`.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/repobee/repobee/pull/174/graphs/tree.svg?width=650&token=5vOKgkphZe&height=150&src=pr)](https://codecov.io/gh/repobee/repobee/pull/174?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #174      +/-   ##
==========================================
- Coverage   93.18%   92.83%   -0.36%     
==========================================
  Files          17       17              
  Lines        1160     1116      -44     
  Branches      206      200       -6     
==========================================
- Hits         1081     1036      -45     
- Misses         64       65       +1     
  Partials       15       15
```


| [Impacted Files](https://codecov.io/gh/repobee/repobee/pull/174?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [repobee/github\_api.py](https://codecov.io/gh/repobee/repobee/pull/174/diff?src=pr&el=tree#diff-cmVwb2JlZS9naXRodWJfYXBpLnB5) | `92.44% <ø> (-0.54%)` | :arrow_down: |
| [repobee/util.py](https://codecov.io/gh/repobee/repobee/pull/174/diff?src=pr&el=tree#diff-cmVwb2JlZS91dGlsLnB5) | `94.11% <ø> (-1.63%)` | :arrow_down: |
| [repobee/git.py](https://codecov.io/gh/repobee/repobee/pull/174/diff?src=pr&el=tree#diff-cmVwb2JlZS9naXQucHk=) | `96.05% <ø> (-0.42%)` | :arrow_down: |
| [repobee/command.py](https://codecov.io/gh/repobee/repobee/pull/174/diff?src=pr&el=tree#diff-cmVwb2JlZS9jb21tYW5kLnB5) | `95.37% <ø> (-0.46%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/repobee/repobee/pull/174?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/repobee/repobee/pull/174?src=pr&el=footer). Last update [9f90b85...b0e86a3](https://codecov.io/gh/repobee/repobee/pull/174?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

diff --git a/repobee/__version.py b/repobee/__version.py
index 67bc602..9c73af2 100644
--- a/repobee/__version.py
+++ b/repobee/__version.py
@@ -1,1 +1,1 @@
-__version__ = "1.3.0"
+__version__ = "1.3.1"
diff --git a/repobee/command.py b/repobee/command.py
index b37ac31..5a6964c 100644
--- a/repobee/command.py
+++ b/repobee/command.py
@@ -67,11 +67,6 @@ def setup_student_repos(
         user: Username of the administrator that setting up the repos.
         api: A GitHubAPI instance used to interface with the GitHub instance.
     """
-    util.validate_types(user=(user, str), api=(api, GitHubAPI))
-    util.validate_non_empty(
-        master_repo_urls=master_repo_urls, students=students, user=user
-    )
-
     urls = list(master_repo_urls)  # safe copy
 
     with tempfile.TemporaryDirectory() as tmpdir:
@@ -100,8 +95,6 @@ def add_students_to_teams(
     Returns:
         all teams associated with the students in the students list.
     """
-    util.validate_types(api=(api, GitHubAPI))
-    util.validate_non_empty(students=students)
     # TODO simply pass the group to ensure_teams_and_members instead
     member_lists = {str(group): group.members for group in students}
     return api.ensure_teams_and_members(member_lists)
@@ -172,14 +165,6 @@ def update_student_repos(
         api: A GitHubAPI instance used to interface with the GitHub instance.
         issue: An optional issue to open in repos to which pushing fails.
     """
-    util.validate_types(
-        user=(user, str),
-        api=(api, GitHubAPI),
-        issue=(issue, (tuples.Issue, type(None))),
-    )
-    util.validate_non_empty(
-        master_repo_urls=master_repo_urls, user=user, students=students
-    )
     urls = list(master_repo_urls)  # safe copy
 
     if len(set(urls)) != len(urls):
@@ -241,11 +226,6 @@ def list_issues(
         default info.
         author: Only show issues by this author.
     """
-    util.validate_types(api=(api, GitHubAPI))
-    util.validate_non_empty(
-        master_repo_names=master_repo_names, students=students
-    )
-
     repo_names = util.generate_repo_names(students, master_repo_names)
     max_repo_name_length = max(map(len, repo_names))
 
@@ -347,13 +327,7 @@ def open_issue(
         issue: An issue to open.
         api: A GitHubAPI instance used to interface with the GitHub instance.
     """
-    util.validate_types(issue=(issue, tuples.Issue), api=(api, GitHubAPI))
-    util.validate_non_empty(
-        master_repo_names=master_repo_names, students=students, issue=issue
-    )
-
     repo_names = util.generate_repo_names(students, master_repo_names)
-
     api.open_issue(issue.title, issue.body, repo_names)
 
 
@@ -371,15 +345,7 @@ def close_issue(
         students: An iterable of student GitHub usernames.
         api: A GitHubAPI instance used to interface with the GitHub instance.
     """
-    util.validate_types(title_regex=(title_regex, str), api=(api, GitHubAPI))
-    util.validate_non_empty(
-        title_regex=title_regex,
-        master_repo_names=master_repo_names,
-        students=students,
-    )
-
     repo_names = util.generate_repo_names(students, master_repo_names)
-
     api.close_issue(title_regex, repo_names)
 
 
@@ -395,11 +361,6 @@ def clone_repos(
         students: Student usernames.
         api: A GitHubAPI instance.
     """
-    util.validate_types(api=(api, GitHubAPI))
-    util.validate_non_empty(
-        master_repo_names=master_repo_names, students=students
-    )
-
     repo_names = util.generate_repo_names(students, master_repo_names)
     repo_urls = api.get_repo_urls(repo_names)
 
@@ -441,9 +402,6 @@ def migrate_repos(
         the username that is used in the push.
         api: A GitHubAPI instance used to interface with the GitHub instance.
     """
-    util.validate_types(user=(user, str), api=(api, GitHubAPI))
-    util.validate_non_empty(master_repo_urls=master_repo_urls, user=user)
-
     master_team, *_ = api.ensure_teams_and_members({MASTER_TEAM: []})
 
     master_names = [util.repo_name(url) for url in master_repo_urls]
@@ -502,13 +460,6 @@ def assign_peer_reviews(
             (consequently, the amount of reviews of each repo)
         api: A GitHubAPI instance used to interface with the GitHub instance.
     """
-    util.validate_types(
-        api=(api, GitHubAPI), issue=(issue, (tuples.Issue, type(None)))
-    )
-    util.validate_non_empty(
-        master_repo_names=master_repo_names, students=students
-    )
-
     # currently only supports single students
     # TODO support groups
     assert all(map(lambda g: len(g.members) == 1, students))
@@ -545,10 +496,6 @@ def purge_review_teams(
         master_repo_names: Names of master repos.
         students: An iterable of student GitHub usernames.
     """
-    util.validate_non_empty(
-        master_repo_names=master_repo_names, students=students
-    )
-
     review_team_names = [
         util.generate_review_team_name(student, master_repo_name)
         for student in students
diff --git a/repobee/git.py b/repobee/git.py
index 70c0bb9..b416db5 100644
--- a/repobee/git.py
+++ b/repobee/git.py
@@ -12,7 +12,6 @@ import collections
 import daiquiri
 from typing import Iterable, List, Any, Callable
 
-from repobee import util
 from repobee import exception
 
 CONCURRENT_TASKS = 20
@@ -79,13 +78,6 @@ def clone_single(
         cwd: Working directory. Defaults to the current directory.
         token: A GitHub OAUTH token.
     """
-    util.validate_types(
-        repo_url=(repo_url, str),
-        single_branch=(single_branch, bool),
-        branch=(branch, (str, type(None))),
-        cwd=(cwd, (str)),
-    )
-
     if isinstance(branch, str) and not branch:
         raise ValueError("branch must not be empty")
 
@@ -157,9 +149,6 @@ def clone(
         URLs from which cloning failed.
     """
     # TODO valdate repo_urls
-    util.validate_types(single_branch=(single_branch, bool), cwd=(cwd, str))
-    util.validate_non_empty(repo_urls=repo_urls, single_branch=single_branch)
-
     return [
         exc.url
         for exc in _batch_execution(
@@ -177,10 +166,6 @@ async def _push_async(pt: Push, user: str, token: str):
         user: The username to use in the push.
         token: A GitHub OAUTH token.
     """
-    util.validate_types(push_tuple=(pt, Push), user=(user, str))
-
-    util.validate_non_empty(user=user)
-
     command = [
         "git",
         "push",
@@ -225,10 +210,6 @@ def _push_no_retry(
         urls to which pushes failed with exception.PushFailedError. Other
         errors are only logged.
     """
-    # TODO valdate push_tuples
-    util.validate_types(user=(user, str))
-    util.validate_non_empty(push_tuples=push_tuples, user=user)
-
     return [
         exc.url
         for exc in _batch_execution(_push_async, push_tuples, user, token)
@@ -254,7 +235,6 @@ def push(
         urls to which pushes failed with exception.PushFailedError. Other
         errors are only logged.
     """
-    util.validate_types(tries=(tries, int))
     if tries < 1:
         raise ValueError("tries must be larger than 0")
     # confusing, but failed_pts needs an initial value
diff --git a/repobee/github_api.py b/repobee/github_api.py
index dc8bf0c..6243699 100644
--- a/repobee/github_api.py
+++ b/repobee/github_api.py
@@ -20,7 +20,6 @@ import github
 
 from repobee import exception
 from repobee import tuples
-from repobee import util
 
 REQUIRED_OAUTH_SCOPES = {"admin:org", "repo"}
 
@@ -613,16 +612,6 @@ class GitHubAPI:
                 "variable is properly set, or supply the `--token` option."
             )
 
-        util.validate_types(
-            base_url=(base_url, str),
-            token=(token, str),
-            user=(user, str),
-            org_name=(org_name, str),
-        )
-        util.validate_non_empty(
-            base_url=base_url, token=token, user=user, org_name=org_name
-        )
-
         g = github.Github(login_or_token=token, base_url=base_url)
 
         LOGGER.info("trying to fetch user information ...")
diff --git a/repobee/util.py b/repobee/util.py
index dd4da5b..aa36303 100644
--- a/repobee/util.py
+++ b/repobee/util.py
@@ -13,43 +13,6 @@ from typing import Iterable, Generator, Union
 from repobee import tuples
 
 
-def validate_non_empty(**kwargs) -> None:
-    r"""Validate that arguments are not empty. Raise ValueError if any argument
-    is empty.
-
-    Args:
-        **kwargs: Mapping on the form {param_name: argument} where param_name
-        is the name of the parameter and argument is the value passed in.
-    """
-    for param_name, argument in kwargs.items():
-        if not argument:
-            raise ValueError("{} must not be empty".format(param_name))
-
-
-def validate_types(**kwargs) -> None:
-    r"""Validate argument types. Raise TypeError if there is a mismatch.
-
-    Args:
-        **kwargs: Mapping on the form {param_name: (argument, expected_type)},
-        where param_name is the name of the parameter, argument is the passed
-        in value and expected type is either a single type, or a tuple of
-        types.
-    """
-    for param_name, (argument, expected_types) in kwargs.items():
-        if not isinstance(argument, expected_types):
-            if isinstance(expected_types, tuple):
-                exp_type_str = " or ".join(
-                    [t.__name__ for t in expected_types]
-                )
-            else:
-                exp_type_str = expected_types.__name__
-            raise TypeError(
-                "{} is of type {.__class__.__name__}, expected {}".format(
-                    param_name, argument, exp_type_str
-                )
-            )
-
-
 def read_issue(issue_path: str) -> tuples.Issue:
     """Attempt to read an issue from a textfile. The first line of the file
     is interpreted as the issue's title.
@@ -70,7 +33,6 @@ def generate_repo_name(team_name: str, master_repo_name: str) -> str:
         team_name: Name of the associated team.
         master_repo_name: Name of the template repository.
     """
-    validate_non_empty(team_name=team_name, master_repo_name=master_repo_name)
     return "{}-{}".format(team_name, master_repo_name)
 
 
@@ -87,9 +49,6 @@ def generate_repo_names(
     Returns:
         a list of repo names for all combinations of team and master repo.
     """
-    validate_non_empty(
-        team_names=team_names, master_repo_names=master_repo_names
-    )
     master_repo_names = list(
         master_repo_names
     )  # needs to be traversed multiple times

Remove type validation and associated tests
It's only in the way and adds very little in terms of safety. Should use MyPy or something similar to semi-validate type safety instead.
diff --git a/tests/test_command.py b/tests/test_command.py
index 4aed2b7..227bd76 100644
--- a/tests/test_command.py
+++ b/tests/test_command.py
@@ -1,6 +1,6 @@
 import os
 import pytest
-from unittest.mock import patch, MagicMock, Mock, call, ANY, PropertyMock
+from unittest.mock import patch, MagicMock, call, ANY, PropertyMock
 
 import repobee
 from repobee import command
@@ -94,33 +94,6 @@ STUDENT_REPO_NAMES = tuple(
 raise_ = functions.raise_
 
 
-@pytest.fixture(autouse=True)
-def validate_types_mock(request, mocker):
-    """Mock util.validate_types to only work on non-mock items."""
-    if "novalidatemock" in request.keywords:
-        return
-    util_validate = util.validate_types
-
-    def validate(**kwargs):
-        """Mocked validate that skips Mock objects as types."""
-        remove = set()
-        for param_name, (argument, expected_types) in kwargs.items():
-            if (
-                isinstance(expected_types, (Mock, MagicMock))
-                or isinstance(expected_types, tuple)
-                and any(
-                    isinstance(obj, (Mock, MagicMock))
-                    for obj in expected_types
-                )
-            ):
-                remove.add(param_name)
-        util_validate(
-            **{key: val for key, val in kwargs.items() if key not in remove}
-        )
-
-    return mocker.patch("repobee.util.validate_types", side_effect=validate)
-
-
 @pytest.fixture(autouse=True)
 def git_mock(request, mocker):
     """Mocks the whole git module so that there are no accidental
@@ -267,31 +240,6 @@ def assert_raises_on_duplicate_master_urls(function, master_urls, students):
     assert str(exc_info.value) == "master_repo_urls contains duplicates"
 
 
-RAISES_ON_EMPTY_ARGS_PARAMETRIZATION = (
-    "master_urls, students, user, empty_arg",
-    [
-        ([], list(STUDENTS), USER, "master_repo_urls"),
-        (list(MASTER_URLS), [], USER, "students"),
-        (list(MASTER_URLS), list(STUDENTS), "", "user"),
-    ],
-)
-
-RAISES_ON_EMPTY_ARGS_IDS = [
-    "|".join([str(val) for val in line])
-    for line in RAISES_ON_EMPTY_ARGS_PARAMETRIZATION[1]
-]
-
-RAISES_ON_INVALID_TYPE_PARAMETRIZATION = (
-    "user, api, type_error_arg",
-    [(3, API, "user"), ("slarse", 4, "api")],
-)
-
-RAISES_ON_EMPTY_INVALID_TYPE_IDS = [
-    "|".join([str(val) for val in line])
-    for line in RAISES_ON_INVALID_TYPE_PARAMETRIZATION[1]
-]
-
-
 class TestSetupStudentRepos:
     """Tests for setup_student_repos."""
 
@@ -320,29 +268,6 @@ class TestSetupStudentRepos:
             command.setup_student_repos(master_urls, students, USER, api_mock)
         assert str(exc_info.value) == "master_repo_urls contains duplicates"
 
-    @pytest.mark.parametrize(
-        *RAISES_ON_EMPTY_ARGS_PARAMETRIZATION, ids=RAISES_ON_EMPTY_ARGS_IDS
-    )
-    def test_raises_empty_args(
-        self, mocker, api_mock, master_urls, user, students, empty_arg
-    ):
-        """None of the arguments are allowed to be empty."""
-        with pytest.raises(ValueError):
-            command.setup_student_repos(master_urls, students, user, api_mock)
-
-    @pytest.mark.noapimock
-    @pytest.mark.parametrize(
-        *RAISES_ON_INVALID_TYPE_PARAMETRIZATION,
-        ids=RAISES_ON_EMPTY_INVALID_TYPE_IDS
-    )
-    def test_raises_on_invalid_type(
-        self, master_urls, students, user, api, type_error_arg
-    ):
-        """Test that the non-itrable arguments are type checked."""
-        with pytest.raises(TypeError) as exc_info:
-            command.setup_student_repos(master_urls, students, user, api)
-        assert type_error_arg in str(exc_info.value)
-
     def test_happy_path(
         self,
         mocker,
@@ -391,35 +316,6 @@ class TestUpdateStudentRepos:
             command.update_student_repos(master_urls, students, USER, api_mock)
         assert str(exc_info.value) == "master_repo_urls contains duplicates"
 
-    @pytest.mark.parametrize(
-        *RAISES_ON_EMPTY_ARGS_PARAMETRIZATION, ids=RAISES_ON_EMPTY_ARGS_IDS
-    )
-    def test_raises_empty_args(
-        self, mocker, api_mock, master_urls, user, students, empty_arg
-    ):
-        """None of the arguments are allowed to be empty."""
-        with pytest.raises(ValueError) as exc_info:
-            command.update_student_repos(
-                master_repo_urls=master_urls,
-                students=students,
-                user=user,
-                api=api_mock,
-            )
-        assert empty_arg in str(exc_info)
-
-    @pytest.mark.noapimock
-    @pytest.mark.parametrize(
-        *RAISES_ON_INVALID_TYPE_PARAMETRIZATION,
-        ids=RAISES_ON_EMPTY_INVALID_TYPE_IDS
-    )
-    def test_raises_on_invalid_type(
-        self, master_urls, students, user, api, type_error_arg
-    ):
-        """Test that the non-itrable arguments are type checked."""
-        with pytest.raises(TypeError) as exc_info:
-            command.update_student_repos(master_urls, students, user, api)
-        assert type_error_arg in str(exc_info.value)
-
     def test_happy_path(
         self,
         git_mock,
@@ -546,22 +442,6 @@ class TestUpdateStudentRepos:
 class TestOpenIssue:
     """Tests for open_issue."""
 
-    # TODO expand to also test org_name and github_api_base_url can probably
-    # use the RAISES_ON_EMPTY_ARGS_PARAMETRIZATION for that, somehow
-    @pytest.mark.parametrize(
-        "master_repo_names, students, empty_arg",
-        [
-            ([], list(STUDENTS), "master_repo_names"),
-            (list(MASTER_NAMES), [], "students"),
-        ],
-    )
-    def test_raises_on_empty_args(
-        self, api_mock, master_repo_names, students, empty_arg
-    ):
-        with pytest.raises(ValueError) as exc_info:
-            command.open_issue(ISSUE, master_repo_names, students, api_mock)
-        assert empty_arg in str(exc_info)
-
     def test_happy_path(self, mocker, api_mock):
         master_names = ["week-1", "week-2"]
         students = list("abc")
@@ -587,36 +467,6 @@ class TestOpenIssue:
 class TestCloseIssue:
     """Tests for close_issue."""
 
-    @pytest.mark.parametrize(
-        "master_repo_names, students, empty_arg",
-        [
-            ([], list(STUDENTS), "master_repo_names"),
-            (list(MASTER_NAMES), [], "students"),
-        ],
-    )
-    def test_raises_on_empty_args(
-        self, api_mock, master_repo_names, students, empty_arg
-    ):
-        """only the regex is allowed ot be empty."""
-        with pytest.raises(ValueError) as exc_info:
-            command.close_issue(
-                "someregex", master_repo_names, students, api_mock
-            )
-        assert empty_arg in str(exc_info)
-
-    @pytest.mark.noapimock
-    @pytest.mark.parametrize(
-        "title_regex, api, type_error_arg",
-        [(2, API, "title_regex"), ("someregex", 41, "api")],
-    )
-    def test_raises_on_invalid_type(
-        self, master_names, students, title_regex, api, type_error_arg
-    ):
-        """Test that the non-itrable arguments are type checked."""
-        with pytest.raises(TypeError) as exc_info:
-            command.close_issue(title_regex, master_names, students, api)
-        assert type_error_arg in str(exc_info.value)
-
     def test_happy_path(self, api_mock):
         title_regex = r"some-regex\d\w"
         master_names = ["week-1", "week-2"]
@@ -689,20 +539,6 @@ class TestCloneRepos:
             "repobee.config.get_plugin_names", return_value=PLUGINS
         )
 
-    @pytest.mark.parametrize(
-        "master_repo_names, students, empty_arg",
-        [
-            ([], list(STUDENTS), "master_repo_names"),
-            (list(MASTER_NAMES), [], "students"),
-        ],
-    )
-    def test_raises_on_empty_args(
-        self, api_mock, master_repo_names, students, empty_arg
-    ):
-        with pytest.raises(ValueError) as exc_info:
-            command.clone_repos(master_repo_names, students, api_mock)
-        assert empty_arg in str(exc_info)
-
     def test_happy_path(self, api_mock, git_mock, master_names, students):
         """Tests that the correct calls are made when there are no errors."""
         expected_urls = [
@@ -735,17 +571,6 @@ class TestCloneRepos:
 class TestMigrateRepo:
     """Tests for migrate_repo."""
 
-    @pytest.mark.parametrize(
-        "master_repo_urls, user, , empty_arg",
-        [([], USER, "master_repo_urls"), (["https://some_url"], "", "user")],
-    )
-    def test_raises_on_empty_args(
-        self, api_mock, master_repo_urls, user, empty_arg
-    ):
-        with pytest.raises(ValueError) as exc_info:
-            command.migrate_repos(master_repo_urls, user, api_mock)
-        assert empty_arg in str(exc_info)
-
     @pytest.mark.nogitmock
     def test_happy_path(
         self, mocker, api_mock, ensure_teams_and_members_mock, tmpdir
@@ -912,7 +737,7 @@ class TestCheckPeerReviewProgress:
         ]
         # TODO change this when groups are supported
         single_students = [g.members[0] for g in students]
-        
+
         command.check_peer_review_progress(
             master_names, students, title_regex, 2, api_mock
         )
diff --git a/tests/test_git.py b/tests/test_git.py
index 68844ff..166db57 100644
--- a/tests/test_git.py
+++ b/tests/test_git.py
@@ -110,23 +110,6 @@ def test_insert_empty_token_raises():
     assert "empty token" in str(exc)
 
 
-@pytest.mark.parametrize(
-    "repo_url, single_branch, branch, cwd, type_error_arg",
-    [
-        (32, True, "master", ".", "repo_url"),
-        ("some_url", 42, "master", ".", "single_branch"),
-        ("some_url", False, 42, ".", "branch"),
-        ("some_url", True, "master", 42, "cwd"),
-    ],
-)
-def test_clone_single_raises_on_type_errors(
-    env_setup, repo_url, single_branch, branch, cwd, type_error_arg
-):
-    with pytest.raises(TypeError) as exc_info:
-        git.clone_single(repo_url, TOKEN, single_branch, branch, cwd)
-    assert type_error_arg in str(exc_info)
-
-
 def test_clone_single_raises_on_empty_branch(env_setup):
     with pytest.raises(ValueError) as exc:
         git.clone_single(URL_TEMPLATE.format(""), TOKEN, branch="")
@@ -224,21 +207,6 @@ class TestPush:
 
         assert "tries must be larger than 0" in str(exc_info)
 
-    def test_raises_on_non_str_user(self, env_setup, push_tuples):
-        with pytest.raises(TypeError) as exc_info:
-            git.push(push_tuples, 32, TOKEN)
-        assert "user" in str(exc_info)
-
-    def test_raises_on_empty_push_tuples(self, env_setup):
-        with pytest.raises(ValueError) as exc_info:
-            git.push([], USER, TOKEN)
-        assert "push_tuples" in str(exc_info)
-
-    def test_raises_on_empty_user(self, env_setup, push_tuples):
-        with pytest.raises(ValueError) as exc_info:
-            git.push(push_tuples, "", TOKEN)
-        assert "user" in str(exc_info)
-
     def test(self, env_setup, push_tuples, aio_subproc):
         """Test that push works as expected when no exceptions are thrown by
         tasks.
diff --git a/tests/test_util.py b/tests/test_util.py
index c1f8f81..a6835c9 100644
--- a/tests/test_util.py
+++ b/tests/test_util.py
@@ -81,21 +81,6 @@ class TestReadIssue:
         assert issue.body == expected_body
 
 
-@pytest.mark.parametrize(
-    "team_name, master_repo_name, empty_arg",
-    [
-        ("", "some-repo-name", "team_name"),
-        ("some-team-name", "", "master_repo_name"),
-    ],
-)
-def test_generate_repo_name_raises_on_empty_arg(
-    team_name, master_repo_name, empty_arg
-):
-    with pytest.raises(ValueError) as exc:
-        util.generate_repo_name(team_name, master_repo_name)
-    assert empty_arg in str(exc.value)
-
-
 @pytest.mark.parametrize(
     "url, expected_name",
     [

pip install -e .[TEST]
parse_log_pytest
requirements.txt
pytest
apt-get update apt-get install -y gcc
3.7
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
appdirs==1.4.4
certifi @ file:///croot/certifi_1671487769961/work/certifi
cffi==1.15.1
charset-normalizer==3.4.1
codecov==2.1.13
colored==1.4.4
coverage==7.2.7
cryptography==44.0.2
daiquiri==3.2.1
Deprecated==1.2.18
exceptiongroup==1.2.2
idna==3.10
importlib-metadata==6.7.0
iniconfig==2.0.0
packaging==24.0
pluggy==1.2.0
pycparser==2.21
PyGithub==2.3.0
PyJWT==2.8.0
PyNaCl==1.5.0
pytest==7.4.4
pytest-cov==4.1.0
pytest-mock==3.11.1
python-json-logger==3.0.1
-e git+https://github.com/repobee/repobee.git@9f90b85a1ff502c64c6dadc8152d792ed95072fa#egg=repobee
repobee-plug==0.12.0
requests==2.31.0
tomli==2.0.1
typing_extensions==4.7.1
urllib3==2.0.7
wrapt==1.16.0
zipp==3.15.0

name: repobee
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=22.3.1=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - appdirs==1.4.4
      - cffi==1.15.1
      - charset-normalizer==3.4.1
      - codecov==2.1.13
      - colored==1.4.4
      - coverage==7.2.7
      - cryptography==44.0.2
      - daiquiri==3.2.1
      - deprecated==1.2.18
      - exceptiongroup==1.2.2
      - idna==3.10
      - importlib-metadata==6.7.0
      - iniconfig==2.0.0
      - packaging==24.0
      - pluggy==1.2.0
      - pycparser==2.21
      - pygithub==2.3.0
      - pyjwt==2.8.0
      - pynacl==1.5.0
      - pytest==7.4.4
      - pytest-cov==4.1.0
      - pytest-mock==3.11.1
      - python-json-logger==3.0.1
      - repobee==1.3.0
      - repobee-plug==0.12.0
      - requests==2.31.0
      - tomli==2.0.1
      - typing-extensions==4.7.1
      - urllib3==2.0.7
      - wrapt==1.16.0
      - zipp==3.15.0
prefix: /opt/conda/envs/repobee

tests/test_command.py::TestSetupStudentRepos::test_raises_on_clone_failure tests/test_command.py::TestSetupStudentRepos::test_raises_on_duplicate_master_urls tests/test_command.py::TestSetupStudentRepos::test_happy_path tests/test_command.py::TestUpdateStudentRepos::test_raises_on_duplicate_master_urls tests/test_command.py::TestUpdateStudentRepos::test_happy_path tests/test_command.py::TestUpdateStudentRepos::test_issues_on_exceptions[issue0] tests/test_command.py::TestUpdateStudentRepos::test_issues_on_exceptions[None] tests/test_command.py::TestUpdateStudentRepos::test_issues_arent_opened_on_exceptions_if_unspeficied tests/test_command.py::TestOpenIssue::test_happy_path tests/test_command.py::TestCloseIssue::test_happy_path tests/test_command.py::TestCloneRepos::test_happy_path tests/test_command.py::TestMigrateRepo::test_happy_path tests/test_command.py::TestListIssues::test_happy_path[None-True--open] tests/test_command.py::TestListIssues::test_happy_path[None-True--closed] tests/test_command.py::TestListIssues::test_happy_path[None-True--all] tests/test_command.py::TestListIssues::test_happy_path[None-True-^.*$-open] tests/test_command.py::TestListIssues::test_happy_path[None-True-^.*$-closed] tests/test_command.py::TestListIssues::test_happy_path[None-True-^.*$-all] tests/test_command.py::TestListIssues::test_happy_path[None-False--open] tests/test_command.py::TestListIssues::test_happy_path[None-False--closed] tests/test_command.py::TestListIssues::test_happy_path[None-False--all] tests/test_command.py::TestListIssues::test_happy_path[None-False-^.*$-open] tests/test_command.py::TestListIssues::test_happy_path[None-False-^.*$-closed] tests/test_command.py::TestListIssues::test_happy_path[None-False-^.*$-all] tests/test_command.py::TestListIssues::test_happy_path[slarse-True--open] tests/test_command.py::TestListIssues::test_happy_path[slarse-True--closed] tests/test_command.py::TestListIssues::test_happy_path[slarse-True--all] tests/test_command.py::TestListIssues::test_happy_path[slarse-True-^.*$-open] tests/test_command.py::TestListIssues::test_happy_path[slarse-True-^.*$-closed] tests/test_command.py::TestListIssues::test_happy_path[slarse-True-^.*$-all] tests/test_command.py::TestListIssues::test_happy_path[slarse-False--open] tests/test_command.py::TestListIssues::test_happy_path[slarse-False--closed] tests/test_command.py::TestListIssues::test_happy_path[slarse-False--all] tests/test_command.py::TestListIssues::test_happy_path[slarse-False-^.*$-open] tests/test_command.py::TestListIssues::test_happy_path[slarse-False-^.*$-closed] tests/test_command.py::TestListIssues::test_happy_path[slarse-False-^.*$-all] tests/test_command.py::TestAssignPeerReviewers::test_happy_path
tests/test_command.py::TestAssignPeerReviewers::test_too_few_students_raises[3-3] tests/test_command.py::TestAssignPeerReviewers::test_too_few_students_raises[3-4] tests/test_command.py::TestAssignPeerReviewers::test_zero_reviews_raises
tests/test_command.py::test_purge_review_teams tests/test_command.py::TestCheckPeerReviewProgress::test_happy_path tests/test_git.py::test_insert_token tests/test_git.py::test_insert_empty_token_raises tests/test_git.py::test_clone_single_raises_on_empty_branch tests/test_git.py::test_clone_single_raises_on_non_zero_exit_from_git_clone tests/test_git.py::test_clone_single_issues_correct_command_with_defaults tests/test_git.py::test_clone_single_issues_correct_command_without_single_branch tests/test_git.py::test_clone_single_issues_correct_command_with_single_other_branch tests/test_git.py::test_clone_single_issues_correct_command_with_cwd tests/test_git.py::TestPush::test_push_raises_when_tries_is_less_than_one[0] tests/test_git.py::TestPush::test_push_raises_when_tries_is_less_than_one[-2] tests/test_git.py::TestPush::test_push_raises_when_tries_is_less_than_one[-10] tests/test_git.py::TestPush::test tests/test_git.py::TestPush::test_tries_all_calls_despite_exceptions tests/test_git.py::TestPush::test_stops_retrying_when_failed_pushes_succeed tests/test_git.py::TestPush::test_tries_all_calls_when_repos_up_to_date tests/test_git.py::TestClone::test_happy_path[besttoken1337] tests/test_git.py::TestClone::test_happy_path[something-else-entirely] tests/test_git.py::TestClone::test_tries_all_calls_despite_exceptions tests/test_git.py::TestClone::test_tries_all_calls_despite_exceptions_lower_level tests/test_util.py::TestReadIssue::test_raises_when_file_does_not_exist tests/test_util.py::TestReadIssue::test_raises_when_path_points_to_dir tests/test_util.py::TestReadIssue::test_empty_title_and_body_if_file_is_empty tests/test_util.py::TestReadIssue::test_only_title tests/test_util.py::TestReadIssue::test_title_and_body tests/test_util.py::test_repo_name_extracts_correct_part[https://github.com/slarse/some-repo-some-repo] tests/test_util.py::test_repo_name_extracts_correct_part[https://github.com/slarse/some-repo.git-some-repo] tests/test_util.py::test_repo_name_extracts_correct_part[https://gitrepourls/repos/some-repo/base-name-base-name] tests/test_util.py::test_repo_name_extracts_correct_part[https://gitrepourls/repos/some-repo/base-name.git-base-name] tests/test_util.py::TestFindFilesByExtension::test_find_java_files tests/test_util.py::TestFindFilesByExtension::test_find_python_files tests/test_util.py::TestFindFilesByExtension::test_find_java_py_md_files tests/test_util.py::TestFindFilesByExtension::test_works_when_no_files_found tests/test_util.py::TestFindFilesByExtension::test_does_not_find_files_when_dot_is_omitted
repobee/__version.py repobee/github_api.py repobee/command.py repobee/git.py repobee/util.py
repobee/__version.py repobee/github_api.py repobee/command.py repobee/git.py repobee/util.py