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

allow 'name' in key word arguments of url_for() and url_path_for() (#608) #611

Closed
wants to merge 8 commits into from

Conversation

dansan
Copy link
Contributor

@dansan dansan commented Aug 22, 2019

Patch replaces

def url_path_for(self, name: str, **path_params: str) -> URLPath:

with

def url_path_for(self, *args: str, **kwargs: str) -> URLPath:
    assert len(args) == 1, "Exactly one positional argument required: the routes name."
    name = args[0]

(also for url_for())
Not entirely sure about the assertion text...

Without the above change, these existing (now modified) tests fail:

  • tests/test_routing.py::test_url_path_for
  • tests/test_routing.py::test_url_for
  • tests/test_routing.py::test_reverse_mount_urls

And this new one:

  • tests/test_requests.py::test_request_url_for

@dansan
Copy link
Contributor Author

dansan commented Aug 22, 2019

Were multiple commits, because I had forgotten coverage and black. I squashed them together, thus the force-push.

Copy link
Member

@tomchristie tomchristie left a comment

Choose a reason for hiding this comment

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

Lovely stuff - couple of minor changes suggested - otherwise looks ace!

tests/test_routing.py Outdated Show resolved Hide resolved
starlette/routing.py Outdated Show resolved Hide resolved
@dansan dansan force-pushed the master branch 5 times, most recently from fbc1e12 to 0ddea63 Compare August 28, 2019 07:23
@dansan
Copy link
Contributor Author

dansan commented Aug 28, 2019

I reverted the usernamename changes, added a decorator to check the *args and added a test for the assertions.
I didn't use the decorator in templating.py, because I'm unsure about importing issues/policies.
(Wow - Travis is really clobbering me ;) Enforcing good standards and more automated QA... I think I want that at my work too...

starlette/routing.py Outdated Show resolved Hide resolved
starlette/templating.py Outdated Show resolved Hide resolved
tests/test_requests.py Outdated Show resolved Hide resolved
@dansan
Copy link
Contributor Author

dansan commented Sep 13, 2019

Hi @blueyed ,
thanks for the review.
I'm unsure about the procedure here. Github was nagging about the "Changes requested" by @tomchristie , so I clicked "request re-review" to get rid of it ^.^ although you're doing it now. Not intended as a rejection of your review, just to make github happy.
I made the changes you requested.

@nwalsh1995
Copy link
Contributor

Bumping this PR since I am affected by this same problem and would love to see this land!

@dansan
Copy link
Contributor Author

dansan commented Nov 19, 2019

I updated the code to be mergable to master.

@tomchristie
Copy link
Member

Great stuff.

I'd probably prefer if we drop the verify_args_is_only_route decorator. The method on the Router class should make a proper type check.
The Route/Mount/WebSocketRoute cases can just perform a dumber assert len(args) == 1 check.

@dansan
Copy link
Contributor Author

dansan commented Nov 28, 2019

I replaced the decorator with the asserts and the type check: f4f4cd1

@fhscholl
Copy link

Any possibility this is going to get merged?

@Kludex
Copy link
Sponsor Member

Kludex commented Dec 11, 2021

We still have this "bug". Would you mind rebasing it? I know 2.5 years is a lot... But would you mind rebasing it @dansan ?

If not, I'd like to close the PR and creating an issue about this.

@dansan
Copy link
Contributor Author

dansan commented Jan 1, 2022

@Kludex Sorry, had no time before the holidays to get into this.
Patch is rebased.
Thanks for waking this old issue up.

@Kludex Kludex added this to the Version 0.22.0 milestone Jun 11, 2022
@Kludex
Copy link
Sponsor Member

Kludex commented Aug 13, 2022

Is it bad to replace name by __name? @adriangb

@adriangb
Copy link
Member

Is it bad to replace name by __name? @adriangb

It means that anyone calling url_for(name="foo") where "foo" is the route name would experience a breaking change. But the same thing would happen with the current patch of name = args[0]. I think the only difference with the *args version is that the __name version (and subsequently the (/, name: str, ...)` version once Python 3.7 is our minimum version) put the intent in the function signature instead of burying it in the implementation.

@Kludex
Copy link
Sponsor Member

Kludex commented Sep 24, 2022

Can we deprecate the parameter "name"? Maybe warning when the caller uses "name=".

See:

import inspect


def potato(a: int, b: str) -> str:
    print(inspect.stack()[-1].code_context)
    return b


potato(1, b=2)

@Kludex Kludex mentioned this pull request Oct 3, 2022
11 tasks
@alex-oleshkevich
Copy link
Member

Can we deprecate the parameter "name"? Maybe warning when the caller uses "name=".

This is a good solution to have before 1.0.
After we can have something like def url_for(self, name_:str, **path_params: Any) -> URL and clearly reserve name_ for internal use by documenting it.

@Kludex Kludex modified the milestones: Version 0.22.0, Version 0.23.0 Nov 20, 2022
@Kludex Kludex modified the milestones: Version 0.23.0, Version 0.24.0 Dec 8, 2022
@Kludex Kludex modified the milestones: Version 0.24.0, Version 0.26.0 Feb 6, 2023
@Kludex
Copy link
Sponsor Member

Kludex commented Feb 9, 2023

Is it bad to replace name by __name? @adriangb

It means that anyone calling url_for(name="foo") where "foo" is the route name would experience a breaking change. But the same thing would happen with the current patch of name = args[0]. I think the only difference with the *args version is that the __name version (and subsequently the (/, name: str, ...)` version once Python 3.7 is our minimum version) put the intent in the function signature instead of burying it in the implementation.

Let's take a decision here.

Options:

  1. Go with this PR, and further revert + / on the signature.
  2. Go with a less possible name like __name, and further addition of / to the signature.
  3. ?

@abersheeran
Copy link
Member

abersheeran commented Feb 10, 2023

This PR may need to be considered in conjunction with #1385 .

There are several solutions to solve these two problems at the same time:

  • def url_for(self, name: str, path_params: dict[str, Any], query_params: dict[str, Any]) -> str
  • def url_for(self, *args: str, **kwargs: str) -> URL: Add query params to URL object.
  • def url_for(self, *args: str, **kwargs: str) -> str: Unknown parameters in kwargs as query params. (like flask)
  • def url_for(self, __name: str, **path_params: dict[str, Any], __query_params: dict[str, Any]) -> str
  • def url_for(self, __name: str, **path_params: dict[str, Any]) -> URL

@Kludex
Copy link
Sponsor Member

Kludex commented Feb 10, 2023

I believe we prefer this one: def url_for(self, __name: str, **path_params: dict[str, Any]) -> URL.

@alex-oleshkevich
Copy link
Member

alex-oleshkevich commented Feb 10, 2023

Leading underscores are less discoverable. When you type n IDEs suggest you name parameter. When the parameter starts with _ then the autocompleting list if empty or not helpful.

What if we do like this def url_for(self, name_: str, **path_params: dict[str, Any]) -> URL. This is a far more common pattern I see in the codebases. And I don't remember if I ever seen name_ query parameter.

@Kludex
Copy link
Sponsor Member

Kludex commented Feb 10, 2023

The goal is to be less discoverable. 🤔

The idea is to move to def url_for(self, name: str, /, **path_params: dict[str, Any]) -> URL when Python 3.7 support is no longer needed.

@Kludex
Copy link
Sponsor Member

Kludex commented Feb 13, 2023

I'm not sure if my last comment was that clear.

The goal of having __name is to signalize that we want it to be only a positional argument, so we can move to name: str, /, **path_params) later on.

