nanoatp


Namenanoatp JSON
Version 0.5.1 PyPI version JSON
download
home_pageNone
SummaryA nano implementation of the AT Protocol for Python.
upload_time2025-02-16 20:32:48
maintainerNone
docs_urlNone
authorNone
requires_python>=3.9
licenseNone
keywords atproto atprotocol bluesky
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # nanoatp

[![PyPI](https://img.shields.io/pypi/v/nanoatp?color=blue)](https://pypi.org/project/nanoatp/)
[![GitHub License](https://img.shields.io/github/license/susumuota/nanoatp)](https://github.com/susumuota/nanoatp/blob/main/LICENSE)
[![GitHub last commit](https://img.shields.io/github/last-commit/susumuota/nanoatp)](https://github.com/susumuota/nanoatp/commits)
 
EN |
[JA](https://github-com.translate.goog/susumuota/nanoatp?_x_tr_sl=en&_x_tr_tl=ja&_x_tr_hl=ja&_x_tr_pto=wapp) |
[ES](https://github-com.translate.goog/susumuota/nanoatp?_x_tr_sl=en&_x_tr_tl=es&_x_tr_hl=es&_x_tr_pto=wapp) |
[ZH](https://github-com.translate.goog/susumuota/nanoatp?_x_tr_sl=en&_x_tr_tl=zh-CN&_x_tr_hl=zh-CN&_x_tr_pto=wapp)

A nano implementation of the AT Protocol for Python.

## Demo

- A bot built with nanoatp that summarizes the top 30 most popular arXiv papers on Reddit and Hacker News in the last 30 days and posts them to Bluesky.
  - [@paper.bsky.social](https://bsky.app/profile/paper.bsky.social)
  - [Source code](https://github.com/susumuota/arxiv-reddit-summary)

## Getting started

- First, install the package.

```bash
pip install nanoatp
```

- Set your credentials as environment variables. Or you can pass them to `BskyAgent.login()`.

```bash
export ATP_IDENTIFIER="foo.bsky.social"
export ATP_PASSWORD="password"
```

- Then in your application,

```python
from nanoatp import BskyAgent, RichText

agent = BskyAgent("https://bsky.social")
agent.login()

# post a simple text
record = {"text": "Hello World!"}
response = agent.post(record)
print(response)

# create a RichText
rt = RichText("Hello @nanoatp.bsky.social, check out this link: https://huggingface.co/")
rt.detectFacets(agent)
print(rt.facets)

# upload an image
image = agent.uploadImage("example.png")

# post a RichText with an image
embed = {"$type": "app.bsky.embed.images", "images": [image]}
record = {"text": rt.text, "facets": rt.facets, "embed": embed}
response = agent.post(record)
print(response)

# upload an external link (create a link card with title, description and thumbnail)
uri = rt.facets[1]["features"][0]["uri"]  # https://huggingface.co/
external = agent.uploadExternal(uri)

# post a RichText with an external link
embed = {"$type": "app.bsky.embed.external", "external": external}
record = {"text": rt.text, "facets": rt.facets, "embed": embed}
response = agent.post(record)
print(response)
```

See [examples](https://github.com/susumuota/nanoatp/tree/main/examples) for more.

## Usage

### Session management

Log into a server using these APIs. You'll need an active session for most methods.

```python
from nanoatp import BskyAgent

agent = BskyAgent("https://bsky.social")

# if you don't specify credentials,
# ATP_IDENTIFIER and ATP_PASSWORD environment variables will be used
agent.login("alice@mail.com", "hunter2")
```

### API calls

The agent includes methods for many common operations, including:

```python
# Feeds and content
agent.getPost(repo, rkey, cid)
agent.post(record)
agent.deletePost(postUri)
agent.uploadBlob(data, encoding)
agent.uploadImage(path, alt, encoding)  # wrapper for uploadBlob
agent.uploadExternal(url)  # wrapper for uploadBlob

# Identity
agent.resolveHandle(handle)

# Session management
agent.login(identifier, password)
```

### Rich text

Some records (ie posts) use the `app.bsky.richtext` lexicon. At the moment richtext is only used for links and mentions, but it will be extended over time to include bold, italic, and so on.

ℹ️ Currently the implementation is very naive. I have not tested it with UTF-16 text.

```python
from nanoatp import BskyAgent, RichText

agent = BskyAgent()
agent.login()

rt = RichText("Hello @nanoatp.bsky.social, check out this link: https://example.com")
rt.detectFacets(agent)
record = {"text": rt.text, "facets": rt.facets}
agent.post(record)
```

## Advanced

### Advanced API calls

The methods above are convenience wrappers. It covers most but not all available methods.

The AT Protocol identifies methods and records with reverse-DNS names. You can use them on the agent as well:

```python
res1 = agent._repo_createRecord(
    agent.session["did"],  # repo
    "app.bsky.feed.post",  # collection
    {
        "$type": "app.bsky.feed.post",
        "text": "Hello, world!",
        "createdAt": datetime.datetime.now(datetime.timezone.utc).isoformat().replace("+00:00", "Z")
    }
)
```

## Development

```bash
export ATP_IDENTIFIER="foo.bsky.social"
export ATP_PASSWORD="password"
git clone https://github.com/susumuota/nanoatp.git
cd nanoatp
uv sync
source .venv/bin/activate
ptw . -s
```

## TODO:

- [ ] split BskyAgent and AtpAgent code
- [ ] implement a proper RichText parser with UTF-16 (currently it's very naive)
- [ ] type definitions
- [ ] structured tests
- [ ] more APIs

## License

MIT License. See [LICENSE](LICENSE) for details.

## Author

Susumu Ota
- https://bsky.app/profile/ota.bsky.social
- https://github.com/susumuota
            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "nanoatp",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": "atproto, atprotocol, bluesky",
    "author": null,
    "author_email": "Susumu OTA <1632335+susumuota@users.noreply.github.com>",
    "download_url": "https://files.pythonhosted.org/packages/c9/ed/10794f3f8557687c488625f51dea5025e04c332b75433e513081ca42a33f/nanoatp-0.5.1.tar.gz",
    "platform": null,
    "description": "# nanoatp\n\n[![PyPI](https://img.shields.io/pypi/v/nanoatp?color=blue)](https://pypi.org/project/nanoatp/)\n[![GitHub License](https://img.shields.io/github/license/susumuota/nanoatp)](https://github.com/susumuota/nanoatp/blob/main/LICENSE)\n[![GitHub last commit](https://img.shields.io/github/last-commit/susumuota/nanoatp)](https://github.com/susumuota/nanoatp/commits)\n&emsp;\nEN |\n[JA](https://github-com.translate.goog/susumuota/nanoatp?_x_tr_sl=en&_x_tr_tl=ja&_x_tr_hl=ja&_x_tr_pto=wapp) |\n[ES](https://github-com.translate.goog/susumuota/nanoatp?_x_tr_sl=en&_x_tr_tl=es&_x_tr_hl=es&_x_tr_pto=wapp) |\n[ZH](https://github-com.translate.goog/susumuota/nanoatp?_x_tr_sl=en&_x_tr_tl=zh-CN&_x_tr_hl=zh-CN&_x_tr_pto=wapp)\n\nA nano implementation of the AT Protocol for Python.\n\n## Demo\n\n- A bot built with nanoatp that summarizes the top 30 most popular arXiv papers on Reddit and Hacker News in the last 30 days and posts them to Bluesky.\n  - [@paper.bsky.social](https://bsky.app/profile/paper.bsky.social)\n  - [Source code](https://github.com/susumuota/arxiv-reddit-summary)\n\n## Getting started\n\n- First, install the package.\n\n```bash\npip install nanoatp\n```\n\n- Set your credentials as environment variables. Or you can pass them to `BskyAgent.login()`.\n\n```bash\nexport ATP_IDENTIFIER=\"foo.bsky.social\"\nexport ATP_PASSWORD=\"password\"\n```\n\n- Then in your application,\n\n```python\nfrom nanoatp import BskyAgent, RichText\n\nagent = BskyAgent(\"https://bsky.social\")\nagent.login()\n\n# post a simple text\nrecord = {\"text\": \"Hello World!\"}\nresponse = agent.post(record)\nprint(response)\n\n# create a RichText\nrt = RichText(\"Hello @nanoatp.bsky.social, check out this link: https://huggingface.co/\")\nrt.detectFacets(agent)\nprint(rt.facets)\n\n# upload an image\nimage = agent.uploadImage(\"example.png\")\n\n# post a RichText with an image\nembed = {\"$type\": \"app.bsky.embed.images\", \"images\": [image]}\nrecord = {\"text\": rt.text, \"facets\": rt.facets, \"embed\": embed}\nresponse = agent.post(record)\nprint(response)\n\n# upload an external link (create a link card with title, description and thumbnail)\nuri = rt.facets[1][\"features\"][0][\"uri\"]  # https://huggingface.co/\nexternal = agent.uploadExternal(uri)\n\n# post a RichText with an external link\nembed = {\"$type\": \"app.bsky.embed.external\", \"external\": external}\nrecord = {\"text\": rt.text, \"facets\": rt.facets, \"embed\": embed}\nresponse = agent.post(record)\nprint(response)\n```\n\nSee [examples](https://github.com/susumuota/nanoatp/tree/main/examples) for more.\n\n## Usage\n\n### Session management\n\nLog into a server using these APIs. You'll need an active session for most methods.\n\n```python\nfrom nanoatp import BskyAgent\n\nagent = BskyAgent(\"https://bsky.social\")\n\n# if you don't specify credentials,\n# ATP_IDENTIFIER and ATP_PASSWORD environment variables will be used\nagent.login(\"alice@mail.com\", \"hunter2\")\n```\n\n### API calls\n\nThe agent includes methods for many common operations, including:\n\n```python\n# Feeds and content\nagent.getPost(repo, rkey, cid)\nagent.post(record)\nagent.deletePost(postUri)\nagent.uploadBlob(data, encoding)\nagent.uploadImage(path, alt, encoding)  # wrapper for uploadBlob\nagent.uploadExternal(url)  # wrapper for uploadBlob\n\n# Identity\nagent.resolveHandle(handle)\n\n# Session management\nagent.login(identifier, password)\n```\n\n### Rich text\n\nSome records (ie posts) use the `app.bsky.richtext` lexicon. At the moment richtext is only used for links and mentions, but it will be extended over time to include bold, italic, and so on.\n\n\u2139\ufe0f Currently the implementation is very naive. I have not tested it with UTF-16 text.\n\n```python\nfrom nanoatp import BskyAgent, RichText\n\nagent = BskyAgent()\nagent.login()\n\nrt = RichText(\"Hello @nanoatp.bsky.social, check out this link: https://example.com\")\nrt.detectFacets(agent)\nrecord = {\"text\": rt.text, \"facets\": rt.facets}\nagent.post(record)\n```\n\n## Advanced\n\n### Advanced API calls\n\nThe methods above are convenience wrappers. It covers most but not all available methods.\n\nThe AT Protocol identifies methods and records with reverse-DNS names. You can use them on the agent as well:\n\n```python\nres1 = agent._repo_createRecord(\n    agent.session[\"did\"],  # repo\n    \"app.bsky.feed.post\",  # collection\n    {\n        \"$type\": \"app.bsky.feed.post\",\n        \"text\": \"Hello, world!\",\n        \"createdAt\": datetime.datetime.now(datetime.timezone.utc).isoformat().replace(\"+00:00\", \"Z\")\n    }\n)\n```\n\n## Development\n\n```bash\nexport ATP_IDENTIFIER=\"foo.bsky.social\"\nexport ATP_PASSWORD=\"password\"\ngit clone https://github.com/susumuota/nanoatp.git\ncd nanoatp\nuv sync\nsource .venv/bin/activate\nptw . -s\n```\n\n## TODO:\n\n- [ ] split BskyAgent and AtpAgent code\n- [ ] implement a proper RichText parser with UTF-16 (currently it's very naive)\n- [ ] type definitions\n- [ ] structured tests\n- [ ] more APIs\n\n## License\n\nMIT License. See [LICENSE](LICENSE) for details.\n\n## Author\n\nSusumu Ota\n- https://bsky.app/profile/ota.bsky.social\n- https://github.com/susumuota",
    "bugtrack_url": null,
    "license": null,
    "summary": "A nano implementation of the AT Protocol for Python.",
    "version": "0.5.1",
    "project_urls": {
        "documentation": "https://github.com/susumuota/nanoatp#readme",
        "homepage": "https://github.com/susumuota/nanoatp",
        "repository": "https://github.com/susumuota/nanoatp"
    },
    "split_keywords": [
        "atproto",
        " atprotocol",
        " bluesky"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "64b87983aafb3df01d63c0dc2b9ff3fbf0787fbbe92496567f169deb1b8edb59",
                "md5": "bb4415cd4a4b6f857c637d2e8ffb61a1",
                "sha256": "6da67c81d469d1b329f7cc2f710619f1a426840b18f87b7031d0a437b95387bb"
            },
            "downloads": -1,
            "filename": "nanoatp-0.5.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "bb4415cd4a4b6f857c637d2e8ffb61a1",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 8085,
            "upload_time": "2025-02-16T20:32:47",
            "upload_time_iso_8601": "2025-02-16T20:32:47.156538Z",
            "url": "https://files.pythonhosted.org/packages/64/b8/7983aafb3df01d63c0dc2b9ff3fbf0787fbbe92496567f169deb1b8edb59/nanoatp-0.5.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "c9ed10794f3f8557687c488625f51dea5025e04c332b75433e513081ca42a33f",
                "md5": "1d16c986fbba3b661ff6fcfd659a96e0",
                "sha256": "00a1ac0f4082bd43e7253b75b3ebd2078709c5e95ed2402bb2bda709f8c0b7c8"
            },
            "downloads": -1,
            "filename": "nanoatp-0.5.1.tar.gz",
            "has_sig": false,
            "md5_digest": "1d16c986fbba3b661ff6fcfd659a96e0",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 8914,
            "upload_time": "2025-02-16T20:32:48",
            "upload_time_iso_8601": "2025-02-16T20:32:48.386269Z",
            "url": "https://files.pythonhosted.org/packages/c9/ed/10794f3f8557687c488625f51dea5025e04c332b75433e513081ca42a33f/nanoatp-0.5.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-02-16 20:32:48",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "susumuota",
    "github_project": "nanoatp#readme",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "nanoatp"
}
        
Elapsed time: 0.51577s