GithubHelp home page GithubHelp logo

a16z / farcaster-py Goto Github PK

View Code? Open in Web Editor NEW
116.0 8.0 23.0 11.65 MB

A Python SDK for the Farcaster network

Home Page: https://a16z.github.io/farcaster-py/

License: MIT License

Makefile 3.77% Dockerfile 0.77% Python 95.46%
api farcaster pydantic python social

farcaster-py's Introduction

farcaster-py

Build status Python Version Dependencies Status Code style: black Security: bandit Pre-commit Semantic Versions License Coverage Report chat

farcaster-py is a modern Python SDK for the Farcaster protocol

Full documentation can be found here

Installation

pip install -U farcaster

or install with Poetry:

poetry add farcaster

Usage

This SDK leverages the Warpcast API. Warpcast is one of many Farcaster clients. As more APIs are created and hosted by different clients, these will be added to the SDK.

To use the Warpcast API you need to have a Farcaster account. We will use the mnemonic or private key of the Farcaster custody account (not your main wallet) to connect to the API.

First, save your Farcaster mnemonic or private key to a .env file. Now you can initialize the client, and automatically connect to the Farcaster API!

import os
from farcaster import Warpcast
from dotenv import load_dotenv # can be installed with `pip install python-dotenv`

load_dotenv()

client = Warpcast(mnemonic=os.environ.get("<MNEMONIC_ENV_VAR>"))

print(client.get_healthcheck())

Examples

Get a cast

response = client.get_cast("0x321712dc8eccc5d2be38e38c1ef0c8916c49949a80ffe20ec5752bb23ea4d86f")
print(response.cast.author.username) # "dwr"

Publish a cast

response = client.post_cast(text="Hello world!")
print(response.cast.hash) # "0x...."

Get a user by username

user = client.get_user_by_username("mason")
print(user.username) # "mason"

Get a user's followers using a fid (farcaster ID)

response = client.get_followers(fid=50)
print(response.users) # [user1, user2, user3]

Stream recent casts

for cast in client.stream_casts():
    if cast:
        print(cast.text) # "Hello world!"

Get users who recently joined Farcaster

response = client.get_recent_users()
print(response.users) # [user1, user2, user3]

Get your own user object

user = client.get_me()
print(user.username) # "you"

Recast a cast

response = client.recast("0x....")
print(response.cast.hash) # "0x...."

and many, many more things. The full specification can be found on the Reference page.

Please note that support for Python 3.7 is no longer actively maintained. Python 3.8, 3.9, or 3.10 are recommended.

๐Ÿ›ก License

License

This project is licensed under the terms of the MIT license. See LICENSE for more details.

Disclaimer

This code is being provided as is. No guarantee, representation or warranty is being made, express or implied, as to the safety or correctness of the code. It has not been audited and as such there can be no assurance it will work as intended, and users may experience delays, failures, errors, omissions or loss of transmitted information. Nothing in this repo should be construed as investment advice or legal advice for any particular facts or circumstances and is not meant to replace competent counsel. It is strongly advised for you to contact a reputable attorney in your jurisdiction for any questions or concerns with respect thereto. a16z is not liable for any use of the foregoing, and users should proceed with caution and use at their own risk. See our disclosures page for more info.

farcaster-py's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

farcaster-py's Issues

No returns when using get_mention_and_reply_notifications()

Checklist

  • I've searched the project's issues.

โ“ Question

get_mention_and_reply_notifications() doesn't return anything.

I got following response when I used this function.
('notifications', [])
('cursor', None)

I checked client connection , I can interact with other functions (such as following, post, like others.. etc.)
only get_mention_and_reply_notifications() doesn't working

๐Ÿ“Ž Additional context

image

Can devs create new Farcaster accounts via SDK?

# To use the Farcaster API you need to have a Farcaster account. 
# Next, save your Farcaster mnemonic or private key to a .env file.
# Now you can initialize the client, and automatically connect to the Farcaster API!

import os
from farcaster import MerkleApiClient
from dotenv import load_dotenv

load_dotenv()

