Open bswck opened 1 week ago
Nice. Thanks for documenting the motivation and especially finding prior art. I'd not thought to look at __all__
. I particularly appreciate the ability to declare the variable Final
, which apparently can be done without overspecifying the type.
I do see the value in supporting valid syntax. Especially since this library is being shared for more than just the pip-run
cli.
On the other hand, there's lots of valid Python syntax that this construct doesn't support, such as mutation (__requires__.append('another')
) or multi-value assignment (__requires__, __index_url__ = ...
) or non-literal assignment (__requires__ = [...] + [...]
).
I'm a little worried that nobody has asked for this feature. Are you wanting for yourself to add type annotations to a __requires__
directive? Do you know of any other users who would use this feature if it existed?
I'm also apprehensive as it starts to violate the zen of "preferably one obvious way to do it".
Overall, I'm inclined to say we should do it, especially if the functional approach can be maintained (such as drafted in c9a7094). I promise to be more forgiving for another PR.
I'm also apprehensive as it starts to violate the zen of "preferably one obvious way to do it".
But does it? Depends on how you describe it.
I do believe that we could say there is no more ways to do it with this feature: the obvious way to specify requirements without passing them via sys.argv
to pip-run (which already means there are two ways) is to declare a sequence of strings (or a single string! doesn't it already violate the zen? there are three ways already) gathering the requirements.
Syntax isn't what violates the zen here, I believe. I think it's just about some basic flexibility, but that's an opinion, not a helpful fact.
In other words, what I mean is:
__requires__: list[str] = ["jaraco.functools"]
and
__requires__ = ["jaraco.functools"]
are essentially identical, so why not support both, given the cost is so low?
On the other hand, there's lots of valid Python syntax that this construct doesn't support, such as mutation (
__requires__.append('another')
) or multi-value assignment (__requires__, __index_url__ = ...
) or non-literal assignment (__requires__ = [...] + [...]
).
Yes. Additionally, we do not support (__requires__ := ...)
which does set the value at runtime.
But these things were obvious since the beginning.
If Python had something called "build time", we could be more dynamic and actually collect these variables from the "build time", instead of analyzing the code. But I don't think it makes sense to have build time in an interpreted language like Python... does it?
\
I'm a little worried that nobody has asked for this feature. Are you wanting for yourself to add type annotations to a requires directive? Do you know of any other users who would use this feature if it existed?
Well, let me be the first one then. I wanted to declare a requirement list without overspecifying the type, that is __requires__: Final = [...]
:)
And I'm pretty sure some people would use it. But I can't speak for them.
I promise to be more forgiving for another PR.
Alright, see you there!
Annotating
__requires__
/__index_url__
might be discouraged becausepip-run
only supports literal assignments of__requires__
/__index_url__
.This issue aims to advocate for supporting this case nonetheless:
or this case
and so on.
Since
__requires__
(and__index_url__
as well) is expected to be an immutable literal defined in one place, I'd suggest:typing.Final
which signals: "hey, you shouldn't be reassigning this name__requires__
here"__requires__
), e.g.__requires__: Final[Sequence[str]]
(not a huge fan becausestr
is itself aSequence[str]
, but it correctly matches all types of valid__requires__
values) or__requires__: Final[tuple[str, ...]]
which I think best resembles strings' atomicity.This practice has a bunch of users. Let's check for
__all__
, which is a common package-related module-level dunder name, typically not expected to change dynamically:This feature:
Moreover, it might increase general type safety knowing that
__requires__
can either be a collection of strings or a single string, treated atomically.I do think this feature is in
pip-run
's philosophy and makes its usability wider at not much of a cost.