diff options
-rw-r--r-- | README.rst | 2 | ||||
-rw-r--r-- | docs/index.rst | 8 | ||||
-rw-r--r-- | mastodon/Mastodon.py | 57 |
3 files changed, 51 insertions, 16 deletions
@@ -1,7 +1,7 @@ | |||
1 | Mastodon.py | 1 | Mastodon.py |
2 | =========== | 2 | =========== |
3 | Python wrapper for the Mastodon ( https://github.com/tootsuite/mastodon/ ) API. | 3 | Python wrapper for the Mastodon ( https://github.com/tootsuite/mastodon/ ) API. |
4 | Feature complete for public API as of Mastodon version 2.8.0 and easy to get started with: | 4 | Feature complete for public API as of Mastodon version 2.8.2 and easy to get started with: |
5 | 5 | ||
6 | .. code-block:: python | 6 | .. code-block:: python |
7 | 7 | ||
diff --git a/docs/index.rst b/docs/index.rst index 96a0665..4e95bbb 100644 --- a/docs/index.rst +++ b/docs/index.rst | |||
@@ -54,9 +54,10 @@ node running Mastodon by setting `api_base_url` when creating the | |||
54 | api object (or creating an app). | 54 | api object (or creating an app). |
55 | 55 | ||
56 | Mastodon.py aims to implement the complete public Mastodon API. As | 56 | Mastodon.py aims to implement the complete public Mastodon API. As |
57 | of this time, it is feature complete for Mastodon version 2.8.0. Pleromas | 57 | of this time, it is feature complete for Mastodon version 2.8.2. Pleromas |
58 | Mastodon API layer, while not an official target, should also be basically | 58 | Mastodon API layer, while not an official target, should also be basically |
59 | compatible. | 59 | compatible, and Mastodon.py does make some allowances for behaviour that isn't |
60 | strictly like Mastodons. | ||
60 | 61 | ||
61 | A note about rate limits | 62 | A note about rate limits |
62 | ------------------------ | 63 | ------------------------ |
@@ -781,6 +782,9 @@ Mastodon.py throws a `MastodonVersionError`. | |||
781 | 782 | ||
782 | With the following functions, you can make Mastodon.py re-check the server | 783 | With the following functions, you can make Mastodon.py re-check the server |
783 | version or explicitly determine if a specific minimum Version is available. | 784 | version or explicitly determine if a specific minimum Version is available. |
785 | Long-running applications that aim to support multiple Mastodon versions | ||
786 | should do this from time to time in case a server they are running against | ||
787 | updated. | ||
784 | 788 | ||
785 | .. automethod:: Mastodon.retrieve_mastodon_version | 789 | .. automethod:: Mastodon.retrieve_mastodon_version |
786 | .. automethod:: Mastodon.verify_minimum_version | 790 | .. automethod:: Mastodon.verify_minimum_version |
diff --git a/mastodon/Mastodon.py b/mastodon/Mastodon.py index d725dd9..174e798 100644 --- a/mastodon/Mastodon.py +++ b/mastodon/Mastodon.py | |||
@@ -155,12 +155,12 @@ class Mastodon: | |||
155 | } | 155 | } |
156 | __VALID_SCOPES = ['read', 'write', 'follow', 'push'] + __SCOPE_SETS['read'] + __SCOPE_SETS['write'] | 156 | __VALID_SCOPES = ['read', 'write', 'follow', 'push'] + __SCOPE_SETS['read'] + __SCOPE_SETS['write'] |
157 | 157 | ||
158 | __SUPPORTED_MASTODON_VERSION = "2.4.3" | 158 | __SUPPORTED_MASTODON_VERSION = "2.8.2" |
159 | 159 | ||
160 | # Dict versions | 160 | # Dict versions |
161 | __DICT_VERSION_APPLICATION = "2.7.2" | 161 | __DICT_VERSION_APPLICATION = "2.7.2" |
162 | __DICT_VERSION_MENTION = "1.0.0" | 162 | __DICT_VERSION_MENTION = "1.0.0" |
163 | __DICT_VERSION_MEDIA = "2.3.0" | 163 | __DICT_VERSION_MEDIA = "2.8.2" |
164 | __DICT_VERSION_ACCOUNT = "2.4.0" | 164 | __DICT_VERSION_ACCOUNT = "2.4.0" |
165 | __DICT_VERSION_POLL = "2.8.0" | 165 | __DICT_VERSION_POLL = "2.8.0" |
166 | __DICT_VERSION_STATUS = bigger_version(bigger_version(bigger_version(bigger_version(bigger_version("2.8.0", | 166 | __DICT_VERSION_STATUS = bigger_version(bigger_version(bigger_version(bigger_version(bigger_version("2.8.0", |
@@ -202,7 +202,8 @@ class Mastodon: | |||
202 | Specify `api_base_url` if you want to register an app on an instance different from the flagship one. | 202 | Specify `api_base_url` if you want to register an app on an instance different from the flagship one. |
203 | Specify `website` to give a website for your app. | 203 | Specify `website` to give a website for your app. |
204 | 204 | ||
205 | Specify `session` with a requests.Session for it to be used instead of the deafult. | 205 | Specify `session` with a requests.Session for it to be used instead of the deafult. This can be |
206 | used to, amongst other things, adjust proxy or ssl certificate settings. | ||
206 | 207 | ||
207 | Presently, app registration is open by default, but this is not guaranteed to be the case for all | 208 | Presently, app registration is open by default, but this is not guaranteed to be the case for all |
208 | future mastodon instances or even the flagship instance in the future. | 209 | future mastodon instances or even the flagship instance in the future. |
@@ -357,13 +358,16 @@ class Mastodon: | |||
357 | self.mastodon_major, self.mastodon_minor, self.mastodon_patch = parse_version_string(version_str) | 358 | self.mastodon_major, self.mastodon_minor, self.mastodon_patch = parse_version_string(version_str) |
358 | return version_str | 359 | return version_str |
359 | 360 | ||
360 | def verify_minimum_version(self, version_str): | 361 | def verify_minimum_version(self, version_str, cached=False): |
361 | """ | 362 | """ |
362 | Update version info from server and verify that at least the specified version is present. | 363 | Update version info from server and verify that at least the specified version is present. |
363 | 364 | ||
365 | If you specify "cached", the version info update part is skipped. | ||
366 | |||
364 | Returns True if version requirement is satisfied, False if not. | 367 | Returns True if version requirement is satisfied, False if not. |
365 | """ | 368 | """ |
366 | self.retrieve_mastodon_version() | 369 | if not cached: |
370 | self.retrieve_mastodon_version() | ||
367 | major, minor, patch = parse_version_string(version_str) | 371 | major, minor, patch = parse_version_string(version_str) |
368 | if major > self.mastodon_major: | 372 | if major > self.mastodon_major: |
369 | return False | 373 | return False |
@@ -1107,7 +1111,16 @@ class Mastodon: | |||
1107 | ### | 1111 | ### |
1108 | # Reading data: Searching | 1112 | # Reading data: Searching |
1109 | ### | 1113 | ### |
1110 | @api_version("2.8.0", "2.8.0", __DICT_VERSION_SEARCHRESULT) | 1114 | def __ensure_search_params_acceptable(self, account_id, offset, min_id, max_id): |
1115 | """ | ||
1116 | Internal Helper: Throw a MastodonVersionError if version is < 2.8.0 but parameters | ||
1117 | for search that are available only starting with 2.8.0 are specified. | ||
1118 | """ | ||
1119 | if not account_id is None or not offset is None or not min_id is None or not max_id is None: | ||
1120 | if self.verify_minimum_version("2.8.0", cached=True) == False: | ||
1121 | raise MastodonVersionError("Advanced search parameters require Mastodon 2.8.0+") | ||
1122 | |||
1123 | @api_version("1.1.0", "2.8.0", __DICT_VERSION_SEARCHRESULT) | ||
1111 | def search(self, q, resolve=True, result_type=None, account_id=None, offset=None, min_id=None, max_id=None): | 1124 | def search(self, q, resolve=True, result_type=None, account_id=None, offset=None, min_id=None, max_id=None): |
1112 | """ | 1125 | """ |
1113 | Fetch matching hashtags, accounts and statuses. Will perform webfinger | 1126 | Fetch matching hashtags, accounts and statuses. Will perform webfinger |
@@ -1122,12 +1135,22 @@ class Mastodon: | |||
1122 | 1135 | ||
1123 | `offset`, `min_id` and `max_id` can be used to paginate. | 1136 | `offset`, `min_id` and `max_id` can be used to paginate. |
1124 | 1137 | ||
1138 | Will use search_v1 (no tag dicts in return values) on Mastodon versions before | ||
1139 | 2.4.1), search_v2 otherwise. Parameters other than resolve are only available | ||
1140 | on Mastodon 2.8.0 or above - this function will throw a MastodonVersionError | ||
1141 | if you try to use them on versions before that. Note that the cached version | ||
1142 | number will be used for this to avoid uneccesary requests. | ||
1143 | |||
1125 | Returns a `search result dict`_, with tags as `hashtag dicts`_. | 1144 | Returns a `search result dict`_, with tags as `hashtag dicts`_. |
1126 | """ | 1145 | """ |
1127 | return self.search_v2(q, resolve=resolve, result_type=result_type, account_id=account_id, | 1146 | if self.verify_minimum_version("2.4.1", cached=True) == True: |
1128 | offset=offset, min_id=min_id, max_id=max_id) | 1147 | return self.search_v2(q, resolve=resolve, result_type=result_type, account_id=account_id, |
1129 | 1148 | offset=offset, min_id=min_id, max_id=max_id) | |
1130 | @api_version("1.1.0", "2.1.0", __DICT_VERSION_SEARCHRESULT) | 1149 | else: |
1150 | self.__ensure_search_params_acceptable(account_id, offset, min_id, max_id) | ||
1151 | return self.search_v1(q, resolve=resolve) | ||
1152 | |||
1153 | @api_version("1.1.0", "2.1.0", "2.1.0") | ||
1131 | def search_v1(self, q, resolve=False): | 1154 | def search_v1(self, q, resolve=False): |
1132 | """ | 1155 | """ |
1133 | Identical to `search_v2()`, except in that it does not return | 1156 | Identical to `search_v2()`, except in that it does not return |
@@ -1140,7 +1163,7 @@ class Mastodon: | |||
1140 | del params['resolve'] | 1163 | del params['resolve'] |
1141 | return self.__api_request('GET', '/api/v1/search', params) | 1164 | return self.__api_request('GET', '/api/v1/search', params) |
1142 | 1165 | ||
1143 | @api_version("2.8.0", "2.8.0", __DICT_VERSION_SEARCHRESULT) | 1166 | @api_version("2.4.1", "2.8.0", __DICT_VERSION_SEARCHRESULT) |
1144 | def search_v2(self, q, resolve=True, result_type=None, account_id=None, offset=None, min_id=None, max_id=None): | 1167 | def search_v2(self, q, resolve=True, result_type=None, account_id=None, offset=None, min_id=None, max_id=None): |
1145 | """ | 1168 | """ |
1146 | Identical to `search_v1()`, except in that it returns tags as | 1169 | Identical to `search_v1()`, except in that it returns tags as |
@@ -1148,6 +1171,7 @@ class Mastodon: | |||
1148 | 1171 | ||
1149 | Returns a `search result dict`_. | 1172 | Returns a `search result dict`_. |
1150 | """ | 1173 | """ |
1174 | self.__ensure_search_params_acceptable(account_id, offset, min_id, max_id) | ||
1151 | params = self.__generate_params(locals()) | 1175 | params = self.__generate_params(locals()) |
1152 | 1176 | ||
1153 | if resolve == False: | 1177 | if resolve == False: |
@@ -1429,7 +1453,9 @@ class Mastodon: | |||
1429 | status_post returns a `scheduled toot dict`_ instead. | 1453 | status_post returns a `scheduled toot dict`_ instead. |
1430 | 1454 | ||
1431 | Pass `poll` to attach a poll to the status. An appropriate object can be | 1455 | Pass `poll` to attach a poll to the status. An appropriate object can be |
1432 | constructed using `make_poll()`_ | 1456 | constructed using `make_poll()`_ . Note that as of Mastodon version |
1457 | 2.8.2, you can only have either media or a poll attached, not both at | ||
1458 | the same time. | ||
1433 | 1459 | ||
1434 | Specify `content_type` to set the content type of your post on Pleroma. | 1460 | Specify `content_type` to set the content type of your post on Pleroma. |
1435 | It accepts 'text/plain' (default), 'text/markdown', and 'text/html'. | 1461 | It accepts 'text/plain' (default), 'text/markdown', and 'text/html'. |
@@ -1445,7 +1471,12 @@ class Mastodon: | |||
1445 | scheduled_at = self.__consistent_isoformat_utc(scheduled_at) | 1471 | scheduled_at = self.__consistent_isoformat_utc(scheduled_at) |
1446 | 1472 | ||
1447 | params_initial = locals() | 1473 | params_initial = locals() |
1448 | 1474 | ||
1475 | # Validate poll/media exclusivity | ||
1476 | if not poll is None: | ||
1477 | if (not media_ids is None) and len(media_ids) != 0: | ||
1478 | raise ValueError('Status can have media or poll attached - not both.') | ||
1479 | |||
1449 | # Validate visibility parameter | 1480 | # Validate visibility parameter |
1450 | valid_visibilities = ['private', 'public', 'unlisted', 'direct'] | 1481 | valid_visibilities = ['private', 'public', 'unlisted', 'direct'] |
1451 | if params_initial['visibility'] == None: | 1482 | if params_initial['visibility'] == None: |