@alex-oleshkevich
Copy link
Member

There is no difference between __name or name_. But from DX perspective name_ is more clear.

@Kludex
Copy link
Sponsor Member

Kludex commented Feb 13, 2023

There is no difference between __name or name_. But from DX perspective name_ is more clear.

I see the goal here being exactly the opposite... Why would you want the IDE to show name__? People would get tempted to use the keyword and write url_for(name__="name"). I want to avoid people from writing the parameter so in a future release it can be removed. 🤔

@Kludex Kludex mentioned this pull request Feb 14, 2023
8 tasks
@Kludex
Copy link
Sponsor Member

Kludex commented Feb 15, 2023

Is it possible to have a different signature depending on the Python version? Maybe we should already do this...

@alex-oleshkevich
Copy link
Member

Is it possible to have a different signature depending on the Python version? Maybe we should already do this...

I am aware that it could be an unexpected side effect when devs will update the project's python version.
Maybe we should enforce it at mypy level at this state?

@Kludex
Copy link
Sponsor Member

Kludex commented Feb 16, 2023

Is it possible to have a different signature depending on the Python version? Maybe we should already do this...

I am aware that it could be an unexpected side effect when devs will update the project's python version. Maybe we should enforce it at mypy level at this state?

You mean this?

import typing


if typing.TYPE_CHECKING:
    def potato(__name: str, /) -> str:
        """Potato."""
        return __name
else:
    def potato(__name: str) -> str:
        """Potato."""
        return __name

potato(__name="potato")  # ERROR HERE

It's not possible due to syntax error. 😢

@Kludex
Copy link
Sponsor Member

Kludex commented Feb 27, 2023

Anyone subscribed here is against the __name proposal with further addition of positional-only argument on __name (when we drop support for Python 3.7)?

@Kludex
Copy link
Sponsor Member

Kludex commented Mar 9, 2023

@Kludex Kludex closed this Mar 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

10 participants