Skip to content

Commit c9b5d3b

Browse files
chore: improve type-hinting for managers
The 'managers' are dynamically created. This unfortunately means that we don't have any type-hints for them and so editors which understand type-hints won't know that they are valid attributes. * Add the type-hints for the managers we define. * Add a unit test that makes sure that the type-hints and the '_managers' attribute are kept in sync with each other. * Add unit test that makes sure specified managers in '_managers' have a name ending in 'Managers' to keep with current convention. * Make RESTObject._managers always present with a default value of None. * Fix a type-issue revealed now that mypy knows what the type is
1 parent b8a47ba commit c9b5d3b

21 files changed

+249
-20
lines changed

gitlab/base.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class RESTObject(object):
4949
_parent_attrs: Dict[str, Any]
5050
_short_print_attr: Optional[str] = None
5151
_updated_attrs: Dict[str, Any]
52+
_managers: Optional[Iterable[Tuple[str, str]]] = None
5253
manager: "RESTManager"
5354

5455
def __init__(self, manager: "RESTManager", attrs: Dict[str, Any]) -> None:
@@ -150,13 +151,13 @@ def __hash__(self) -> int:
150151
return hash(self.get_id())
151152

152153
def _create_managers(self) -> None:
153-
managers = getattr(self, "_managers", None)
154-
if managers is None:
154+
if self._managers is None:
155155
return
156156

157157
for attr, cls_name in self._managers:
158158
cls = getattr(self._module, cls_name)
159159
manager = cls(self.manager.gitlab, parent=self)
160+
# Since we have our own __setattr__ method, we can't use setattr()
160161
self.__dict__[attr] = manager
161162

162163
def _update_attrs(self, new_attrs: Dict[str, Any]) -> None:

gitlab/v4/cli.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,10 @@ def do_custom(self) -> Any:
9999
def do_project_export_download(self) -> None:
100100
try:
101101
project = self.gl.projects.get(int(self.args["project_id"]), lazy=True)
102-
data = project.exports.get().download()
102+
export_status = project.exports.get()
103+
if TYPE_CHECKING:
104+
assert export_status is not None
105+
data = export_status.download()
103106
sys.stdout.buffer.write(data)
104107

105108
except Exception as e:

gitlab/v4/objects/boards.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class GroupBoardListManager(CRUDMixin, RESTManager):
2626

2727

2828
class GroupBoard(SaveMixin, ObjectDeleteMixin, RESTObject):
29+
lists: GroupBoardListManager
2930
_managers = (("lists", "GroupBoardListManager"),)
3031

3132

@@ -49,6 +50,7 @@ class ProjectBoardListManager(CRUDMixin, RESTManager):
4950

5051

5152
class ProjectBoard(SaveMixin, ObjectDeleteMixin, RESTObject):
53+
lists: ProjectBoardListManager
5254
_managers = (("lists", "ProjectBoardListManager"),)
5355

5456

gitlab/v4/objects/commits.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717

