Repository: PyGithub/PyGithub

Issue:
Add support for adding/updating organization membership
Add support for this endpoint. 

https://developer.github.com/v3/orgs/members/#add-or-update-organization-membership



Discussion:
I'd really like to see this in PyGithub too...

So.. this seems to work fine, can we get it merged in?  It's been months...
how to invite someone with just email id using PyGithub ?
Hmm, what's the status of this issue? I see the following PRs that appear to address it:

- https://github.com/PyGithub/PyGithub/pull/424
- https://github.com/PyGithub/PyGithub/pull/726

Neither of the above have unittests.

But these 2 commits referenced above add the tests:
- https://github.com/jbweston/PyGithub/commit/c1ce18a24632e8d4b0752b19ab3fec9806e54593
- https://github.com/jwplayer/PyGithub/commit/3fb0e82d71bb112f3d4632e6b5883fd98d680866


@tjboring You are right. Would you like to glue the pieces together so we can merge this change?
@sfdye Sure. Let me figure out the best way to proceed. I'll update this thread with the steps once I figure it out.
@sfdye I'm open to other suggestions, but what I've come up with is this:

- create a new fork
- copy/paste the changes from PRs 424 and 726
- write tests and get them to pass
- create new PR
@sfdye I'm getting a 404 trying to create the replay data:

```
$ python -m github.tests Organization.testAddMembers --record --auth_with_token
GET /orgs/BeaverSoftware None {'Authorization': 'token XXXXXX', 'User-Agent': 'PyGithub/Python'} => 404
```
@tjboring As I mentioned in another thread, the `BeaverSoftware` organization does not seem to exist anymore. 

Maybe you can open a PR to merge the commits first and I will take a look? 
I figured out a workaround. PR forthcoming.

Resolving patch:
diff --git a/github/Organization.py b/github/Organization.py
--- a/github/Organization.py
+++ b/github/Organization.py
@@ -37,6 +37,7 @@
 ################################################################################
 
 import datetime
+import json
 
 import github.GithubObject
 import github.PaginatedList
@@ -288,6 +289,23 @@ def url(self):
         self._completeIfNotSet(self._url)
         return self._url.value
 
+    def add_to_members(self, member, role=github.GithubObject.NotSet):
+        """
+        :calls: `PUT /orgs/:org/memberships/:user <https://developer.github.com/v3/orgs/members/#add-or-update-organization-membership>`_
+        :param member: :class:`github.NamedUser.NamedUser`
+        :param role: string
+        :rtype: None
+        """
+        assert isinstance(role, (str, unicode)), role
+        assert isinstance(member, github.NamedUser.NamedUser), member
+        url_parameters = {
+            "role": role,
+        }
+        headers, data = self._requester.requestJsonAndCheck(
+            "PUT",
+            self.url + "/memberships/" + member._identity, parameters=url_parameters
+        )
+
     def add_to_public_members(self, public_member):
         """
         :calls: `PUT /orgs/:org/public_members/:user <http://developer.github.com/v3/orgs/members>`_
@@ -726,6 +744,18 @@ def has_in_public_members(self, public_member):
         )
         return status == 204
 
+    def remove_from_membership(self, member):
+        """
+        :calls: `DELETE /orgs/:org/memberships/:user <https://developer.github.com/v3/orgs/members/#remove-organization-membership>`_
+        :param member: :class:`github.NamedUser.NamedUser`
+        :rtype: None
+        """
+        assert isinstance(member, github.NamedUser.NamedUser), member
+        headers, data = self._requester.requestJsonAndCheck(
+            "DELETE",
+            self.url + "/memberships/" + member._identity
+        )
+
     def remove_from_members(self, member):
         """
         :calls: `DELETE /orgs/:org/members/:user <http://developer.github.com/v3/orgs/members>`_


Test patch:
diff --git a/github/tests/Organization.py b/github/tests/Organization.py
--- a/github/tests/Organization.py
+++ b/github/tests/Organization.py
@@ -41,35 +41,53 @@ def setUp(self):
         self.org = self.g.get_organization("BeaverSoftware")
 
     def testAttributes(self):
