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

Feature: nested string interpolations #610

Open
Jasha10 opened this issue Mar 16, 2021 · 7 comments
Open

Feature: nested string interpolations #610

Jasha10 opened this issue Mar 16, 2021 · 7 comments

Comments

@Jasha10
Copy link
Collaborator

Jasha10 commented Mar 16, 2021

Currently nested interpolations, e.g. "${b_${c}}", do not seem to be supported.

Here is an example:

from omegaconf import OmegaConf

cfg = OmegaConf.create(
    {
        "a": "${b_${c}}",
        "c": 123,
        "b_123": "xyz",
    }
)
print(cfg.a)

The desired output would be xyz.
The current behavior is to throw a GrammarParserError.

Describe alternatives you've considered
Here is a workaround that uses getattr to explicitly dereference the interpolation:

cfg = OmegaConf.create(
    {
        "a_ptr": "b_${c}",
        "c": 123,
        "b_123": "xyz",
    }
)
print(getattr(cfg, cfg.a_ptr))

Additional context

>>> omegaconf.__version__
'2.1.0dev20'
@omry
Copy link
Owner

omry commented Mar 16, 2021

String interpolations does not support nested interpolations right now.
You can see examples of supported forms of nested interpolations in the docs.
I am not sure how hard it would be to add (@odelalleau, I am pretty sure you thought about it, what do you think?).
We should probably either enable it or document that it's not supported at this time.

@Jasha10, do you have an actual use case or are you just pointing it out because it surprised you?

@omry omry changed the title Feature: nested interpolations Feature: nested interpolations in string interpolations Mar 16, 2021
@omry omry changed the title Feature: nested interpolations in string interpolations Feature: nested string interpolations Mar 16, 2021
@odelalleau
Copy link
Collaborator

odelalleau commented Mar 16, 2021

I am not sure how hard it would be to add (@odelalleau, I am pretty sure you thought about it, what do you think?).

IIRC at some point you mentioned that there was no need to support it so it's not something I kept -- pretty sure it was possible in one of my many versions :)
(but I may not be remembering correctly, it's been a while -- probably sometime around July/August 2020)

There are some workarounds in case someone really needs it:

# Use an intermediate variable to hold the full name
cfg = OmegaConf.create(
    {
        "a_ref": "b_${c}",
        "a": "${${a_ref}}",
        "c": 123,
        "b_123": "xyz",
    }
)
print(cfg.a)
# Use a resolver
OmegaConf.register_new_resolver("identity", lambda x: x)
cfg = OmegaConf.create(
    {
        "a": "${${identity:b_${c}}}",
        "c": 123,
        "b_123": "xyz",
    }
)
print(cfg.a)

In terms of enabling it in the grammar, it wouldn't be too hard, it just wouldn't play nice with #600 => would need to change a bit the approach taken here (handling $ in the parser instead of the lexer -- it's doable, actually my first version was doing that before I realized it was simpler to do it at the lexer level).

@Jasha10
Copy link
Collaborator Author

Jasha10 commented Mar 16, 2021

Yes, I do have a use case. I'll try to come up with a minimal practical example...

Edit: for future reference, here is my motivating example:

@dataclass
class Config:
    provider: str  # provider1 or provider2
    service: str  # serviceA or serviceB
    message_format: str = "${message_format_table.${provider}_${service}}"
    message_format_table: Dict[str, str] = ...

@omry
Copy link
Owner

omry commented Mar 16, 2021

Yeah yeah, blame me.
I was probably just trying to cut down on the scope :P.

If anyone wants to try to enable it go ahead but I am learning toward revisiting in 2.2.

@Jasha10
Copy link
Collaborator Author

Jasha10 commented Mar 16, 2021

There are some workarounds in case someone really needs it:

# Use an intermediate variable to hold the full name
cfg = OmegaConf.create(
    {
        "a_ref": "b_${c}",
        "a": "${${a_ref}}",
        ...

I wasn't aware that this was possible. Thanks for the tip!

@odelalleau
Copy link
Collaborator

If anyone wants to try to enable it go ahead but I am learning toward revisiting in 2.2.

Not going for it myself but @Jasha10 if you want to take a stab at it let me know, I'll give you some pointers.

@Jasha10
Copy link
Collaborator Author

Jasha10 commented Mar 16, 2021

Ok, sounds good :)

Edit: just reread the above, I think revisiting in 2.2 sounds better given that there exist viable workarounds.

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

No branches or pull requests

4 participants