halcy / mastodon.py Goto Github PK
View Code? Open in Web Editor NEWPython wrapper for the Mastodon ( https://github.com/mastodon/mastodon/ ) API.
License: MIT License
Python wrapper for the Mastodon ( https://github.com/mastodon/mastodon/ ) API.
License: MIT License
Trying to login (on octodon.social instance) failes with an API error thrown:
mastodon.Mastodon.MastodonAPIError: Granted scopes "read" differ from requested scopes "follow read write".
The login is successful when only asking for the "read" scope but then only read functions can be used, of course.
App creation and registration work and ...oauth/authorized_applications also confirms that read, write and follow privilege is enabled.
This worked before. It might be relevant that octodon was updated to Mastodon v1.1.2 yesterday...?
when a request is denied because of rate limits, MastodonRatelimitError is never raised, instead a plain MastodonAPIError is raised
MastodonAPIError: Mastodon API returned error: Throttled
File "libforget/mastodon.py", line 180, in refresh_posts
status = api.status(post.mastodon_id)
File "mastodon/Mastodon.py", line 297, in status
return self.__api_request('GET', url)
File "mastodon/Mastodon.py", line 1079, in __api_request
raise MastodonAPIError("Mastodon API returned error: " + str(response['error']))
and that's not all:
if "error" in response and response["error"] == "Throttled":
this only works if the logged-in user has their locale set to english! surprise! mastodon localises errors in the api ๐
i believe the status code to watch for would be 429 but i havent tested it
i'll try to get a PR submitted for both of these issues sometime tomorrow โจ
I think that the library must try to use https instead of http, simply because by definition it's more secure.
ยป it must try to connect to "https://framapiaf.org" if "http://framapiaf.org" is configured. If it works, he must use it. If request fails, it toggles on http only.
It would be particularly useful because lots of instances only accept https requests and deny http.
It would avoid much research for developers if like me they forget to type the S.
>>> mastodon_api = Mastodon(
... client_id = "mtt_mastodon_client.secret",
... access_token = "mtt_mastodon_user.secret",
... ratelimit_method = "wait",
... api_base_url = "http://framapiaf.org"
... )
>>> mastodon_api.status_post('test', visibility="private")
mastodon.Mastodon.MastodonAPIError: Endpoint not found.
>>>
>>> mastodon_api = Mastodon(
... client_id = "mtt_mastodon_client.secret",
... access_token = "mtt_mastodon_user.secret",
... ratelimit_method = "wait",
... api_base_url = "https://framapiaf.org"
... )
>>> mastodon_api.status_post('test', visibility="private")
{...}
The status_post
method takes a in_reply_to_id
parameter, but it doesn't seem to actually use it anywhere or pass it to the API call.
The log_in() method always fails when passed a known-good login. It appears to always try to login to mastodon.social, even when passed another instance.
Please show a successful login on another instance and post sample code.
Context: https://github.com/enkiv2/mastodonVoyeur/blob/master/MastoVoyeur.py
I request the local timeline from a mastodon instance and loop through toots; I have discovered that the array I get contains no toots with mentions, even when it contains toots from the same user both newer and older that have to mentions. This is not limited to mentions of remote users.
If the API response has an empty "Link:" header, a KeyError will be raised. This could be fixed by __api_request handling an empty "link" header.
It's possible this is a requests bug, but I'm getting a KeyError here using mastodon.py with framapiaf.org (a French mastodon host).
KeyError: 'rel'
Uncaught exception. Entering post mortem debugging
(pdb) l
959 # Parse link headers
960 if isinstance(response, list) and 'Link' in response_object.headers:
961 tmp_urls = requests.utils.parse_header_links(response_object.headers['Link'].rstrip('>').replace('>,<', ',<'))
962 for url in tmp_urls:
963 -> if url['rel'] == 'next':
964 # Be paranoid and extract max_id specifically
965 next_url = url['url']
966 matchgroups = re.search(r"max_id=([0-9]*)", next_url)
967
968 if matchgroups:
(Pdb) url
{'url': ''}
(Pdb) response_object.headers['Link']
''
I am trying to post an image that is created by a script, how ever I cant seem to post it.
from the following code:
mastodon = mastodon_bot(botname, email, password, instance_url) media = mastodon.media_post('newGif.gif') postData = "Glitching #gifs all day " + media['url'] print(mastodon.status_post(postData ,None,media,None,'unlisted',"#glitchArt"))
I get the following error message:
{'error': 'Cannot attach more than 4 files'}
but I am only trying to attach one media file.
Apparently whenever I try to search, I get this error :
Traceback (most recent call last): File "MapBot.py", line 133, in <module> main(sys.argv) File "MapBot.py", line 27, in main geopulses = Mastodon.search(HASH_MARKER, False) File "/anaconda3/lib/python3.6/site-packages/mastodon/Mastodon.py", line 436, in search params = self.__generate_params(locals()) AttributeError: 'str' object has no attribute '_Mastodon__generate_params'
I've logged in myself before calling search, and the value of HASH_MARKER is "#geoCoords" but I've tried with different strings and it produced the same error.
when trying to use
token = mastodon.log_in(username=username, password=password)
meet the behavior :
File "lib/python3.6/site-packages/mastodon/Mastodon.py", ... in __json_date_parse
json_object[k] = dateutil.parser.parse(v)
File "lib/python3.6/site-packages/mastodon/Mastodon.py", ..., in __json_date_parse
raise MastodonAPIError('Encountered invalid date.')
mastodon.Mastodon.MastodonAPIError: Encountered invalid date.
http://dateutil.readthedocs.io/en/stable/_modules/dateutil/parser.html#parse
in python 3 dateutil.parser.parse wait a string, and it's a timestamp that is given to dateutil
when running test, there are missing lib ; so seetup.py could be like this
from setuptools import setup
install_requires = [
'pytest==3.2.1',
'python-dateutil==2.6.1',
'pytz==2017.2',
'requests==2.18.4',
'six==1.10.0',
]
setup(name='Mastodon.py',
version='1.0.8',
description='Python wrapper for the Mastodon API',
packages=['mastodon'],
setup_requires=['pytest-runner'],
tests_require=['pytest'],
install_requires=install_requires,
url='https://github.com/halcy/Mastodon.py',
author='Lorenz Diener',
author_email='[email protected]',
license='MIT',
keywords='mastodon api microblogging',
classifiers=[
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'Topic :: Communications',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 3',
]
)
You could also provide a requirements.txt too that will contain all that lib
Attempting to create the Mastodon app with the following code:
new_masto_app = Mastodon.create_app(
'lastshoutapp',
api_base_url="https://mastodon.cloud",
to_file = 'pytooter_clientcred.txt'
)
And receive the following error:
Traceback (most recent call last):
File "git/misc/scripts/create_mastodon_app.py", line 9, in
to_file = 'pytooter_clientcred.txt'
File "/usr/lib/python2.7/site-packages/mastodon/Mastodon.py", line 67, in create_app
raise MastodonNetworkError("Could not complete request: %s" % e)
mastodon.Mastodon.MastodonNetworkError: Could not complete request: HTTPSConnectionPool(host='mastodon.cloud', port=443): Max retries exceeded with url: /api/v1/apps (Caused by SSLError(SSLError(1, u'[SSL: WRONG_CURVE] wrong curve (_ssl.c:661)'),))
I'm currently packaging Mastodon.py for our package manager and distro (Guix, GuixSD) and had to notice you are mandatory depending on a python package which has last seen a (pypi- ) release in 2013.
Could you drop this in favor of more actively maintained python packages?
Isn't "dateutil" part of the python standard (2 and 3)?
it's not a server issue; they can be seen with curl
:
curl --header "Authorization: Bearer ${TOKEN}" -sS 'https://mastodon.social/api/v1/streaming/hashtag?tag=mastodon'
logging shows the requests connection to the proper endpoint but it's unclear if the tag is getting specified properly. successfully streaming to the 'public' endpoint looks basically the same:
2017-05-08 23:03:55|requests.packages.urllib3.connectionpool|MainProcess|DEBUG| Starting new HTTPS connection (1): mastodon.social
2017-05-08 23:04:10|requests.packages.urllib3.connectionpool|MainProcess|DEBUG| https://mastodon.social:443 "GET /api/v1/streaming/hashtag HTTP/1.1" 200 None
(on the plus side, they don't seem to be throwing errors, either.)
There is now an API endpoint for clearing a user's notifications, which is missing from this library: https://github.com/tootsuite/documentation/blob/master/Using-the-API/API.md#clearing-notifications
POST /api/v1/notifications/clear
When Mastodon encounters multiple leading /'s in a URL, it throws a 404 error (resulting in parse errors for the streaming API). The streaming API generates multiple leading /'s when accessing an endpoint.
The fact this doesn't work is probably a bug in Mastodon, but should be fixed in Mastodon.py as well.
It seems the status_post
method only acepts three level of visibility: public, private, unlisted.
Is there any way to send a direct message (only visile to mentioned users) using Mastodon.py?
This seems possible using Mstodon API, so it may be just a matter of adding "direct" to available options in sttus_post
? But maybe I'm missing something :)
Hi,
Using this code I got a severe crash only in one case: when the followers number of the account is 40:
res = mastodon.account_followers(userid)
for page in mastodon.fetch_remaining(res):
nbfollowers += 1
Below is the issue:
Traceback (most recent call last):
File "./mastocount.py", line 35, in <module>
Main()
File "/home/chaica/progra/python/mastocount/mastocount/main.py", line 38, in __init__
self.main()
File "/home/chaica/progra/python/mastocount/mastocount/main.py", line 63, in main
followers = get_followers(credentials)
File "/home/chaica/progra/python/mastocount/mastocount/followers.py", line 38, in get_followers
for page in mastodon.fetch_remaining(res):
File "/usr/local/lib/python3.5/dist-packages/mastodon/Mastodon.py", line 814, in fetch_remaining
current_page = self.fetch_next(current_page)
File "/usr/local/lib/python3.5/dist-packages/mastodon/Mastodon.py", line 773, in fetch_next
return self.__api_request(method, endpoint, params)
File "/usr/local/lib/python3.5/dist-packages/mastodon/Mastodon.py", line 963, in __api_request
if url['rel'] == 'next':
KeyError: 'rel'
It's only produce when my number of followers is equal to the parameter limit of account_followers. Without limit, it breaks if the number of account followers is 40.
This code perfectly works on 3 other accounts with different number of account_followers and works on the same account if the number of followers is different of 40.
I tested modifying the limit and each time account followers number equals limit, it breaks.
Let me know if you need more information,
Carl
You could parse the Link header to get previous/next result sets for connections
API documentation specifies these endpoints return an empty dict.
While trying to use credentials of an newly-created app, I do have the following error message on https://framapiaf.org Using the same code to create the app on https://mastodon.social allows a normal use of Mastodon.py
$ python3
>>> from mastodon import Mastodon
>>> mastodon = Mastodon(
... client_id = 'boost_clientcred.txt',
... access_token = 'boost_usercred.txt'
... )
>>> mastodon.toot('this is a test')
{'error': 'The access token is invalid'}
>>>
The new credentials appears in the Authorized apps page in both cases.
Let me know if you need more information.
Regards,
Carl
The README says that Mastodon.py is compatible with Mastodon v1.6, can we update it to deal with the bigint ID numbers in v2.0.0? Ideally Mastodon.py should return ID numbers as python integers no matter what version of Mastodon we're communicating with, and automatically convert them to/from strings as needed.
Password login in apps is convenient, but not best practice. OAuth support is desirable.
There are lots of calls that require an 'id' parameter: status*, account*, etc.). In particular, I'm interested in using account_statuses().
I assume this is the integer user ID.
What is the most straightforward way to get the user ID for any user on any instance?
that's what I'm getting
Could not complete request: [SSL: UNKNOWN_PROTOCOL] unknown protocol (_ssl.c:645)
for calling
Mastodon.create_app(
'twitter2mastodon',
api_base_url = 'https://mstdn.io/',
to_file = 'twitter2mastodon.secret'
)
Thanks !
I could now do this like that foxmask/django-th#196 :)
notice : if you want, you can use https://saythanks.io/ to receive thanks for anybody :)
Modularizing the API to allow for separation of logic.
Just to make the API easier to extend and build off of.
Thoughts?
When I try uploading a media file as data I get an error:
#!/usr/bin/env python3
from mastodon import Mastodon
image_bytes = open("/Users/ed/Pictures/clouds.jpg", "rb").read()
mastodon = Mastodon(client_id='pytooter_clientcred.txt')
resp = mastodon.media_post(image_bytes, "image/jpeg")
Here's the error:
Traceback (most recent call last):
File "image.py", line 10, in <module>
resp = mastodon.media_post(image_bytes, "image/jpeg")
File "/Users/ed/Projects/Mastodon.py/mastodon/Mastodon.py", line 568, in media_post
if os.path.isfile(media_file) and mime_type == None:
File "/Users/ed/Projects/Mastodon.py/.venv/bin/../lib/python3.6/genericpath.py", line 30, in isfile
st = os.stat(path)
ValueError: stat: embedded null character in path
Possibly missing timeout settings?
Hi,
While using pagination, it crashes when my account followers number is 320. It does not happen on other accounts with a different account followers number:
$ ./mastocount.py -c coins.ini
Traceback (most recent call last):
File "./mastocount.py", line 35, in <module>
Main()
File "/home/chaica/progra/python/mastocount/mastocount/main.py", line 36, in __init__
self.main()
File "/home/chaica/progra/python/mastocount/mastocount/main.py", line 44, in main
followers = get_followers(credential)
File "/home/chaica/progra/python/mastocount/mastocount/followers.py", line 38, in get_followers
for page in mastodon.fetch_remaining(res):
File "/usr/local/lib/python3.5/dist-packages/mastodon/Mastodon.py", line 814, in fetch_remaining
current_page = self.fetch_next(current_page)
File "/usr/local/lib/python3.5/dist-packages/mastodon/Mastodon.py", line 760, in fetch_next
if '_pagination_next' in previous_page[-1]:
IndexError: list index out of range
It does not happen with the same account if the number is not 320, e.g 319.
Cheers,
Carl
I'm getting a very odd error when using the fetch remaining method. fetch_next works fine if I pass a previous page but the moment I try to do a call to fetch_remaining nothing seems to work.
Have you seen this behavior before?
Sample code
first_page = mastodon.timeline_local(since_id=last_seen_toot_id)
remaining_pages = mastodon.fetch_remaining(first_page)
Stack Trace
Traceback (most recent call last):
File ".\toot_bot.py", line 224, in
welcome(CONFIG)
File ".\toot_bot.py", line 144, in welcome
mastodon.public_stream(WelcomeBot(config))
File "C:\Users\mcros\src\mastodon_bot\BotStreamListeners.py", line 37, in init
self.replay_toots(True)
File "C:\Users\mcros\src\mastodon_bot\BotStreamListeners.py", line 55, in replay_toots
remaining_pages = mastodon.fetch_remaining(first_page)
File "C:\Program Files\Python36\lib\site-packages\mastodon\Mastodon.py", line 814, in fetch_remaining
current_page = self.fetch_next(current_page)
File "C:\Program Files\Python36\lib\site-packages\mastodon\Mastodon.py", line 760, in fetch_next
if '_pagination_next' in previous_page[-1]:
IndexError: list index out of range
In some circumstances it seems mastodon will respond with an empty link header. This shouldn't raise an exception
Mastodon: Request to endpoint "/api/v1/accounts/1/statuses" using method "GET".
Parameters: {'limit': 40, 'since_id': '6', 'max_id': 7}
Headers: {'Authorization': 'Bearer aaabbbcccdddeeefff'}
Files: {}
Mastodon: Response received with code 200.
response headers: {'X-Frame-Options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Content-Type-Options': 'nosniff', 'Content-Type': 'application/json; charset=utf-8', 'Link': '', 'Vary': 'Accept-Encoding, Origin', 'Content-Encoding': 'gzip', 'ETag': 'W/"0e4553e4ec97dd1f5d499c85b7dcc538"', 'Cache-Control': 'max-age=0, private, must-revalidate', 'X-Request-Id': 'd87dcb95-eaf9-48e9-97f6-3ffd385c01ae', 'X-Runtime': '0.020305', 'Transfer-Encoding': 'chunked'}
Response text content: []
Traceback (most recent call last):
File "/home/codl/dev/forget/venv/lib/python3.6/site-packages/celery/app/trace.py", line 374, in trace_task
R = retval = fun(*args, **kwargs)
File "tasks.py", line 39, in __call__
super().__call__(*args, **kwargs)
File "/home/codl/dev/forget/venv/lib/python3.6/site-packages/celery/app/trace.py", line 629, in __protected_call__
return self.run(*args, **kwargs)
File "/home/codl/dev/forget/venv/lib/python3.6/site-packages/celery/app/base.py", line 472, in run
return task._orig_run(*args, **kwargs)
File "tasks.py", line 55, in fetch_acc
cursor = action(acc, cursor)
File "/home/codl/dev/forget/lib/mastodon.py", line 105, in fetch_acc
statuses = api.account_statuses(acc.mastodon_id, **kwargs)
File "/home/codl/dev/forget/venv/lib/python3.6/site-packages/mastodon/Mastodon.py", line 364, in account_statuses
return self.__api_request('GET', '/api/v1/accounts/' + str(id) + '/statuses', params)
File "/home/codl/dev/forget/venv/lib/python3.6/site-packages/mastodon/Mastodon.py", line 963, in __api_request
if url['rel'] == 'next':
KeyError: 'rel'
I've written my first working script based on Mastodon.py. It's called "ReadMyToots", and it pulls down all toots you've written, converts them to plain text, then saves them in chronological order (earliest toot first) to a file.
This is a feature that should probably be built into Mastodon, but until that day comes, this script should help.
I created it to make it easier to catch up with folks I follow: Reading a text file of their toots in the order written is much faster and easier than the web interface.
It also works great for the stories some folks are tooting, such as this one by Redshirt27.
As the first working version, I'm certain there's tons of room for improvement. Please let me know in the comments!
How do I set a "Help Wanted" label on this?
In the official API documentation about this endpoint, it says you have to use a POST request. However, Mastodon.py uses a GET request which results in an endpoint not found exception.
Is there a 'correct' way to setup the library when using an account with 2FA/TOTP enabled?
I tried a few forms and could not get the authentication/login to work correctly.
all three of the streams throw immediately when connecting to a http-only server
Hi,
I use Mastodon.py v 1.1.1
When I try to upload an image, I get the error in the subject.
the code is
try:
toot_media = toot_api.media_post(media_file=media, mime_type=mime_type)
# create the post with the media id
toot_api.status_post(content, media_ids=toot_media['id'])
except Exception as inst:
logger.critical("Mastodon ERR {}".format(inst))
CRITICAL Mastodon ERR Mastodon API returned error: Validation failed: File content type is invalid, File is invalid
the error is met on that line https://github.com/halcy/Mastodon.py/blob/master/mastodon/Mastodon.py#L803
all function calls and function declarations are not pep8 compliant.
eg there is no blank before and after = signal
You can check with flake8
Once I trigger the process to get the token, I redirect the user to his mastodon instance, once on the url of the mastodon instance like this one
http://masto.home/oauth/authorize?client_id=69bc411afddc0a660849ba5fe04ef41a2062fccc60ca677e53a5c5b630b306b2&response_type=code&redirect_uri=https%3A%2F%2Ffoxmask.eu%2Fth%2Fcallbackmastodon%2F&scope=read+write+follow
(those URL are fake ; I create that @ home for dev purpose)
i'm in front of the page which tells me:
connected as @[email protected]
redirection URL is not valid
What is wrong with the redirect_uri ?
are the following lines in mastodon.py correct?
(761) params = previous_page[-1]['_pagination_next'] -- shouldn't that be "[0]" instead of "[-1]"
(785) params = next_page[-1]['_pagination_prev']
(972) next_params['max_id'] = int(matchgroups.group(1)) -- shouldn't that be 'since_id' instead of 'max_id'?
(984) prev_params['max_id'] = int(matchgroups.group(1))
I'm using feed2toot which uses Mastodon.py and I have a number of news bots on my instance. I just set the default post visibility to Unlisted on their accounts, and noticed that feed2toot wasn't honoring the setting, so I went to look at the source code.
In the source code, I found that feed2toot uses the .toot() call, and according to Mastodon.py's documentation, the default for this is binary: Posts are either public or followers-only, depending on whether or not the account is locked. But this isn't the right behavior. What it should do is to look at the default visibility that the user has set, and base it on that.
I can't stop my bots from filling up the local timeline without this, so getting it fixed is kind of urgent...
Hi! I am trying to use Mastodon.py on my custom instance.
The code:
from mastodon import Mastodon
# Register app - only once!
Mastodon.create_app(
'testapp',
to_file = 'test_clientcred.txt',
api_base_url='https://hackertribe.io'
)
# Log in - either every time, or use persisted
mastodon = Mastodon(client_id = 'test_clientcred.txt')
mastodon.log_in(
'myemail',
'mypassword',
to_file = 'test_usercred.txt'
)
# Create actual instance
mastodon = Mastodon(
client_id = 'test_clientcred.txt',
access_token = 'test_usercred.txt'
)
mastodon.toot('Tooting using Mastodon.py, on a custom instance!')
returns the error:
mastodon.Mastodon.MastodonIllegalArgumentError: Invalid user name, password or scopes: 'access_token'
Can you help me out? What am I doing wrong?
The REST API item "follow_by_uri" does not appear to be supported.
Is this intentional? What other API items are missing?
This one is tough and I don't know the best way to handle it, but...
Basically, Mastodon redirects things under /api/v1/streaming to a different URL (via 301) when configured to do so, due to the nature of various setups.
But it only redirects things under that endpoint, sub-endpoints like /api/v1/streaming/public return 404.
Worse still, requests strips the Authorization header when redirecting.
So, the right thing to determine the streaming endpoint:
I'll try to implement it, meanwhile I'm working on server-side workarounds for Mastodon.
You can also simplify "!= None" by "is not None" or "== False" by "is False" or "if foo == True:" by "if foo:"
or here https://github.com/halcy/Mastodon.py/blob/master/mastodon/Mastodon.py#L1060-L1065
you can do
return self._token_expired < datetime.datetime.now()
You can check with pylint for example
or at least it should detect it and throw a helpful error
instead what happens is that the hash is passed verbatim to Requests and a request for /api/v1/timelines/tag/#foobar
is made, which inevitably returns a 404 and throws a confusing "endpoint not found"
Mastodon.py should support 2FA for logging in.
when given a bad password or email, log_in() produces the proper MastodonIllegalArgumentError and an additional MastodonAPIError. i can only seem to catch one of them; traceback and raw html from the second gets dumped all over the screen. this is in a terminal client, so several screenfuls of unavoidable junk text is less than userfriendly.
this is a change from earlier versions; neither v1.0.2 nor v1.0.5 throw the extra MastodonAPIError.
Hi,
If my understanding is correct, Mastodon has streaming API(s), but I can't see it in Mastodon.py's doc.
Is it a planned feature?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.