-        self.assertEqual(self.org.avatar_url, "https://secure.gravatar.com/avatar/d563e337cac2fdc644e2aaaad1e23266?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-orgs.png")
-        self.assertEqual(self.org.billing_email, "BeaverSoftware@vincent-jacques.net")
-        self.assertEqual(self.org.blog, None)
-        self.assertEqual(self.org.collaborators, 0)
+        self.assertEqual(self.org.avatar_url, "https://avatars1.githubusercontent.com/u/1?v=4")
+        self.assertEqual(self.org.billing_email, "foo@example.com")
+        self.assertEqual(self.org.blog, "http://www.example.com")
+        self.assertEqual(self.org.collaborators, 9)
         self.assertEqual(self.org.company, None)
-        self.assertEqual(self.org.created_at, datetime.datetime(2012, 2, 9, 19, 20, 12))
-        self.assertEqual(self.org.disk_usage, 112)
-        self.assertEqual(self.org.email, None)
+        self.assertEqual(self.org.created_at, datetime.datetime(2014, 1, 9, 16, 56, 17))
+        self.assertEqual(self.org.disk_usage, 2)
+        self.assertEqual(self.org.email, '')
         self.assertEqual(self.org.followers, 0)
         self.assertEqual(self.org.following, 0)
         self.assertEqual(self.org.gravatar_id, None)
         self.assertEqual(self.org.html_url, "https://github.com/BeaverSoftware")
-        self.assertEqual(self.org.id, 1424031)
+        self.assertEqual(self.org.id, 1)
         self.assertEqual(self.org.location, "Paris, France")
         self.assertEqual(self.org.login, "BeaverSoftware")
-        self.assertEqual(self.org.name, None)
+        self.assertEqual(self.org.name, "BeaverSoftware")
         self.assertEqual(self.org.owned_private_repos, 0)
         self.assertEqual(self.org.plan.name, "free")
-        self.assertEqual(self.org.plan.private_repos, 0)
-        self.assertEqual(self.org.plan.space, 307200)
+        self.assertEqual(self.org.plan.private_repos, 3)
+        self.assertEqual(self.org.plan.space, 1)
         self.assertEqual(self.org.private_gists, 0)
         self.assertEqual(self.org.public_gists, 0)
-        self.assertEqual(self.org.public_repos, 2)
-        self.assertEqual(self.org.total_private_repos, 0)
+        self.assertEqual(self.org.public_repos, 27)
+        self.assertEqual(self.org.total_private_repos, 7)
         self.assertEqual(self.org.type, "Organization")
         self.assertEqual(self.org.url, "https://api.github.com/orgs/BeaverSoftware")
 
         # test __repr__() based on this attributes
-        self.assertEqual(self.org.__repr__(), 'Organization(name=None, id=1424031)')
+        self.assertEqual(self.org.__repr__(), 'Organization(name="BeaverSoftware", id=1)')
+
+    def testAddMembersDefaultRole(self):
+        lyloa = self.g.get_user("lyloa")
+        self.assertFalse(self.org.has_in_members(lyloa))
+        self.org.add_to_members(lyloa, role='member')
+        # 'Pending' members won't be in /orgs/:org/members/:user
+        self.assertFalse(self.org.has_in_members(lyloa))
+        self.org.remove_from_membership(lyloa)
+        self.assertFalse(self.org.has_in_members(lyloa))
+
+    def testAddMembersAdminRole(self):
+        lyloa = self.g.get_user("lyloa")
+        self.assertFalse(self.org.has_in_members(lyloa))
+        self.org.add_to_members(lyloa, role='admin')
+        # 'Pending' members won't be in /orgs/:org/members/:user
+        self.assertFalse(self.org.has_in_members(lyloa))
+        self.org.remove_from_membership(lyloa)
+        self.assertFalse(self.org.has_in_members(lyloa))
 
     def testEditWithoutArguments(self):
         self.org.edit()
