Add ability to persist base urls with clientid/secret/token (fixes #200)
This commit is contained in:
pare
5c4916bd81
commit
ca45cd65aa
S'han modificat 3 arxius amb 65 adicions i 19 eliminacions
|
@ -267,8 +267,9 @@ class Mastodon:
|
||||||
|
|
||||||
if to_file is not None:
|
if to_file is not None:
|
||||||
with open(to_file, 'w') as secret_file:
|
with open(to_file, 'w') as secret_file:
|
||||||
secret_file.write(response['client_id'] + '\n')
|
secret_file.write(response['client_id'] + "\n")
|
||||||
secret_file.write(response['client_secret'] + '\n')
|
secret_file.write(response['client_secret'] + "\n")
|
||||||
|
secret_file.write(api_base_url + "\n")
|
||||||
|
|
||||||
return (response['client_id'], response['client_secret'])
|
return (response['client_id'], response['client_secret'])
|
||||||
|
|
||||||
|
@ -276,7 +277,7 @@ class Mastodon:
|
||||||
# Authentication, including constructor
|
# Authentication, including constructor
|
||||||
###
|
###
|
||||||
def __init__(self, client_id=None, client_secret=None, access_token=None,
|
def __init__(self, client_id=None, client_secret=None, access_token=None,
|
||||||
api_base_url=__DEFAULT_BASE_URL, debug_requests=False,
|
api_base_url=None, debug_requests=False,
|
||||||
ratelimit_method="wait", ratelimit_pacefactor=1.1,
|
ratelimit_method="wait", ratelimit_pacefactor=1.1,
|
||||||
request_timeout=__DEFAULT_TIMEOUT, mastodon_version=None,
|
request_timeout=__DEFAULT_TIMEOUT, mastodon_version=None,
|
||||||
version_check_mode = "created", session=None):
|
version_check_mode = "created", session=None):
|
||||||
|
@ -285,9 +286,12 @@ class Mastodon:
|
||||||
give a `client_id` and it is not a file, you must also give a secret. If you specify an
|
give a `client_id` and it is not a file, you must also give a secret. If you specify an
|
||||||
`access_token` then you don't need to specify a `client_id`. It is allowed to specify
|
`access_token` then you don't need to specify a `client_id`. It is allowed to specify
|
||||||
neither - in this case, you will be restricted to only using endpoints that do not
|
neither - in this case, you will be restricted to only using endpoints that do not
|
||||||
require authentication.
|
require authentication. If a file is given as `client_id`, client ID, secret and
|
||||||
|
base url are read from that file.
|
||||||
|
|
||||||
You can also specify an `access_token`, directly or as a file (as written by `log_in()`_).
|
You can also specify an `access_token`, directly or as a file (as written by `log_in()`_). If
|
||||||
|
a file is given, Mastodon.py also tries to load the base URL from this file, if present. A
|
||||||
|
client id and secret are not required in this case.
|
||||||
|
|
||||||
Mastodon.py can try to respect rate limits in several ways, controlled by `ratelimit_method`.
|
Mastodon.py can try to respect rate limits in several ways, controlled by `ratelimit_method`.
|
||||||
"throw" makes functions throw a `MastodonRatelimitError` when the rate
|
"throw" makes functions throw a `MastodonRatelimitError` when the rate
|
||||||
|
@ -298,8 +302,9 @@ class Mastodon:
|
||||||
even in "wait" and "pace" mode, requests can still fail due to network or other problems! Also
|
even in "wait" and "pace" mode, requests can still fail due to network or other problems! Also
|
||||||
note that "pace" and "wait" are NOT thread safe.
|
note that "pace" and "wait" are NOT thread safe.
|
||||||
|
|
||||||
Specify `api_base_url` if you wish to talk to an instance other than the flagship one.
|
Specify `api_base_url` if you wish to talk to an instance other than the flagship one. When
|
||||||
If a file is given as `client_id`, client ID and secret are read from that file.
|
reading from client id or access token files as written by Mastodon.py 1.5.0 or larger,
|
||||||
|
this can be omitted.
|
||||||
|
|
||||||
By default, a timeout of 300 seconds is used for all requests. If you wish to change this,
|
By default, a timeout of 300 seconds is used for all requests. If you wish to change this,
|
||||||
pass the desired timeout (in seconds) as `request_timeout`.
|
pass the desired timeout (in seconds) as `request_timeout`.
|
||||||
|
@ -317,7 +322,10 @@ class Mastodon:
|
||||||
changed after the version of Mastodon that is connected has been released. If it is set to "none",
|
changed after the version of Mastodon that is connected has been released. If it is set to "none",
|
||||||
version checking is disabled.
|
version checking is disabled.
|
||||||
"""
|
"""
|
||||||
|
self.api_base_url = None
|
||||||
|
if not api_base_url is None:
|
||||||
self.api_base_url = Mastodon.__protocolize(api_base_url)
|
self.api_base_url = Mastodon.__protocolize(api_base_url)
|
||||||
|
|
||||||
self.client_id = client_id
|
self.client_id = client_id
|
||||||
self.client_secret = client_secret
|
self.client_secret = client_secret
|
||||||
self.access_token = access_token
|
self.access_token = access_token
|
||||||
|
@ -364,6 +372,13 @@ class Mastodon:
|
||||||
with open(self.client_id, 'r') as secret_file:
|
with open(self.client_id, 'r') as secret_file:
|
||||||
self.client_id = secret_file.readline().rstrip()
|
self.client_id = secret_file.readline().rstrip()
|
||||||
self.client_secret = secret_file.readline().rstrip()
|
self.client_secret = secret_file.readline().rstrip()
|
||||||
|
|
||||||
|
try_base_url = secret_file.readline().rstrip()
|
||||||
|
if (not try_base_url is None) and len(try_base_url) != 0:
|
||||||
|
try_base_url = Mastodon.__protocolize(try_base_url)
|
||||||
|
if not (self.api_base_url is None or try_base_url == self.api_base_url):
|
||||||
|
raise MastodonIllegalArgumentError('Mismatch in base URLs between files and/or specified')
|
||||||
|
self.api_base_url = try_base_url
|
||||||
else:
|
else:
|
||||||
if self.client_secret is None:
|
if self.client_secret is None:
|
||||||
raise MastodonIllegalArgumentError('Specified client id directly, but did not supply secret')
|
raise MastodonIllegalArgumentError('Specified client id directly, but did not supply secret')
|
||||||
|
@ -372,6 +387,13 @@ class Mastodon:
|
||||||
with open(self.access_token, 'r') as token_file:
|
with open(self.access_token, 'r') as token_file:
|
||||||
self.access_token = token_file.readline().rstrip()
|
self.access_token = token_file.readline().rstrip()
|
||||||
|
|
||||||
|
try_base_url = token_file.readline().rstrip()
|
||||||
|
if (not try_base_url is None) and len(try_base_url) != 0:
|
||||||
|
try_base_url = Mastodon.__protocolize(try_base_url)
|
||||||
|
if not (self.api_base_url is None or try_base_url == self.api_base_url):
|
||||||
|
raise MastodonIllegalArgumentError('Mismatch in base URLs between files and/or specified')
|
||||||
|
self.api_base_url = try_base_url
|
||||||
|
|
||||||
def retrieve_mastodon_version(self):
|
def retrieve_mastodon_version(self):
|
||||||
"""
|
"""
|
||||||
Determine installed mastodon version and set major, minor and patch (not including RC info) accordingly.
|
Determine installed mastodon version and set major, minor and patch (not including RC info) accordingly.
|
||||||
|
@ -508,7 +530,8 @@ class Mastodon:
|
||||||
|
|
||||||
if to_file is not None:
|
if to_file is not None:
|
||||||
with open(to_file, 'w') as token_file:
|
with open(to_file, 'w') as token_file:
|
||||||
token_file.write(response['access_token'] + '\n')
|
token_file.write(response['access_token'] + "\n")
|
||||||
|
token_file.write(self.api_base_url + "\n")
|
||||||
|
|
||||||
self.__logged_in_id = None
|
self.__logged_in_id = None
|
||||||
|
|
||||||
|
@ -572,7 +595,8 @@ class Mastodon:
|
||||||
|
|
||||||
if to_file is not None:
|
if to_file is not None:
|
||||||
with open(to_file, 'w') as token_file:
|
with open(to_file, 'w') as token_file:
|
||||||
token_file.write(response['access_token'] + '\n')
|
token_file.write(response['access_token'] + "\n")
|
||||||
|
token_file.write(self.api_base_url + "\n")
|
||||||
|
|
||||||
self.__logged_in_id = None
|
self.__logged_in_id = None
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,6 @@ def test_log_in_password(api_anonymous):
|
||||||
password='mastodonadmin')
|
password='mastodonadmin')
|
||||||
assert token
|
assert token
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.vcr()
|
@pytest.mark.vcr()
|
||||||
def test_log_in_password_incorrect(api_anonymous):
|
def test_log_in_password_incorrect(api_anonymous):
|
||||||
with pytest.raises(MastodonIllegalArgumentError):
|
with pytest.raises(MastodonIllegalArgumentError):
|
||||||
|
@ -38,7 +37,6 @@ def test_log_in_password_incorrect(api_anonymous):
|
||||||
username='admin@localhost',
|
username='admin@localhost',
|
||||||
password='hunter2')
|
password='hunter2')
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.vcr()
|
@pytest.mark.vcr()
|
||||||
def test_log_in_password_to_file(api_anonymous, tmpdir):
|
def test_log_in_password_to_file(api_anonymous, tmpdir):
|
||||||
filepath = tmpdir.join('token')
|
filepath = tmpdir.join('token')
|
||||||
|
@ -46,18 +44,42 @@ def test_log_in_password_to_file(api_anonymous, tmpdir):
|
||||||
username='admin@localhost',
|
username='admin@localhost',
|
||||||
password='mastodonadmin',
|
password='mastodonadmin',
|
||||||
to_file=str(filepath))
|
to_file=str(filepath))
|
||||||
token = filepath.read_text('UTF-8').rstrip()
|
token = filepath.read_text('UTF-8').rstrip().split("\n")[0]
|
||||||
assert token
|
assert token
|
||||||
api = api_anonymous
|
api = api_anonymous
|
||||||
api.access_token = token
|
api.access_token = token
|
||||||
assert api.account_verify_credentials()
|
assert api.account_verify_credentials()
|
||||||
|
|
||||||
|
@pytest.mark.vcr()
|
||||||
|
def test_url_errors(tmpdir):
|
||||||
|
clientid_good = tmpdir.join("clientid")
|
||||||
|
token_good = tmpdir.join("token")
|
||||||
|
clientid_bad = tmpdir.join("clientid_bad")
|
||||||
|
token_bad = tmpdir.join("token_bad")
|
||||||
|
|
||||||
|
clientid_good.write_text("foo\nbar\nhttps://zombo.com\n", "UTF-8")
|
||||||
|
token_good.write_text("foo\nhttps://zombo.com\n", "UTF-8")
|
||||||
|
clientid_bad.write_text("foo\nbar\nhttps://evil.org\n", "UTF-8")
|
||||||
|
token_bad.write_text("foo\nhttps://evil.org\n", "UTF-8")
|
||||||
|
|
||||||
|
api = Mastodon(client_id = clientid_good, access_token = token_good)
|
||||||
|
assert api
|
||||||
|
assert api.api_base_url == "https://zombo.com"
|
||||||
|
assert Mastodon(client_id = clientid_good, access_token = token_good, api_base_url = "zombo.com")
|
||||||
|
|
||||||
|
with pytest.raises(MastodonIllegalArgumentError):
|
||||||
|
Mastodon(client_id = clientid_good, access_token = token_bad, api_base_url = "zombo.com")
|
||||||
|
|
||||||
|
with pytest.raises(MastodonIllegalArgumentError):
|
||||||
|
Mastodon(client_id = clientid_bad, access_token = token_good, api_base_url = "zombo.com")
|
||||||
|
|
||||||
|
with pytest.raises(MastodonIllegalArgumentError):
|
||||||
|
Mastodon(client_id = clientid_bad, access_token = token_bad, api_base_url = "zombo.com")
|
||||||
|
|
||||||
@pytest.mark.skip(reason="Not sure how to test this without setting up selenium or a similar browser automation suite to click on the allow button")
|
@pytest.mark.skip(reason="Not sure how to test this without setting up selenium or a similar browser automation suite to click on the allow button")
|
||||||
def test_log_in_code(api_anonymous):
|
def test_log_in_code(api_anonymous):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skip(reason="Not supported by Mastodon >:@ (yet?)")
|
@pytest.mark.skip(reason="Not supported by Mastodon >:@ (yet?)")
|
||||||
def test_log_in_refresh(api_anonymous):
|
def test_log_in_refresh(api_anonymous):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -31,7 +31,7 @@ def test_create_app(mocker, to_file=None, redirect_uris=None, website=None):
|
||||||
def test_create_app_to_file(mocker, tmpdir):
|
def test_create_app_to_file(mocker, tmpdir):
|
||||||
filepath = tmpdir.join('credentials')
|
filepath = tmpdir.join('credentials')
|
||||||
test_create_app(mocker, to_file=str(filepath))
|
test_create_app(mocker, to_file=str(filepath))
|
||||||
assert filepath.read_text('UTF-8') == "foo\nbar\n"
|
assert filepath.read_text('UTF-8') == "foo\nbar\nhttps://example.com\n"
|
||||||
|
|
||||||
def test_create_app_redirect_uris(mocker):
|
def test_create_app_redirect_uris(mocker):
|
||||||
test_create_app(mocker, redirect_uris='http://example.net')
|
test_create_app(mocker, redirect_uris='http://example.net')
|
||||||
|
|
Loading…
Referencia en una nova incidència