MarshalX / atproto

The AT Protocol (🦋 Bluesky) SDK for Python 🐍
https://atproto.blue
MIT License
289 stars 32 forks source link

IpldLink model validation fails #338

Closed dananev closed 3 months ago

dananev commented 3 months ago

Hi! Thanks for the SDK!

I was working with it and got a tiny issue. When you try to instantiate IpldLink with link field validation fails:

pydantic_core._pydantic_core.ValidationError: 1 validation error for IpldLink
$link
  Field required [type=missing, input_value={'link': 'bafkreia4linnhp...w34txua76r6kbphuf3vsia'}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.7/v/missing

To fix the issue either link should be declared with serialization_alias instead of plain alias or we should add model_config to IpldLink.

class IpldLink(BaseModel):
    """CID representation in JSON."""

    model_config = ConfigDict(populate_by_name=True)

    link: str = Field(alias='$link')  #: CID.

I can raise a small pull-request to fix the issue.

Thanks!

MarshalX commented 3 months ago

Hi! Could you please provide the plain JSON needed to add unit tests for this case? It seems that ‘model_config’ was probably just forgotten in this model

dananev commented 3 months ago

Here or in the pull-request? Without aliases it's basically:

{"link":"bafkreia4linnhpphw5fughdn3wok7okklggww34txua76r6kbphuf3vsia"}

I found out another thing. Probably, ref in BlobRef shouldn't be Union[str, IpldLink], but only IpldLink. For example, this snippet returns 400:

embed = models.AppBskyEmbedExternal.Main(
    external=models.AppBskyEmbedExternal.External(
        description="Yet another The Room gif",
        title="oh hi mark",
        uri="https://giphy.com/gifs/theroom-the-room-26CaLWA2dcqz6hS4U",
        thumb=BlobRef(
            mime_type="image/jpeg",
            size=316179,
            ref="bafkreia4linnhpphw5fughdn3wok7okklggww34txua76r6kbphuf3vsia",
        )
    )
)

record = client.send_post(
    text="https://giphy.com/gifs/theroom-the-room-26CaLWA2dcqz6hS4U",
    embed=embed,
)

Exception:

atproto_client.exceptions.BadRequestError: Response(success=False, status_code=400, content=XrpcError(error='InvalidRequest', message='Invalid app.bsky.feed.post record: Record/embed/external/thumb should be a blob ref'), headers={'Date': 'Sun, 16 Jun 2024 19:32:08 GMT', 'Content-Type': 'application/json; charset=utf-8', 'Content-Length': '122', 'Connection': 'keep-alive', 'X-Powered-By': 'Express', 'Access-Control-Allow-Origin': '*', 'ETag': 'W/"7a-/Nk9d44dleWoqVCOpDSZq5x1q0M"', 'Vary': 'Accept-Encoding'})
MarshalX commented 3 months ago

Well, the ref could be in raw and in JSON formats. Also, there is a deprecated blob type and a new one. this class tries to support everything in one

https://atproto.com/specs/data-model#blob-type

ref (link, required): CID reference to blob, with multicodec type raw. In JSON, encoded as a $link object as usual

MarshalX commented 3 months ago

Without aliases it's basically: {"link":"bafkreia4linnhpphw5fughdn3wok7okklggww34txua76r6kbphuf3vsia"}

that's strange because we have test for it:

https://github.com/MarshalX/atproto/blob/d32f836fffbdc1e3c37be7c6332c809479f34f1b/tests/test_atproto_client/models/tests/test_blob_ref.py#L20-L31

and

https://github.com/MarshalX/atproto/blob/d32f836fffbdc1e3c37be7c6332c809479f34f1b/tests/test_atproto_client/models/tests/test_blob_ref.py#L6-L17

btw $ is required

MarshalX commented 3 months ago

@dananev It is a sporadic case when you want to create a BlobRef by yourself. Typically, it is returned, for example, in a firehose as raw bytes. When you call a function like upload_blob, the process goes through XRPC, which communicates using JSON. Therefore, the response will be in the $link format. If you are trying to construct a BlobRef to use it with XRPC (specifically with the send_post method), you will need to create it in a JSON-compatible format.

So instead of

thumb = BlobRef(
    mime_type='text/plain',
    size=0,
    ref='blabla',
)

you need to do

thumb = BlobRef(
    mime_type='text/plain',
    size=0,
    ref=IpldLink(link='blabla'),
)

I fixed this kind of creation in the linked PR. Probably it could be a good idea to have methods in BlobRef which will convert between representations. RAW and JSON.

I still can't reproduce the initial issue :( Probably you just missed $. The key must be $link instead of link

MarshalX commented 3 months ago

@dananev please try to create BlobRef as I mentioned above using SDK from the main branch. It should work fine with send_post method. This bug fix will be included in the next release

To install SDK from the main branch:

pip uninstall atproto
pip install git+https://github.com/MarshalX/atproto.git@main
dananev commented 3 months ago

All good now, thank you for the quick fix!

MarshalX commented 3 months ago

@dananev FYI https://github.com/MarshalX/atproto/pull/348