diff --git a/github/tests/ReplayData/Organization.setUp.txt b/github/tests/ReplayData/Organization.setUp.txt
--- a/github/tests/ReplayData/Organization.setUp.txt
+++ b/github/tests/ReplayData/Organization.setUp.txt
@@ -6,6 +6,5 @@ None
 {'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
 None
 200
-[('status', '200 OK'), ('x-ratelimit-remaining', '4997'), ('content-length', '716'), ('server', 'nginx/1.0.13'), ('connection', 'keep-alive'), ('x-ratelimit-limit', '5000'), ('etag', '"bd349122929faf5f9be3e53d9ad41d08"'), ('date', 'Fri, 11 May 2012 09:07:56 GMT'), ('content-type', 'application/json; charset=utf-8')]
-{"type":"Organization","url":"https://api.github.com/orgs/BeaverSoftware","billing_email":"BeaverSoftware@vincent-jacques.net","disk_usage":112,"plan":{"private_repos":0,"space":307200,"name":"free"},"html_url":"https://github.com/BeaverSoftware","blog":null,"login":"BeaverSoftware","public_gists":0,"email":null,"avatar_url":"https://secure.gravatar.com/avatar/d563e337cac2fdc644e2aaaad1e23266?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-orgs.png","total_private_repos":0,"private_gists":0,"collaborators":0,"created_at":"2012-02-09T19:20:12Z","company":null,"location":"Paris, France","followers":0,"following":0,"name":null,"owned_private_repos":0,"id":1424031,"public_repos":2}
-
+[('content-length', '1337'), ('x-runtime-rack', '0.067917'), ('vary', 'Accept, Authorization, Cookie, X-GitHub-OTP'), ('x-oauth-scopes', 'admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion'), ('x-xss-protection', '1; mode=block'), ('x-content-type-options', 'nosniff'), ('x-accepted-oauth-scopes', 'admin:org, read:org, repo, user, write:org'), ('etag', '"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('referrer-policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('status', '200 OK'), ('x-ratelimit-remaining', '4998'), ('x-github-media-type', 'github.v3; format=json'), ('access-control-expose-headers', 'ETag, Link, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval'), ('last-modified', 'Tue, 24 Oct 2017 12:11:24 GMT'), ('date', 'Fri, 06 Apr 2018 12:54:55 GMT'), ('access-control-allow-origin', '*'), ('content-security-policy', "default-src 'none'"), ('strict-transport-security', 'max-age=31536000; includeSubdomains; preload'), ('server', 'GitHub.com'), ('x-ratelimit-limit', '5000'), ('x-frame-options', 'deny'), ('content-type', 'application/json; charset=utf-8'), ('x-ratelimit-reset', '1523022613')]
+{"login":"BeaverSoftware","id":1,"url":"https://api.github.com/orgs/BeaverSoftware", "repos_url":"https://api.github.com/orgs/BeaverSoftware/repos","events_url":"https://api.github .com/orgs/BeaverSoftware/events","hooks_url":"https://api.github.com/orgs/BeaverSoftware/hooks", "issues_url":"https://api.github.com/orgs/BeaverSoftware/issues","members_url":"https://api.github .com/orgs/BeaverSoftware/members{/member}","public_members_url":"https://api.github.com/orgs/BeaverSoftware/public_members{/member}","avatar_url":"https://avatars1.githubusercontent.com/u/1?v=4","description":"BeaverSoftware writes software.","name":"BeaverSoftware","company":null,"blog":"http://www.example.com","location":"Paris, France","email":"","has_organization_projects":true,"has_repository_projects":true,"public_repos":27,"public_gists":0,"followers":0,"following":0,"html_url":"https://github.com/BeaverSoftware","created_at":"2014-01-09T16:56:17Z","updated_at":"2017-10-24T12:11:24Z","type":"Organization","total_private_repos":7,"owned_private_repos":0,"private_gists":0,"disk_usage":2,"collaborators":9,"billing_email":"foo@example.com","plan":{"name":"free","space":1,"private_repos":3,"filled_seats":3,"seats":0},"default_repository_permission":"none","members_can_create_repositories":false}
diff --git a/github/tests/ReplayData/Organization.testAddMembersAdminRole.txt b/github/tests/ReplayData/Organization.testAddMembersAdminRole.txt
new file mode 100644
--- /dev/null
+++ b/github/tests/ReplayData/Organization.testAddMembersAdminRole.txt
@@ -0,0 +1,65 @@
+https
+GET
+api.github.com
+None
+/users/lyloa
+{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+None
+200
+[('content-length', '1136'), ('x-runtime-rack', '0.049683'), ('vary', 'Accept, Authorization, Cookie, X-GitHub-OTP'), ('x-oauth-scopes', 'admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion'), ('x-xss-protection', '1; mode=block'), ('x-content-type-options', 'nosniff'), ('x-accepted-oauth-scopes', ''), ('etag', '"00000000000000000000000000000000"'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('referrer-policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('status', '200 OK'), ('x-ratelimit-remaining', '4997'), ('x-github-media-type', 'github.v3; format=json'), ('access-control-expose-headers', 'ETag, Link, 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-request-id', '0000:0000:000000:000000:00000000'), ('last-modified', 'Thu, 05 Apr 2018 00:55:17 GMT'), ('date', 'Fri, 06 Apr 2018 12:54:56 GMT'), ('access-control-allow-origin', '*'), ('content-security-policy', "default-src 'none'"), ('strict-transport-security', 'max-age=31536000; includeSubdomains; preload'), ('server', 'GitHub.com'), ('x-ratelimit-limit', '5000'), ('x-frame-options', 'deny'), ('content-type', 'application/json; charset=utf-8'), ('x-ratelimit-reset', '1523022613')]
+{"login":"lyloa","id":1,"avatar_url":"https://avatars1.githubusercontent.com/u/28614060?v=4","gravatar_id":"","url":"https://api.github.com/users/lyloa","html_url":"https://github.com/lyloa","followers_url":"https://api.github.com/users/lyloa/followers","following_url":"https://api.github.com/users/lyloa/following{/other_user}","gists_url":"https://api.github.com/users/lyloa/gists{/gist_id}","starred_url":"https://api.github.com/users/lyloa/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lyloa/subscriptions","organizations_url":"https://api.github.com/users/lyloa/orgs","repos_url":"https://api.github.com/users/lyloa/repos","events_url":"https://api.github.com/users/lyloa/events{/privacy}","received_events_url":"https://api.github.com/users/lyloa/received_events","type":"User","site_admin":false,"name":"Lyloa","company":null,"blog":"","location":null,"email":"lyloa@example.com","hireable":null,"bio":null,"public_repos":1,"public_gists":0,"followers":0,"following":0,"created_at":"2017-05-11T02:10:56Z","updated_at":"2018-04-05T00:55:17Z"}
+
+https
+GET
+api.github.com
+None
+/orgs/BeaverSoftware/members/lyloa
+{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+None
+404
+[('status', '404 Not Found'), ('content-length', '157'), ('x-github-media-type', 'github.v3; format=json'), ('content-security-policy', "default-src 'none'"), ('x-content-type-options', 'nosniff'), ('access-control-expose-headers', 'ETag, Link, 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-request-id', '0000:0000:000000:0000000:00000000'), ('strict-transport-security', 'max-age=31536000; includeSubdomains; preload'), ('x-ratelimit-remaining', '4996'), ('server', 'GitHub.com'), ('access-control-allow-origin', '*'), ('x-ratelimit-limit', '5000'), ('x-runtime-rack', '0.036899'), ('x-xss-protection', '1; mode=block'), ('date', 'Fri, 06 Apr 2018 12:54:56 GMT'), ('x-frame-options', 'deny'), ('x-oauth-scopes', 'admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion'), ('referrer-policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('content-type', 'application/json; charset=utf-8'), ('x-accepted-oauth-scopes', 'read:org, repo, user'), ('x-ratelimit-reset', '1523022613')]
+{"message":"User does not exist or is not a member of the organization","documentation_url":"https://developer.github.com/v3/orgs/members/#check-membership"}
+
+https
+PUT
+api.github.com
+None
+/orgs/BeaverSoftware/memberships/lyloa?role=admin
+{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+None
+200
+[('content-length', '1718'), ('x-runtime-rack', '0.264296'), ('vary', 'Accept, Authorization, Cookie, X-GitHub-OTP'), ('x-oauth-scopes', 'admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion'), ('x-xss-protection', '1; mode=block'), ('x-content-type-options', 'nosniff'), ('x-accepted-oauth-scopes', 'admin:org, repo'), ('etag', '"00000000000000000000000000000000"'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('referrer-policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('status', '200 OK'), ('x-ratelimit-remaining', '4995'), ('x-github-media-type', 'github.v3; format=json'), ('access-control-expose-headers', 'ETag, Link, 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-request-id', '0000:0000:000000:0000000:00000000'), ('date', 'Fri, 06 Apr 2018 12:54:57 GMT'), ('access-control-allow-origin', '*'), ('content-security-policy', "default-src 'none'"), ('strict-transport-security', 'max-age=31536000; includeSubdomains; preload'), ('server', 'GitHub.com'), ('x-ratelimit-limit', '5000'), ('x-frame-options', 'deny'), ('content-type', 'application/json; charset=utf-8'), ('x-ratelimit-reset', '1523022613')]
+{"url":"https://api.github.com/orgs/BeaverSoftware/memberships/lyloa","state":"pending", "role":"member","organization_url":"https://api.github.com/orgs/BeaverSoftware","user":{"login":"lyloa","id":1,"avatar_url":"https://avatars1.githubusercontent.com/u/28614060?v=4","gravatar_id":"","url":"https://api.github.com/users/lyloa","html_url":"https://github.com/lyloa","followers_url":"https://api.github.com/users/lyloa/followers","following_url":"https://api.github.com/users/lyloa/following{/other_user}","gists_url":"https://api.github.com/users/lyloa/gists{/gist_id}","starred_url":"https://api.github.com/users/lyloa/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lyloa/subscriptions","organizations_url":"https://api.github.com/users/lyloa/orgs","repos_url":"https://api.github.com/users/lyloa/repos","events_url":"https://api.github.com/users/lyloa/events{/privacy}","received_events_url":"https://api.github.com/users/lyloa/received_events","type":"User","site_admin":false},"organization":{"login":"BeaverSoftware","id":0000000,"url":"https://api.github.com/orgs/BeaverSoftware","repos_url":"https://api.github.com/orgs/BeaverSoftware/repos","events_url":"https://api.github.com/orgs/BeaverSoftware/events","hooks_url":"https://api.github.com/orgs/BeaverSoftware/hooks","issues_url":"https://api.github.com/orgs/BeaverSoftware/issues","members_url":"https://api.github.com/orgs/BeaverSoftware/members{/member}","public_members_url":"https://api.github.com/orgs/BeaverSoftware/public_members{/member}","avatar_url":"https://avatars1.githubusercontent.com/u/6361338?v=4","description":"Beaver Software is dead.."}}
+
+https
+GET
+api.github.com
+None
+/orgs/BeaverSoftware/members/lyloa
+{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+None
+404
+[('status', '404 Not Found'), ('content-length', '157'), ('x-github-media-type', 'github.v3; format=json'), ('content-security-policy', "default-src 'none'"), ('x-content-type-options', 'nosniff'), ('access-control-expose-headers', 'ETag, Link, 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-request-id', '0000:0000:000000:0000000:00000000'), ('strict-transport-security', 'max-age=31536000; includeSubdomains; preload'), ('x-ratelimit-remaining', '4996'), ('server', 'GitHub.com'), ('access-control-allow-origin', '*'), ('x-ratelimit-limit', '5000'), ('x-runtime-rack', '0.036899'), ('x-xss-protection', '1; mode=block'), ('date', 'Fri, 06 Apr 2018 12:54:56 GMT'), ('x-frame-options', 'deny'), ('x-oauth-scopes', 'admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion'), ('referrer-policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('content-type', 'application/json; charset=utf-8'), ('x-accepted-oauth-scopes', 'read:org, repo, user'), ('x-ratelimit-reset', '1523022613')]
+{"message":"User does not exist or is not a member of the organization","documentation_url":"https://developer.github.com/v3/orgs/members/#check-membership"}
+
+https
+DELETE
+api.github.com
+None
+/orgs/BeaverSoftware/memberships/lyloa
+{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+None
+204
+[('status', '204 No Content'), ('x-ratelimit-remaining', '4993'), ('x-github-media-type', 'github.v3; format=json'), ('content-security-policy', "default-src 'none'"), ('x-content-type-options', 'nosniff'), ('access-control-expose-headers', 'ETag, Link, 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-request-id', '0000:0000:000000:0000000:00000000'), ('strict-transport-security', 'max-age=31536000; includeSubdomains; preload'), ('server', 'GitHub.com'), ('access-control-allow-origin', '*'), ('x-ratelimit-limit', '5000'), ('x-runtime-rack', '0.183118'), ('x-xss-protection', '1; mode=block'), ('date', 'Fri, 06 Apr 2018 12:54:58 GMT'), ('x-frame-options', 'deny'), ('x-oauth-scopes', 'admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion'), ('referrer-policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('content-type', 'application/octet-stream'), ('x-accepted-oauth-scopes', 'admin:org, repo'), ('x-ratelimit-reset', '1523022613')]
+
+
+https
+GET
+api.github.com
+None
+/orgs/BeaverSoftware/members/lyloa
+{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+None
+404
+[('status', '404 Not Found'), ('content-length', '157'), ('x-github-media-type', 'github.v3; format=json'), ('content-security-policy', "default-src 'none'"), ('x-content-type-options', 'nosniff'), ('access-control-expose-headers', 'ETag, Link, 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-request-id', '0000:0000:000000:0000000:00000000'), ('strict-transport-security', 'max-age=31536000; includeSubdomains; preload'), ('x-ratelimit-remaining', '4992'), ('server', 'GitHub.com'), ('access-control-allow-origin', '*'), ('x-ratelimit-limit', '5000'), ('x-runtime-rack', '0.024546'), ('x-xss-protection', '1; mode=block'), ('date', 'Fri, 06 Apr 2018 12:54:58 GMT'), ('x-frame-options', 'deny'), ('x-oauth-scopes', 'admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion'), ('referrer-policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('content-type', 'application/json; charset=utf-8'), ('x-accepted-oauth-scopes', 'read:org, repo, user'), ('x-ratelimit-reset', '1523022613')]
+{"message":"User does not exist or is not a member of the organization","documentation_url":"https://developer.github.com/v3/orgs/members/#check-membership"}
diff --git a/github/tests/ReplayData/Organization.testAddMembersDefaultRole.txt b/github/tests/ReplayData/Organization.testAddMembersDefaultRole.txt
new file mode 100644
--- /dev/null
+++ b/github/tests/ReplayData/Organization.testAddMembersDefaultRole.txt
@@ -0,0 +1,65 @@
+https
+GET
+api.github.com
+None
+/users/lyloa
+{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+None
+200
+[('content-length', '1136'), ('x-runtime-rack', '0.059358'), ('vary', 'Accept, Authorization, Cookie, X-GitHub-OTP'), ('x-oauth-scopes', 'admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion'), ('x-xss-protection', '1; mode=block'), ('x-content-type-options', 'nosniff'), ('x-accepted-oauth-scopes', ''), ('etag', '"XXX"'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('referrer-policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('status', '200 OK'), ('x-ratelimit-remaining', '4974'), ('x-github-media-type', 'github.v3; format=json'), ('access-control-expose-headers', 'ETag, Link, 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-request-id', 'FFFF:ffff:ffFFff:fffffff:FFFFFFFF'), ('last-modified', 'Thu, 05 Apr 2018 00:55:17 GMT'), ('date', 'Thu, 05 Apr 2018 17:09:05 GMT'), ('access-control-allow-origin', '*'), ('content-security-policy', "default-src 'none'"), ('strict-transport-security', 'max-age=31536000; includeSubdomains; preload'), ('server', 'GitHub.com'), ('x-ratelimit-limit', '5000'), ('x-frame-options', 'deny'), ('content-type', 'application/json; charset=utf-8'), ('x-ratelimit-reset', '1522950939')]
+{"login":"lyloa","id":1,"avatar_url":"https://avatars1.githubusercontent.com/u/1?v=4", "gravatar_id":"","url":"https://api.github.com/users/lyloa","html_url":"https://github.com/lyloa","followers_url":"https://api.github.com/users/lyloa/followers","following_url":"https://api.github.com/users/lyloa/following{/other_user}","gists_url":"https://api.github.com/users/lyloa/gists{/gist_id}","starred_url":"https://api.github.com/users/lyloa/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lyloa/subscriptions","organizations_url":"https://api.github.com/users/lyloa/orgs","repos_url":"https://api.github.com/users/lyloa/repos","events_url":"https://api.github.com/users/lyloa/events{/privacy}","received_events_url":"https://api.github.com/users/lyloa/received_events","type":"User","site_admin":false,"name":"lyloa","company":null,"blog":"","location":null,"email":"lyloa@example.com","hireable":null,"bio":null,"public_repos":1,"public_gists":0,"followers":0,"following":0,"created_at":"2017-05-11T02:10:56Z","updated_at":"2018-04-05T00:55:17Z"}
+
+https
+GET
+api.github.com
+None
+/orgs/BeaverSoftware/members/lyloa
+{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+None
+404
+[('status', '404 Not Found'), ('content-length', '157'), ('x-github-media-type', 'github.v3; format=json'), ('content-security-policy', "default-src 'none'"), ('x-content-type-options', 'nosniff'), ('access-control-expose-headers', 'ETag, Link, 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-request-id', 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'), ('strict-transport-security', 'max-age=31536000; includeSubdomains; preload'), ('x-ratelimit-remaining', '4973'), ('server', 'GitHub.com'), ('access-control-allow-origin', '*'), ('x-ratelimit-limit', '5000'), ('x-runtime-rack', '0.035748'), ('x-xss-protection', '1; mode=block'), ('date', 'Thu, 05 Apr 2018 17:09:06 GMT'), ('x-frame-options', 'deny'), ('x-oauth-scopes', 'admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion'), ('referrer-policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('content-type', 'application/json; charset=utf-8'), ('x-accepted-oauth-scopes', 'read:org, repo, user'), ('x-ratelimit-reset', '1522950939')]
+{"message":"User does not exist or is not a member of the organization","documentation_url":"https://developer.github.com/v3/orgs/members/#check-membership"}
+
+https
+PUT
+api.github.com
+None
+/orgs/BeaverSoftware/memberships/lyloa?role=member
+{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+None
+200
+[('content-length', '1718'), ('x-runtime-rack', '0.352123'), ('vary', 'Accept, Authorization, Cookie, X-GitHub-OTP'), ('x-oauth-scopes', 'admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion'), ('x-xss-protection', '1; mode=block'), ('x-content-type-options', 'nosniff'), ('x-accepted-oauth-scopes', 'admin:org, repo'), ('etag', '"92186"'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('referrer-policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('status', '200 OK'), ('x-ratelimit-remaining', '4972'), ('x-github-media-type', 'github.v3; format=json'), ('access-control-expose-headers', 'ETag, Link, 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-request-id', 'ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'), ('date', 'Thu, 05 Apr 2018 17:09:06 GMT'), ('access-control-allow-origin', '*'), ('content-security-policy', "default-src 'none'"), ('strict-transport-security', 'max-age=31536000; includeSubdomains; preload'), ('server', 'GitHub.com'), ('x-ratelimit-limit', '5000'), ('x-frame-options', 'deny'), ('content-type', 'application/json; charset=utf-8'), ('x-ratelimit-reset', '1522950939')]
+{"url":"https://api.github.com/orgs/BeaverSoftware/memberships/lyloa","state":"pending", "role":"member","organization_url":"https://api.github.com/orgs/BeaverSoftware","user":{"login":"lyloa","id":1,"avatar_url":"https://avatars1.githubusercontent.com/u/28614060?v=4","gravatar_id":"","url":"https://api.github.com/users/lyloa","html_url":"https://github.com/lyloa","followers_url":"https://api.github.com/users/lyloa/followers","following_url":"https://api.github.com/users/lyloa/following{/other_user}","gists_url":"https://api.github.com/users/lyloa/gists{/gist_id}","starred_url":"https://api.github.com/users/lyloa/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lyloa/subscriptions","organizations_url":"https://api.github.com/users/lyloa/orgs","repos_url":"https://api.github.com/users/lyloa/repos","events_url":"https://api.github.com/users/lyloa/events{/privacy}","received_events_url":"https://api.github.com/users/lyloa/received_events","type":"User","site_admin":false},"organization":{"login":"BeaverSoftware","id":0000000,"url":"https://api.github.com/orgs/BeaverSoftware","repos_url":"https://api.github.com/orgs/BeaverSoftware/repos","events_url":"https://api.github.com/orgs/BeaverSoftware/events","hooks_url":"https://api.github.com/orgs/BeaverSoftware/hooks","issues_url":"https://api.github.com/orgs/BeaverSoftware/issues","members_url":"https://api.github.com/orgs/BeaverSoftware/members{/member}","public_members_url":"https://api.github.com/orgs/BeaverSoftware/public_members{/member}","avatar_url":"https://avatars1.githubusercontent.com/u/6361338?v=4","description":"Beaver Software is dead.."}}
+
+https
+GET
+api.github.com
+None
+/orgs/BeaverSoftware/members/lyloa
+{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+None
+404
+[('status', '404 Not Found'), ('content-length', '157'), ('x-github-media-type', 'github.v3; format=json'), ('content-security-policy', "default-src 'none'"), ('x-content-type-options', 'nosniff'), ('access-control-expose-headers', 'ETag, Link, 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-request-id', 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'), ('strict-transport-security', 'max-age=31536000; includeSubdomains; preload'), ('x-ratelimit-remaining', '4969'), ('server', 'GitHub.com'), ('access-control-allow-origin', '*'), ('x-ratelimit-limit', '5000'), ('x-runtime-rack', '0.032600'), ('x-xss-protection', '1; mode=block'), ('date', 'Thu, 05 Apr 2018 17:09:08 GMT'), ('x-frame-options', 'deny'), ('x-oauth-scopes', 'admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion'), ('referrer-policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('content-type', 'application/json; charset=utf-8'), ('x-accepted-oauth-scopes', 'read:org, repo, user'), ('x-ratelimit-reset', '1522950939')]
+{"message":"User does not exist or is not a member of the organization","documentation_url":"https://developer.github.com/v3/orgs/members/#check-membership"}
+
+https
+DELETE
+api.github.com
+None
+/orgs/BeaverSoftware/memberships/lyloa
+{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+None
+204
+[('status', '204 No Content'), ('x-ratelimit-remaining', '4970'), ('x-github-media-type', 'github.v3; format=json'), ('content-security-policy', "default-src 'none'"), ('x-content-type-options', 'nosniff'), ('access-control-expose-headers', 'ETag, Link, 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-request-id', 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'), ('strict-transport-security', 'max-age=31536000; includeSubdomains; preload'), ('server', 'GitHub.com'), ('access-control-allow-origin', '*'), ('x-ratelimit-limit', '5000'), ('x-runtime-rack', '0.140419'), ('x-xss-protection', '1; mode=block'), ('date', 'Thu, 05 Apr 2018 17:09:07 GMT'), ('x-frame-options', 'deny'), ('x-oauth-scopes', 'admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion'), ('referrer-policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('content-type', 'application/octet-stream'), ('x-accepted-oauth-scopes', 'admin:org, repo'), ('x-ratelimit-reset', '1522950939')]
+
+
+https
+GET
+api.github.com
+None
+/orgs/BeaverSoftware/members/lyloa
+{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+None
+404
+[('status', '404 Not Found'), ('content-length', '157'), ('x-github-media-type', 'github.v3; format=json'), ('content-security-policy', "default-src 'none'"), ('x-content-type-options', 'nosniff'), ('access-control-expose-headers', 'ETag, Link, 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-request-id', 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'), ('strict-transport-security', 'max-age=31536000; includeSubdomains; preload'), ('x-ratelimit-remaining', '4969'), ('server', 'GitHub.com'), ('access-control-allow-origin', '*'), ('x-ratelimit-limit', '5000'), ('x-runtime-rack', '0.032600'), ('x-xss-protection', '1; mode=block'), ('date', 'Thu, 05 Apr 2018 17:09:08 GMT'), ('x-frame-options', 'deny'), ('x-oauth-scopes', 'admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion'), ('referrer-policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('content-type', 'application/json; charset=utf-8'), ('x-accepted-oauth-scopes', 'read:org, repo, user'), ('x-ratelimit-reset', '1522950939')]
+{"message":"User does not exist or is not a member of the organization","documentation_url":"https://developer.github.com/v3/orgs/members/#check-membership"}