diff options
Diffstat (limited to 'mastodon')
-rw-r--r-- | mastodon/Mastodon.py | 469 | ||||
-rw-r--r-- | mastodon/streaming.py | 117 |
2 files changed, 350 insertions, 236 deletions
diff --git a/mastodon/Mastodon.py b/mastodon/Mastodon.py index 8dcdf1b..a2986cb 100644 --- a/mastodon/Mastodon.py +++ b/mastodon/Mastodon.py | |||
@@ -229,30 +229,25 @@ class Mastodon: | |||
229 | __DICT_VERSION_HASHTAG = "2.3.4" | 229 | __DICT_VERSION_HASHTAG = "2.3.4" |
230 | __DICT_VERSION_EMOJI = "3.0.0" | 230 | __DICT_VERSION_EMOJI = "3.0.0" |
231 | __DICT_VERSION_RELATIONSHIP = "3.3.0" | 231 | __DICT_VERSION_RELATIONSHIP = "3.3.0" |
232 | __DICT_VERSION_NOTIFICATION = bigger_version(bigger_version( | 232 | __DICT_VERSION_NOTIFICATION = bigger_version(bigger_version("1.0.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS) |
233 | "1.0.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS) | ||
234 | __DICT_VERSION_CONTEXT = bigger_version("1.0.0", __DICT_VERSION_STATUS) | 233 | __DICT_VERSION_CONTEXT = bigger_version("1.0.0", __DICT_VERSION_STATUS) |
235 | __DICT_VERSION_LIST = "2.1.0" | 234 | __DICT_VERSION_LIST = "2.1.0" |
236 | __DICT_VERSION_CARD = "3.2.0" | 235 | __DICT_VERSION_CARD = "3.2.0" |
237 | __DICT_VERSION_SEARCHRESULT = bigger_version(bigger_version(bigger_version( | 236 | __DICT_VERSION_SEARCHRESULT = bigger_version(bigger_version(bigger_version("1.0.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS), __DICT_VERSION_HASHTAG) |
238 | "1.0.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS), __DICT_VERSION_HASHTAG) | ||
239 | __DICT_VERSION_ACTIVITY = "2.1.2" | 237 | __DICT_VERSION_ACTIVITY = "2.1.2" |
240 | __DICT_VERSION_REPORT = "2.9.1" | 238 | __DICT_VERSION_REPORT = "2.9.1" |
241 | __DICT_VERSION_PUSH = "2.4.0" | 239 | __DICT_VERSION_PUSH = "2.4.0" |
242 | __DICT_VERSION_PUSH_NOTIF = "2.4.0" | 240 | __DICT_VERSION_PUSH_NOTIF = "2.4.0" |
243 | __DICT_VERSION_FILTER = "2.4.3" | 241 | __DICT_VERSION_FILTER = "2.4.3" |
244 | __DICT_VERSION_CONVERSATION = bigger_version(bigger_version( | 242 | __DICT_VERSION_CONVERSATION = bigger_version(bigger_version("2.6.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS) |
245 | "2.6.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS) | 243 | __DICT_VERSION_SCHEDULED_STATUS = bigger_version("2.7.0", __DICT_VERSION_STATUS) |
246 | __DICT_VERSION_SCHEDULED_STATUS = bigger_version( | ||
247 | "2.7.0", __DICT_VERSION_STATUS) | ||
248 | __DICT_VERSION_PREFERENCES = "2.8.0" | 244 | __DICT_VERSION_PREFERENCES = "2.8.0" |
249 | __DICT_VERSION_ADMIN_ACCOUNT = bigger_version( | 245 | __DICT_VERSION_ADMIN_ACCOUNT = bigger_version("2.9.1", __DICT_VERSION_ACCOUNT) |
250 | "2.9.1", __DICT_VERSION_ACCOUNT) | ||
251 | __DICT_VERSION_FEATURED_TAG = "3.0.0" | 246 | __DICT_VERSION_FEATURED_TAG = "3.0.0" |
252 | __DICT_VERSION_MARKER = "3.0.0" | 247 | __DICT_VERSION_MARKER = "3.0.0" |
253 | __DICT_VERSION_REACTION = "3.1.0" | 248 | __DICT_VERSION_REACTION = "3.1.0" |
254 | __DICT_VERSION_ANNOUNCEMENT = bigger_version( | 249 | __DICT_VERSION_ANNOUNCEMENT = bigger_version("3.1.0", __DICT_VERSION_REACTION) |
255 | "3.1.0", __DICT_VERSION_REACTION) | 250 | __DICT_VERSION_STATUS_EDIT = "3.5.0" |
256 | 251 | ||
257 | ### | 252 | ### |
258 | # Registering apps | 253 | # Registering apps |
@@ -378,7 +373,7 @@ class Mastodon: | |||
378 | If no other `User-Agent` is specified, "mastodonpy" will be used. | 373 | If no other `User-Agent` is specified, "mastodonpy" will be used. |
379 | """ | 374 | """ |
380 | self.api_base_url = None | 375 | self.api_base_url = None |
381 | if not api_base_url is None: | 376 | if api_base_url is not None: |
382 | self.api_base_url = Mastodon.__protocolize(api_base_url) | 377 | self.api_base_url = Mastodon.__protocolize(api_base_url) |
383 | 378 | ||
384 | self.client_id = client_id | 379 | self.client_id = client_id |
@@ -419,7 +414,7 @@ class Mastodon: | |||
419 | self.client_secret = secret_file.readline().rstrip() | 414 | self.client_secret = secret_file.readline().rstrip() |
420 | 415 | ||
421 | try_base_url = secret_file.readline().rstrip() | 416 | try_base_url = secret_file.readline().rstrip() |
422 | if (not try_base_url is None) and len(try_base_url) != 0: | 417 | if try_base_url is not None and len(try_base_url) != 0: |
423 | try_base_url = Mastodon.__protocolize(try_base_url) | 418 | try_base_url = Mastodon.__protocolize(try_base_url) |
424 | if not (self.api_base_url is None or try_base_url == self.api_base_url): | 419 | if not (self.api_base_url is None or try_base_url == self.api_base_url): |
425 | raise MastodonIllegalArgumentError( | 420 | raise MastodonIllegalArgumentError( |
@@ -440,7 +435,7 @@ class Mastodon: | |||
440 | self.access_token = token_file.readline().rstrip() | 435 | self.access_token = token_file.readline().rstrip() |
441 | 436 | ||
442 | try_base_url = token_file.readline().rstrip() | 437 | try_base_url = token_file.readline().rstrip() |
443 | if (not try_base_url is None) and len(try_base_url) != 0: | 438 | if try_base_url is not None and len(try_base_url) != 0: |
444 | try_base_url = Mastodon.__protocolize(try_base_url) | 439 | try_base_url = Mastodon.__protocolize(try_base_url) |
445 | if not (self.api_base_url is None or try_base_url == self.api_base_url): | 440 | if not (self.api_base_url is None or try_base_url == self.api_base_url): |
446 | raise MastodonIllegalArgumentError( | 441 | raise MastodonIllegalArgumentError( |
@@ -457,7 +452,7 @@ class Mastodon: | |||
457 | self.version_check_worked = None | 452 | self.version_check_worked = None |
458 | 453 | ||
459 | # Versioning | 454 | # Versioning |
460 | if mastodon_version == None and self.version_check_mode != 'none': | 455 | if mastodon_version is None and self.version_check_mode != 'none': |
461 | self.retrieve_mastodon_version() | 456 | self.retrieve_mastodon_version() |
462 | elif self.version_check_mode != 'none': | 457 | elif self.version_check_mode != 'none': |
463 | try: | 458 | try: |
@@ -632,7 +627,7 @@ class Mastodon: | |||
632 | self.__logged_in_id = None | 627 | self.__logged_in_id = None |
633 | 628 | ||
634 | # Retry version check if needed (might be required in limited federation mode) | 629 | # Retry version check if needed (might be required in limited federation mode) |
635 | if self.version_check_worked == False: | 630 | if not self.version_check_worked: |
636 | self.retrieve_mastodon_version() | 631 | self.retrieve_mastodon_version() |
637 | 632 | ||
638 | return response['access_token'] | 633 | return response['access_token'] |
@@ -698,7 +693,7 @@ class Mastodon: | |||
698 | params['client_id'] = self.client_id | 693 | params['client_id'] = self.client_id |
699 | params['client_secret'] = self.client_secret | 694 | params['client_secret'] = self.client_secret |
700 | 695 | ||
701 | if agreement == False: | 696 | if not agreement: |
702 | del params['agreement'] | 697 | del params['agreement'] |
703 | 698 | ||
704 | # Step 1: Get a user-free token via oauth | 699 | # Step 1: Get a user-free token via oauth |
@@ -865,24 +860,24 @@ class Mastodon: | |||
865 | 860 | ||
866 | Returns a list of `toot dicts`_. | 861 | Returns a list of `toot dicts`_. |
867 | """ | 862 | """ |
868 | if max_id != None: | 863 | if max_id is not None: |
869 | max_id = self.__unpack_id(max_id, dateconv=True) | 864 | max_id = self.__unpack_id(max_id, dateconv=True) |
870 | 865 | ||
871 | if min_id != None: | 866 | if min_id is not None: |
872 | min_id = self.__unpack_id(min_id, dateconv=True) | 867 | min_id = self.__unpack_id(min_id, dateconv=True) |
873 | 868 | ||
874 | if since_id != None: | 869 | if since_id is not None: |
875 | since_id = self.__unpack_id(since_id, dateconv=True) | 870 | since_id = self.__unpack_id(since_id, dateconv=True) |
876 | 871 | ||
877 | params_initial = locals() | 872 | params_initial = locals() |
878 | 873 | ||
879 | if local == False: | 874 | if not local: |
880 | del params_initial['local'] | 875 | del params_initial['local'] |
881 | 876 | ||
882 | if remote == False: | 877 | if not remote: |
883 | del params_initial['remote'] | 878 | del params_initial['remote'] |
884 | 879 | ||
885 | if only_media == False: | 880 | if not only_media: |
886 | del params_initial['only_media'] | 881 | del params_initial['only_media'] |
887 | 882 | ||
888 | if timeline == "local": | 883 | if timeline == "local": |
@@ -950,13 +945,13 @@ class Mastodon: | |||
950 | 945 | ||
951 | Returns a list of `conversation dicts`_. | 946 | Returns a list of `conversation dicts`_. |
952 | """ | 947 | """ |
953 | if max_id != None: | 948 | if max_id is not None: |
954 | max_id = self.__unpack_id(max_id, dateconv=True) | 949 | max_id = self.__unpack_id(max_id, dateconv=True) |
955 | 950 | ||
956 | if min_id != None: | 951 | if min_id is not None: |
957 | min_id = self.__unpack_id(min_id, dateconv=True) | 952 | min_id = self.__unpack_id(min_id, dateconv=True) |
958 | 953 | ||
959 | if since_id != None: | 954 | if since_id is not None: |
960 | since_id = self.__unpack_id(since_id, dateconv=True) | 955 | since_id = self.__unpack_id(since_id, dateconv=True) |
961 | 956 | ||
962 | params = self.__generate_params(locals()) | 957 | params = self.__generate_params(locals()) |
@@ -1093,8 +1088,8 @@ class Mastodon: | |||
1093 | 1088 | ||
1094 | Returns a list of `notification dicts`_. | 1089 | Returns a list of `notification dicts`_. |
1095 | """ | 1090 | """ |
1096 | if not mentions_only is None: | 1091 | if mentions_only is not None: |
1097 | if not exclude_types is None: | 1092 | if exclude_types is not None: |
1098 | if mentions_only: | 1093 | if mentions_only: |
1099 | exclude_types = ["follow", "favourite", | 1094 | exclude_types = ["follow", "favourite", |
1100 | "reblog", "poll", "follow_request"] | 1095 | "reblog", "poll", "follow_request"] |
@@ -1103,16 +1098,16 @@ class Mastodon: | |||
1103 | 'Cannot specify exclude_types when mentions_only is present') | 1098 | 'Cannot specify exclude_types when mentions_only is present') |
1104 | del mentions_only | 1099 | del mentions_only |
1105 | 1100 | ||
1106 | if max_id != None: | 1101 | if max_id is not None: |
1107 | max_id = self.__unpack_id(max_id, dateconv=True) | 1102 | max_id = self.__unpack_id(max_id, dateconv=True) |
1108 | 1103 | ||
1109 | if min_id != None: | 1104 | if min_id is not None: |
1110 | min_id = self.__unpack_id(min_id, dateconv=True) | 1105 | min_id = self.__unpack_id(min_id, dateconv=True) |
1111 | 1106 | ||
1112 | if since_id != None: | 1107 | if since_id is not None: |
1113 | since_id = self.__unpack_id(since_id, dateconv=True) | 1108 | since_id = self.__unpack_id(since_id, dateconv=True) |
1114 | 1109 | ||
1115 | if account_id != None: | 1110 | if account_id is not None: |
1116 | account_id = self.__unpack_id(account_id) | 1111 | account_id = self.__unpack_id(account_id) |
1117 | 1112 | ||
1118 | if id is None: | 1113 | if id is None: |
@@ -1178,23 +1173,23 @@ class Mastodon: | |||
1178 | Returns a list of `toot dicts`_. | 1173 | Returns a list of `toot dicts`_. |
1179 | """ | 1174 | """ |
1180 | id = self.__unpack_id(id) | 1175 | id = self.__unpack_id(id) |
1181 | if max_id != None: | 1176 | if max_id is not None: |
1182 | max_id = self.__unpack_id(max_id, dateconv=True) | 1177 | max_id = self.__unpack_id(max_id, dateconv=True) |
1183 | 1178 | ||
1184 | if min_id != None: | 1179 | if min_id is not None: |
1185 | min_id = self.__unpack_id(min_id, dateconv=True) | 1180 | min_id = self.__unpack_id(min_id, dateconv=True) |
1186 | 1181 | ||
1187 | if since_id != None: | 1182 | if since_id is not None: |
1188 | since_id = self.__unpack_id(since_id, dateconv=True) | 1183 | since_id = self.__unpack_id(since_id, dateconv=True) |
1189 | 1184 | ||
1190 | params = self.__generate_params(locals(), ['id']) | 1185 | params = self.__generate_params(locals(), ['id']) |
1191 | if pinned == False: | 1186 | if not pinned: |
1192 | del params["pinned"] | 1187 | del params["pinned"] |
1193 | if only_media == False: | 1188 | if not only_media: |
1194 | del params["only_media"] | 1189 | del params["only_media"] |
1195 | if exclude_replies == False: | 1190 | if not exclude_replies: |
1196 | del params["exclude_replies"] | 1191 | del params["exclude_replies"] |
1197 | if exclude_reblogs == False: | 1192 | if not exclude_reblogs: |
1198 | del params["exclude_reblogs"] | 1193 | del params["exclude_reblogs"] |
1199 | 1194 | ||
1200 | url = '/api/v1/accounts/{0}/statuses'.format(str(id)) | 1195 | url = '/api/v1/accounts/{0}/statuses'.format(str(id)) |
@@ -1208,13 +1203,13 @@ class Mastodon: | |||
1208 | Returns a list of `user dicts`_. | 1203 | Returns a list of `user dicts`_. |
1209 | """ | 1204 | """ |
1210 | id = self.__unpack_id(id) | 1205 | id = self.__unpack_id(id) |
1211 | if max_id != None: | 1206 | if max_id is not None: |
1212 | max_id = self.__unpack_id(max_id, dateconv=True) | 1207 | max_id = self.__unpack_id(max_id, dateconv=True) |
1213 | 1208 | ||
1214 | if min_id != None: | 1209 | if min_id is not None: |
1215 | min_id = self.__unpack_id(min_id, dateconv=True) | 1210 | min_id = self.__unpack_id(min_id, dateconv=True) |
1216 | 1211 | ||
1217 | if since_id != None: | 1212 | if since_id is not None: |
1218 | since_id = self.__unpack_id(since_id, dateconv=True) | 1213 | since_id = self.__unpack_id(since_id, dateconv=True) |
1219 | 1214 | ||
1220 | params = self.__generate_params(locals(), ['id']) | 1215 | params = self.__generate_params(locals(), ['id']) |
@@ -1229,13 +1224,13 @@ class Mastodon: | |||
1229 | Returns a list of `user dicts`_. | 1224 | Returns a list of `user dicts`_. |
1230 | """ | 1225 | """ |
1231 | id = self.__unpack_id(id) | 1226 | id = self.__unpack_id(id) |
1232 | if max_id != None: | 1227 | if max_id is not None: |
1233 | max_id = self.__unpack_id(max_id, dateconv=True) | 1228 | max_id = self.__unpack_id(max_id, dateconv=True) |
1234 | 1229 | ||
1235 | if min_id != None: | 1230 | if min_id is not None: |
1236 | min_id = self.__unpack_id(min_id, dateconv=True) | 1231 | min_id = self.__unpack_id(min_id, dateconv=True) |
1237 | 1232 | ||
1238 | if since_id != None: | 1233 | if since_id is not None: |
1239 | since_id = self.__unpack_id(since_id, dateconv=True) | 1234 | since_id = self.__unpack_id(since_id, dateconv=True) |
1240 | 1235 | ||
1241 | params = self.__generate_params(locals(), ['id']) | 1236 | params = self.__generate_params(locals(), ['id']) |
@@ -1359,7 +1354,7 @@ class Mastodon: | |||
1359 | continue | 1354 | continue |
1360 | 1355 | ||
1361 | filter_string = re.escape(keyword_filter["phrase"]) | 1356 | filter_string = re.escape(keyword_filter["phrase"]) |
1362 | if keyword_filter["whole_word"] == True: | 1357 | if keyword_filter["whole_word"]: |
1363 | filter_string = "\\b" + filter_string + "\\b" | 1358 | filter_string = "\\b" + filter_string + "\\b" |
1364 | filter_strings.append(filter_string) | 1359 | filter_strings.append(filter_string) |
1365 | filter_re = re.compile("|".join(filter_strings), flags=re.IGNORECASE) | 1360 | filter_re = re.compile("|".join(filter_strings), flags=re.IGNORECASE) |
@@ -1435,8 +1430,8 @@ class Mastodon: | |||
1435 | Internal Helper: Throw a MastodonVersionError if version is < 2.8.0 but parameters | 1430 | Internal Helper: Throw a MastodonVersionError if version is < 2.8.0 but parameters |
1436 | for search that are available only starting with 2.8.0 are specified. | 1431 | for search that are available only starting with 2.8.0 are specified. |
1437 | """ | 1432 | """ |
1438 | if not account_id is None or not offset is None or not min_id is None or not max_id is None: | 1433 | if any(item is not None for item in (account_id, offset, min_id, max_id)): |
1439 | if self.verify_minimum_version("2.8.0", cached=True) == False: | 1434 | if not self.verify_minimum_version("2.8.0", cached=True): |
1440 | raise MastodonVersionError("Advanced search parameters require Mastodon 2.8.0+") | 1435 | raise MastodonVersionError("Advanced search parameters require Mastodon 2.8.0+") |
1441 | 1436 | ||
1442 | @api_version("1.1.0", "2.8.0", __DICT_VERSION_SEARCHRESULT) | 1437 | @api_version("1.1.0", "2.8.0", __DICT_VERSION_SEARCHRESULT) |
@@ -1465,7 +1460,7 @@ class Mastodon: | |||
1465 | 1460 | ||
1466 | Returns a `search result dict`_, with tags as `hashtag dicts`_. | 1461 | Returns a `search result dict`_, with tags as `hashtag dicts`_. |
1467 | """ | 1462 | """ |
1468 | if self.verify_minimum_version("2.4.1", cached=True) == True: | 1463 | if self.verify_minimum_version("2.4.1", cached=True): |
1469 | return self.search_v2(q, resolve=resolve, result_type=result_type, account_id=account_id, offset=offset, min_id=min_id, max_id=max_id) | 1464 | return self.search_v2(q, resolve=resolve, result_type=result_type, account_id=account_id, offset=offset, min_id=min_id, max_id=max_id) |
1470 | else: | 1465 | else: |
1471 | self.__ensure_search_params_acceptable( | 1466 | self.__ensure_search_params_acceptable( |
@@ -1481,7 +1476,7 @@ class Mastodon: | |||
1481 | Returns a `search result dict`_. | 1476 | Returns a `search result dict`_. |
1482 | """ | 1477 | """ |
1483 | params = self.__generate_params(locals()) | 1478 | params = self.__generate_params(locals()) |
1484 | if resolve == False: | 1479 | if not resolve: |
1485 | del params['resolve'] | 1480 | del params['resolve'] |
1486 | return self.__api_request('GET', '/api/v1/search', params) | 1481 | return self.__api_request('GET', '/api/v1/search', params) |
1487 | 1482 | ||
@@ -1499,10 +1494,10 @@ class Mastodon: | |||
1499 | account_id, offset, min_id, max_id) | 1494 | account_id, offset, min_id, max_id) |
1500 | params = self.__generate_params(locals()) | 1495 | params = self.__generate_params(locals()) |
1501 | 1496 | ||
1502 | if resolve == False: | 1497 | if not resolve: |
1503 | del params["resolve"] | 1498 | del params["resolve"] |
1504 | 1499 | ||
1505 | if exclude_unreviewed == False or not self.verify_minimum_version("3.0.0", cached=True): | 1500 | if not exclude_unreviewed or not self.verify_minimum_version("3.0.0", cached=True): |
1506 | del params["exclude_unreviewed"] | 1501 | del params["exclude_unreviewed"] |
1507 | 1502 | ||
1508 | if "result_type" in params: | 1503 | if "result_type" in params: |
@@ -1564,13 +1559,13 @@ class Mastodon: | |||
1564 | """ | 1559 | """ |
1565 | id = self.__unpack_id(id) | 1560 | id = self.__unpack_id(id) |
1566 | 1561 | ||
1567 | if max_id != None: | 1562 | if max_id is not None: |
1568 | max_id = self.__unpack_id(max_id, dateconv=True) | 1563 | max_id = self.__unpack_id(max_id, dateconv=True) |
1569 | 1564 | ||
1570 | if min_id != None: | 1565 | if min_id is not None: |
1571 | min_id = self.__unpack_id(min_id, dateconv=True) | 1566 | min_id = self.__unpack_id(min_id, dateconv=True) |
1572 | 1567 | ||
1573 | if since_id != None: | 1568 | if since_id is not None: |
1574 | since_id = self.__unpack_id(since_id, dateconv=True) | 1569 | since_id = self.__unpack_id(since_id, dateconv=True) |
1575 | 1570 | ||
1576 | params = self.__generate_params(locals(), ['id']) | 1571 | params = self.__generate_params(locals(), ['id']) |
@@ -1586,13 +1581,13 @@ class Mastodon: | |||
1586 | 1581 | ||
1587 | Returns a list of `user dicts`_. | 1582 | Returns a list of `user dicts`_. |
1588 | """ | 1583 | """ |
1589 | if max_id != None: | 1584 | if max_id is not None: |
1590 | max_id = self.__unpack_id(max_id, dateconv=True) | 1585 | max_id = self.__unpack_id(max_id, dateconv=True) |
1591 | 1586 | ||
1592 | if min_id != None: | 1587 | if min_id is not None: |
1593 | min_id = self.__unpack_id(min_id, dateconv=True) | 1588 | min_id = self.__unpack_id(min_id, dateconv=True) |
1594 | 1589 | ||
1595 | if since_id != None: | 1590 | if since_id is not None: |
1596 | since_id = self.__unpack_id(since_id, dateconv=True) | 1591 | since_id = self.__unpack_id(since_id, dateconv=True) |
1597 | 1592 | ||
1598 | params = self.__generate_params(locals()) | 1593 | params = self.__generate_params(locals()) |
@@ -1605,13 +1600,13 @@ class Mastodon: | |||
1605 | 1600 | ||
1606 | Returns a list of `user dicts`_. | 1601 | Returns a list of `user dicts`_. |
1607 | """ | 1602 | """ |
1608 | if max_id != None: | 1603 | if max_id is not None: |
1609 | max_id = self.__unpack_id(max_id, dateconv=True) | 1604 | max_id = self.__unpack_id(max_id, dateconv=True) |
1610 | 1605 | ||
1611 | if min_id != None: | 1606 | if min_id is not None: |
1612 | min_id = self.__unpack_id(min_id, dateconv=True) | 1607 | min_id = self.__unpack_id(min_id, dateconv=True) |
1613 | 1608 | ||
1614 | if since_id != None: | 1609 | if since_id is not None: |
1615 | since_id = self.__unpack_id(since_id, dateconv=True) | 1610 | since_id = self.__unpack_id(since_id, dateconv=True) |
1616 | 1611 | ||
1617 | params = self.__generate_params(locals()) | 1612 | params = self.__generate_params(locals()) |
@@ -1642,13 +1637,13 @@ class Mastodon: | |||
1642 | 1637 | ||
1643 | Returns a list of `toot dicts`_. | 1638 | Returns a list of `toot dicts`_. |
1644 | """ | 1639 | """ |
1645 | if max_id != None: | 1640 | if max_id is not None: |
1646 | max_id = self.__unpack_id(max_id, dateconv=True) | 1641 | max_id = self.__unpack_id(max_id, dateconv=True) |
1647 | 1642 | ||
1648 | if min_id != None: | 1643 | if min_id is not None: |
1649 | min_id = self.__unpack_id(min_id, dateconv=True) | 1644 | min_id = self.__unpack_id(min_id, dateconv=True) |
1650 | 1645 | ||
1651 | if since_id != None: | 1646 | if since_id is not None: |
1652 | since_id = self.__unpack_id(since_id, dateconv=True) | 1647 | since_id = self.__unpack_id(since_id, dateconv=True) |
1653 | 1648 | ||
1654 | params = self.__generate_params(locals()) | 1649 | params = self.__generate_params(locals()) |
@@ -1664,13 +1659,13 @@ class Mastodon: | |||
1664 | 1659 | ||
1665 | Returns a list of `user dicts`_. | 1660 | Returns a list of `user dicts`_. |
1666 | """ | 1661 | """ |
1667 | if max_id != None: | 1662 | if max_id is not None: |
1668 | max_id = self.__unpack_id(max_id, dateconv=True) | 1663 | max_id = self.__unpack_id(max_id, dateconv=True) |
1669 | 1664 | ||
1670 | if min_id != None: | 1665 | if min_id is not None: |
1671 | min_id = self.__unpack_id(min_id, dateconv=True) | 1666 | min_id = self.__unpack_id(min_id, dateconv=True) |
1672 | 1667 | ||
1673 | if since_id != None: | 1668 | if since_id is not None: |
1674 | since_id = self.__unpack_id(since_id, dateconv=True) | 1669 | since_id = self.__unpack_id(since_id, dateconv=True) |
1675 | 1670 | ||
1676 | params = self.__generate_params(locals()) | 1671 | params = self.__generate_params(locals()) |
@@ -1686,13 +1681,13 @@ class Mastodon: | |||
1686 | 1681 | ||
1687 | Returns a list of blocked domain URLs (as strings, without protocol specifier). | 1682 | Returns a list of blocked domain URLs (as strings, without protocol specifier). |
1688 | """ | 1683 | """ |
1689 | if max_id != None: | 1684 | if max_id is not None: |
1690 | max_id = self.__unpack_id(max_id, dateconv=True) | 1685 | max_id = self.__unpack_id(max_id, dateconv=True) |
1691 | 1686 | ||
1692 | if min_id != None: | 1687 | if min_id is not None: |
1693 | min_id = self.__unpack_id(min_id, dateconv=True) | 1688 | min_id = self.__unpack_id(min_id, dateconv=True) |
1694 | 1689 | ||
1695 | if since_id != None: | 1690 | if since_id is not None: |
1696 | since_id = self.__unpack_id(since_id, dateconv=True) | 1691 | since_id = self.__unpack_id(since_id, dateconv=True) |
1697 | 1692 | ||
1698 | params = self.__generate_params(locals()) | 1693 | params = self.__generate_params(locals()) |
@@ -1792,13 +1787,13 @@ class Mastodon: | |||
1792 | 1787 | ||
1793 | Returns a list of `toot dicts`_. | 1788 | Returns a list of `toot dicts`_. |
1794 | """ | 1789 | """ |
1795 | if max_id != None: | 1790 | if max_id is not None: |
1796 | max_id = self.__unpack_id(max_id, dateconv=True) | 1791 | max_id = self.__unpack_id(max_id, dateconv=True) |
1797 | 1792 | ||
1798 | if min_id != None: | 1793 | if min_id is not None: |
1799 | min_id = self.__unpack_id(min_id, dateconv=True) | 1794 | min_id = self.__unpack_id(min_id, dateconv=True) |
1800 | 1795 | ||
1801 | if since_id != None: | 1796 | if since_id is not None: |
1802 | since_id = self.__unpack_id(since_id, dateconv=True) | 1797 | since_id = self.__unpack_id(since_id, dateconv=True) |
1803 | 1798 | ||
1804 | params = self.__generate_params(locals()) | 1799 | params = self.__generate_params(locals()) |
@@ -1807,6 +1802,82 @@ class Mastodon: | |||
1807 | ### | 1802 | ### |
1808 | # Writing data: Statuses | 1803 | # Writing data: Statuses |
1809 | ### | 1804 | ### |
1805 | def __status_internal(self, status, in_reply_to_id=None, media_ids=None, | ||
1806 | sensitive=False, visibility=None, spoiler_text=None, | ||
1807 | language=None, idempotency_key=None, content_type=None, | ||
1808 | scheduled_at=None, poll=None, quote_id=None, edit=False): | ||
1809 | if quote_id is not None: | ||
1810 | if self.feature_set != "fedibird": | ||
1811 | raise MastodonIllegalArgumentError('quote_id is only available with feature set fedibird') | ||
1812 | quote_id = self.__unpack_id(quote_id) | ||
1813 | |||
1814 | if content_type is not None: | ||
1815 | if self.feature_set != "pleroma": | ||
1816 | raise MastodonIllegalArgumentError('content_type is only available with feature set pleroma') | ||
1817 | # It would be better to read this from nodeinfo and cache, but this is easier | ||
1818 | if not content_type in ["text/plain", "text/html", "text/markdown", "text/bbcode"]: | ||
1819 | raise MastodonIllegalArgumentError('Invalid content type specified') | ||
1820 | |||
1821 | if in_reply_to_id is not None: | ||
1822 | in_reply_to_id = self.__unpack_id(in_reply_to_id) | ||
1823 | |||
1824 | if scheduled_at is not None: | ||
1825 | scheduled_at = self.__consistent_isoformat_utc(scheduled_at) | ||
1826 | |||
1827 | params_initial = locals() | ||
1828 | |||
1829 | # Validate poll/media exclusivity | ||
1830 | if poll is not None: | ||
1831 | if media_ids is not None and len(media_ids) != 0: | ||
1832 | raise ValueError( | ||
1833 | 'Status can have media or poll attached - not both.') | ||
1834 | |||
1835 | # Validate visibility parameter | ||
1836 | valid_visibilities = ['private', 'public', 'unlisted', 'direct'] | ||
1837 | if params_initial['visibility'] is None: | ||
1838 | del params_initial['visibility'] | ||
1839 | else: | ||
1840 | params_initial['visibility'] = params_initial['visibility'].lower() | ||
1841 | if params_initial['visibility'] not in valid_visibilities: | ||
1842 | raise ValueError('Invalid visibility value! Acceptable values are %s' % valid_visibilities) | ||
1843 | |||
1844 | if params_initial['language'] is None: | ||
1845 | del params_initial['language'] | ||
1846 | |||
1847 | if params_initial['sensitive'] is False: | ||
1848 | del [params_initial['sensitive']] | ||
1849 | |||
1850 | headers = {} | ||
1851 | if idempotency_key is not None: | ||
1852 | headers['Idempotency-Key'] = idempotency_key | ||
1853 | |||
1854 | if media_ids is not None: | ||
1855 | try: | ||
1856 | media_ids_proper = [] | ||
1857 | if not isinstance(media_ids, (list, tuple)): | ||
1858 | media_ids = [media_ids] | ||
1859 | for media_id in media_ids: | ||
1860 | media_ids_proper.append(self.__unpack_id(media_id)) | ||
1861 | except Exception as e: | ||
1862 | raise MastodonIllegalArgumentError("Invalid media dict: %s" % e) | ||
1863 | |||
1864 | params_initial["media_ids"] = media_ids_proper | ||
1865 | |||
1866 | if params_initial['content_type'] is None: | ||
1867 | del params_initial['content_type'] | ||
1868 | |||
1869 | use_json = False | ||
1870 | if poll is not None: | ||
1871 | use_json = True | ||
1872 | |||
1873 | params = self.__generate_params(params_initial, ['idempotency_key', 'edit']) | ||
1874 | if edit is None: | ||
1875 | # Post | ||
1876 | return self.__api_request('POST', '/api/v1/statuses', params, headers=headers, use_json=use_json) | ||
1877 | else: | ||
1878 | # Edit | ||
1879 | return self.__api_request('PUT', '/api/v1/statuses/{0}'.format(str(self.__unpack_id(edit))), params, headers=headers, use_json=use_json) | ||
1880 | |||
1810 | @api_version("1.0.0", "2.8.0", __DICT_VERSION_STATUS) | 1881 | @api_version("1.0.0", "2.8.0", __DICT_VERSION_STATUS) |
1811 | def status_post(self, status, in_reply_to_id=None, media_ids=None, | 1882 | def status_post(self, status, in_reply_to_id=None, media_ids=None, |
1812 | sensitive=False, visibility=None, spoiler_text=None, | 1883 | sensitive=False, visibility=None, spoiler_text=None, |
@@ -1867,77 +1938,21 @@ class Mastodon: | |||
1867 | 1938 | ||
1868 | Returns a `toot dict`_ with the new status. | 1939 | Returns a `toot dict`_ with the new status. |
1869 | """ | 1940 | """ |
1870 | if quote_id != None: | 1941 | return self.__status_internal( |
1871 | if self.feature_set != "fedibird": | 1942 | status, |
1872 | raise MastodonIllegalArgumentError( | 1943 | in_reply_to_id, |
1873 | 'quote_id is only available with feature set fedibird') | 1944 | media_ids, |
1874 | quote_id = self.__unpack_id(quote_id) | 1945 | sensitive, |
1875 | 1946 | visibility, | |
1876 | if content_type != None: | 1947 | spoiler_text, |
1877 | if self.feature_set != "pleroma": | 1948 | language, |
1878 | raise MastodonIllegalArgumentError( | 1949 | idempotency_key, |
1879 | 'content_type is only available with feature set pleroma') | 1950 | content_type, |
1880 | # It would be better to read this from nodeinfo and cache, but this is easier | 1951 | scheduled_at, |
1881 | if not content_type in ["text/plain", "text/html", "text/markdown", "text/bbcode"]: | 1952 | poll, |
1882 | raise MastodonIllegalArgumentError( | 1953 | quote_id, |
1883 | 'Invalid content type specified') | 1954 | edit=None |
1884 | 1955 | ) | |
1885 | if in_reply_to_id != None: | ||
1886 | in_reply_to_id = self.__unpack_id(in_reply_to_id) | ||
1887 | |||
1888 | if scheduled_at != None: | ||
1889 | scheduled_at = self.__consistent_isoformat_utc(scheduled_at) | ||
1890 | |||
1891 | params_initial = locals() | ||
1892 | |||
1893 | # Validate poll/media exclusivity | ||
1894 | if not poll is None: | ||
1895 | if (not media_ids is None) and len(media_ids) != 0: | ||
1896 | raise ValueError( | ||
1897 | 'Status can have media or poll attached - not both.') | ||
1898 | |||
1899 | # Validate visibility parameter | ||
1900 | valid_visibilities = ['private', 'public', 'unlisted', 'direct'] | ||
1901 | if params_initial['visibility'] == None: | ||
1902 | del params_initial['visibility'] | ||
1903 | else: | ||
1904 | params_initial['visibility'] = params_initial['visibility'].lower() | ||
1905 | if params_initial['visibility'] not in valid_visibilities: | ||
1906 | raise ValueError('Invalid visibility value! Acceptable ' | ||
1907 | 'values are %s' % valid_visibilities) | ||
1908 | |||
1909 | if params_initial['language'] == None: | ||
1910 | del params_initial['language'] | ||
1911 | |||
1912 | if params_initial['sensitive'] is False: | ||
1913 | del [params_initial['sensitive']] | ||
1914 | |||
1915 | headers = {} | ||
1916 | if idempotency_key != None: | ||
1917 | headers['Idempotency-Key'] = idempotency_key | ||
1918 | |||
1919 | if media_ids is not None: | ||
1920 | try: | ||
1921 | media_ids_proper = [] | ||
1922 | if not isinstance(media_ids, (list, tuple)): | ||
1923 | media_ids = [media_ids] | ||
1924 | for media_id in media_ids: | ||
1925 | media_ids_proper.append(self.__unpack_id(media_id)) | ||
1926 | except Exception as e: | ||
1927 | raise MastodonIllegalArgumentError("Invalid media " | ||
1928 | "dict: %s" % e) | ||
1929 | |||
1930 | params_initial["media_ids"] = media_ids_proper | ||
1931 | |||
1932 | if params_initial['content_type'] == None: | ||
1933 | del params_initial['content_type'] | ||
1934 | |||
1935 | use_json = False | ||
1936 | if not poll is None: | ||
1937 | use_json = True | ||
1938 | |||
1939 | params = self.__generate_params(params_initial, ['idempotency_key']) | ||
1940 | return self.__api_request('POST', '/api/v1/statuses', params, headers=headers, use_json=use_json) | ||
1941 | 1956 | ||
1942 | @api_version("1.0.0", "2.8.0", __DICT_VERSION_STATUS) | 1957 | @api_version("1.0.0", "2.8.0", __DICT_VERSION_STATUS) |
1943 | def toot(self, status): | 1958 | def toot(self, status): |
@@ -1950,6 +1965,45 @@ class Mastodon: | |||
1950 | """ | 1965 | """ |
1951 | return self.status_post(status) | 1966 | return self.status_post(status) |
1952 | 1967 | ||
1968 | @api_version("3.5.0", "3.5.0", __DICT_VERSION_STATUS) | ||
1969 | def status_update(self, id, status = None, spoiler_text = None, sensitive = None, media_ids = None, poll = None): | ||
1970 | """ | ||
1971 | Edit a status. The meanings of the fields are largely the same as in `status_post()`_, | ||
1972 | though not every field can be edited. | ||
1973 | |||
1974 | Note that editing a poll will reset the votes. | ||
1975 | """ | ||
1976 | return self.__status_internal( | ||
1977 | status = status, | ||
1978 | media_ids = media_ids, | ||
1979 | sensitive = sensitive, | ||
1980 | spoiler_text = spoiler_text, | ||
1981 | poll = poll, | ||
1982 | edit = id | ||
1983 | ) | ||
1984 | |||
1985 | @api_version("3.5.0", "3.5.0", __DICT_VERSION_STATUS_EDIT) | ||
1986 | def status_history(self, id): | ||
1987 | """ | ||
1988 | Returns the edit history of a status as a list of `status edit dicts`_, starting | ||
1989 | from the original form. Note that this means that a status that has been edited | ||
1990 | once will have *two* entries in this list, a status that has been edited twice | ||
1991 | will have three, and so on. | ||
1992 | """ | ||
1993 | id = self.__unpack_id(id) | ||
1994 | return self.__api_request('GET', "/api/v1/statuses/{0}/history".format(str(id))) | ||
1995 | |||
1996 | def status_source(self, id): | ||
1997 | """ | ||
1998 | Returns the source of a status for editing. | ||
1999 | |||
2000 | Return value is a dictionary containing exactly the parameters you could pass to | ||
2001 | `status_update()`_ to change nothing about the status, except `status` is `text` | ||
2002 | instead. | ||
2003 | """ | ||
2004 | id = self.__unpack_id(id) | ||
2005 | return self.__api_request('GET', "/api/v1/statuses/{0}/source".format(str(id))) | ||
2006 | |||
1953 | @api_version("1.0.0", "2.8.0", __DICT_VERSION_STATUS) | 2007 | @api_version("1.0.0", "2.8.0", __DICT_VERSION_STATUS) |
1954 | def status_reply(self, to_status, status, in_reply_to_id=None, media_ids=None, | 2008 | def status_reply(self, to_status, status, in_reply_to_id=None, media_ids=None, |
1955 | sensitive=False, visibility=None, spoiler_text=None, | 2009 | sensitive=False, visibility=None, spoiler_text=None, |
@@ -1985,9 +2039,9 @@ class Mastodon: | |||
1985 | mentioned_accounts.values())) + status | 2039 | mentioned_accounts.values())) + status |
1986 | 2040 | ||
1987 | # Retain visibility / cw | 2041 | # Retain visibility / cw |
1988 | if visibility == None and 'visibility' in to_status: | 2042 | if visibility is None and 'visibility' in to_status: |
1989 | visibility = to_status.visibility | 2043 | visibility = to_status.visibility |
1990 | if spoiler_text == None and 'spoiler_text' in to_status: | 2044 | if spoiler_text is None and 'spoiler_text' in to_status: |
1991 | spoiler_text = to_status.spoiler_text | 2045 | spoiler_text = to_status.spoiler_text |
1992 | 2046 | ||
1993 | keyword_args["status"] = status | 2047 | keyword_args["status"] = status |
@@ -2251,9 +2305,9 @@ class Mastodon: | |||
2251 | Returns a `relationship dict`_ containing the updated relationship to the user. | 2305 | Returns a `relationship dict`_ containing the updated relationship to the user. |
2252 | """ | 2306 | """ |
2253 | id = self.__unpack_id(id) | 2307 | id = self.__unpack_id(id) |
2254 | params = self.__generate_params(locals()) | 2308 | params = self.__generate_params(locals(), ["id"]) |
2255 | 2309 | ||
2256 | if params["reblogs"] == None: | 2310 | if params["reblogs"] is None: |
2257 | del params["reblogs"] | 2311 | del params["reblogs"] |
2258 | 2312 | ||
2259 | url = '/api/v1/accounts/{0}/follow'.format(str(id)) | 2313 | url = '/api/v1/accounts/{0}/follow'.format(str(id)) |
@@ -2357,7 +2411,7 @@ class Mastodon: | |||
2357 | params_initial = collections.OrderedDict(locals()) | 2411 | params_initial = collections.OrderedDict(locals()) |
2358 | 2412 | ||
2359 | # Convert fields | 2413 | # Convert fields |
2360 | if fields != None: | 2414 | if fields is not None: |
2361 | if len(fields) > 4: | 2415 | if len(fields) > 4: |
2362 | raise MastodonIllegalArgumentError( | 2416 | raise MastodonIllegalArgumentError( |
2363 | 'A maximum of four fields are allowed.') | 2417 | 'A maximum of four fields are allowed.') |
@@ -2376,9 +2430,9 @@ class Mastodon: | |||
2376 | 2430 | ||
2377 | # Create file info | 2431 | # Create file info |
2378 | files = {} | 2432 | files = {} |
2379 | if not avatar is None: | 2433 | if avatar is not None: |
2380 | files["avatar"] = self.__load_media_file(avatar, avatar_mime_type) | 2434 | files["avatar"] = self.__load_media_file(avatar, avatar_mime_type) |
2381 | if not header is None: | 2435 | if header is not None: |
2382 | files["header"] = self.__load_media_file(header, header_mime_type) | 2436 | files["header"] = self.__load_media_file(header, header_mime_type) |
2383 | 2437 | ||
2384 | params = self.__generate_params(params_initial) | 2438 | params = self.__generate_params(params_initial) |
@@ -2591,13 +2645,13 @@ class Mastodon: | |||
2591 | """ | 2645 | """ |
2592 | account_id = self.__unpack_id(account_id) | 2646 | account_id = self.__unpack_id(account_id) |
2593 | 2647 | ||
2594 | if not status_ids is None: | 2648 | if status_ids is not None: |
2595 | if not isinstance(status_ids, list): | 2649 | if not isinstance(status_ids, list): |
2596 | status_ids = [status_ids] | 2650 | status_ids = [status_ids] |
2597 | status_ids = list(map(lambda x: self.__unpack_id(x), status_ids)) | 2651 | status_ids = list(map(lambda x: self.__unpack_id(x), status_ids)) |
2598 | 2652 | ||
2599 | params_initial = locals() | 2653 | params_initial = locals() |
2600 | if forward == False: | 2654 | if not forward: |
2601 | del params_initial['forward'] | 2655 | del params_initial['forward'] |
2602 | 2656 | ||
2603 | params = self.__generate_params(params_initial) | 2657 | params = self.__generate_params(params_initial) |
@@ -2663,10 +2717,10 @@ class Mastodon: | |||
2663 | files = {'file': self.__load_media_file( | 2717 | files = {'file': self.__load_media_file( |
2664 | media_file, mime_type, file_name)} | 2718 | media_file, mime_type, file_name)} |
2665 | 2719 | ||
2666 | if focus != None: | 2720 | if focus is not None: |
2667 | focus = str(focus[0]) + "," + str(focus[1]) | 2721 | focus = str(focus[0]) + "," + str(focus[1]) |
2668 | 2722 | ||
2669 | if not thumbnail is None: | 2723 | if thumbnail is not None: |
2670 | if not self.verify_minimum_version("3.2.0", cached=True): | 2724 | if not self.verify_minimum_version("3.2.0", cached=True): |
2671 | raise MastodonVersionError( | 2725 | raise MastodonVersionError( |
2672 | 'Thumbnail requires version > 3.2.0') | 2726 | 'Thumbnail requires version > 3.2.0') |
@@ -2684,7 +2738,7 @@ class Mastodon: | |||
2684 | # Wait for processing? | 2738 | # Wait for processing? |
2685 | if synchronous: | 2739 | if synchronous: |
2686 | if self.verify_minimum_version("3.1.4"): | 2740 | if self.verify_minimum_version("3.1.4"): |
2687 | while not "url" in ret_dict or ret_dict.url == None: | 2741 | while not "url" in ret_dict or ret_dict.url is None: |
2688 | try: | 2742 | try: |
2689 | ret_dict = self.media(ret_dict) | 2743 | ret_dict = self.media(ret_dict) |
2690 | time.sleep(1.0) | 2744 | time.sleep(1.0) |
@@ -2707,13 +2761,13 @@ class Mastodon: | |||
2707 | """ | 2761 | """ |
2708 | id = self.__unpack_id(id) | 2762 | id = self.__unpack_id(id) |
2709 | 2763 | ||
2710 | if focus != None: | 2764 | if focus is not None: |
2711 | focus = str(focus[0]) + "," + str(focus[1]) | 2765 | focus = str(focus[0]) + "," + str(focus[1]) |
2712 | 2766 | ||
2713 | params = self.__generate_params( | 2767 | params = self.__generate_params( |
2714 | locals(), ['id', 'thumbnail', 'thumbnail_mime_type']) | 2768 | locals(), ['id', 'thumbnail', 'thumbnail_mime_type']) |
2715 | 2769 | ||
2716 | if not thumbnail is None: | 2770 | if thumbnail is not None: |
2717 | if not self.verify_minimum_version("3.2.0", cached=True): | 2771 | if not self.verify_minimum_version("3.2.0", cached=True): |
2718 | raise MastodonVersionError( | 2772 | raise MastodonVersionError( |
2719 | 'Thumbnail requires version > 3.2.0') | 2773 | 'Thumbnail requires version > 3.2.0') |
@@ -2819,25 +2873,25 @@ class Mastodon: | |||
2819 | 'policy': policy | 2873 | 'policy': policy |
2820 | } | 2874 | } |
2821 | 2875 | ||
2822 | if follow_events != None: | 2876 | if follow_events is not None: |
2823 | params['data[alerts][follow]'] = follow_events | 2877 | params['data[alerts][follow]'] = follow_events |
2824 | 2878 | ||
2825 | if favourite_events != None: | 2879 | if favourite_events is not None: |
2826 | params['data[alerts][favourite]'] = favourite_events | 2880 | params['data[alerts][favourite]'] = favourite_events |
2827 | 2881 | ||
2828 | if reblog_events != None: | 2882 | if reblog_events is not None: |
2829 | params['data[alerts][reblog]'] = reblog_events | 2883 | params['data[alerts][reblog]'] = reblog_events |
2830 | 2884 | ||
2831 | if mention_events != None: | 2885 | if mention_events is not None: |
2832 | params['data[alerts][mention]'] = mention_events | 2886 | params['data[alerts][mention]'] = mention_events |
2833 | 2887 | ||
2834 | if poll_events != None: | 2888 | if poll_events is not None: |
2835 | params['data[alerts][poll]'] = poll_events | 2889 | params['data[alerts][poll]'] = poll_events |
2836 | 2890 | ||
2837 | if follow_request_events != None: | 2891 | if follow_request_events is not None: |
2838 | params['data[alerts][follow_request]'] = follow_request_events | 2892 | params['data[alerts][follow_request]'] = follow_request_events |
2839 | 2893 | ||
2840 | if follow_request_events != None: | 2894 | if follow_request_events is not None: |
2841 | params['data[alerts][status]'] = status_events | 2895 | params['data[alerts][status]'] = status_events |
2842 | 2896 | ||
2843 | # Canonicalize booleans | 2897 | # Canonicalize booleans |
@@ -2857,22 +2911,22 @@ class Mastodon: | |||
2857 | """ | 2911 | """ |
2858 | params = {} | 2912 | params = {} |
2859 | 2913 | ||
2860 | if follow_events != None: | 2914 | if follow_events is not None: |
2861 | params['data[alerts][follow]'] = follow_events | 2915 | params['data[alerts][follow]'] = follow_events |
2862 | 2916 | ||
2863 | if favourite_events != None: | 2917 | if favourite_events is not None: |
2864 | params['data[alerts][favourite]'] = favourite_events | 2918 | params['data[alerts][favourite]'] = favourite_events |
2865 | 2919 | ||
2866 | if reblog_events != None: | 2920 | if reblog_events is not None: |
2867 | params['data[alerts][reblog]'] = reblog_events | 2921 | params['data[alerts][reblog]'] = reblog_events |
2868 | 2922 | ||
2869 | if mention_events != None: | 2923 | if mention_events is not None: |
2870 | params['data[alerts][mention]'] = mention_events | 2924 | params['data[alerts][mention]'] = mention_events |
2871 | 2925 | ||
2872 | if poll_events != None: | 2926 | if poll_events is not None: |
2873 | params['data[alerts][poll]'] = poll_events | 2927 | params['data[alerts][poll]'] = poll_events |
2874 | 2928 | ||
2875 | if follow_request_events != None: | 2929 | if follow_request_events is not None: |
2876 | params['data[alerts][follow_request]'] = follow_request_events | 2930 | params['data[alerts][follow_request]'] = follow_request_events |
2877 | 2931 | ||
2878 | # Canonicalize booleans | 2932 | # Canonicalize booleans |
@@ -2951,19 +3005,19 @@ class Mastodon: | |||
2951 | 3005 | ||
2952 | Returns a list of `admin account dicts`_. | 3006 | Returns a list of `admin account dicts`_. |
2953 | """ | 3007 | """ |
2954 | if max_id != None: | 3008 | if max_id is not None: |
2955 | max_id = self.__unpack_id(max_id, dateconv=True) | 3009 | max_id = self.__unpack_id(max_id, dateconv=True) |
2956 | 3010 | ||
2957 | if min_id != None: | 3011 | if min_id is not None: |
2958 | min_id = self.__unpack_id(min_id, dateconv=True) | 3012 | min_id = self.__unpack_id(min_id, dateconv=True) |
2959 | 3013 | ||
2960 | if since_id != None: | 3014 | if since_id is not None: |
2961 | since_id = self.__unpack_id(since_id, dateconv=True) | 3015 | since_id = self.__unpack_id(since_id, dateconv=True) |
2962 | 3016 | ||
2963 | params = self.__generate_params( | 3017 | params = self.__generate_params( |
2964 | locals(), ['remote', 'status', 'staff_only']) | 3018 | locals(), ['remote', 'status', 'staff_only']) |
2965 | 3019 | ||
2966 | if remote == True: | 3020 | if remote: |
2967 | params["remote"] = True | 3021 | params["remote"] = True |
2968 | 3022 | ||
2969 | mod_statuses = ["active", "pending", | 3023 | mod_statuses = ["active", "pending", |
@@ -2971,7 +3025,7 @@ class Mastodon: | |||
2971 | if not status in mod_statuses: | 3025 | if not status in mod_statuses: |
2972 | raise ValueError("Invalid moderation status requested.") | 3026 | raise ValueError("Invalid moderation status requested.") |
2973 | 3027 | ||
2974 | if staff_only == True: | 3028 | if staff_only: |
2975 | params["staff"] = True | 3029 | params["staff"] = True |
2976 | 3030 | ||
2977 | for mod_status in mod_statuses: | 3031 | for mod_status in mod_statuses: |
@@ -3083,11 +3137,11 @@ class Mastodon: | |||
3083 | if action is None: | 3137 | if action is None: |
3084 | action = "none" | 3138 | action = "none" |
3085 | 3139 | ||
3086 | if send_email_notification == False: | 3140 | if not send_email_notification: |
3087 | send_email_notification = None | 3141 | send_email_notification = None |
3088 | 3142 | ||
3089 | id = self.__unpack_id(id) | 3143 | id = self.__unpack_id(id) |
3090 | if not report_id is None: | 3144 | if report_id is not None: |
3091 | report_id = self.__unpack_id(report_id) | 3145 | report_id = self.__unpack_id(report_id) |
3092 | 3146 | ||
3093 | params = self.__generate_params(locals(), ['id', 'action']) | 3147 | params = self.__generate_params(locals(), ['id', 'action']) |
@@ -3107,22 +3161,22 @@ class Mastodon: | |||
3107 | 3161 | ||
3108 | Returns a list of `report dicts`_. | 3162 | Returns a list of `report dicts`_. |
3109 | """ | 3163 | """ |
3110 | if max_id != None: | 3164 | if max_id is not None: |
3111 | max_id = self.__unpack_id(max_id, dateconv=True) | 3165 | max_id = self.__unpack_id(max_id, dateconv=True) |
3112 | 3166 | ||
3113 | if min_id != None: | 3167 | if min_id is not None: |
3114 | min_id = self.__unpack_id(min_id, dateconv=True) | 3168 | min_id = self.__unpack_id(min_id, dateconv=True) |
3115 | 3169 | ||
3116 | if since_id != None: | 3170 | if since_id is not None: |
3117 | since_id = self.__unpack_id(since_id, dateconv=True) | 3171 | since_id = self.__unpack_id(since_id, dateconv=True) |
3118 | 3172 | ||
3119 | if not account_id is None: | 3173 | if account_id is not None: |
3120 | account_id = self.__unpack_id(account_id) | 3174 | account_id = self.__unpack_id(account_id) |
3121 | 3175 | ||
3122 | if not target_account_id is None: | 3176 | if target_account_id is not None: |
3123 | target_account_id = self.__unpack_id(target_account_id) | 3177 | target_account_id = self.__unpack_id(target_account_id) |
3124 | 3178 | ||
3125 | if resolved == False: | 3179 | if not resolved: |
3126 | resolved = None | 3180 | resolved = None |
3127 | 3181 | ||
3128 | params = self.__generate_params(locals()) | 3182 | params = self.__generate_params(locals()) |
@@ -3279,12 +3333,12 @@ class Mastodon: | |||
3279 | # Figure out what size to decode to | 3333 | # Figure out what size to decode to |
3280 | decode_components_x, decode_components_y = blurhash.components( | 3334 | decode_components_x, decode_components_y = blurhash.components( |
3281 | media_dict["blurhash"]) | 3335 | media_dict["blurhash"]) |
3282 | if size_per_component == False: | 3336 | if size_per_component: |
3283 | decode_size_x = out_size[0] | ||
3284 | decode_size_y = out_size[1] | ||
3285 | else: | ||
3286 | decode_size_x = decode_components_x * out_size[0] | 3337 | decode_size_x = decode_components_x * out_size[0] |
3287 | decode_size_y = decode_components_y * out_size[1] | 3338 | decode_size_y = decode_components_y * out_size[1] |
3339 | else: | ||
3340 | decode_size_x = out_size[0] | ||
3341 | decode_size_y = out_size[1] | ||
3288 | 3342 | ||
3289 | # Decode | 3343 | # Decode |
3290 | decoded_image = blurhash.decode( | 3344 | decoded_image = blurhash.decode( |
@@ -3454,7 +3508,7 @@ class Mastodon: | |||
3454 | """ | 3508 | """ |
3455 | Fetch the logged in user's ID, with caching. ID is reset on calls to log_in. | 3509 | Fetch the logged in user's ID, with caching. ID is reset on calls to log_in. |
3456 | """ | 3510 | """ |
3457 | if self.__logged_in_id == None: | 3511 | if self.__logged_in_id is None: |
3458 | self.__logged_in_id = self.account_verify_credentials().id | 3512 | self.__logged_in_id = self.account_verify_credentials().id |
3459 | return self.__logged_in_id | 3513 | return self.__logged_in_id |
3460 | 3514 | ||
@@ -3477,7 +3531,7 @@ class Mastodon: | |||
3477 | "updated_at", "last_status_at", "starts_at", "ends_at", "published_at", "edited_at"] | 3531 | "updated_at", "last_status_at", "starts_at", "ends_at", "published_at", "edited_at"] |
3478 | for k, v in json_object.items(): | 3532 | for k, v in json_object.items(): |
3479 | if k in known_date_fields: | 3533 | if k in known_date_fields: |
3480 | if v != None: | 3534 | if v is not None: |
3481 | try: | 3535 | try: |
3482 | if isinstance(v, int): | 3536 | if isinstance(v, int): |
3483 | json_object[k] = datetime.datetime.fromtimestamp(v, pytz.utc) | 3537 | json_object[k] = datetime.datetime.fromtimestamp(v, pytz.utc) |
@@ -3565,9 +3619,9 @@ class Mastodon: | |||
3565 | 3619 | ||
3566 | # Generate request headers | 3620 | # Generate request headers |
3567 | headers = copy.deepcopy(headers) | 3621 | headers = copy.deepcopy(headers) |
3568 | if not self.access_token is None: | 3622 | if self.access_token is not None: |
3569 | headers['Authorization'] = 'Bearer ' + self.access_token | 3623 | headers['Authorization'] = 'Bearer ' + self.access_token |
3570 | if not access_token_override is None: | 3624 | if access_token_override is not None: |
3571 | headers['Authorization'] = 'Bearer ' + access_token_override | 3625 | headers['Authorization'] = 'Bearer ' + access_token_override |
3572 | 3626 | ||
3573 | # Add user-agent | 3627 | # Add user-agent |
@@ -3576,7 +3630,7 @@ class Mastodon: | |||
3576 | 3630 | ||
3577 | # Determine base URL | 3631 | # Determine base URL |
3578 | base_url = self.api_base_url | 3632 | base_url = self.api_base_url |
3579 | if not base_url_override is None: | 3633 | if base_url_override is not None: |
3580 | base_url = base_url_override | 3634 | base_url = base_url_override |
3581 | 3635 | ||
3582 | if self.debug_requests: | 3636 | if self.debug_requests: |
@@ -3594,13 +3648,12 @@ class Mastodon: | |||
3594 | response_object = None | 3648 | response_object = None |
3595 | try: | 3649 | try: |
3596 | kwargs = dict(headers=headers, files=files, timeout=self.request_timeout) | 3650 | kwargs = dict(headers=headers, files=files, timeout=self.request_timeout) |
3597 | if use_json == False: | 3651 | if use_json: |
3598 | if method == 'GET': | ||
3599 | kwargs['params'] = params | ||
3600 | else: | ||
3601 | kwargs['data'] = params | ||
3602 | else: | ||
3603 | kwargs['json'] = params | 3652 | kwargs['json'] = params |
3653 | elif method == 'GET': | ||
3654 | kwargs['params'] = params | ||
3655 | else: | ||
3656 | kwargs['data'] = params | ||
3604 | 3657 | ||
3605 | # Block list with exactly three entries, matching on hashes of the instance API domain | 3658 | # Block list with exactly three entries, matching on hashes of the instance API domain |
3606 | # For more information, have a look at the docs | 3659 | # For more information, have a look at the docs |
@@ -3636,7 +3689,7 @@ class Mastodon: | |||
3636 | ratelimit_intrep = None | 3689 | ratelimit_intrep = None |
3637 | 3690 | ||
3638 | try: | 3691 | try: |
3639 | if not ratelimit_intrep is None and ratelimit_intrep == response_object.headers['X-RateLimit-Reset']: | 3692 | if ratelimit_intrep is not None and ratelimit_intrep == response_object.headers['X-RateLimit-Reset']: |
3640 | self.ratelimit_reset = int( | 3693 | self.ratelimit_reset = int( |
3641 | response_object.headers['X-RateLimit-Reset']) | 3694 | response_object.headers['X-RateLimit-Reset']) |
3642 | else: | 3695 | else: |
@@ -3689,7 +3742,7 @@ class Mastodon: | |||
3689 | request_complete = False | 3742 | request_complete = False |
3690 | continue | 3743 | continue |
3691 | 3744 | ||
3692 | if skip_error_check == False: | 3745 | if not skip_error_check: |
3693 | if response_object.status_code == 404: | 3746 | if response_object.status_code == 404: |
3694 | ex_type = MastodonNotFoundError | 3747 | ex_type = MastodonNotFoundError |
3695 | if not error_msg: | 3748 | if not error_msg: |
@@ -3718,7 +3771,7 @@ class Mastodon: | |||
3718 | if return_response_object: | 3771 | if return_response_object: |
3719 | return response_object | 3772 | return response_object |
3720 | 3773 | ||
3721 | if parse == True: | 3774 | if parse: |
3722 | try: | 3775 | try: |
3723 | response = response_object.json( | 3776 | response = response_object.json( |
3724 | object_hook=self.__json_hooks) | 3777 | object_hook=self.__json_hooks) |
@@ -3881,7 +3934,7 @@ class Mastodon: | |||
3881 | 3934 | ||
3882 | def close(self): | 3935 | def close(self): |
3883 | self.closed = True | 3936 | self.closed = True |
3884 | if not self.connection is None: | 3937 | if self.connection is not None: |
3885 | self.connection.close() | 3938 | self.connection.close() |
3886 | 3939 | ||
3887 | def is_alive(self): | 3940 | def is_alive(self): |
@@ -3907,7 +3960,7 @@ class Mastodon: | |||
3907 | 3960 | ||
3908 | # Run until closed or until error if not autoreconnecting | 3961 | # Run until closed or until error if not autoreconnecting |
3909 | while self.running: | 3962 | while self.running: |
3910 | if not self.connection is None: | 3963 | if self.connection is not None: |
3911 | with closing(self.connection) as r: | 3964 | with closing(self.connection) as r: |
3912 | try: | 3965 | try: |
3913 | listener.handle_stream(r) | 3966 | listener.handle_stream(r) |
@@ -3978,10 +4031,8 @@ class Mastodon: | |||
3978 | 4031 | ||
3979 | param_keys = list(params.keys()) | 4032 | param_keys = list(params.keys()) |
3980 | for key in param_keys: | 4033 | for key in param_keys: |
3981 | if isinstance(params[key], bool) and params[key] == False: | 4034 | if isinstance(params[key], bool): |
3982 | params[key] = '0' | 4035 | params[key] = '1' if params[key] else '0' |
3983 | if isinstance(params[key], bool) and params[key] == True: | ||
3984 | params[key] = '1' | ||
3985 | 4036 | ||
3986 | for key in param_keys: | 4037 | for key in param_keys: |
3987 | if params[key] is None or key in exclude: | 4038 | if params[key] is None or key in exclude: |
diff --git a/mastodon/streaming.py b/mastodon/streaming.py index e43d7d6..ed09705 100644 --- a/mastodon/streaming.py +++ b/mastodon/streaming.py | |||
@@ -22,18 +22,50 @@ class StreamListener(object): | |||
22 | Mastodon.hashtag_stream().""" | 22 | Mastodon.hashtag_stream().""" |
23 | 23 | ||
24 | def on_update(self, status): | 24 | def on_update(self, status): |
25 | """A new status has appeared. 'status' is the parsed JSON dictionary | 25 | """A new status has appeared. `status` is the parsed `status dict` |
26 | describing the status.""" | 26 | describing the status.""" |
27 | pass | 27 | pass |
28 | 28 | ||
29 | def on_delete(self, status_id): | ||
30 | """A status has been deleted. `status_id` is the status' integer ID.""" | ||
31 | pass | ||
32 | |||
33 | def on_notification(self, notification): | ||
34 | """A new notification. `notification` is the parsed `notification dict` | ||
35 | describing the notification.""" | ||
36 | pass | ||
37 | |||
38 | def on_filters_changed(self): | ||
39 | """Filters have changed. Does not contain a payload, you will have to | ||
40 | refetch filters yourself.""" | ||
41 | pass | ||
42 | |||
43 | def on_conversation(self, conversation): | ||
44 | """A direct message (in the direct stream) has been received. `conversation` | ||
45 | is the parsed `conversation dict` dictionary describing the conversation""" | ||
46 | pass | ||
47 | |||
48 | def on_announcement(self, annoucement): | ||
49 | """A new announcement has been published. `announcement` is the parsed | ||
50 | `announcement dict` describing the newly posted announcement.""" | ||
51 | pass | ||
52 | |||
53 | def on_announcement_reaction(self, TODO): | ||
54 | """Someone has reacted to an announcement. TODO: what is payload lol""" | ||
55 | pass | ||
56 | |||
57 | def on_announcement_delete(self, annoucement_id): | ||
58 | """An announcement has been deleted. `annoucement_id` is the id of the | ||
59 | deleted announcement.""" | ||
60 | pass | ||
61 | |||
29 | def on_status_update(self, status): | 62 | def on_status_update(self, status): |
30 | """A status has been edited. 'status' is the parsed JSON dictionary | 63 | """A status has been edited. 'status' is the parsed JSON dictionary |
31 | describing the updated status.""" | 64 | describing the updated status.""" |
32 | pass | 65 | pass |
33 | 66 | ||
34 | def on_notification(self, notification): | 67 | def on_encrypted_message(self, unclear): |
35 | """A new notification. 'notification' is the parsed JSON dictionary | 68 | """An encrypted message has been received. Currently unused.""" |
36 | describing the notification.""" | ||
37 | pass | 69 | pass |
38 | 70 | ||
39 | def on_abort(self, err): | 71 | def on_abort(self, err): |
@@ -47,15 +79,6 @@ class StreamListener(object): | |||
47 | """ | 79 | """ |
48 | pass | 80 | pass |
49 | 81 | ||
50 | def on_delete(self, status_id): | ||
51 | """A status has been deleted. status_id is the status' integer ID.""" | ||
52 | pass | ||
53 | |||
54 | def on_conversation(self, conversation): | ||
55 | """A direct message (in the direct stream) has been received. conversation | ||
56 | contains the resulting conversation dict.""" | ||
57 | pass | ||
58 | |||
59 | def on_unknown_event(self, name, unknown_event=None): | 82 | def on_unknown_event(self, name, unknown_event=None): |
60 | """An unknown mastodon API event has been received. The name contains the event-name and unknown_event | 83 | """An unknown mastodon API event has been received. The name contains the event-name and unknown_event |
61 | contains the content of the unknown event. | 84 | contains the content of the unknown event. |
@@ -148,8 +171,7 @@ class StreamListener(object): | |||
148 | for_stream = json.loads(event['stream']) | 171 | for_stream = json.loads(event['stream']) |
149 | except: | 172 | except: |
150 | for_stream = None | 173 | for_stream = None |
151 | payload = json.loads( | 174 | payload = json.loads(data, object_hook=Mastodon._Mastodon__json_hooks) |
152 | data, object_hook=Mastodon._Mastodon__json_hooks) | ||
153 | except KeyError as err: | 175 | except KeyError as err: |
154 | exception = MastodonMalformedEventError( | 176 | exception = MastodonMalformedEventError( |
155 | 'Missing field', err.args[0], event) | 177 | 'Missing field', err.args[0], event) |
@@ -188,11 +210,13 @@ class StreamListener(object): | |||
188 | handler(name, payload, for_stream) | 210 | handler(name, payload, for_stream) |
189 | else: | 211 | else: |
190 | if handler != self.on_unknown_event: | 212 | if handler != self.on_unknown_event: |
191 | handler(payload) | 213 | if handler == self.on_filters_changed: |
214 | handler() | ||
215 | else: | ||
216 | handler(payload) | ||
192 | else: | 217 | else: |
193 | handler(name, payload) | 218 | handler(name, payload) |
194 | 219 | ||
195 | |||
196 | class CallbackStreamListener(StreamListener): | 220 | class CallbackStreamListener(StreamListener): |
197 | """ | 221 | """ |
198 | Simple callback stream handler class. | 222 | Simple callback stream handler class. |
@@ -202,22 +226,41 @@ class CallbackStreamListener(StreamListener): | |||
202 | for diagnostics. | 226 | for diagnostics. |
203 | """ | 227 | """ |
204 | 228 | ||
205 | def __init__(self, update_handler=None, local_update_handler=None, delete_handler=None, notification_handler=None, conversation_handler=None, unknown_event_handler=None, status_update_handler=None): | 229 | def __init__(self, |
230 | update_handler=None, | ||
231 | local_update_handler=None, | ||
232 | delete_handler=None, | ||
233 | notification_handler=None, | ||
234 | conversation_handler=None, | ||
235 | unknown_event_handler=None, | ||
236 | status_update_handler=None, | ||
237 | filters_changed_handler=None, | ||
238 | announcement_handler=None, | ||
239 | announcement_reaction_handler=None, | ||
240 | announcement_delete_handler=None, | ||
241 | encryted_message_handler=None | ||
242 | |||
243 | ): | ||
206 | super(CallbackStreamListener, self).__init__() | 244 | super(CallbackStreamListener, self).__init__() |
207 | self.update_handler = update_handler | 245 | self.update_handler = update_handler |
208 | self.local_update_handler = local_update_handler | 246 | self.local_update_handler = local_update_handler |
209 | self.delete_handler = delete_handler | 247 | self.delete_handler = delete_handler |
210 | self.notification_handler = notification_handler | 248 | self.notification_handler = notification_handler |
249 | self.filters_changed_handler = filters_changed_handler | ||
211 | self.conversation_handler = conversation_handler | 250 | self.conversation_handler = conversation_handler |
212 | self.unknown_event_handler = unknown_event_handler | 251 | self.unknown_event_handler = unknown_event_handler |
213 | self.status_update_handler = status_update_handler | 252 | self.status_update_handler = status_update_handler |
253 | self.announcement_handler = announcement_handler | ||
254 | self.announcement_reaction_handler = announcement_reaction_handler | ||
255 | self.announcement_delete_handler = announcement_delete_handler | ||
256 | self.encryted_message_handler = encryted_message_handler | ||
214 | 257 | ||
215 | def on_update(self, status): | 258 | def on_update(self, status): |
216 | if self.update_handler != None: | 259 | if self.update_handler is not None: |
217 | self.update_handler(status) | 260 | self.update_handler(status) |
218 | 261 | ||
219 | try: | 262 | try: |
220 | if self.local_update_handler != None and not "@" in status["account"]["acct"]: | 263 | if self.local_update_handler is not None and not "@" in status["account"]["acct"]: |
221 | self.local_update_handler(status) | 264 | self.local_update_handler(status) |
222 | except Exception as err: | 265 | except Exception as err: |
223 | six.raise_from( | 266 | six.raise_from( |
@@ -226,21 +269,41 @@ class CallbackStreamListener(StreamListener): | |||
226 | ) | 269 | ) |
227 | 270 | ||
228 | def on_delete(self, deleted_id): | 271 | def on_delete(self, deleted_id): |
229 | if self.delete_handler != None: | 272 | if self.delete_handler is not None: |
230 | self.delete_handler(deleted_id) | 273 | self.delete_handler(deleted_id) |
231 | 274 | ||
232 | def on_notification(self, notification): | 275 | def on_notification(self, notification): |
233 | if self.notification_handler != None: | 276 | if self.notification_handler is not None: |
234 | self.notification_handler(notification) | 277 | self.notification_handler(notification) |
235 | 278 | ||
279 | def on_filters_changed(self): | ||
280 | if self.filters_changed_handler is not None: | ||
281 | self.filters_changed_handler() | ||
282 | |||
236 | def on_conversation(self, conversation): | 283 | def on_conversation(self, conversation): |
237 | if self.conversation_handler != None: | 284 | if self.conversation_handler is not None: |
238 | self.conversation_handler(conversation) | 285 | self.conversation_handler(conversation) |
239 | 286 | ||
240 | def on_unknown_event(self, name, unknown_event=None): | 287 | def on_announcement(self, annoucement): |
241 | if self.unknown_event_handler != None: | 288 | if self.announcement_handler is not None: |
242 | self.unknown_event_handler(name, unknown_event) | 289 | self.announcement_handler(annoucement) |
290 | |||
291 | def on_announcement_reaction(self, TODO): | ||
292 | if self.announcement_reaction_handler is not None: | ||
293 | self.announcement_reaction_handler(TODO) | ||
294 | |||
295 | def on_announcement_delete(self, annoucement_id): | ||
296 | if self.announcement_delete_handler is not None: | ||
297 | self.announcement_delete_handler(annoucement_id) | ||
243 | 298 | ||
244 | def on_status_update(self, status): | 299 | def on_status_update(self, status): |
245 | if self.status_update_handler != None: | 300 | if self.status_update_handler is not None: |
246 | self.status_update_handler(status) | 301 | self.status_update_handler(status) |
302 | |||
303 | def on_encrypted_message(self, unclear): | ||
304 | if self.encryted_message_handler is not None: | ||
305 | self.encryted_message_handler(unclear) | ||
306 | |||
307 | def on_unknown_event(self, name, unknown_event=None): | ||
308 | if self.unknown_event_handler is not None: | ||
309 | self.unknown_event_handler(name, unknown_event) \ No newline at end of file | ||