Repository: PyGithub/PyGithub

Issue:
How to remove sent invitations
I used repo.add_to_collaborators to add massively some users to some repositories, but now I have to revert the action for those who haven't accepted the invitation yet, how can I list the invitations and cancel them?
Is there a way to use with PyGithub this API [example](https://developer.github.com/v3/repos/invitations/#delete-a-repository-invitation)?


Discussion:
The invitations API is only partially implemented, but I'll look at adding code to list and delete invitations for repositories today.
Thank you so much @s-t-e-v-e-n-k !
https://github.com/PyGithub/PyGithub/pull/1156 is the first part of this work.
Wow! this feature is going so fast!

Resolving patch:
diff --git a/github/Repository.py b/github/Repository.py
--- a/github/Repository.py
+++ b/github/Repository.py
@@ -814,6 +814,30 @@ def get_collaborator_permission(self, collaborator):
         )
         return data["permission"]
 
+    def get_pending_invitations(self):
+        """
+        :calls: `GET /repos/:owner/:repo/invitations <https://developer.github.com/v3/repos/invitations>`_
+        :rtype: :class:`github.PaginatedList.PaginatedList` of :class:`github.Invitation.Invitation`
+        """
+        return github.PaginatedList.PaginatedList(
+            github.Invitation.Invitation,
+            self._requester,
+            self.url + "/invitations",
+            None
+        )
+
+    def remove_invitation(self, invite_id):
+        """
+        :calls: `DELETE /repos/:owner/:repo/invitations/:invitation_id <https://developer.github.com/v3/repos/invitations>`_
+        :rtype: None
+        """
+        assert isinstance(invite_id, int), invite_id
+
+        headers, data = self._requester.requestJsonAndCheck(
+            "DELETE",
+            self.url + "/invitations/" + str(invite_id)
+        )
+
     def compare(self, base, head):
         """
         :calls: `GET /repos/:owner/:repo/compare/:base...:head <http://developer.github.com/v3/repos/commits>`_


Test patch:
diff --git a/tests/ReplayData/Repository.testGetPendingInvitations.txt b/tests/ReplayData/Repository.testGetPendingInvitations.txt
new file mode 100644
--- /dev/null
+++ b/tests/ReplayData/Repository.testGetPendingInvitations.txt
@@ -0,0 +1,32 @@
+https
+GET
+api.github.com
+None
+/users/Lyloa
+{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+None
+200
+[('status', '200 OK'), ('content-length', '554'), ('x-ratelimit-limit', '5000'), ('x-ratelimit-remaining', '4955'), ('server', 'nginx/1.0.13'), ('connection', 'keep-alive'), ('etag', '"4e931612aa9051643f0a428d2ae60b2e"'), ('date', 'Sun, 27 May 2012 05:34:26 GMT'), ('content-type', 'application/json; charset=utf-8')]
+{"type":"User","url":"https://api.github.com/users/Lyloa","html_url":"https://github.com/Lyloa","company":null,"gravatar_id":"1517ed584458ccf83e03f5d77d9699d7","avatar_url":"https://secure.gravatar.com/avatar/1517ed584458ccf83e03f5d77d9699d7?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","followers":1,"following":0,"created_at":"2011-10-16T14:36:46Z","blog":null,"login":"Lyloa","public_gists":0,"hireable":false,"name":"Lyloa","bio":null,"id":1131432,"public_repos":0,"location":"Paris","email":"nyu@lyloa.net"}
+
+https
+PUT
+api.github.com
+None
+/repos/jacquev6/PyGithub/collaborators/Lyloa
+{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+None
+204
+[('status', '204 No Content'), ('x-ratelimit-remaining', '4953'), ('server', 'nginx/1.0.13'), ('connection', 'keep-alive'), ('x-ratelimit-limit', '5000'), ('etag', '"d41d8cd98f00b204e9800998ecf8427e"'), ('date', 'Sun, 27 May 2012 05:34:27 GMT')]
+
+
+https
+GET
+api.github.com
+None
+/repos/jacquev6/PyGithub/invitations
+{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+None
+200
+[('content-length', '2085'), ('x-runtime-rack', '0.048639'), ('etag', '"23ec009b721d7456726f15f2c6dc5f9d"'), ('status', '200 OK'), ('x-ratelimit-remaining', '4892'), ('x-github-media-type', 'github.v3; format=json'), ('date', 'Thu, 28 Dec 2017 16:31:19 GMT'), ('server', 'GitHub.com'), ('x-ratelimit-limit', '5000'), ('content-type', 'application/json; charset=utf-8'), ('x-ratelimit-reset', '1514478935')]
+[{"node_id":"MDIwOlJlcG9zaXRvcnlJbnZpdGF0aW9uMTcyODUzODg=","repository":{"deployments_url":"https://api.github.com/repos/jacquev6/PyGithub/deployments","forks_url":"https://api.github.com/repos/jacquev6/PyGithub/forks","subscription_url":"https://api.github.com/repos/jacquev6/PyGithub/subscription","collaborators_url":"https://api.github.com/repos/jacquev6/PyGithub/collaborators{/collaborator}","private":false,"owner":{"disk_usage":16692,"total_private_repos":5,"gravatar_id":"b68de5ae38616c296fa345d2b9df2225","hireable":false,"id":327146,"blog":"http://vincent-jacques.net","followers":13,"location":"Paris,France","type":"User","email":"vincent@vincent-jacques.net","private_gists":5,"owned_private_repos":5,"company":"Criteo","html_url":"https://github.com/jacquev6","node_id":"MDQ6VXNlcjMyNzE0Ng==","plan":{"collaborators":1,"name":"micro","private_repos":5,"space":614400},"bio":"","public_gists":1,"collaborators":0,"name":"VincentJacques","url":"https://api.github.com/users/jacquev6","created_at":"2010-07-09T06:10:06Z","public_repos":10,"avatar_url":"https://secure.gravatar.com/avatar/b68de5ae38616c296fa345d2b9df2225?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","following":24,"login":"jacquev6"},"tags_url":"https://api.github.com/repos/jacquev6/PyGithub/tags","contributors_url":"https://api.github.com/repos/jacquev6/PyGithub/contributors","downloads_url":"https://api.github.com/repos/jacquev6/PyGithub/downloads","git_tags_url":"https://api.github.com/repos/jacquev6/PyGithub/git/tags{/sha}","languages_url":"https://api.github.com/repos/jacquev6/PyGithub/languages","fork":true,"releases_url":"https://api.github.com/repos/jacquev6/PyGithub/releases{/id}","labels_url":"https://api.github.com/repos/jacquev6/PyGithub/labels{/name}","events_url":"https://api.github.com/repos/jacquev6/PyGithub/events","html_url":"https://github.com/jacquev6/PyGithub","compare_url":"https://api.github.com/repos/jacquev6/PyGithub/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jacquev6/PyGithub/merges","blobs_url":"https://api.github.com/repos/jacquev6/PyGithub/git/blobs{/sha}","name":"PyGithub","git_commits_url":"https://api.github.com/repos/jacquev6/PyGithub/git/commits{/sha}","subscribers_url":"https://api.github.com/repos/jacquev6/PyGithub/subscribers","issues_url":"https://api.github.com/repos/jacquev6/PyGithub/issues{/number}","pulls_url":"https://api.github.com/repos/jacquev6/PyGithub/pulls{/number}","issue_comment_url":"https://api.github.com/repos/jacquev6/PyGithub/issues/comments{/number}","full_name":"jacquev6/PyGithub","contents_url":"https://api.github.com/repos/jacquev6/PyGithub/contents/{+path}","id":129349732,"keys_url":"https://api.github.com/repos/jacquev6/PyGithub/keys{/key_id}","issue_events_url":"https://api.github.com/repos/jacquev6/PyGithub/issues/events{/number}","assignees_url":"https://api.github.com/repos/jacquev6/PyGithub/assignees{/user}","statuses_url":"https://api.github.com/repos/jacquev6/PyGithub/statuses/{sha}","git_refs_url":"https://api.github.com/repos/jacquev6/PyGithub/git/refs{/sha}","commits_url":"https://api.github.com/repos/jacquev6/PyGithub/commits{/sha}","description":"TypedinteractionswiththeGitHubAPIv3","archive_url":"https://api.github.com/repos/jacquev6/PyGithub/{archive_format}{/ref}","milestones_url":"https://api.github.com/repos/jacquev6/PyGithub/milestones{/number}","comments_url":"https://api.github.com/repos/jacquev6/PyGithub/comments{/number}","node_id":"MDEwOlJlcG9zaXRvcnkxMjkzNDk3MzI=","notifications_url":"https://api.github.com/repos/jacquev6/PyGithub/notifications{?since,all,participating}","branches_url":"https://api.github.com/repos/jacquev6/PyGithub/branches{/branch}","hooks_url":"https://api.github.com/repos/jacquev6/PyGithub/hooks","url":"https://api.github.com/repos/jacquev6/PyGithub","teams_url":"https://api.github.com/repos/jacquev6/PyGithub/teams","trees_url":"https://api.github.com/repos/jacquev6/PyGithub/git/trees{/sha}","stargazers_url":"https://api.github.com/repos/jacquev6/PyGithub/stargazers"},"permissions":"write","url":"https://api.github.com/user/repository_invitations/17285388","created_at":"2019-06-27T11:47:00Z","invitee":{"following_url":"https://api.github.com/users/Lyloa/following{/other_user}","gists_url":"https://api.github.com/users/Lyloa/gists{/gist_id}","organizations_url":"https://api.github.com/users/Lyloa/orgs","url":"https://api.github.com/users/Lyloa","events_url":"https://api.github.com/users/Lyloa/events{/privacy}","html_url":"https://github.com/Lyloa","subscriptions_url":"https://api.github.com/users/Lyloa/subscriptions","avatar_url":"https://avatars3.githubusercontent.com/u/52282986?v=4","repos_url":"https://api.github.com/users/Lyloa/repos","received_events_url":"https://api.github.com/users/Lyloa/received_events","gravatar_id":"","starred_url":"https://api.github.com/users/Lyloa/starred{/owner}{/repo}","site_admin":false,"login":"Lyloa","node_id":"MDQ6VXNlcjUyMjgyOTg2","type":"User","id":52282986,"followers_url":"https://api.github.com/users/Lyloa/followers"},"inviter":{"disk_usage":16692,"total_private_repos":5,"gravatar_id":"b68de5ae38616c296fa345d2b9df2225","hireable":false,"id":327146,"blog":"http://vincent-jacques.net","followers":13,"location":"Paris,France","type":"User","email":"vincent@vincent-jacques.net","private_gists":5,"owned_private_repos":5,"company":"Criteo","html_url":"https://github.com/jacquev6","node_id":"MDQ6VXNlcjMyNzE0Ng==","plan":{"collaborators":1,"name":"micro","private_repos":5,"space":614400},"bio":"","public_gists":1,"collaborators":0,"name":"VincentJacques","url":"https://api.github.com/users/jacquev6","created_at":"2010-07-09T06:10:06Z","public_repos":10,"avatar_url":"https://secure.gravatar.com/avatar/b68de5ae38616c296fa345d2b9df2225?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","following":24,"login":"jacquev6"},"html_url":"https://github.com/jacquev6/PyGithub/invitations","id":17285388}]
diff --git a/tests/ReplayData/Repository.testRemoveInvitation.txt b/tests/ReplayData/Repository.testRemoveInvitation.txt
new file mode 100644
--- /dev/null
+++ b/tests/ReplayData/Repository.testRemoveInvitation.txt
@@ -0,0 +1,11 @@
+https
+DELETE
+api.github.com
+None
+/repos/jacquev6/PyGithub/invitations/17285388
+{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+None
+204
+[('status', '204 No Content'), ('x-ratelimit-remaining', '4992'), ('x-github-media-type', 'github.v3; format=json'), ('x-content-type-options', 'nosniff'), ('content-security-policy', "default-src 'none'"), ('access-control-expose-headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type'), ('strict-transport-security', 'max-age=31536000; includeSubdomains; preload'), ('vary', 'Accept-Encoding'), ('x-accepted-oauth-scopes', ''), ('server', 'GitHub.com'), ('x-ratelimit-limit', '5000'), ('x-oauth-scopes', 'public_repo, repo:status'), ('date', 'Tue, 02 Jul 2019 04:13:39 GMT'), ('x-frame-options', 'deny'), ('access-control-allow-origin', '*'), ('referrer-policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('content-type', 'application/octet-stream'), ('x-xss-protection', '1; mode=block'), ('x-ratelimit-reset', '1562044419')]
+
+
diff --git a/tests/Repository.py b/tests/Repository.py
--- a/tests/Repository.py
+++ b/tests/Repository.py
@@ -299,6 +299,15 @@ def testCollaborators(self):
     def testCollaboratorPermission(self):
         self.assertEqual(self.repo.get_collaborator_permission('jacquev6'), 'admin')
 
+    def testGetPendingInvitations(self):
+        lyloa = self.g.get_user("Lyloa")
+        self.repo.add_to_collaborators(lyloa)
+        invitations = self.repo.get_pending_invitations()
+        self.assertListKeyEqual(invitations, lambda u: u.invitee.login, ["Lyloa"])
+
+    def testRemoveInvitation(self):
+        self.repo.remove_invitation(17285388)
+
     def testCollaboratorPermissionNoPushAccess(self):
         with self.assertRaises(github.GithubException) as raisedexp:
             self.repo.get_collaborator_permission('lyloa')