Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IpldLink model validation fails #338

Closed
dananev opened this issue Jun 16, 2024 · 8 comments · Fixed by #340
Closed

IpldLink model validation fails #338

dananev opened this issue Jun 16, 2024 · 8 comments · Fixed by #340

Comments

@dananev
Copy link

dananev commented Jun 16, 2024

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
Copy link
Owner

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
Copy link
Author

dananev commented Jun 16, 2024

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
Copy link
Owner

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
Copy link
Owner

MarshalX commented Jun 16, 2024

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

that's strange because we have test for it:

def test_blob_ref_from_ipld_json() -> None:
plain_cid = 'bafyreidfayvfuwqa7qlnopdjiqrxzs6blmoeu4rujcjtnci5beludirz2a'
plain_blob_ref = {
'mimeType': 'text/plain',
'size': 0,
'$type': 'blob',
'ref': {'$link': plain_cid},
}
instance = get_or_create(plain_blob_ref, BlobRef)
assert isinstance(instance, BlobRef)
assert instance.cid == CID.decode(plain_cid)

and

def test_blob_ref_from_ipld() -> None:
plain_cid = 'bafyreidfayvfuwqa7qlnopdjiqrxzs6blmoeu4rujcjtnci5beludirz2a'
plain_blob_ref = {
'mimeType': 'text/plain',
'size': 0,
'$type': 'blob',
'ref': plain_cid,
}
instance = get_or_create(plain_blob_ref, BlobRef)
assert isinstance(instance, BlobRef)
assert instance.cid == CID.decode(plain_cid)

btw $ is required

@MarshalX
Copy link
Owner

MarshalX commented Jun 16, 2024

@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
Copy link
Owner

MarshalX commented Jun 16, 2024

@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
Copy link
Author

dananev commented Jun 17, 2024

All good now, thank you for the quick fix!

@MarshalX
Copy link
Owner

@dananev FYI #348

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants