Skip to content

Commit

Permalink
Partially annotated parseresult.py and _mixin.py.
Browse files Browse the repository at this point in the history
- After review, we don't actually need a generic namedtuple to make this work in a type stub. Inline annotations seemingly work fine so far and don't significantly change the runtime. This might be option 4, which can hold until 3.11 is the lowest supported version.
 - However, in the meantime, `ParseResultMixin` can be made generic in a helpful way with `typing.AnyStr`.
 - `port` is a strange case and might be annotated too narrowly or incorrectly; based on some of the ways that it's populated, it might sometimes be an int.
- Prefixed `_typing_compat.Self` imports with underscore to avoid poluting namespace with public variables.
  • Loading branch information
Sachaa-Thanasius committed Jun 16, 2024
1 parent f4d150f commit 0179352
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 102 deletions.
52 changes: 30 additions & 22 deletions src/rfc3986/_mixin.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
"""Module containing the implementation of the URIMixin class."""
import typing as t
import warnings

from . import exceptions as exc
from . import misc
from . import normalizers
from . import validators
from ._typing_compat import Self as _Self


class _AuthorityInfo(t.TypedDict):
userinfo: t.Optional[str]
host: t.Optional[str]
port: t.Optional[str]


class URIMixin:
"""Mixin with all shared methods for URIs and IRIs."""

def authority_info(self):
def authority_info(self) -> _AuthorityInfo:
"""Return a dictionary with the ``userinfo``, ``host``, and ``port``.
If the authority is not valid, it will raise a
Expand Down Expand Up @@ -51,11 +59,11 @@ def authority_info(self):

return matches

def _match_subauthority(self):
def _match_subauthority(self) -> t.Optional[t.Match[str]]:
return misc.SUBAUTHORITY_MATCHER.match(self.authority)

@property
def _validator(self):
def _validator(self) -> validators.Validator:
v = getattr(self, "_cached_validator", None)
if v is not None:
return v
Expand All @@ -65,7 +73,7 @@ def _validator(self):
return self._cached_validator

@property
def host(self):
def host(self) -> t.Optional[str]:
"""If present, a string representing the host."""
try:
authority = self.authority_info()
Expand All @@ -74,7 +82,7 @@ def host(self):
return authority["host"]

@property
def port(self):
def port(self) -> t.Optional[str]:
"""If present, the port extracted from the authority."""
try:
authority = self.authority_info()
Expand All @@ -83,15 +91,15 @@ def port(self):
return authority["port"]

@property
def userinfo(self):
def userinfo(self) -> t.Optional[str]:
"""If present, the userinfo extracted from the authority."""
try:
authority = self.authority_info()
except exc.InvalidAuthority:
return None
return authority["userinfo"]

def is_absolute(self):
def is_absolute(self) -> bool:
"""Determine if this URI Reference is an absolute URI.
See http://tools.ietf.org/html/rfc3986#section-4.3 for explanation.
Expand Down Expand Up @@ -135,7 +143,7 @@ def is_valid(self, **kwargs: bool) -> bool:
]
return all(v(r) for v, r in validators)

def authority_is_valid(self, require=False):
def authority_is_valid(self, require: bool = False) -> bool:
"""Determine if the authority component is valid.
.. deprecated:: 1.1.0
Expand Down Expand Up @@ -165,7 +173,7 @@ def authority_is_valid(self, require=False):
require=require,
)

def scheme_is_valid(self, require=False):
def scheme_is_valid(self, require: bool = False) -> bool:
"""Determine if the scheme component is valid.
.. deprecated:: 1.1.0
Expand All @@ -184,7 +192,7 @@ def scheme_is_valid(self, require=False):
)
return validators.scheme_is_valid(self.scheme, require)

def path_is_valid(self, require=False):
def path_is_valid(self, require: bool = False) -> bool:
"""Determine if the path component is valid.
.. deprecated:: 1.1.0
Expand All @@ -203,7 +211,7 @@ def path_is_valid(self, require=False):
)
return validators.path_is_valid(self.path, require)

def query_is_valid(self, require=False):
def query_is_valid(self, require: bool = False) -> bool:
"""Determine if the query component is valid.
.. deprecated:: 1.1.0
Expand All @@ -222,7 +230,7 @@ def query_is_valid(self, require=False):
)
return validators.query_is_valid(self.query, require)

def fragment_is_valid(self, require=False):
def fragment_is_valid(self, require: bool = False) -> bool:
"""Determine if the fragment component is valid.
.. deprecated:: 1.1.0
Expand All @@ -241,7 +249,7 @@ def fragment_is_valid(self, require=False):
)
return validators.fragment_is_valid(self.fragment, require)

def normalized_equality(self, other_ref):
def normalized_equality(self, other_ref) -> bool:
"""Compare this URIReference to another URIReference.
:param URIReference other_ref: (required), The reference with which
Expand All @@ -251,7 +259,7 @@ def normalized_equality(self, other_ref):
"""
return tuple(self.normalize()) == tuple(other_ref.normalize())

def resolve_with(self, base_uri, strict=False):
def resolve_with(self, base_uri, strict: bool = False) -> _Self:
"""Use an absolute URI Reference to resolve this relative reference.
Assuming this is a relative reference that you would like to resolve,
Expand Down Expand Up @@ -323,14 +331,14 @@ def resolve_with(self, base_uri, strict=False):
)
return target

def unsplit(self):
def unsplit(self) -> str:
"""Create a URI string from the components.
:returns: The URI Reference reconstituted as a string.
:rtype: str
"""
# See http://tools.ietf.org/html/rfc3986#section-5.3
result_list = []
result_list: list[str] = []
if self.scheme:
result_list.extend([self.scheme, ":"])
if self.authority:
Expand All @@ -345,12 +353,12 @@ def unsplit(self):

def copy_with(
self,
scheme=misc.UseExisting,
authority=misc.UseExisting,
path=misc.UseExisting,
query=misc.UseExisting,
fragment=misc.UseExisting,
):
scheme: t.Optional[str] = misc.UseExisting,
authority: t.Optional[str] = misc.UseExisting,
path: t.Optional[str] = misc.UseExisting,
query: t.Optional[str] = misc.UseExisting,
fragment: t.Optional[str] = misc.UseExisting,
) -> _Self:
"""Create a copy of this reference with the new components.
:param str scheme:
Expand Down
4 changes: 2 additions & 2 deletions src/rfc3986/iri.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from . import misc
from . import normalizers
from . import uri
from ._typing_compat import Self
from ._typing_compat import Self as _Self


try:
Expand Down Expand Up @@ -91,7 +91,7 @@ def from_string(
cls,
iri_string: t.Union[str, bytes],
encoding: str = "utf-8",
) -> Self:
) -> _Self:
"""Parse a IRI reference from the given unicode IRI string.
:param str iri_string: Unicode IRI to be parsed into a reference.
Expand Down
2 changes: 1 addition & 1 deletion src/rfc3986/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,4 @@ def merge_paths(base_uri: "uri.URIReference", relative_path: str) -> str:
return path[:index] + "/" + relative_path


UseExisting = object()
UseExisting: t.Any = object()
Loading

0 comments on commit 0179352

Please sign in to comment.