I’m seeing some behaviour when querying a layer’s permissionToSave that seems to be a bug but perhaps I’m misunderstanding it’s intended use?
We’re using an Asset resolver so maybe that has something to do with it, but I’d appreciate if someone could confirm or deny this test and whether permissionToSave should be returning False in this case?
Open a stage that you know has read-only layers and is using Ar URI’s…
import os
from pxr import Usd
stage = Usd.Stage.Open('your:/uri')
for layer in stage.GetUsedLayers():
if layer.permissionToSave:
if not os.access(layer.realPath, os.W_OK):
print(f"File is not writable: {layer.identifier}")
I did notice that permissionToSave does return False in the case of runtime anonymous layers, but should it also return False in the case of read-only layers?
I can perhaps see the ArGetResolver() falling through to a different resolver than the one you provided to Stage Open if its not the highest priority resolver in the current context.
Hey, I was looking into this. Our resolver returns a full path as the resolvedPath, not the URIs. As such, it appears that the default resolver is active for the CanWriteAssetToPath() call, which always returns true.
I know we could have our resolver return URIs as the resolvedPath, but I’m not sure we’re ready to go that route.
It seems like the options are to patch the default resolver to check for write permissions rather than always return true, or I saw there appears to be a way to override the default resolver via a SetPreferredResolver().
I was just curious of the opinions on these options? Is there something else I have overlooked?
Yeah, our guidance for URI resolvers when you are concerned with URI-relative anchoring and issues like the one you’re encountering, where USD’s logic is operating on resolved paths, is to have your resolver return a URI, and then do the “to local” translation on-demand in OpenAsset, etc. But agreed that could have pipeline implications to work out to make such a change.
I don’t recall atm for sure why we shied away from putting real logic into ArDefaultResolver::CanWriteAssetToPath(), but I suspect it was based on past experience where not all filesystems returned reliable results, and that causing frustration (reporting you can’t write when actually you should be able to, and then you’re stuck, with a DCC that is actually checking properly).
It does leave you in a pickle, though, and seems like it shouldn’t be a reason to force you to subclass, although given that you are already providing a plugin for your own URI resolver for all your DCC’s using USD, perhaps it’s not too big a lift? Please feel free to file an Issue on this, though, and we can discuss whether there’s anything we might be able to do. As an example, would you be willing to set an environment variable that would activate the DefaultResolver to do filesystem permissions checking?
Yeah, I think overriding the default resolver is the path forward for us if we are to fix the issue studio-wide. We do depend on some software vendors’ USD builds, so it is hard to patch USD itself because we have not overridden their builds.
That said, I was looking at how ArchStatIsWritable() is written, and I’m presuming that would probably work for us if the default resolver checked for writability with that. If that were hidden behind an env switch, we would probably try it out (I’ll check if the team wants to try that internally, since it would at least fix the problem in a few places).
Hey @pkilgo , we think it would be fine for us to specialize the ArDefaultResolver::CanWriteAssetToPath() to call ArchStatIsWritable(), if you’d like to make a GitHub Issue for that?
However, we do want to sound a note of caution on relying on it too much, because ArchStatIsWritable() may still be quite wrong for filesystems with different features such as access control lists that stat() does not take into account.
In fact, a year or so ago we scrubbed some of our core code to stop doing access checks prior to writing files and instead just atempt to write the file, and then seeing if it succeeded, in response to issues that SideFX and others reported.
If your pipeline code is calling SdfLayer::Save(), you will get back a boolean success value that you could use for this purpose. Currently, UsdStage::Save() does not return a success value, but we would consider changing it so that it returns true only if all dirty layers were successfully saved, and possibly add an optional out parameter that would return list of layers or layer identifiers that did not cleanly save. Let us know if this would be valuable.
After some thought, I don’t think we’ll be pursuing on our end right now, and keep using our workaround for the time being.
We’re using a network file system on Windows which I think is subject to ACLs that you called out. Though, I did not directly use ArchStatIsWritable() and used Python’s os.access(), which hopefully is a good enough test.