aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'mastodon')
-rw-r--r--mastodon/Mastodon.py83
1 files changed, 57 insertions, 26 deletions
diff --git a/mastodon/Mastodon.py b/mastodon/Mastodon.py
index 6a783b4..a60994e 100644
--- a/mastodon/Mastodon.py
+++ b/mastodon/Mastodon.py
@@ -320,11 +320,9 @@ class Mastodon:
320 ### 320 ###
321 # Authentication, including constructor 321 # Authentication, including constructor
322 ### 322 ###
323 def __init__(self, client_id=None, client_secret=None, access_token=None, 323 def __init__(self, client_id=None, client_secret=None, access_token=None, api_base_url=None, debug_requests=False,
324 api_base_url=None, debug_requests=False, 324 ratelimit_method="wait", ratelimit_pacefactor=1.1, request_timeout=__DEFAULT_TIMEOUT, mastodon_version=None,
325 ratelimit_method="wait", ratelimit_pacefactor=1.1, 325 version_check_mode="created", session=None, feature_set="mainline", user_agent="mastodonpy", lang=None):
326 request_timeout=__DEFAULT_TIMEOUT, mastodon_version=None,
327 version_check_mode="created", session=None, feature_set="mainline", user_agent="mastodonpy"):
328 """ 326 """
329 Create a new API wrapper instance based on the given `client_secret` and `client_id` on the 327 Create a new API wrapper instance based on the given `client_secret` and `client_id` on the
330 instance given by `api_base_url`. If you give a `client_id` and it is not a file, you must 328 instance given by `api_base_url`. If you give a `client_id` and it is not a file, you must
@@ -371,6 +369,10 @@ class Mastodon:
371 the app name will be used as `User-Agent` header as default. It is possible to modify old secret files and append 369 the app name will be used as `User-Agent` header as default. It is possible to modify old secret files and append
372 a client app name to use it as a `User-Agent` name. 370 a client app name to use it as a `User-Agent` name.
373 371
372 `lang` can be used to change the locale Mastodon will use to generate responses. Valid parameters are all ISO 639-1 (two letter)
373 or for a language that has none, 639-3 (three letter) language codes. This affects some error messages (those related to validation) and
374 trends. You can change the language using `set_language()`_.
375
374 If no other `User-Agent` is specified, "mastodonpy" will be used. 376 If no other `User-Agent` is specified, "mastodonpy" will be used.
375 """ 377 """
376 self.api_base_url = api_base_url 378 self.api_base_url = api_base_url
@@ -383,7 +385,7 @@ class Mastodon:
383 self.ratelimit_method = ratelimit_method 385 self.ratelimit_method = ratelimit_method
384 self._token_expired = datetime.datetime.now() 386 self._token_expired = datetime.datetime.now()
385 self._refresh_token = None 387 self._refresh_token = None
386 388
387 self.__logged_in_id = None 389 self.__logged_in_id = None
388 390
389 self.ratelimit_limit = 300 391 self.ratelimit_limit = 300
@@ -406,6 +408,9 @@ class Mastodon:
406 # General defined user-agent 408 # General defined user-agent
407 self.user_agent = user_agent 409 self.user_agent = user_agent
408 410
411 # Save language
412 self.lang = lang
413
409 # Token loading 414 # Token loading
410 if self.client_id is not None: 415 if self.client_id is not None:
411 if os.path.isfile(self.client_id): 416 if os.path.isfile(self.client_id):
@@ -467,6 +472,13 @@ class Mastodon:
467 if ratelimit_method not in ["throw", "wait", "pace"]: 472 if ratelimit_method not in ["throw", "wait", "pace"]:
468 raise MastodonIllegalArgumentError("Invalid ratelimit method.") 473 raise MastodonIllegalArgumentError("Invalid ratelimit method.")
469 474
475 def set_language(self, lang):
476 """
477 Set the locale Mastodon will use to generate responses. Valid parameters are all ISO 639-1 (two letter) or, for languages that do
478 not have one, 639-3 (three letter) language codes. This affects some error messages (those related to validation) and trends.
479 """
480 self.lang = lang
481
470 def __normalize_version_string(self, version_string): 482 def __normalize_version_string(self, version_string):
471 # Split off everything after the first space, to take care of Pleromalikes so that the parser doesn't get confused in case those have a + somewhere in their version 483 # Split off everything after the first space, to take care of Pleromalikes so that the parser doesn't get confused in case those have a + somewhere in their version
472 version_string = version_string.split(" ")[0] 484 version_string = version_string.split(" ")[0]
@@ -538,24 +550,27 @@ class Mastodon:
538 """ 550 """
539 return Mastodon.__SUPPORTED_MASTODON_VERSION 551 return Mastodon.__SUPPORTED_MASTODON_VERSION
540 552
541 def auth_request_url(self, client_id=None, redirect_uris="urn:ietf:wg:oauth:2.0:oob", scopes=__DEFAULT_SCOPES, force_login=False, state=None): 553 def auth_request_url(self, client_id=None, redirect_uris="urn:ietf:wg:oauth:2.0:oob", scopes=__DEFAULT_SCOPES, force_login=False, state=None, lang=None):
542 """ 554 """
543 Returns the URL that a client needs to request an OAuth grant from the server. 555 Returns the URL that a client needs to request an OAuth grant from the server.
544 556
545 To log in with OAuth, send your user to this URL. The user will then log in and 557 To log in with OAuth, send your user to this URL. The user will then log in and
546 get a code which you can pass to log_in. 558 get a code which you can pass to `log_in()`_.
547 559
548 scopes are as in `log_in()`_, redirect_uris is where the user should be redirected to 560 `scopes` are as in `log_in()`_, redirect_uris is where the user should be redirected to
549 after authentication. Note that redirect_uris must be one of the URLs given during 561 after authentication. Note that `redirect_uris` must be one of the URLs given during
550 app registration. When using urn:ietf:wg:oauth:2.0:oob, the code is simply displayed, 562 app registration. When using urn:ietf:wg:oauth:2.0:oob, the code is simply displayed,
551 otherwise it is added to the given URL as the "code" request parameter. 563 otherwise it is added to the given URL as the "code" request parameter.
552 564
553 Pass force_login if you want the user to always log in even when already logged 565 Pass force_login if you want the user to always log in even when already logged
554 into web Mastodon (i.e. when registering multiple different accounts in an app). 566 into web Mastodon (i.e. when registering multiple different accounts in an app).
555 567
556 State is the oauth `state`parameter to pass to the server. It is strongly suggested 568 `state` is the oauth `state` parameter to pass to the server. It is strongly suggested
557 to use a random, nonguessable value (i.e. nothing meaningful and no incrementing ID) 569 to use a random, nonguessable value (i.e. nothing meaningful and no incrementing ID)
558 to preserve security guarantees. It can be left out for non-web login flows. 570 to preserve security guarantees. It can be left out for non-web login flows.
571
572 Pass an ISO 639-1 (two letter) or, for languages that do not have one, 639-3 (three letter)
573 language code as `lang` to control the display language for the oauth form.
559 """ 574 """
560 if client_id is None: 575 if client_id is None:
561 client_id = self.client_id 576 client_id = self.client_id
@@ -571,6 +586,7 @@ class Mastodon:
571 params['scope'] = " ".join(scopes) 586 params['scope'] = " ".join(scopes)
572 params['force_login'] = force_login 587 params['force_login'] = force_login
573 params['state'] = state 588 params['state'] = state
589 params['lang'] = lang
574 formatted_params = urlencode(params) 590 formatted_params = urlencode(params)
575 return "".join([self.api_base_url, "/oauth/authorize?", formatted_params]) 591 return "".join([self.api_base_url, "/oauth/authorize?", formatted_params])
576 592
@@ -672,8 +688,9 @@ class Mastodon:
672 Creates a new user account with the given username, password and email. "agreement" 688 Creates a new user account with the given username, password and email. "agreement"
673 must be set to true (after showing the user the instance's user agreement and having 689 must be set to true (after showing the user the instance's user agreement and having
674 them agree to it), "locale" specifies the language for the confirmation email as an 690 them agree to it), "locale" specifies the language for the confirmation email as an
675 ISO 639-1 (two-letter) language code. `reason` can be used to specify why a user 691 ISO 639-1 (two letter) or, if a language does not have one, 639-3 (three letter) language
676 would like to join if approved-registrations mode is on. 692 code. `reason` can be used to specify why a user would like to join if approved-registrations
693 mode is on.
677 694
678 Does not require an access token, but does require a client grant. 695 Does not require an access token, but does require a client grant.
679 696
@@ -1542,10 +1559,10 @@ class Mastodon:
1542 """ 1559 """
1543 Alias for `trending_tags()`_ 1560 Alias for `trending_tags()`_
1544 """ 1561 """
1545 return self.trending_tags(limit = limit) 1562 return self.trending_tags(limit=limit)
1546 1563
1547 @api_version("3.5.0", "3.5.0", __DICT_VERSION_HASHTAG) 1564 @api_version("3.5.0", "3.5.0", __DICT_VERSION_HASHTAG)
1548 def trending_tags(self, limit=None): 1565 def trending_tags(self, limit=None, lang=None):
1549 """ 1566 """
1550 Fetch trending-hashtag information, if the instance provides such information. 1567 Fetch trending-hashtag information, if the instance provides such information.
1551 1568
@@ -1557,6 +1574,8 @@ class Mastodon:
1557 Important versioning note: This endpoint does not exist for Mastodon versions 1574 Important versioning note: This endpoint does not exist for Mastodon versions
1558 between 2.8.0 (inclusive) and 3.0.0 (exclusive). 1575 between 2.8.0 (inclusive) and 3.0.0 (exclusive).
1559 1576
1577 Pass `lang` to override the global locale parameter, which may affect trend ordering.
1578
1560 Returns a list of `hashtag dicts`_, sorted by the instance's trending algorithm, 1579 Returns a list of `hashtag dicts`_, sorted by the instance's trending algorithm,
1561 descending. 1580 descending.
1562 """ 1581 """
@@ -1575,6 +1594,8 @@ class Mastodon:
1575 Specify `limit` to limit how many results are returned (the maximum number 1594 Specify `limit` to limit how many results are returned (the maximum number
1576 of results is 10, the endpoint is not paginated). 1595 of results is 10, the endpoint is not paginated).
1577 1596
1597 Pass `lang` to override the global locale parameter, which may affect trend ordering.
1598
1578 Returns a list of `toot dicts`_, sorted by the instances's trending algorithm, 1599 Returns a list of `toot dicts`_, sorted by the instances's trending algorithm,
1579 descending. 1600 descending.
1580 """ 1601 """
@@ -1981,7 +2002,8 @@ class Mastodon:
1981 displayed. 2002 displayed.
1982 2003
1983 Specify `language` to override automatic language detection. The parameter 2004 Specify `language` to override automatic language detection. The parameter
1984 accepts all valid ISO 639-2 language codes. 2005 accepts all valid ISO 639-1 (2-letter) or for languages where that do not
2006 have one, 639-3 (three letter) language codes.
1985 2007
1986 You can set `idempotency_key` to a value to uniquely identify an attempt 2008 You can set `idempotency_key` to a value to uniquely identify an attempt
1987 at posting a status. Even if you call this function more than once, 2009 at posting a status. Even if you call this function more than once,
@@ -3638,6 +3660,7 @@ class Mastodon:
3638 """ 3660 """
3639 known_date_fields = ["created_at", "week", "day", "expires_at", "scheduled_at", 3661 known_date_fields = ["created_at", "week", "day", "expires_at", "scheduled_at",
3640 "updated_at", "last_status_at", "starts_at", "ends_at", "published_at", "edited_at"] 3662 "updated_at", "last_status_at", "starts_at", "ends_at", "published_at", "edited_at"]
3663 mark_delete = []
3641 for k, v in json_object.items(): 3664 for k, v in json_object.items():
3642 if k in known_date_fields: 3665 if k in known_date_fields:
3643 if v is not None: 3666 if v is not None:
@@ -3648,7 +3671,10 @@ class Mastodon:
3648 json_object[k] = dateutil.parser.parse(v) 3671 json_object[k] = dateutil.parser.parse(v)
3649 except: 3672 except:
3650 # When we can't parse a date, we just leave the field out 3673 # When we can't parse a date, we just leave the field out
3651 del json_object[k] 3674 mark_delete.append(k)
3675 # Two step process because otherwise python gets very upset
3676 for k in mark_delete:
3677 del json_object[k]
3652 return json_object 3678 return json_object
3653 3679
3654 @staticmethod 3680 @staticmethod
@@ -3701,12 +3727,20 @@ class Mastodon:
3701 isotime = isotime[:-2] + ":" + isotime[-2:] 3727 isotime = isotime[:-2] + ":" + isotime[-2:]
3702 return isotime 3728 return isotime
3703 3729
3704 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): 3730 def __api_request(self, method, endpoint, params={}, files={}, headers={}, access_token_override=None, base_url_override=None,
3731 do_ratelimiting=True, use_json=False, parse=True, return_response_object=False, skip_error_check=False, lang_override=None):
3705 """ 3732 """
3706 Internal API request helper. 3733 Internal API request helper.
3707 """ 3734 """
3708 response = None 3735 response = None
3709 remaining_wait = 0 3736 remaining_wait = 0
3737
3738 # Add language to params if not None
3739 lang = self.lang
3740 if lang_override is not None:
3741 lang = lang_override
3742 if lang is not None:
3743 params["lang"] = lang
3710 3744
3711 # "pace" mode ratelimiting: Assume constant rate of requests, sleep a little less long than it 3745 # "pace" mode ratelimiting: Assume constant rate of requests, sleep a little less long than it
3712 # would take to not hit the rate limit at that request rate. 3746 # would take to not hit the rate limit at that request rate.
@@ -3765,8 +3799,7 @@ class Mastodon:
3765 else: 3799 else:
3766 kwargs['data'] = params 3800 kwargs['data'] = params
3767 3801
3768 response_object = self.session.request( 3802 response_object = self.session.request(method, base_url + endpoint, **kwargs)
3769 method, base_url + endpoint, **kwargs)
3770 except Exception as e: 3803 except Exception as e:
3771 raise MastodonNetworkError( 3804 raise MastodonNetworkError(
3772 "Could not complete request: %s" % e) 3805 "Could not complete request: %s" % e)
@@ -3809,15 +3842,14 @@ class Mastodon:
3809 3842
3810 # Handle response 3843 # Handle response
3811 if self.debug_requests: 3844 if self.debug_requests:
3812 print('Mastodon: Response received with code ' + 3845 print('Mastodon: Response received with code ' + str(response_object.status_code) + '.')
3813 str(response_object.status_code) + '.')
3814 print('response headers: ' + str(response_object.headers)) 3846 print('response headers: ' + str(response_object.headers))
3815 print('Response text content: ' + str(response_object.text)) 3847 print('Response text content: ' + str(response_object.text))
3816 3848
3817 if not response_object.ok: 3849 if not response_object.ok:
3818 try: 3850 try:
3819 response = response_object.json( 3851 response = response_object.json(object_hook=self.__json_hooks)
3820 object_hook=self.__json_hooks) 3852 print(response)
3821 if isinstance(response, dict) and 'error' in response: 3853 if isinstance(response, dict) and 'error' in response:
3822 error_msg = response['error'] 3854 error_msg = response['error']
3823 elif isinstance(response, str): 3855 elif isinstance(response, str):
@@ -3871,8 +3903,7 @@ class Mastodon:
3871 3903
3872 if parse: 3904 if parse:
3873 try: 3905 try:
3874 response = response_object.json( 3906 response = response_object.json(object_hook=self.__json_hooks)
3875 object_hook=self.__json_hooks)
3876 except: 3907 except:
3877 raise MastodonAPIError( 3908 raise MastodonAPIError(
3878 "Could not parse response as JSON, response code was %s, " 3909 "Could not parse response as JSON, response code was %s, "
Powered by cgit v1.2.3 (git 2.41.0)