client = MerkleApiClient(mnemonic=os.environ.get("<MNEMONIC_ENV_VAR>"))

print(client.get_healthcheck())

Compare to Nostr which allows generating new keys:

from nostr.key import PrivateKey

private_key = PrivateKey()
public_key = private_key.public_key
print(f"Private key: {private_key.bech32()}")
print(f"Public key: {public_key.bech32()}")

get_cast error

got error: {'message': 'Path /v2/cast?hash={hash} does not exist'}

cast created with post_cast disappears after 24h

๐Ÿ› Bug Report

The method post_cast creates a cast, however it disappears after a given period of time (24h).

๐Ÿ”ฌ How To Reproduce

Steps to reproduce the behavior:

# farcaster = "^0.7.11"
c2 = Warpcast(private_key="MY-PRIVATE-KEY")
cast = c2.post_cast("test cast")
cast_hash = cast.cast.hash
print (f"cast_hash {cast_hash}")
# ... Wait 24h
c2 = Warpcast(private_key="MY-PRIVATE-KEY")
cast = c2.get_cast(cast_hash)
$ Error
    c2.get_cast(cast.cast.hash)
  File "/home/gabrielfior/miniconda3/envs/PMA/lib/python3.10/site-packages/farcaster/client.py", line 338, in get_cast
    response = self._get(
  File "/home/gabrielfior/miniconda3/envs/PMA/lib/python3.10/site-packages/farcaster/client.py", line 89, in _get
    raise Exception(response["errors"])  # pragma: no cover
Exception: [{'message': 'Cast 0xabdea1ff98521bef0c1f5e24ef0461ae21d91805 does not exist'}]

For example, the post with hash 0xabdea1ff98521bef0c1f5e24ef0461ae21d91805 was created 1 day ago and now it doesn't exist anymore.

Code sample

See above

Environment

  • OS - Linux (Ubuntu)
  • Python version - Python 3.10.14

Screenshots

๐Ÿ“ˆ Expected behavior

I expected the cast to be stored permanently and be available for later retrieval.

How do you post an image with the post_cast method?

Checklist

  • [x ] I've searched the project's issues.

โ“ Question

How can I post an image?

The documentation shows to pass an Embed, but it is not shown if it should be an HTTP link (which I have tried) or an URI to a local file (which I have tried).

๐Ÿ“Ž Additional context

Strict URL parsing breaks on existing casts

๐Ÿ› Bug Report

Utilizing Pydantic's AnyUrl requires that all URLs are compliant. There is at least one existing cast that will break this validation: https://sharecaster.xyz/0x51629f662558a79ce16aed38d5000ddb3afa24215767a88772c4e4e43f07d27d

This is because their cast includes a URL with two fragments: https://polygonscan.com/address/0x8abb83abc180ad1e96f75884ca24d45cc7560af2#code#F1#L107

Farcaster Link: farcaster://casts/0x51629f662558a79ce16aed38d5000ddb3afa24215767a88772c4e4e43f07d27d/0xabe1c1260eee6b0de1867bf503fbfeca997f4f46a20db2abb435566d81951752

This bug prevents farcaster-py from being used for any historic indexing.

๐Ÿ”ฌ How To Reproduce

This can be reproduced directly with Pydantic by attempting to validate the URL from the referenced cast above.

>>> from pydantic import BaseModel, AnyUrl
>>> class Model(BaseModel):
...     url: AnyUrl
... 
>>> Model(url="https://polygonscan.com/address/0x8abb83abc180ad1e96f75884ca24d45cc7560af2#code#F1#L107")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pydantic/main.py", line 342, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for Model
url
  URL invalid, extra characters found after valid URL: '#F1#L107' (type=value_error.url.extra; extra=#F1#L107)

Alternatively, you can attempt to pull this cast directly

>>> from farcaster import Warpcast
>>> client = Warpcast(...)
>>> client.get_cast("0x51629f662558a79ce16aed38d5000ddb3afa24215767a88772c4e4e43f07d27d")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/REDACTED/lib/python3.7/site-packages/farcaster/client.py", line 323, in get_cast
    return CastGetResponse(**response).result
  File "pydantic/main.py", line 342, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for CastGetResponse
result -> cast -> attachments -> openGraph -> 0 -> url
  URL invalid, extra characters found after valid URL: '#F1#L107' (type=value_error.url.extra; extra=#F1#L107)

๐Ÿ“ˆ Expected behavior

Output from the Warpcast API should be accepted as-is. Alternatively, farcaster-py should have the option to be less opinionated about validation.

"ImportError: cannot import name 'getargspec' from 'inspect'" on a generic install

๐Ÿ› Bug Report

I was trying to use the package but it fails at the very first interaction. This is the result of running the healthcheck on a generic example from readme

(farcaster-analytics) โžœ  farcaster-analytics python main.py                                                                                     
Traceback (most recent call last):
  File "/Users/wojciechkulikowski/projects/farcaster-analytics/main.py", line 2, in <module>
    from farcaster import Warpcast
  File "/Users/wojciechkulikowski/.local/share/virtualenvs/farcaster-analytics-Dcob0k81/lib/python3.11/site-packages/farcaster/__init__.py", line 5, in <module>
    from .client import Warpcast  # noqa
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/wojciechkulikowski/.local/share/virtualenvs/farcaster-analytics-Dcob0k81/lib/python3.11/site-packages/farcaster/client.py", line 9, in <module>
    from eth_account.account import Account
  File "/Users/wojciechkulikowski/.local/share/virtualenvs/farcaster-analytics-Dcob0k81/lib/python3.11/site-packages/eth_account/__init__.py", line 1, in <module>
    from eth_account.account import (
  File "/Users/wojciechkulikowski/.local/share/virtualenvs/farcaster-analytics-Dcob0k81/lib/python3.11/site-packages/eth_account/account.py", line 71, in <module>
    from eth_account.messages import (
  File "/Users/wojciechkulikowski/.local/share/virtualenvs/farcaster-analytics-Dcob0k81/lib/python3.11/site-packages/eth_account/messages.py", line 25, in <module>
    from eth_account._utils.structured_data.hashing import (
  File "/Users/wojciechkulikowski/.local/share/virtualenvs/farcaster-analytics-Dcob0k81/lib/python3.11/site-packages/eth_account/_utils/structured_data/hashing.py", line 9, in <module>
    from eth_abi import (
  File "/Users/wojciechkulikowski/.local/share/virtualenvs/farcaster-analytics-Dcob0k81/lib/python3.11/site-packages/eth_abi/__init__.py", line 3, in <module>
    from eth_abi.abi import (  # NOQA
  File "/Users/wojciechkulikowski/.local/share/virtualenvs/farcaster-analytics-Dcob0k81/lib/python3.11/site-packages/eth_abi/abi.py", line 1, in <module>
    from eth_abi.codec import (
  File "/Users/wojciechkulikowski/.local/share/virtualenvs/farcaster-analytics-Dcob0k81/lib/python3.11/site-packages/eth_abi/codec.py", line 16, in <module>
    from eth_abi.decoding import (
  File "/Users/wojciechkulikowski/.local/share/virtualenvs/farcaster-analytics-Dcob0k81/lib/python3.11/site-packages/eth_abi/decoding.py", line 14, in <module>
    from eth_abi.base import (
  File "/Users/wojciechkulikowski/.local/share/virtualenvs/farcaster-analytics-Dcob0k81/lib/python3.11/site-packages/eth_abi/base.py", line 7, in <module>
    from .grammar import (
  File "/Users/wojciechkulikowski/.local/share/virtualenvs/farcaster-analytics-Dcob0k81/lib/python3.11/site-packages/eth_abi/grammar.py", line 4, in <module>
    import parsimonious
  File "/Users/wojciechkulikowski/.local/share/virtualenvs/farcaster-analytics-Dcob0k81/lib/python3.11/site-packages/parsimonious/__init__.py", line 9, in <module>
    from parsimonious.grammar import Grammar, TokenGrammar
  File "/Users/wojciechkulikowski/.local/share/virtualenvs/farcaster-analytics-Dcob0k81/lib/python3.11/site-packages/parsimonious/grammar.py", line 14, in <module>
    from parsimonious.expressions import (Literal, Regex, Sequence, OneOf,
  File "/Users/wojciechkulikowski/.local/share/virtualenvs/farcaster-analytics-Dcob0k81/lib/python3.11/site-packages/parsimonious/expressions.py", line 9, in <module>
    from inspect import getargspec
ImportError: cannot import name 'getargspec' from 'inspect' (/opt/homebrew/Cellar/[email protected]/3.11.2_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/inspect.py)

๐Ÿ”ฌ How To Reproduce

Steps to reproduce the behavior:

Follow README, try to run the health check

Code sample

from farcaster import Warpcast

client = Warpcast(mnemonic="<valid mnemonic>")

print(client.get_healthcheck())

Environment

  • OS: macOS
  • Python version: 3.11.2

casting with a parent

There is a cast(name A for example) that I have and I know its hash. I want to cast another cast(name B) and I want A to be B's parent. I tried post_cast() but I couldn't figure out how should I give the parent field true information. I have tried:
parent = hash_of _A
parent = A(the ApiCast type)
but none of them seemed to work. what is true format for doing this task? can you give me an example? I would appreciate it.

Cursor not included in response for iterable endpoints

๐Ÿ› Bug Report

When making a call to most endpoints exposed by farcaster-py, there is an option of including a cursor to continue an existing iteration. However, the response of these endpoints does NOT include the cursor returned by Merkle. This makes it impossible (to do in a reasonable way) to iterate over results.

For example, a call to get_recent_casts(...) returns a CastsResult object that is derived from CastsGetResponse. However, we should also be including the cursor in CastsGetResponse.

class CastsGetResponse(BaseModel):
result: CastsResult
next: Optional[Next] = None

def get_recent_casts(
self,
cursor: NoneStr = None,
limit: PositiveInt = 100,
) -> CastsResult:
"""Get all recent casts
Args:
cursor (NoneStr, optional): cursor, defaults to None
limit (PositiveInt, optional): limit, defaults to 100
Returns:
CastsResult: model containing casts
"""
response = self._get(
"recent-casts",
params={"cursor": cursor, "limit": limit},
)
return CastsGetResponse(**response).result

๐Ÿ“ˆ Expected behavior

A call to get_recent_casts(...) (and other iterable endpoints) should also return a cursor associated with that iteration.

Can't import anything from farcaster

๐Ÿ› Bug Report

Don't think farcaster isn't initializing correctly, since I get the circular import error when trying to import anything from it.

๐Ÿ”ฌ How To Reproduce

$ pip install -U farcaster
$ pip install eth-account python-dotenv # 
import time
import os

from farcaster import MerkleApiClient
from eth_account.account import Account
from dotenv import load_dotenv

load_dotenv()
Account.enable_unaudited_hdwallet_features()
ETH_ACCOUNT_SIGNER = Account.from_mnemonic(os.environ.get("<MNEMONIC_ENV_VAR>"))

Errors out at from farcaster import MerkleApiClient

Environment

  • OS: macOS
  • Python version: 3.9.16

๐Ÿ“ˆ Expected behavior

Run the first example listed in the read me here.

Support Hubs

๐Ÿš€ Feature Request

Support hubs, and make the user experience as close to the traditional Warpcast API experience as possible.

๐Ÿ”ˆ Motivation

The Warpcast API is being deprecated at the end of the year.

๐Ÿ“Ž Additional context

Hubs use protobuf, so to interface with them we must generate protobuf types for each request/response and message type.

This makes the user experience a lot worse in Python, so we will need to create helper classes and functions that abstract away as much of the overhead as possible.

Initial work can be found here: #518

Progress:

  • Create initial Hub client class
  • Add generated protobuf classes
  • Implement initial tests and Proof of Concept
  • Support every message type in the Hubble protocol
  • Create helper methods and classes to abstract away nuance of protobuf
  • Explore strong typing for request/response and message types
  • Write unit tests and integration tests for all hub endpoints and helper functions

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.