{"id":13427528,"url":"https://github.com/MarshalX/atproto","last_synced_at":"2025-03-16T00:30:48.581Z","repository":{"id":162662905,"uuid":"569485568","full_name":"MarshalX/atproto","owner":"MarshalX","description":"The AT Protocol (🦋 Bluesky) SDK for Python 🐍","archived":false,"fork":false,"pushed_at":"2025-03-10T21:57:55.000Z","size":2410,"stargazers_count":543,"open_issues_count":18,"forks_count":59,"subscribers_count":14,"default_branch":"main","last_synced_at":"2025-03-14T20:52:56.968Z","etag":null,"topics":["at-protocol","atp","atproto","atprotocol","bluesky","bluesky-client","bluesky-feed","bsky","did","social-media","xrpc"],"latest_commit_sha":null,"homepage":"https://atproto.blue","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MarshalX.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"MarshalX"}},"created_at":"2022-11-22T23:48:57.000Z","updated_at":"2025-03-11T23:34:13.000Z","dependencies_parsed_at":null,"dependency_job_id":"f4d9c882-6c3e-48e3-9629-b2d40b9d2ee4","html_url":"https://github.com/MarshalX/atproto","commit_stats":{"total_commits":398,"total_committers":23,"mean_commits":"17.304347826086957","dds":0.0879396984924623,"last_synced_commit":"8cec1d2f94bef240fc84f8ef35944dc0ed62528c"},"previous_names":[],"tags_count":58,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarshalX%2Fatproto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarshalX%2Fatproto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarshalX%2Fatproto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarshalX%2Fatproto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MarshalX","download_url":"https://codeload.github.com/MarshalX/atproto/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243672370,"owners_count":20328762,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["at-protocol","atp","atproto","atprotocol","bluesky","bluesky-client","bluesky-feed","bsky","did","social-media","xrpc"],"created_at":"2024-07-31T01:00:30.632Z","updated_at":"2025-03-16T00:30:48.576Z","avatar_url":"https://github.com/MarshalX.png","language":"Python","funding_links":["https://github.com/sponsors/MarshalX"],"categories":["\u003ca name='clients-and-libraries'\u003e\u003c/a\u003e Clients and Libraries","Python"],"sub_categories":["\u003ca name='python'\u003e\u003c/a\u003e Python"],"readme":"\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://github.com/MarshalX/atproto\"\u003e\n        \u003cimg alt=\"Logo of atproto SDK for Python by Midjourney'\" src=\"https://github.com/MarshalX/atproto/raw/main/.github/images/logo.png\"\u003e\n    \u003c/a\u003e\n    \u003cbr\u003e\n    \u003cb\u003eAutogenerated from lexicons, well type hinted, documented, sync and async SDK for Python\u003c/b\u003e\n    \u003cbr\u003e\n    \u003ca href=\"https://github.com/MarshalX/atproto/tree/main/examples\"\u003e\n        Examples\n    \u003c/a\u003e\n    •\n    \u003ca href=\"https://atproto.blue\"\u003e\n        Documentation\n    \u003c/a\u003e\n    •\n    \u003ca href=\"https://discord.gg/PCyVJXU9jN\"\u003e\n        Discord Bluesky API\n    \u003c/a\u003e\n\u003c/p\u003e\n\n## The AT Protocol SDK\n\n\u003e ⚠️ Under construction. Until the 1.0.0 release compatibility between versions is not guaranteed. \n\nCode snippet:\n\n```python\nfrom atproto import Client, client_utils\n\n\ndef main():\n    client = Client()\n    profile = client.login('my-handle', 'my-password')\n    print('Welcome,', profile.display_name)\n    \n    text = client_utils.TextBuilder().text('Hello World from ').link('Python SDK', 'https://atproto.blue')\n    post = client.send_post(text)\n    client.like(post.uri, post.cid)\n\n\nif __name__ == '__main__':\n    main()\n\n```\n\n\u003cdetails\u003e\n  \u003csummary\u003eCode snippet of async version\u003c/summary\u003e\n\n```python\nimport asyncio\n\nfrom atproto import AsyncClient, client_utils\n\n\nasync def main():\n    client = AsyncClient()\n    profile = await client.login('my-handle', 'my-password')\n    print('Welcome,', profile.display_name)\n\n    text = client_utils.TextBuilder().text('Hello World from ').link('Python SDK', 'https://atproto.blue')\n    post = await client.send_post(text)\n    await client.like(post.uri, post.cid)\n\n    \nif __name__ == '__main__':\n    # use run() for a higher Python version\n    asyncio.get_event_loop().run_until_complete(main())\n\n```\n\u003c/details\u003e\n\n💬 [Direct Messages (Chats)](https://atproto.blue/en/latest/dm.html)\n\n🍿 [Example project with custom feed generator](https://github.com/MarshalX/bluesky-feed-generator)\n\n🔥 [Firehose data streaming is available](https://atproto.blue/en/latest/atproto_firehose/index.html)\n\n🌐 [Identity resolvers for DID and Handle](https://atproto.blue/en/latest/atproto_identity/index.html)\n\n### Introduction\n\nThis SDK attempts to implement everything that provides ATProto. There is support for Lexicon Schemes, XRPC clients, Firehose, Identity, DID keys, signatures, and more. All models, queries, and procedures are generated automatically. The main focus is on the lexicons of atproto.com and bsky.app, but it doesn't have a vendor lock on it. Feel free to use the code generator for your own lexicon schemes. The SDK also provides utilities to work with CID, NSID, AT URI Schemes, DAG-CBOR, CAR files, DID Documents and more.\n\n### Requirements\n\n- Python 3.8 or higher.\n\n### Installing\n\n``` bash\npip install atproto\n```\n\n### Quick start\n\nFirst of all, you need to create the instance of the XRPC Client. To do so, you have two major options: asynchronous and synchronous. The difference is only in the import and how you call the methods. If you are not familiar with async, use sync instead.\n\nFor sync:\n\n```python\nfrom atproto import Client\n\nclient = Client()\n# By default, it uses the server of bsky.app. To change this behavior, pass the base api URL to constructor\n# Client('https://example.com')\n```\n\nFor async:\n\n```python\nfrom atproto import AsyncClient\n\nclient = AsyncClient()\n# By default, it uses the server of bsky.app. To change this behavior, pass the base api URL to constructor\n# AsyncClient('https://example.com')\n```\n\nIn the snippets below, only the sync version will be presented.\n\nRight after the creation of the Client instance, you will probably want to access the full API and perform actions by profile. To achieve this, you should log into the network using your handle and password. The password could be app-specific.\n\n```python\nfrom atproto import Client\n\nclient = Client()\nclient.login('my-username', 'my-password')\n```\n\nYou are awesome! Now feel free to pick any high-level method that you want and try it out!\n\nCode to send a post:\n\n```python\nfrom atproto import Client\n\nclient = Client()\nclient.login('my-username', 'my-password')\nclient.send_post(text='Hello World!')\n```\n\nUseful links to continue:\n\n- [List of all methods with documentation](https://atproto.readthedocs.io/en/latest/atproto_client/index.html).\n- [Examples of using the methods](https://github.com/MarshalX/atproto/tree/main/examples).\n\n### SDK structure\n\nThe SDK is built upon the following components:\n\n| Package            | Description                                                                 |\n|--------------------|-----------------------------------------------------------------------------|\n| `atproto`          | Import shortcuts to other packages.                                         |\n| `atproto_cli`      | CLI tool to generate code.                                                  |\n| `atproto_client`   | XRPC Client, data models, and utils like rich text helper.                  |\n| `atproto_codegen`  | Code generator of models, clients, and namespaces.                          |\n| `atproto_core`     | Tools to work with NSID, AT URI Schemes, CID, CAR files, and DID Documents. |\n| `atproto_crypto`   | Crypto utils like multibase, signature verification, work with DID keys.    |\n| `atproto_firehose` | Firehose (data streaming) client and models.                                |\n| `atproto_identity` | Identity resolvers for DID, Handle, AT Protocol data, signing keys.         |\n| `atproto_lexicon`  | Lexicon parser.                                                             |\n| `atproto_server`   | Server-side utils like JWT.                                                 |\n\nI highly recommend that you use the `atproto` package to import everything that you need. \nIt contains shortcuts to all other packages.\n\n### Documentation\n\nThe documentation is live at [atproto.blue](https://atproto.blue/).\n\n### Getting help\n\nYou can get help in several ways:\n- Report bugs, request new features by [creating an issue](https://github.com/MarshalX/atproto/issues/new).\n- Ask questions by [starting a discussion](https://github.com/MarshalX/atproto/discussions/new).\n- Ask questions in [Discord server](https://discord.gg/PCyVJXU9jN).\n\n### Advanced usage\n\nI'll be honest. The high-level Client that was shown in the \"Quick Start\" section is not a real ATProto API. This is syntax sugar built upon the real XRPC methods! The high-level methods do not cover the full needs of developers. To be able to do anything that you want, you should know how to work with low-level API. Let's dive into it!\n\nThe basics:\n- Namespaces – classes that group sub-namespaces and the XRPC queries and procedures. Built upon NSID ATProto semantic.\n- Model – dataclasses for input, output, and params of the methods from namespaces. Models describe Record and all other types in the Lexicon Schemes.\n\n#### Namespaces\n\nThe client contains references to the root of all namespaces. It's `com` and `app` for now.\n\n```python\nfrom atproto import Client\n\nClient().com\nClient().app\n```\n\nTo dive deeper, you can navigate using hints from your IDE. Thanks to a well-type hinted SDK, it's much easier.\n\n```python\nfrom atproto import Client\n\nClient().com.atproto.server.create_session(...)\nClient().com.atproto.sync.get_blob(...)\nClient().app.bsky.feed.get_likes(...)\nClient().app.bsky.graph.get_follows(...)\n```\n\nThe endpoint of the path is always the method you want to call. The method presents a query or procedure in XRPC. You should not care about it much. The only thing you need to know is that the procedures require data objects. Queries could be called with or without params.\n\n#### Records\n\nIn some sub-namespaces, you can find records. Such record classes provide a syntax sugar not defined in the lexicon scheme. This sugar provides a more convenient way to work with repository operations, such as creating a record, deleting a record, and so on.\n\nHere are some available records of Bluesky records:\n\n```python\nfrom atproto import Client\n\nClient().app.bsky.feed.post\nClient().app.bsky.feed.like\nClient().app.bsky.graph.follow\nClient().app.bsky.graph.block\nClient().app.bsky.actor.profile\n# ... more\n```\n\nUsage example with the `post` record:\n\n```python\nfrom atproto import AtUri, Client, models\n\nclient = Client()\nclient.login('my-username', 'my-password')\n\nposts = client.app.bsky.feed.post.list(client.me.did, limit=10)\nfor uri, post in posts.records.items():\n    print(uri, post.text)\n\npost = client.app.bsky.feed.post.get(client.me.did, AtUri.from_str(uri).rkey)\nprint(post.value.text)\n\npost_record = models.AppBskyFeedPost.Record(text='test record namespaces', created_at=client.get_current_time_iso())\nnew_post = client.app.bsky.feed.post.create(client.me.did, post_record)\nprint(new_post)\n\ndeleted_post = client.app.bsky.feed.post.delete(client.me.did, AtUri.from_str(new_post.uri).rkey)\nprint(deleted_post)\n```\n\nPlease note that not all repository operations are covered by these syntax sugars. You can always use the low-level methods to perform any desired action. One such action is updating a record.\n\n#### Models\n\nTo deal with methods, we need to deal with models! Models are available in the `models` module and have NSID-based aliases. Let's take a look at it.\n\n```python\nfrom atproto import models\n\nmodels.ComAtprotoIdentityResolveHandle\nmodels.AppBskyFeedPost\nmodels.AppBskyActorGetProfile\n# 90+ more...\n```\n\nThe model classes in the \"models\" aliases could be:\n\n- Data model\n- Params model\n- Response model\n- Sugar response model\n- Record model\n- Type model\n\nThe only thing you need to know is how to create instances of models. You won't need to work as model-creator for all models. For example, the SDK will create Response models for you.\n\nThere are a few ways to create the instance of a model:\n\n- Dict-based\n- Class-based\n\nThe instances of any data and params models should be passed as arguments to the methods that were described above.\n\nDict-based:\n\n```python\nfrom atproto import Client\n\nclient = Client()\nclient.login('my-username', 'my-password')\n# The params model will be created automatically internally for you!\nprint(client.com.atproto.identity.resolve_handle({'handle': 'marshal.dev'}))\n```\n\nClass-based:\n\n```python\nfrom atproto import Client, models\n\nclient = Client()\nclient.login('my-username', 'my-password')\nparams = models.ComAtprotoIdentityResolveHandle.Params(handle='marshal.dev')\nprint(client.com.atproto.identity.resolve_handle(params))\n```\n\nTip: look at the typehint of the method to figure out the name and the path to the input/data model!\n\nPro Tip: use IDE autocompletion to find necessary models! Just start typing the method name right after the dot (`models.{type method name in camel case`).\n\nModels can be nested to the innermost rings of hell. Be ready for it!\n\nThis is how we can send a post with an image using low-level XRPC Client:\n\n```python\nfrom atproto import Client, models\n\nclient = Client()\nclient.login('my-username', 'my-password')\n\nwith open('cat.jpg', 'rb') as f:\n    img_data = f.read()\n\n    upload = client.upload_blob(img_data)\n    images = [models.AppBskyEmbedImages.Image(alt='Img alt', image=upload.blob)]\n    embed = models.AppBskyEmbedImages.Main(images=images)\n\n    client.com.atproto.repo.create_record(\n        models.ComAtprotoRepoCreateRecord.Data(\n            repo=client.me.did,\n            collection=models.ids.AppBskyFeedPost,\n            record=models.AppBskyFeedPost.Record(\n                created_at=client.get_current_time_iso(), text='Text of the post', embed=embed\n            ),\n        )\n    )\n\n    # of course, you can use the syntax sugar here instead\n    post = models.AppBskyFeedPost.Record(text='Text of the post', embed=embed, created_at=client.get_current_time_iso())\n    client.app.bsky.feed.post.create(client.me.did, post)\n    # or even high-level client\n    client.send_image(text='Text of the post', image=img_data, image_alt='Img alt')\n    # these three methods are equivalent\n```\n\nI hope you are not scared. May the Force be with you. Good luck!\n\n### Change log\n\nThe full change log is available in [CHANGES.md](https://github.com/MarshalX/atproto/blob/main/CHANGES.md).\n\n### Contributing\n\nContributions of all sizes are welcome. The contribution guidelines will be presented later.\n\n### License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMarshalX%2Fatproto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FMarshalX%2Fatproto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMarshalX%2Fatproto/lists"}