Anatomy: expand user and vars in root paths#1884
Conversation
There was a problem hiding this comment.
Pull request overview
This PR extends anatomy root handling so root definitions containing ~, $VAR/${VAR}, or {VAR} can be resolved correctly, and so root-template detection can match paths even when only one side (stored root vs input path) is expanded.
Changes:
- Expand
~and environment variables when computing the current-platform root value. - Enhance
find_root_template_from_pathto compare both original and expanded forms of both stored roots and input paths. - Add an isolated unit-test module covering root matching and remapping scenarios, including env-var and
~expansion cases.
Reviewed changes
Copilot reviewed 2 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
client/ayon_core/pipeline/anatomy/roots.py |
Adds expanduser/expandvars to root value resolution and expands matching logic in find_root_template_from_path. |
tests/client/ayon_core/pipeline/anatomy/test_root_item.py |
Adds unit tests for root resolution, matching, and remapping with expanded/unexpanded inputs. |
tests/client/ayon_core/pipeline/anatomy/__init__.py |
Adds package marker for the new test module location. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
What is the use-case of having |
The use case is client request to be able to use gdrive folder that is per user mounted in their respective home dirs. |
I'd say that this is what should be used. Why I'm against: This will open can of worms. Allowing to do this "easily" looks like you can safely do it, but there is a ton of caviads related to this approach that might make us look bad. I might be wrong, summoning @BigRoy for opinion. |
This is really not practical for whole studio setup. You would have to do it for every site. |
I agree with this. The tricky thing is that these expanded root paths and their 'context' are stored in a variety of places, e.g. in publishes, suddenly we're passing the But regarding using "site root overrides":
This is also agree with. Which makes me think what technically differs between a site root override and this? (Except for the fact that the expanded path is set somewhere?) @iLLiCiTiT from a pipeline/technical perspective code-wise. How much does site specific root overrides really differ from expanding the vars? I think this will need thorough testing, cross-platform with multiple users/home directories - and possibly even with the USD resolver resolving to a published product that uses |
At the end the important bit is that it can be resolved server side, service side, or in USD resolver.
Also |
|
While I agree that this might be dangerous and might break things - there are many more similar things around pipeline. My point is that nothig is forcing you to do it. It just gives you a possibility. If this is documented properly, it is up to the studio to go that way or not. Linux allows you to type |
this won't work as it is not expanded by python |
It is. I just chose wrong env key which is not set by windows. The thing is that with this is looks like you can safely use it, which is not true, you'll block yourself from some features, and it might not work all the time, and it will look like our fault. |
| ) | ||
| except KeyError: | ||
| self.value = ( | ||
| os.path.expandvars( |
There was a problem hiding this comment.
If we gona do it, I'm against using expandvars, only {ENV} should be possible.
There was a problem hiding this comment.
what is the reason? My argument is that using paths with $VAR inside is pretty standard.
There was a problem hiding this comment.
It is standard, but then you have to support it at every place which is using roots, including USD resolver, it is hard to find out if it is missing, and what exact variable it is (it does not have strictly defined end the the variable name). $MY_custom_var is valid env key, but how you find out if it should be $MY or $MY_custom...
There was a problem hiding this comment.
I guess the behavior is clearly defined. VAR = "foo":
lorem $VAR: lorem foo
lorem $VARipsum: lorem
lorem $VAR ipsum: lorem foo ipsum
lorem %VAR%: lorem foo
lorem %VAR%ipsum: lorem fooipsum
os.path.expandvars() is taking care of that in python and the resolver needs to implement {VAR} format anyway so adding $VAR and/or %VAR% is trivial at that point. But I don't really mind. @BigRoy ?
There was a problem hiding this comment.
You can't easily find out if it is missing (without validating it for each platform) and there are limitations, e.g. you can't use $VARipsum (which is missing in your example). I'm 100% against it. I know it is "known", but it is not easily detectable and easy to validate.
There was a problem hiding this comment.
It is there:
lorem $VARipsum: lorem
But it also supports curly bracket format that is standard too. So if you want this to work, you can:
lorem ${VAR}ipsum: lorem fooipsum
and all that is supported by os.path.expandvars()
There was a problem hiding this comment.
This is unresolved expanding and you have no idea it is unresolved
print(os.path.expandvars("$NOTEXISTING"))
>>> $NOTEXISTING
This does require to be more specific, something that should be filled is not
import os
os.environ["TEST"]="value"
print(os.path.expandvars("$TEST_something"))
>>> $TEST_something
Supporting this will only bring issues. At the end it does what the python formatting does, but with less control and more headaches for us.
| # Expand variables in the stored root path so we can compare it | ||
| # against an already-expanded input path (and vice-versa). | ||
| expanded_root_path = self._clean_root( | ||
| os.path.expandvars(os.path.expanduser(root_path)) |
There was a problem hiding this comment.
Root paths should be already expanded in cleaned_data.
There was a problem hiding this comment.
I am not sure I get it - it is not expanded there, only for current platform. so are you suggesting that the expansion logic should be moved to ... probably _clean_path()?
| # is already expanded while the caller passed an unexpanded path, or | ||
| # to normalise both sides consistently. | ||
| expanded_mod_path = self._clean_path( | ||
| os.path.expandvars(os.path.expanduser(path)) |
There was a problem hiding this comment.
We should not allow to pass in not expanded path.
There was a problem hiding this comment.
why? shouldn't one place take care of that intead reimplementing the logic in all places where you want to use this feature before calling find_root_template_from_path()?
There was a problem hiding this comment.
If you call find_root_template_from_path you should have full path, not ~/some/file.
There was a problem hiding this comment.
that is what you get now:
ar = AnatomyRoot(
parent=...,
root_raw_data={"linux": "/home/user/projects"},
name="work",
)
success, result = item.find_root_template_from_path("~/projects/shot/file.ma")you'll get result == "{root[work]}/shot/file.ma"
it handles matching unexpanded paths to expanded roots in various forms (~, $VAR, etc.) and only if it cannot match, it will success == False.
There was a problem hiding this comment.
And where you'd get the path "~/projects/shot/file.ma" from?
|
btw this is draft PR for USD Resolver - ynput/ayon-usd-resolver#80 |

Changelog Description
Expand variables and user
~in root paths.Roots like
~/fooor$HOME/fooor{HOME}/fooshould all resolve correctly. Note that this feature needs to be used with care as dynamic roots can break a lot of things if not used properly.Additional info
This is alternative to #1882
Testing notes:
~should work as expected