Expose .importable_path on the value returned from rx.asset#6348
Expose .importable_path on the value returned from rx.asset#6348adhami3310 merged 2 commits intomainfrom
.importable_path on the value returned from rx.asset#6348Conversation
This allows components to reference the internal path in the `.web` directory for use with JS imports at compile time.
Greptile SummaryThis PR exposes an Confidence Score: 5/5Safe to merge; the pickle edge case is unlikely to affect production use given the compile-time nature of The only finding is a P2 pickle/reconstruction issue that affects an immutable reflex/assets.py — Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["rx.asset(path, shared=...)"] --> B{shared?}
B -- No --> C["AssetPathStr('/{path}')"]
B -- Yes --> D["AssetPathStr('/{external}/{subfolder}/{path}')"]
C --> E["__new__(relative_path)"]
D --> E
E --> F["str value = prepend_frontend_path(relative_path)"]
E --> G["importable_path = '$/public' + relative_path"]
F --> H["Used as URL in HTML/CSS"]
G --> I["Used in JS library/module imports at build time"]
Reviews (1): Last reviewed commit: "Expose `.importable_path` on the value r..." | Re-trigger Greptile |
| class AssetPathStr(str): | ||
| """The relative URL to an asset, with a build-time importable variant. | ||
|
|
||
| Returned by :func:`asset`. The string value is the asset URL with the | ||
| configured ``frontend_path`` prepended; :attr:`importable_path` is the | ||
| same asset prefixed with ``$/public`` so the asset can be referenced by | ||
| a component ``library`` or module import at build time. | ||
|
|
||
| The constructor signature mirrors :class:`str`: the input is interpreted | ||
| as the unprefixed asset path and both forms are derived from it at | ||
| construction time. | ||
| """ | ||
|
|
||
| __slots__ = ("importable_path",) | ||
|
|
||
| importable_path: str | ||
|
|
||
| @overload | ||
| def __new__(cls, object: object = "") -> "AssetPathStr": ... | ||
| @overload | ||
| def __new__( | ||
| cls, | ||
| object: "Buffer", | ||
| encoding: str = "utf-8", | ||
| errors: str = "strict", | ||
| ) -> "AssetPathStr": ... | ||
|
|
||
| def __new__( | ||
| cls, | ||
| object: object = "", | ||
| encoding: str | None = None, | ||
| errors: str | None = None, | ||
| ) -> "AssetPathStr": | ||
| """Construct from an unprefixed, leading-slash asset path. | ||
|
|
||
| Args/semantics mirror :class:`str`. The resulting string is interpreted | ||
| as the asset path (e.g. ``"/external/mod/file.js"``); the | ||
| frontend-prefixed URL is stored as the ``AssetPathStr`` value and | ||
| ``$/public`` + ``relative_path`` as :attr:`importable_path`. | ||
|
|
||
| Args: | ||
| object: The object to stringify (str, bytes, or any object). | ||
| encoding: Encoding to decode ``object`` with when it is bytes-like. | ||
| errors: Error handler for decoding. | ||
|
|
||
| Returns: | ||
| A new ``AssetPathStr`` instance. | ||
| """ | ||
| if encoding is None and errors is None: | ||
| relative_path = str.__new__(str, object) | ||
| else: | ||
| relative_path = str.__new__( | ||
| str, | ||
| object, # pyright: ignore[reportArgumentType] | ||
| "utf-8" if encoding is None else encoding, | ||
| "strict" if errors is None else errors, | ||
| ) | ||
| instance = super().__new__( | ||
| cls, get_config().prepend_frontend_path(relative_path) | ||
| ) | ||
| instance.importable_path = f"$/public{relative_path}" | ||
| return instance |
There was a problem hiding this comment.
Pickle/copy will double-apply
frontend_path
When Python pickles a str subclass it calls cls.__new__(cls, str(self)) on reconstruction — passing the already-prefixed string value back into __new__, which calls prepend_frontend_path a second time. The result is a corrupted double-prefixed path (e.g. /my-app/my-app/external/…) and the importable_path slot is silently lost.
This can be fixed by overriding __getnewargs__ to return the raw relative path (recoverable from importable_path):
def __getnewargs__(self) -> tuple[str]:
# Return the unprefixed path so __new__ reconstructs correctly.
return (self.importable_path[len("$/public"):],)If AssetPathStr is never intended to be serialized/pickled, document that constraint explicitly in the class docstring.
This allows components to reference the internal path in the
.webdirectory for use with JS imports at compile time.