Package: atproto
Autogenerated from lexicons, well type hinted, documented, sync and async SDK for PythonExamples•Documentation•Discord Bluesky APIThe AT Protocol SDK⚠️ Under construction. Until the 1.0.0 release compatibility between versions is not guaranteed.Code snippet:fromatprotoimportClient,client_utilsdefmain():client=Client()profile=client.login('my-handle','my-password')print('Welcome,',profile.display_name)text=client_utils.TextBuilder().text('Hello World from ').link('Python SDK','https://atproto.blue')post=client.send_post(text)client.like(post.uri,post.cid)if__name__=='__main__':main()Code snippet of async versionimportasynciofromatprotoimportAsyncClient,client_utilsasyncdefmain():client=AsyncClient()profile=awaitclient.login('my-handle','my-password')print('Welcome,',profile.display_name)text=client_utils.TextBuilder().text('Hello World from ').link('Python SDK','https://atproto.blue')post=awaitclient.send_post(text)awaitclient.like(post.uri,post.cid)if__name__=='__main__':# use run() for a higher Python versionasyncio.get_event_loop().run_until_complete(main())🍿Example project with custom feed generator🔥Firehose data streaming is available🌐Identity resolvers for DID and HandleIntroductionThis 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. SDK also provides utilities to work with CID, NSID, AT URI Schemes, DAG-CBOR, CAR files, DID Documents and more.RequirementsPython 3.7.1 or higher.InstallingpipinstallatprotoQuick startFirst 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 only in import and how you call the methods. If you are not familiar with async, use sync instead.For sync:fromatprotoimportClientclient=Client()# By default, it uses the server of bsky.app. To change this behavior, pass the base api URL to constructor# Client('https://example.com')For async:fromatprotoimportAsyncClientclient=AsyncClient()# By default, it uses the server of bsky.app. To change this behavior, pass the base api URL to constructor# AsyncClient('https://example.com')In the snippets below, only the sync version will be presented.Right after the creation of the Client instance, you probably want to access the full API and perform actions by profile. To achieve this, you should log in to the network using your handle and password. The password could be app-specific.fromatprotoimportClientclient=Client()client.login('my-username','my-password')You are awesome! Now you feel to pick any high-level method that you want and perform it!Code to send post:fromatprotoimportClientclient=Client()client.login('my-username','my-password')client.send_post(text='Hello World!')Useful links to continue:List of all methods with documentation.Examples of using the methods.SDK structureThe SDK is built upon the following components:PackageDescriptionatprotoImport shortcuts to other packages.atproto_cliCLI tool to generate code.atproto_clientXRPC Client, data models, and utils like rich text helper.atproto_codegenCode generator of models, clients, and namespaces.atproto_coreTools to work with NSID, AT URI Schemes, CID, CAR files, and DID Documents.atproto_cryptoCrypto utils like multibase, signature verification, work with DID keys.atproto_firehoseFirehose (data streaming) client and models.atproto_identityIdentity resolvers for DID, Handle, AT Protocol data, signing keys.atproto_lexiconLexicon parser.atproro_serverServer-side utils like JWT.I highly recommend you to use theatprotopackage to import everything that you need.
It contains shortcuts to all other packages.DocumentationThe documentation is live atatproto.blue.Getting helpYou can get help in several ways:Report bugs, request new features bycreating an issue.Ask questions bystarting a discussion.Ask questions inDiscord server.Advanced usageI'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 are not cover the full need of developers. To be able to do anything that you want, you should know to work with low-level API. Let's dive into it!The basics:Namespaces – classes that group sub-namespaces and the XRPC queries and procedures. Built upon NSID ATProto semantic.Model – dataclasses for input, output, and params of the methods from namespaces. Models describe Record and all other types in the Lexicon Schemes.NamespacesThe client contains references to the root of all namespaces. It'scomandappfor now.fromatprotoimportClientClient().comClient().appTo dive deeper, you can navigate using hints from your IDE. Thanks to well-type hinted SDK, it's much easier.fromatprotoimportClientClient().com.atproto.server.create_session(...)Client().com.atproto.sync.get_blob(...)Client().app.bsky.feed.get_likes(...)Client().app.bsky.graph.get_follows(...)The endpoint of the path is always the method that 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 required data objects. Queries could be called with or without params.RecordsIn 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.Here are some available records of Bluesky records:fromatprotoimportClientClient().app.bsky.feed.postClient().app.bsky.feed.likeClient().app.bsky.graph.followClient().app.bsky.graph.blockClient().app.bsky.actor.profile# ... moreUsage example with thepostrecord:fromatprotoimportAtUri,Client,modelsclient=Client()client.login('my-username','my-password')posts=client.app.bsky.feed.post.list(client.me.did,limit=10)foruri,postinposts.records.items():print(uri,post.text)post=client.app.bsky.feed.post.get(client.me.did,AtUri.from_str(uri).rkey)print(post.value.text)post_record=models.AppBskyFeedPost.Record(text='test record namespaces',created_at=client.get_current_time_iso())new_post=client.app.bsky.feed.post.create(client.me.did,post_record)print(new_post)deleted_post=client.app.bsky.feed.post.delete(client.me.did,AtUri.from_str(new_post.uri).rkey)print(deleted_post)Please 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.ModelsTo deal with methods, we need to deal with models! Models are available in themodelsmodule and have NSID-based aliases. Let's take a look at it.fromatprotoimportmodelsmodels.ComAtprotoIdentityResolveHandlemodels.AppBskyFeedPostmodels.AppBskyActorGetProfile# 90+ more...The model classes in the "models" aliases could be:Data modelParams modelResponse modelSugar response modelRecord modelType modelThe only thing you need to know is how to create instances of models. Not with all models, you will work as model-creator. For example, SDK will create Response models for you.There are a few ways how to create the instance of a model:Dict-basedClass-basedThe instances of data and params models should be passed as arguments to the methods that were described above.Dict-based:fromatprotoimportClientclient=Client()client.login('my-username','my-password')# The params model will be created automatically internally for you!print(client.com.atproto.identity.resolve_handle({'handle':'marshal.dev'}))Class-based:fromatprotoimportClient,modelsclient=Client()client.login('my-username','my-password')params=models.ComAtprotoIdentityResolveHandle.Params(handle='marshal.dev')print(client.com.atproto.identity.resolve_handle(params))Tip: look at typehint of the method to figure out the name and the path to the input/data model!Pro 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).Models could be nested as hell. Be ready for it!This is how we can send a post with the image using low-level XRPC Client:fromatprotoimportClient,modelsclient=Client()client.login('my-username','my-password')withopen('cat.jpg','rb')asf:img_data=f.read()upload=client.upload_blob(img_data)images=[models.AppBskyEmbedImages.Image(alt='Img alt',image=upload.blob)]embed=models.AppBskyEmbedImages.Main(images=images)client.com.atproto.repo.create_record(models.ComAtprotoRepoCreateRecord.Data(repo=client.me.did,collection=models.ids.AppBskyFeedPost,record=models.AppBskyFeedPost.Record(created_at=client.get_current_time_iso(),text='Text of the post',embed=embed),))# of course, you can use the syntax sugar here insteadpost=models.AppBskyFeedPost.Record(text='Text of the post',embed=embed,created_at=client.get_current_time_iso())client.app.bsky.feed.post.create(client.me.did,post)# or even high-level clientclient.send_image(text='Text of the post',image=img_data,image_alt='Img alt')# these three methods are equivalentI hope you are not scared. May the Force be with you. Good luck!Change logThe full change log is available inCHANGES.md.ContributingContributions of all sizes are welcome. The contribution guidelines will be presented later.LicenseMIT