Skip to content

Introduce default_args context manager#39964

Merged
tgamblin merged 4 commits intospack:developfrom
haampie:feature/add-default_args-context-manager
Nov 6, 2023
Merged

Introduce default_args context manager#39964
tgamblin merged 4 commits intospack:developfrom
haampie:feature/add-default_args-context-manager

Conversation

@haampie
Copy link
Copy Markdown
Member

@haampie haampie commented Sep 12, 2023

This adds a rather trivial context manager that lets you deduplicate repeated
arguments in directives, e.g.

depends_on("py-x@1", when="@1", type=("build", "run"))
depends_on("py-x@2", when="@2", type=("build", "run"))
depends_on("py-x@3", when="@3", type=("build", "run"))
depends_on("py-x@4", when="@4", type=("build", "run"))

can be condensed to

with default_args(type=("build", "run")):
    depends_on("py-x@1", when="@1")
    depends_on("py-x@2", when="@2")
    depends_on("py-x@3", when="@3")
    depends_on("py-x@4", when="@4")

The advantage is it's clear for humans, the downside it's less clear for type checkers due to type erasure

@spackbot-app spackbot-app bot requested a review from adamjstewart September 12, 2023 18:40
@haampie haampie changed the title Introduce default_args context manager Introduce default_args context manager Sep 12, 2023
Copy link
Copy Markdown
Member

@tgamblin tgamblin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks awesome to me, but can you make it so that with when is implemented using the same mechanism? i.e., shouldn’t this:

with when(“@2:”):

become syntactic sugar for:

with default_args(when=“@2:”):

?

I think when is special enough to keep, and it’s more readable for its special case. But we don’t need two code paths in the implementation for basically the same thing.

@haampie
Copy link
Copy Markdown
Member Author

haampie commented Sep 13, 2023

Hm, it's not exactly the same, since when combines constraints, while default_args overrides.

What's expected here:

with default_args(type="build"), default_args(type=("link", "run")):
    depends_on("x")

is that equivalent to

depends_on("x", type=("build", "link", "run"))

or

depends_on("x", type=("link", "run"))

@alalazo
Copy link
Copy Markdown
Member

alalazo commented Sep 13, 2023

@tgamblin when deals with a single specific argument, that is known to be a spec literal:

  1. It combines constraints using Spec.constrain
  2. It can be nested (though we don't recommend that in general), and
  3. The when= argument can be in the directive too.

This:

with when("+foo"):
    with when("+bar"):
        depends_on("xxx", when="+baz")

is equivalent to:

depends_on("xxx", when="+foo+bar+baz")

@tgamblin
Copy link
Copy Markdown
Member

tgamblin commented Sep 14, 2023

Ok, I agree with @alalazo and that's a great reason why when should have its own directive.

Are there any other default args worth having special semantics for? I can't think of any off the top of my head that I'd justify implementing semantics other than override for.

but RE: @haampie, this is awful:

with default_args(type="build"), default_args(type=("link", "run")):
    depends_on("x")

I think most people would expect that to be equivalent to depends_on("x", type=("build", "link", "run")) as written, but then you should just write that. Sigh. I guess we could try to catch that in audit or review.

I could see you wanting an override if the second context manager were in the middle of some statements like:

with default_args(when="@2.0:", type="build"):
    depends_on("x")
    with default_args(type=("link", "run")):
        depends_on("y")
        depends_on("z")

but I think we should just encourage people not to do this. I worry about people composing with when() and with default_args() as it's going to be surprising if they use the latter for when. e.g. what should these do and what do they do right now?

with default_args(when="@2.0:", type="build"):
    depends_on("x")
    with when("@3.0:"):
        depends_on("y")
        depends_on("z")

or:

with default_args(when="@2.0:", type="build"):
    depends_on("x")
    with when("@3.0:"):
        depends_on("y")
        depends_on("z")

Should this be disallowed? I kind of think we should just raise and recommend using with when if you try to stick when in default_args.

Finally, I think regardless of what we settle on, the semantics need to be documented with a note saying how they're different from with when.

@adamjstewart
Copy link
Copy Markdown
Member

Are there any other default args worth having special semantics for?

Would love to be able to use with type(...) but I imagine that's not desirable for the same reasons that with args(...) isn't 😆

@tgamblin tgamblin added this to the v0.21.0 milestone Oct 18, 2023
@spackbot-app spackbot-app bot added the documentation Improvements or additions to documentation label Oct 23, 2023
@haampie haampie requested a review from tgamblin October 30, 2023 15:50
@haampie
Copy link
Copy Markdown
Member Author

haampie commented Nov 1, 2023

@haampie
Copy link
Copy Markdown
Member Author

haampie commented Nov 2, 2023

And this one too @tgamblin :D

@tgamblin tgamblin merged commit 1235084 into spack:develop Nov 6, 2023
Comment on lines +53 to +57
depends_on("[email protected]:", when="+colorama")
depends_on("[email protected]:", when="+uvloop")
depends_on("[email protected]:", when="+d")
depends_on("[email protected]:", when="+jupyter")
depends_on("[email protected]:", when="+jupyter")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should be indented...

@haampie haampie deleted the feature/add-default_args-context-manager branch November 9, 2023 23:09
gabrielctn pushed a commit to gabrielctn/spack that referenced this pull request Nov 24, 2023
This adds a rather trivial context manager that lets you deduplicate repeated
arguments in directives, e.g.

```python
depends_on("py-x@1", when="@1", type=("build", "run"))
depends_on("py-x@2", when="@2", type=("build", "run"))
depends_on("py-x@3", when="@3", type=("build", "run"))
depends_on("py-x@4", when="@4", type=("build", "run"))
```

can be condensed to

```python
with default_args(type=("build", "run")):
    depends_on("py-x@1", when="@1")
    depends_on("py-x@2", when="@2")
    depends_on("py-x@3", when="@3")
    depends_on("py-x@4", when="@4")
```

The advantage is it's clear for humans, the downside it's less clear for type checkers due to type erasure.
mtaillefumier pushed a commit to mtaillefumier/spack that referenced this pull request Dec 14, 2023
This adds a rather trivial context manager that lets you deduplicate repeated
arguments in directives, e.g.

```python
depends_on("py-x@1", when="@1", type=("build", "run"))
depends_on("py-x@2", when="@2", type=("build", "run"))
depends_on("py-x@3", when="@3", type=("build", "run"))
depends_on("py-x@4", when="@4", type=("build", "run"))
```

can be condensed to

```python
with default_args(type=("build", "run")):
    depends_on("py-x@1", when="@1")
    depends_on("py-x@2", when="@2")
    depends_on("py-x@3", when="@3")
    depends_on("py-x@4", when="@4")
```

The advantage is it's clear for humans, the downside it's less clear for type checkers due to type erasure.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core PR affects Spack core functionality dependencies directives documentation Improvements or additions to documentation python update-package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants