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

Altering URLs #736

Open
1 task done
chey opened this issue Jun 9, 2022 · 6 comments
Open
1 task done

Altering URLs #736

chey opened this issue Jun 9, 2022 · 6 comments

Comments

@chey
Copy link

chey commented Jun 9, 2022

Is your feature request related to a problem?

No

Describe the solution you'd like

Would like the ability to alter single/multiple parts of a URL in single statement.

Example:

>>> URL("http://localhost:8080").with(host="newhost", port=80)
URL("http://newhost")

or this

>>> URL("http://localhost:8080").with(port=80)
URL("http://localhost")

Describe alternatives you've considered

N/A

Additional context

No response

Code of Conduct

  • I agree to follow the aio-libs Code of Conduct
@chey chey closed this as completed Jun 9, 2022
@chey chey reopened this Jun 9, 2022
@chey
Copy link
Author

chey commented Jun 9, 2022

build doesn't alter URLs:

>>> URL("http://localhost:9090").build(port=8080)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/chey/work/vicinity/venv/lib/python3.10/site-packages/yarl/_url.py", line 216, in build
    raise ValueError('Can\'t build URL with "port" but without "host".')
ValueError: Can't build URL with "port" but without "host".

@mjpieters
Copy link
Contributor

build doesn't alter URLs:

No, URL.build() is a class method and builds a new URL from scratch. It has no knowledge of the existing instance.

You can chain up multiple with_* calls, instead:

>>> URL("http://localhost:8080").with_host("newhost").with_port(80)
URL('http://newhost:80')

Note that with is a keyword in Python so can't be used for a method name; it'd have to be with_ instead or a different name altogether.

That said I'm +0 on adding a URL.with_() method that passes on keyword arguments to .with_{key}(value) calls

def with_(self, **kwargs):
    new = self
    for key, value in kwargs.items():
        new = getattr(new, f"with_{key}")(value)
    return new

If this was added, the actual implementation would be a bit more robust, perhaps with cached mapping of known with_* method names to apply so an exception can be raised early if any of the keywords passed don't fit.

You can add the above locally if you want to:

>>> def with_(self, **kwargs):
...     new = self
...     for key, value in kwargs.items():
...         new = getattr(new, f"with_{key}")(value)
...     return new
...
>>> URL.with_ = with_
>>> URL("http://localhost:8080").with_(host="newhost", port=80)
URL('http://newhost:80')

@chey
Copy link
Author

chey commented Jun 14, 2022

Yes, it's clear with will not be a good method choice. Maybe alter would be sufficient. Looking at pathlib i see names like unparse and unsplit which seem confusing at first glance.

@mjpieters
Copy link
Contributor

Yes, it's clear with will not be a good method choice. Maybe alter would be sufficient.

update() would echo update_query(). Still not sold it is really needed however, but not dead against it at the same time.

Looking at pathlib i see names like unparse and unsplit which seem confusing at first glance.

pathlib doesn't have such methods, maybe you were looking at urllib.parse instead?

@chey
Copy link
Author

chey commented Jun 14, 2022

pathlib doesn't have such methods, maybe you were looking at urllib.parse instead?

Yes, that's what I was referring to.

@chey
Copy link
Author

chey commented Jun 14, 2022

You can add the above locally if you want to:

>>> def with_(self, **kwargs):
...     new = self
...     for key, value in kwargs.items():
...         new = getattr(new, f"with_{key}")(value)
...     return new
...
>>> URL.with_ = with_
>>> URL("http://localhost:8080").with_(host="newhost", port=80)
URL('http://newhost:80')

I did make a similar function to this in order to test out the idea. I suppose one could do a dir scan of URL for with_* in order to add exceptions. Like you said though, that would need to be cached as it would get expensive to scan URL each time.

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

2 participants