Skip to content

Support creating a Raw buffer from a str - #252

Merged
jcrist merged 1 commit into
mainfrom
raw-constructor-from-str
Jan 2, 2023
Merged

Support creating a Raw buffer from a str#252
jcrist merged 1 commit into
mainfrom
raw-constructor-from-str

Conversation

@jcrist

@jcrist jcrist commented Jan 2, 2023

Copy link
Copy Markdown
Member

Previously Raw objects could only be created from a buffer-like object. Since some JSON tooling in Python returns str rather than bytes types, it makes sense to also support creating a Raw object from a str. This saves a method call to str.encode("utf-8") on the user's side.

Previously `Raw` objects could only be created from a buffer-like
object. Since some JSON tooling in Python returns `str` rather than
`bytes` types, it makes sense to also support creating a `Raw` object
from a `str`. This saves a method call to `str.encode("utf-8")` on the
user's side.
@jcrist

jcrist commented Jan 2, 2023

Copy link
Copy Markdown
Member Author

In a quick benchmark, this measurably decrease the cost of creating a Raw object from a str (measurably as a percentage of the total call time, not in absolute time - all of this is pretty fast). Note that we use a dynamically generated str for each call, since the utf-8 encoded representation is cached on str objects.

In [1]: def make_str():                        
   ...:     items = "1,2,3,4,5" * 1000
   ...:     return f"[{items}]"
   ...:                                        

In [2]: from msgspec import Raw

In [3]: %timeit make_str()
538 ns ± 1.52 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

In [4]: %timeit Raw(make_str())
592 ns ± 0.427 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

In [5]: %timeit Raw(make_str().encode("utf-8"))
833 ns ± 1.02 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

One place where this comes up is defining a custom enc_hook for an object, making use of an alternative pre-existing JSON encode method that returns a str type. pydantic.BaseModel.json for example.

With this change, an enc_hook for encoding pydantic models using their existing json method can drop the unnecessary encode("utf-8") call.

def enc_hook(x):
    if isinstance(x, pydantic.BaseModel):
        return msgspec.Raw(x.json())  # previously this would be `msgspec.Raw(x.json().encode("utf-8"))`
    ...

@jcrist
jcrist merged commit e27eb26 into main Jan 2, 2023
@jcrist
jcrist deleted the raw-constructor-from-str branch January 2, 2023 21:17
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 this pull request may close these issues.

1 participant