You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This stemmed from a though I had while discussing #2252
I think there would be several advantages for using a URL class that subclasses str. I have been working on my own URL/URI class for my own purposes and have been using this pattern of str with attributes for years, and I find it super convenient for when something behaves like a string, but I want custom attributes attached to it.
It would only require a few lines changed, and all tests pass without modification. This is going off of master, I know that will change if 2252 merges, but I think it would be similarly doable, and that might be a good time to implement this pattern as well:
class URL(str):
...
_uri_reference: rfc3986.URIReference # needs a reference for now to keep mypy happy
def __new__(cls, url: typing.Union["URL", str] = "", **kwargs: typing.Any) -> "URL":
self = str.__new__(cls, url)
self.__initialize__(url, **kwargs)
return self
def __initialize__(
self, url: typing.Union["URL", str] = "", **kwargs: typing.Any
) -> None:
if isinstance(url, URL): # trap the class type first, since now isinstance(url, str) is True
self._uri_reference = url._uri_reference
elif isinstance(url, str):
...
def join(self, url: URLTypes) -> "URL": # type: ignore
# mypy doesn't like that str.join is a different type
...
Here, I'm renaming __init__ to __initialize__ to prevent it from being automatically called.
The chief advantages:
URL now walks, quacks, and acts like a str
Methods like json.dump "just work" without special encoders
I noticed while debugging that the constructor currently gets called multiple times per initialization. With some refactoring, you could definitely get this down to a single-pass initialization
I'd have to dig into how the current implementation works, but I think the overall memory footprint could be reduced
Disadvantages:
join now conflicts with str.join, which technically violates Liskov substitution principle. I don't think this is a huge gamechanger. Personally I use .joinpath for this functionality, as it mirrors Path.joinpath.
Unforeseen consequences - Hyrum's law, etc. For example, users doing something such as isinstance(url, str)...elif isinstance(url, URL) could be bit by this. This would definitely be considered a breaking change (ideally 1.0, now's the time to do it).
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Hi,
This stemmed from a though I had while discussing #2252
I think there would be several advantages for using a URL class that subclasses
str
. I have been working on my own URL/URI class for my own purposes and have been using this pattern ofstr with attributes
for years, and I find it super convenient for when something behaves like a string, but I want custom attributes attached to it.It would only require a few lines changed, and all tests pass without modification. This is going off of master, I know that will change if 2252 merges, but I think it would be similarly doable, and that might be a good time to implement this pattern as well:
Here, I'm renaming
__init__
to__initialize__
to prevent it from being automatically called.The chief advantages:
URL
now walks, quacks, and acts like astr
json.dump
"just work" without special encodersDisadvantages:
join
now conflicts withstr.join
, which technically violates Liskov substitution principle. I don't think this is a huge gamechanger. Personally I use.joinpath
for this functionality, as it mirrorsPath.joinpath
.isinstance(url, str)...elif isinstance(url, URL)
could be bit by this. This would definitely be considered a breaking change (ideally 1.0, now's the time to do it).Beta Was this translation helpful? Give feedback.
All reactions