1#

2# Copyright (C) 2019-2025 Mathieu Parent <math.parent@gmail.com>

3#

4# This program is free software: you can redistribute it and/or modify

5# it under the terms of the GNU Lesser General Public License as published by

6# the Free Software Foundation, either version 3 of the License, or

7# (at your option) any later version.

8#

9# This program is distributed in the hope that it will be useful,

10# but WITHOUT ANY WARRANTY; without even the implied warranty of

11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

12# GNU Lesser General Public License for more details.

13#

14# You should have received a copy of the GNU Lesser General Public License

15# along with this program. If not, see <http://www.gnu.org/licenses/>.

16

17

18 from __future__ import annotations

19

20 from typing import TYPE_CHECKING

21

22 from gitlab.exceptions import GitlabGetError

23 from requests import codes

24

25 if TYPE_CHECKING: 25 ↛ 26 line 25 didn't jump to line 26 because the condition on line 25 was never true

26 from gitlabracadabra.gitlab.pygitlab import PyGitlab

27

28

29 class UserCache:

30 """Users mapping cache.

31

32 indexed by id and username.

33 """

34

35 def __init__(self, connection: PyGitlab) -> None:

36 """Initialize a Python-Gitlab wrapper.

37

38 Args:

39 connection: A GitlabConnection/PyGitlab.

40 """

41 self._connection = connection

42 self._username2id: dict[str, int | None] = {}

43 self._id2username: dict[int, str | None] = {}

44

45 def map_user(self, user_id: int, user_username: str) -> None:

46 """Map user id and username.

47

48 Args:

49 user_id: User id.

50 user_username: User username.

51 """

52 self._id2username[user_id] = user_username

53 self._username2id[user_username] = user_id

54

55 def username_from_id(self, user_id: int) -> str | None:

56 """Get user username from id.

57

58 Args:

59 user_id: User id.

60

61 Returns:

62 User username.

63

64 Raises:

65 GitlabGetError: Any HTTP error other than 404.

66 """

67 if user_id not in self._id2username: 67 ↛ 76 line 67 didn't jump to line 76 because the condition on line 67 was always true

68 obj_manager = self._connection.pygitlab.users

69 try:

70 user = obj_manager.get(user_id)

71 self.map_user(user.id, user.username)

72 except GitlabGetError as err:

73 if err.response_code != codes["not_found"]:

74 raise

75 self._id2username[user_id] = None

76 return self._id2username[user_id]

77

78 def id_from_username(self, user_username: str) -> int | None:

79 """Get user id from username.

80

81 Args:

82 user_username: User username.

83

84 Returns:

85 User id.

86 """

87 if user_username not in self._username2id:

88 obj_manager = self._connection.pygitlab.users

89 try:

90 user = list(obj_manager.list(username=user_username))[0] # noqa: RUF015

91 self.map_user(user.id, user.username)

92 except IndexError:

93 self._username2id[user_username] = None

94 return self._username2id[user_username]