1818
class ProjectCommit(RESTObject):
1919
_short_print_attr = "title"
20+
21+
comments: "ProjectCommitCommentManager"
22+
discussions: ProjectCommitDiscussionManager
23+
statuses: "ProjectCommitStatusManager"
2024
_managers = (
2125
("comments", "ProjectCommitCommentManager"),
2226
("discussions", "ProjectCommitDiscussionManager"),

gitlab/v4/objects/container_registry.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313

1414
class ProjectRegistryRepository(ObjectDeleteMixin, RESTObject):
15+
tags: "ProjectRegistryTagManager"
1516
_managers = (("tags", "ProjectRegistryTagManager"),)
1617

1718

gitlab/v4/objects/deployments.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111

1212
class ProjectDeployment(SaveMixin, RESTObject):
13+
mergerequests: ProjectDeploymentMergeRequestManager
1314
_managers = (("mergerequests", "ProjectDeploymentMergeRequestManager"),)
1415

1516

gitlab/v4/objects/discussions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222

2323
class ProjectCommitDiscussion(RESTObject):
24+
notes: ProjectCommitDiscussionNoteManager
2425
_managers = (("notes", "ProjectCommitDiscussionNoteManager"),)
2526

2627

@@ -32,6 +33,7 @@ class ProjectCommitDiscussionManager(RetrieveMixin, CreateMixin, RESTManager):
3233

3334

3435
class ProjectIssueDiscussion(RESTObject):
36+
notes: ProjectIssueDiscussionNoteManager
3537
_managers = (("notes", "ProjectIssueDiscussionNoteManager"),)
3638

3739

@@ -43,6 +45,7 @@ class ProjectIssueDiscussionManager(RetrieveMixin, CreateMixin, RESTManager):
4345

4446

4547
class ProjectMergeRequestDiscussion(SaveMixin, RESTObject):
48+
notes: ProjectMergeRequestDiscussionNoteManager
4649
_managers = (("notes", "ProjectMergeRequestDiscussionNoteManager"),)
4750

4851

@@ -59,6 +62,7 @@ class ProjectMergeRequestDiscussionManager(
5962

6063

6164
class ProjectSnippetDiscussion(RESTObject):
65+
notes: ProjectSnippetDiscussionNoteManager
6266
_managers = (("notes", "ProjectSnippetDiscussionNoteManager"),)
6367

6468

gitlab/v4/objects/epics.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323

2424
class GroupEpic(ObjectDeleteMixin, SaveMixin, RESTObject):
2525
_id_attr = "iid"
26+
27+
issues: "GroupEpicIssueManager"
28+
resourcelabelevents: GroupEpicResourceLabelEventManager
2629
_managers = (
2730
("issues", "GroupEpicIssueManager"),
2831
("resourcelabelevents", "GroupEpicResourceLabelEventManager"),

gitlab/v4/objects/groups.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,34 @@
4343

4444
class Group(SaveMixin, ObjectDeleteMixin, RESTObject):
4545
_short_print_attr = "name"
46+
47+
accessrequests: GroupAccessRequestManager
48+
audit_events: GroupAuditEventManager
49+
badges: GroupBadgeManager
50+
billable_members: GroupBillableMemberManager
51+
boards: GroupBoardManager
52+
clusters: GroupClusterManager
53+
customattributes: GroupCustomAttributeManager
54+
deploytokens: GroupDeployTokenManager
55+
descendant_groups: "GroupDescendantGroupManager"
56+
epics: GroupEpicManager
57+
exports: GroupExportManager
58+
hooks: GroupHookManager
59+
imports: GroupImportManager
60+
issues: GroupIssueManager
61+
issues_statistics: GroupIssuesStatisticsManager
62+
labels: GroupLabelManager
63+
members: GroupMemberManager
64+
members_all: GroupMemberAllManager
65+
mergerequests: GroupMergeRequestManager
66+
milestones: GroupMilestoneManager
67+
notificationsettings: GroupNotificationSettingsManager
68+
packages: GroupPackageManager
69+
projects: GroupProjectManager
70+
runners: GroupRunnerManager
71+
subgroups: "GroupSubgroupManager"
72+
variables: GroupVariableManager
73+
wikis: GroupWikiManager
4674
_managers = (
4775
("accessrequests", "GroupAccessRequestManager"),
4876
("audit_events", "GroupAuditEventManager"),

gitlab/v4/objects/issues.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,14 @@ class ProjectIssue(
105105
):
106106
_short_print_attr = "title"
107107
_id_attr = "iid"
108+
109+
awardemojis: ProjectIssueAwardEmojiManager
110+
discussions: ProjectIssueDiscussionManager
111+
links: "ProjectIssueLinkManager"
112+
notes: ProjectIssueNoteManager
113+
resourcelabelevents: ProjectIssueResourceLabelEventManager
114+
resourcemilestoneevents: ProjectIssueResourceMilestoneEventManager
115+
resourcestateevents: ProjectIssueResourceStateEventManager
108116
_managers = (
109117
("awardemojis", "ProjectIssueAwardEmojiManager"),
110118
("discussions", "ProjectIssueDiscussionManager"),

gitlab/v4/objects/members.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ class GroupMemberManager(MemberAllMixin, CRUDMixin, RESTManager):
4343

4444
class GroupBillableMember(ObjectDeleteMixin, RESTObject):
4545
_short_print_attr = "username"
46+
47+
memberships: "GroupBillableMemberMembershipManager"
4648
_managers = (("memberships", "GroupBillableMemberMembershipManager"),)
4749

4850

gitlab/v4/objects/merge_requests.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,19 @@ class ProjectMergeRequest(
139139
):
140140
_id_attr = "iid"
141141

142+
approval_rules: ProjectMergeRequestApprovalRuleManager
143+
approvals: ProjectMergeRequestApprovalManager
144+
awardemojis: ProjectMergeRequestAwardEmojiManager
145+
diffs: "ProjectMergeRequestDiffManager"
146+
discussions: ProjectMergeRequestDiscussionManager
147+
notes: ProjectMergeRequestNoteManager
148+
pipelines: ProjectMergeRequestPipelineManager
149+
resourcelabelevents: ProjectMergeRequestResourceLabelEventManager
150+
resourcemilestoneevents: ProjectMergeRequestResourceMilestoneEventManager
151+
resourcestateevents: ProjectMergeRequestResourceStateEventManager
142152
_managers = (
143-
("approvals", "ProjectMergeRequestApprovalManager"),
144153
("approval_rules", "ProjectMergeRequestApprovalRuleManager"),
154+
("approvals", "ProjectMergeRequestApprovalManager"),
145155
("awardemojis", "ProjectMergeRequestAwardEmojiManager"),
146156
("diffs", "ProjectMergeRequestDiffManager"),
147157
("discussions", "ProjectMergeRequestDiscussionManager"),

gitlab/v4/objects/notes.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class ProjectCommitDiscussionNoteManager(
7171

7272

7373
class ProjectIssueNote(SaveMixin, ObjectDeleteMixin, RESTObject):
74+
awardemojis: ProjectIssueNoteAwardEmojiManager
7475
_managers = (("awardemojis", "ProjectIssueNoteAwardEmojiManager"),)
7576

7677

@@ -104,6 +105,7 @@ class ProjectIssueDiscussionNoteManager(
104105

105106

106107
class ProjectMergeRequestNote(SaveMixin, ObjectDeleteMixin, RESTObject):
108+
awardemojis: ProjectMergeRequestNoteAwardEmojiManager
107109
_managers = (("awardemojis", "ProjectMergeRequestNoteAwardEmojiManager"),)
108110

109111

@@ -137,7 +139,8 @@ class ProjectMergeRequestDiscussionNoteManager(
137139

138140

139141
class ProjectSnippetNote(SaveMixin, ObjectDeleteMixin, RESTObject):
140-
_managers = (("awardemojis", "ProjectSnippetNoteAwardEmojiManager"),)
142+
awardemojis: ProjectMergeRequestNoteAwardEmojiManager
143+
_managers = (("awardemojis", "ProjectMergeRequestNoteAwardEmojiManager"),)
141144

142145

143146
class ProjectSnippetNoteManager(CRUDMixin, RESTManager):

gitlab/v4/objects/packages.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ class GroupPackageManager(ListMixin, RESTManager):
143143

144144

145145
class ProjectPackage(ObjectDeleteMixin, RESTObject):
146+
package_files: "ProjectPackageFileManager"
146147
_managers = (("package_files", "ProjectPackageFileManager"),)
147148

148149

gitlab/v4/objects/pipelines.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,15 @@ def __call__(self, **kwargs):
7474

7575

7676
class ProjectPipeline(RefreshMixin, ObjectDeleteMixin, RESTObject):
77+
bridges: "ProjectPipelineBridgeManager"
78+
jobs: "ProjectPipelineJobManager"
79+
test_report: "ProjectPipelineTestReportManager"
80+
variables: "ProjectPipelineVariableManager"
7781
_managers = (
78-
("jobs", "ProjectPipelineJobManager"),
7982
("bridges", "ProjectPipelineBridgeManager"),
80-
("variables", "ProjectPipelineVariableManager"),
83+
("jobs", "ProjectPipelineJobManager"),
8184
("test_report", "ProjectPipelineTestReportManager"),
85+
("variables", "ProjectPipelineVariableManager"),
8286
)
8387

8488
@cli.register_custom_action("ProjectPipeline")
@@ -199,6 +203,7 @@ class ProjectPipelineScheduleVariableManager(
199203

200204

201205
class ProjectPipelineSchedule(SaveMixin, ObjectDeleteMixin, RESTObject):
206+
variables: ProjectPipelineScheduleVariableManager
202207
_managers = (("variables", "ProjectPipelineScheduleVariableManager"),)
203208

204209
@cli.register_custom_action("ProjectPipelineSchedule")

gitlab/v4/objects/projects.py

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -110,29 +110,88 @@ class GroupProjectManager(ListMixin, RESTManager):
110110

111111
class Project(RefreshMixin, SaveMixin, ObjectDeleteMixin, RepositoryMixin, RESTObject):
112112
_short_print_attr = "path"
113+
114+
access_tokens: ProjectAccessTokenManager
115+
accessrequests: ProjectAccessRequestManager
116+
additionalstatistics: ProjectAdditionalStatisticsManager
117+
approvalrules: ProjectApprovalRuleManager
118+
approvals: ProjectApprovalManager
119+
audit_events: ProjectAuditEventManager
120+
badges: ProjectBadgeManager
121+
boards: ProjectBoardManager
122+
branches: ProjectBranchManager
123+
clusters: ProjectClusterManager
124+
commits: ProjectCommitManager
125+
customattributes: ProjectCustomAttributeManager
126+
deployments: ProjectDeploymentManager
127+
deploytokens: ProjectDeployTokenManager
128+
environments: ProjectEnvironmentManager
129+
events: ProjectEventManager
130+
exports: ProjectExportManager
131+
files: ProjectFileManager
132+
forks: "ProjectForkManager"
133+
generic_packages: GenericPackageManager
134+
hooks: ProjectHookManager
135+
imports: ProjectImportManager
136+
issues: ProjectIssueManager
137+
issues_statistics: ProjectIssuesStatisticsManager
138+
issuesstatistics: ProjectIssuesStatisticsManager
139+
jobs: ProjectJobManager
140+
keys: ProjectKeyManager
141+
labels: ProjectLabelManager
142+
members: ProjectMemberManager
143+
members_all: ProjectMemberAllManager
144+
mergerequests: ProjectMergeRequestManager
145+
milestones: ProjectMilestoneManager
146+
notes: ProjectNoteManager
147+
notificationsettings: ProjectNotificationSettingsManager
148+
packages: ProjectPackageManager
149+
pagesdomains: ProjectPagesDomainManager
150+
pipelines: ProjectPipelineManager
151+
pipelineschedules: ProjectPipelineScheduleManager
152+
protectedbranches: ProjectProtectedBranchManager
153+
protectedtags: ProjectProtectedTagManager
154+
pushrules: ProjectPushRulesManager
155+
releases: ProjectReleaseManager
156+
remote_mirrors: "ProjectRemoteMirrorManager"
157+
repositories: ProjectRegistryRepositoryManager
158+
runners: ProjectRunnerManager
159+
services: ProjectServiceManager
160+
snippets: ProjectSnippetManager
161+
tags: ProjectTagManager
162+
triggers: ProjectTriggerManager
163+
users: ProjectUserManager
164+
variables: ProjectVariableManager
165+
wikis: ProjectWikiManager
166+
113167
_managers = (
114168
("access_tokens", "ProjectAccessTokenManager"),
115169
("accessrequests", "ProjectAccessRequestManager"),
116-
("approvals", "ProjectApprovalManager"),
170+
("additionalstatistics", "ProjectAdditionalStatisticsManager"),
117171
("approvalrules", "ProjectApprovalRuleManager"),
172+
("approvals", "ProjectApprovalManager"),
173+
("audit_events", "ProjectAuditEventManager"),
118174
("badges", "ProjectBadgeManager"),
119175
("boards", "ProjectBoardManager"),
120176
("branches", "ProjectBranchManager"),
121-
("jobs", "ProjectJobManager"),
177+
("clusters", "ProjectClusterManager"),
122178
("commits", "ProjectCommitManager"),
123179
("customattributes", "ProjectCustomAttributeManager"),
124180
("deployments", "ProjectDeploymentManager"),
181+
("deploytokens", "ProjectDeployTokenManager"),
125182
("environments", "ProjectEnvironmentManager"),
126183
("events", "ProjectEventManager"),
127-
("audit_events", "ProjectAuditEventManager"),
128184
("exports", "ProjectExportManager"),
129185
("files", "ProjectFileManager"),
130186
("forks", "ProjectForkManager"),
131187
("generic_packages", "GenericPackageManager"),
132188
("hooks", "ProjectHookManager"),
133-
("keys", "ProjectKeyManager"),
134189
("imports", "ProjectImportManager"),
135190
("issues", "ProjectIssueManager"),
191+
("issues_statistics", "ProjectIssuesStatisticsManager"),
192+
("issuesstatistics", "ProjectIssuesStatisticsManager"), # Deprecated
193+
("jobs", "ProjectJobManager"),
194+
("keys", "ProjectKeyManager"),
136195
("labels", "ProjectLabelManager"),
137196
("members", "ProjectMemberManager"),
138197
("members_all", "ProjectMemberAllManager"),
@@ -143,9 +202,9 @@ class Project(RefreshMixin, SaveMixin, ObjectDeleteMixin, RepositoryMixin, RESTO
143202
("packages", "ProjectPackageManager"),
144203
("pagesdomains", "ProjectPagesDomainManager"),
145204
("pipelines", "ProjectPipelineManager"),
205+
("pipelineschedules", "ProjectPipelineScheduleManager"),
146206
("protectedbranches", "ProjectProtectedBranchManager"),
147207
("protectedtags", "ProjectProtectedTagManager"),
148-
("pipelineschedules", "ProjectPipelineScheduleManager"),
149208
("pushrules", "ProjectPushRulesManager"),
150209
("releases", "ProjectReleaseManager"),
151210
("remote_mirrors", "ProjectRemoteMirrorManager"),
@@ -154,15 +213,10 @@ class Project(RefreshMixin, SaveMixin, ObjectDeleteMixin, RepositoryMixin, RESTO
154213
("services", "ProjectServiceManager"),
155214
("snippets", "ProjectSnippetManager"),
156215
("tags", "ProjectTagManager"),
157-
("users", "ProjectUserManager"),
158216
("triggers", "ProjectTriggerManager"),
217+
("users", "ProjectUserManager"),
159218
("variables", "ProjectVariableManager"),
160219
("wikis", "ProjectWikiManager"),
161-
("clusters", "ProjectClusterManager"),
162-
("additionalstatistics", "ProjectAdditionalStatisticsManager"),
163-
("issues_statistics", "ProjectIssuesStatisticsManager"),
164-
("issuesstatistics", "ProjectIssuesStatisticsManager"), # Deprecated
165-
("deploytokens", "ProjectDeployTokenManager"),
166220
)
167221

168222
@cli.register_custom_action("Project", ("forked_from_id",))

gitlab/v4/objects/releases.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
class ProjectRelease(SaveMixin, RESTObject):
1313
_id_attr = "tag_name"
14+
15+
links: "ProjectReleaseLinkManager"
1416
_managers = (("links", "ProjectReleaseLinkManager"),)
1517

1618

gitlab/v4/objects/runners.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class RunnerJobManager(ListMixin, RESTManager):
3434

3535

3636
class Runner(SaveMixin, ObjectDeleteMixin, RESTObject):
37+
jobs: RunnerJobManager
3738
_managers = (("jobs", "RunnerJobManager"),)
3839

3940

0 commit comments

Comments
 (0)