Skip to content

Commit

Permalink
Merge pull request #306 from amaargiru/master
Browse files Browse the repository at this point in the history
Format code with PEP 8 standards
  • Loading branch information
halcy committed Apr 23, 2023
2 parents c6d9361 + 3b5c4ae commit 17831ec
Show file tree
Hide file tree
Showing 29 changed files with 119 additions and 96 deletions.
5 changes: 3 additions & 2 deletions mastodon/Mastodon.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,14 @@
from .admin import Mastodon as Admin
from .streaming_endpoints import Mastodon as Streaming


###
# The actual Mastodon class
#
# Almost all code is now imported from smaller files to make editing a bit more pleasant
###
class Mastodon(Utility, Authentication, Accounts, Instance, Timeline, Statuses, Polls, Notifications, Hashtags,
Filters, Suggestions, Endorsements, Relationships, Lists, Trends, Search, Favourites, Reports,
class Mastodon(Utility, Authentication, Accounts, Instance, Timeline, Statuses, Polls, Notifications, Hashtags,
Filters, Suggestions, Endorsements, Relationships, Lists, Trends, Search, Favourites, Reports,
Preferences, Push, Admin, Conversations, Media, Streaming):
"""
Thorough and easy to use Mastodon
Expand Down
24 changes: 12 additions & 12 deletions mastodon/accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@

from .internals import Mastodon as Internals


class Mastodon(Internals):
@api_version("2.7.0", "2.7.0", "3.4.0")
def create_account(self, username, password, email, agreement=False, reason=None, locale="en", scopes=_DEFAULT_SCOPES, to_file=None, return_detailed_error=False):
"""
Creates a new user account with the given username, password and email. "agreement"
must be set to true (after showing the user the instance's user agreement and having
them agree to it), "locale" specifies the language for the confirmation email as an
ISO 639-1 (two letter) or, if a language does not have one, 639-3 (three letter) language
code. `reason` can be used to specify why a user would like to join if approved-registrations
ISO 639-1 (two letter) or, if a language does not have one, 639-3 (three letter) language
code. `reason` can be used to specify why a user would like to join if approved-registrations
mode is on.
Does not require an access token, but does require a client grant.
Expand All @@ -30,11 +31,11 @@ def create_account(self, username, password, email, agreement=False, reason=None
By default, the function will throw if the account could not be created. Alternately,
when `return_detailed_error` is passed, Mastodon.py will return the detailed error
response that the API provides (Starting from version 3.4.0 - not checked here) as an dict with
error details as the second return value and the token returned as `None` in case of error.
The dict will contain a text `error` values as well as a `details` value which is a dict with
one optional key for each potential field (`username`, `password`, `email` and `agreement`),
each if present containing a dict with an `error` category and free text `description`.
response that the API provides (Starting from version 3.4.0 - not checked here) as an dict with
error details as the second return value and the token returned as `None` in case of error.
The dict will contain a text `error` values as well as a `details` value which is a dict with
one optional key for each potential field (`username`, `password`, `email` and `agreement`),
each if present containing a dict with an `error` category and free text `description`.
Valid error categories are:
* ERR_BLOCKED - When e-mail provider is not allowed
Expand Down Expand Up @@ -77,7 +78,7 @@ def create_account(self, username, password, email, agreement=False, reason=None
raise MastodonIllegalArgumentError(f'Invalid request: {e}')
self.access_token = response['access_token']
self.__set_refresh_token(response.get('refresh_token'))
self.__set_token_expired(int(response.get('expires_in', 0)))
self.__set_token_expired(int(response.get('expires_in', 0)))
except Exception as e:
raise MastodonIllegalArgumentError('Invalid request')

Expand Down Expand Up @@ -274,14 +275,14 @@ def account_lists(self, id):
def account_lookup(self, acct):
"""
Look up an account from user@instance form (@instance allowed but not required for
local accounts). Will only return accounts that the instance already knows about,
and not do any webfinger requests. Use `account_search` if you need to resolve users
local accounts). Will only return accounts that the instance already knows about,
and not do any webfinger requests. Use `account_search` if you need to resolve users
through webfinger from remote.
Returns an :ref:`account dict <account dict>`.
"""
return self.__api_request('GET', '/api/v1/accounts/lookup', self.__generate_params(locals()))

@api_version("3.5.0", "3.5.0", _DICT_VERSION_FAMILIAR_FOLLOWERS)
def account_familiar_followers(self, id):
"""
Expand Down Expand Up @@ -347,7 +348,6 @@ def account_remove_from_followers(self, id):
"""
id = self.__unpack_id(id)
return self.__api_request('POST', f'/api/v1/accounts/{id}/remove_from_followers')


@api_version("1.0.0", "1.4.0", _DICT_VERSION_RELATIONSHIP)
def account_block(self, id):
Expand Down
25 changes: 13 additions & 12 deletions mastodon/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@

from .internals import Mastodon as Internals


class Mastodon(Internals):
###
# Moderation API
###
@api_version("2.9.1", "4.0.0", _DICT_VERSION_ADMIN_ACCOUNT)
def admin_accounts_v2(self, origin=None, by_domain=None, status=None, username=None, display_name=None, email=None, ip=None,
def admin_accounts_v2(self, origin=None, by_domain=None, status=None, username=None, display_name=None, email=None, ip=None,
permissions=None, invited_by=None, role_ids=None, max_id=None, min_id=None, since_id=None, limit=None):
"""
Fetches a list of accounts that match given criteria. By default, local accounts are returned.
Expand Down Expand Up @@ -65,8 +66,8 @@ def admin_accounts_v2(self, origin=None, by_domain=None, status=None, username=N
@api_version("2.9.1", "2.9.1", _DICT_VERSION_ADMIN_ACCOUNT)
def admin_accounts(self, remote=False, by_domain=None, status='active', username=None, display_name=None, email=None, ip=None, staff_only=False, max_id=None, min_id=None, since_id=None, limit=None):
"""
Currently a synonym for admin_accounts_v1, now deprecated. You are strongly encouraged to use admin_accounts_v2 instead, since this one is kind of bad.
Currently a synonym for admin_accounts_v1, now deprecated. You are strongly encouraged to use admin_accounts_v2 instead, since this one is kind of bad.
!!!!! This function may be switched to calling the v2 API in the future. This is your warning. If you want to keep using v1, use it explicitly. !!!!!
"""
return self.admin_accounts_v1(
Expand Down Expand Up @@ -377,16 +378,16 @@ def admin_domain_blocks(self, id=None, limit:int=None):
id = self.__unpack_id(id)
return self.__api_request('GET', f'/api/v1/admin/domain_blocks/{id}')
else:
params = self.__generate_params(locals(),['limit'])
params = self.__generate_params(locals(), ['limit'])
return self.__api_request('GET', '/api/v1/admin/domain_blocks/', params)

@api_version("4.0.0", "4.0.0", _DICT_VERSION_ADMIN_DOMAIN_BLOCK)
def admin_create_domain_block(self, domain:str, severity:str=None, reject_media:bool=None, reject_reports:bool=None, private_comment:str=None, public_comment:str=None, obfuscate:bool=None):
"""
Perform a moderation action on a domain. Requires scope `admin:write:domain_blocks`.
Valid severities are:
* "silence" - hide all posts from federated timelines and do not show notifications to local users from the remote instance's users unless they are following the remote user.
* "silence" - hide all posts from federated timelines and do not show notifications to local users from the remote instance's users unless they are following the remote user.
* "suspend" - deny interactions with this instance going forward. This action is reversible.
* "limit" - generally used with reject_media=true to force reject media from an instance without silencing or suspending..
Expand All @@ -411,7 +412,7 @@ def admin_update_domain_block(self, id, severity:str=None, reject_media:bool=Non
Modify existing moderation action on a domain. Requires scope `admin:write:domain_blocks`.
Valid severities are:
* "silence" - hide all posts from federated timelines and do not show notifications to local users from the remote instance's users unless they are following the remote user.
* "silence" - hide all posts from federated timelines and do not show notifications to local users from the remote instance's users unless they are following the remote user.
* "suspend" - deny interactions with this instance going forward. This action is reversible.
* "limit" - generally used with reject_media=true to force reject media from an instance without silencing or suspending.
Expand Down Expand Up @@ -481,7 +482,7 @@ def admin_measures(self, start_at, end_at, active_users=False, new_users=False,
for key in ["active_users", "new_users", "interactions", "opened_reports", "resolved_reports"]:
if params_init[key] == True:
keys.append(key)

params = {}
for key in ["tag_accounts", "tag_uses", "tag_servers"]:
if params_init[key] is not None:
Expand All @@ -498,7 +499,7 @@ def admin_measures(self, start_at, end_at, active_users=False, new_users=False,
params["keys"] = keys
params["start_at"] = self.__consistent_isoformat_utc(start_at)
params["end_at"] = self.__consistent_isoformat_utc(end_at)

return self.__api_request('POST', '/api/v1/admin/measures', params, use_json=True)

@api_version("3.5.0", "3.5.0", _DICT_VERSION_ADMIN_DIMENSION)
Expand Down Expand Up @@ -531,7 +532,7 @@ def admin_dimensions(self, start_at, end_at, limit=None, languages=False, source
for key in ["languages", "sources", "servers", "space_usage", "software_versions"]:
if params_init[key] == True:
keys.append(key)

params = {}
for key in ["tag_servers", "tag_languages"]:
if params_init[key] is not None:
Expand All @@ -550,7 +551,7 @@ def admin_dimensions(self, start_at, end_at, limit=None, languages=False, source
params["limit"] = limit
params["start_at"] = self.__consistent_isoformat_utc(start_at)
params["end_at"] = self.__consistent_isoformat_utc(end_at)

return self.__api_request('POST', '/api/v1/admin/dimensions', params, use_json=True)

@api_version("3.5.0", "3.5.0", _DICT_VERSION_ADMIN_RETENTION)
Expand All @@ -568,4 +569,4 @@ def admin_retention(self, start_at, end_at, frequency="day"):
"end_at": self.__consistent_isoformat_utc(end_at),
"frequency": frequency
}
return self.__api_request('POST', '/api/v1/admin/retention', params)
return self.__api_request('POST', '/api/v1/admin/retention', params)
9 changes: 5 additions & 4 deletions mastodon/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from .internals import Mastodon as Internals


class Mastodon(Internals):
###
# Registering apps
Expand Down Expand Up @@ -45,7 +46,7 @@ def create_app(client_name, scopes=_DEFAULT_SCOPES, redirect_uris=None, website=
Returns `client_id` and `client_secret`, both as strings.
"""
if api_base_url is None:
raise MastodonIllegalArgumentError("API base URL is required.")
raise MastodonIllegalArgumentError("API base URL is required.")
api_base_url = Mastodon.__protocolize(api_base_url)

request_data = {
Expand Down Expand Up @@ -91,9 +92,9 @@ def __init__(self, client_id=None, client_secret=None, access_token=None, api_ba
version_check_mode="created", session=None, feature_set="mainline", user_agent=_DEFAULT_USER_AGENT, lang=None):
"""
Create a new API wrapper instance based on the given `client_secret` and `client_id` on the
instance given by `api_base_url`. If you give a `client_id` and it is not a file, you must
instance given by `api_base_url`. If you 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 neither - in this case, you will be restricted to only using endpoints
It is allowed to specify neither - in this case, you will be restricted to only using endpoints
that do not require authentication. If a file is given as `client_id`, client ID, secret and
base url are read from that file.
Expand Down Expand Up @@ -221,7 +222,7 @@ def __init__(self, client_id=None, client_secret=None, access_token=None, api_ba

# Verify we have a base URL, protocolize
if self.api_base_url is None:
raise MastodonIllegalArgumentError("API base URL is required.")
raise MastodonIllegalArgumentError("API base URL is required.")
self.api_base_url = Mastodon.__protocolize(self.api_base_url)

if not version_check_mode in ["created", "changed", "none"]:
Expand Down
3 changes: 2 additions & 1 deletion mastodon/conversations.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

from .internals import Mastodon as Internals

class Mastodon(Internals):

class Mastodon(Internals):
###
# Reading data: Conversations
###
Expand Down
2 changes: 1 addition & 1 deletion mastodon/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,4 @@
}
_VALID_SCOPES = ['read', 'write', 'follow', 'push', 'admin:read', 'admin:write'] + \
_SCOPE_SETS['read'] + _SCOPE_SETS['write'] + \
_SCOPE_SETS['admin:read'] + _SCOPE_SETS['admin:write']
_SCOPE_SETS['admin:read'] + _SCOPE_SETS['admin:write']
3 changes: 2 additions & 1 deletion mastodon/endorsements.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

from .internals import Mastodon as Internals

class Mastodon(Internals):

class Mastodon(Internals):
###
# Reading data: Endorsements
###
Expand Down
2 changes: 1 addition & 1 deletion mastodon/favourites.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from .internals import Mastodon as Internals


class Mastodon(Internals):
###
# Reading data: Favourites
Expand Down Expand Up @@ -59,4 +60,3 @@ def bookmarks(self, max_id=None, min_id=None, since_id=None, limit=None):

params = self.__generate_params(locals())
return self.__api_request('GET', '/api/v1/bookmarks', params)

1 change: 1 addition & 0 deletions mastodon/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from .internals import Mastodon as Internals


class Mastodon(Internals):
###
# Reading data: Keyword filters
Expand Down
1 change: 1 addition & 0 deletions mastodon/hashtags.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from .internals import Mastodon as Internals


class Mastodon(Internals):
###
# Reading data: Featured hashtags
Expand Down
1 change: 1 addition & 0 deletions mastodon/instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from .internals import Mastodon as Internals


class Mastodon(Internals):
###
# Reading data: Instances
Expand Down
16 changes: 8 additions & 8 deletions mastodon/internals.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@
from .compat import urlparse, magic, PurePath
from .defaults import _DEFAULT_STREAM_TIMEOUT, _DEFAULT_STREAM_RECONNECT_WAIT_SEC


###
# Internal helpers, dragons probably
###
class Mastodon():
class Mastodon():
def __datetime_to_epoch(self, date_time):
"""
Converts a python datetime to unix epoch, accounting for
Expand All @@ -37,7 +38,6 @@ def __datetime_to_epoch(self, date_time):
date_time = date_time.replace(tzinfo=datetime.timezone.utc)
return date_time.timestamp()


def __get_logged_in_id(self):
"""
Fetch the logged in user's ID, with caching. ID is reset on calls to log_in.
Expand Down Expand Up @@ -77,7 +77,7 @@ def __json_date_parse(json_object):
mark_delete.append(k)
# Two step process because otherwise python gets very upset
for k in mark_delete:
del json_object[k]
del json_object[k]
return json_object

@staticmethod
Expand All @@ -98,7 +98,7 @@ def __json_strnum_to_bignum(json_object):
"""
Converts json string numerals to native python bignums.
"""
for key in ('id', 'week', 'in_reply_to_id', 'in_reply_to_account_id', 'logins', 'registrations', 'statuses',
for key in ('id', 'week', 'in_reply_to_id', 'in_reply_to_account_id', 'logins', 'registrations', 'statuses',
'day', 'last_read_id', 'value', 'frequency', 'rate', 'invited_by_account_id', 'count'):
if (key in json_object and isinstance(json_object[key], six.text_type)):
try:
Expand Down Expand Up @@ -131,14 +131,14 @@ def __consistent_isoformat_utc(datetime_val):
isotime = isotime[:-2] + ":" + isotime[-2:]
return isotime

def __api_request(self, method, endpoint, params={}, files={}, headers={}, access_token_override=None, base_url_override=None,
def __api_request(self, method, endpoint, params={}, files={}, headers={}, access_token_override=None, base_url_override=None,
do_ratelimiting=True, use_json=False, parse=True, return_response_object=False, skip_error_check=False, lang_override=None):
"""
Internal API request helper.
"""
response = None
remaining_wait = 0

# Add language to params if not None
lang = self.lang
if lang_override is not None:
Expand Down Expand Up @@ -270,7 +270,7 @@ def __api_request(self, method, endpoint, params={}, files={}, headers={}, acces
time.sleep(to_next)
request_complete = False
continue

if not skip_error_check:
if response_object.status_code == 404:
ex_type = MastodonNotFoundError
Expand Down Expand Up @@ -665,4 +665,4 @@ def __normalize_version_string(self, version_string):
return version_string.split("+")[1]
except:
# If this fails, assume that if there is a +, what is before that is the masto version (or that there is no +)
return version_string.split("+")[0]
return version_string.split("+")[0]
1 change: 1 addition & 0 deletions mastodon/lists.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from .internals import Mastodon as Internals


class Mastodon(Internals):
###
# Reading data: Lists
Expand Down
1 change: 1 addition & 0 deletions mastodon/media.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from .internals import Mastodon as Internals


class Mastodon(Internals):
###
# Reading data: Media
Expand Down

0 comments on commit 17831ec

Please sign in to comment.