Source code for brunns.matchers.url

import logging
from collections.abc import Mapping, Sequence
from typing import Union

from deprecated import deprecated
from furl import furl
from hamcrest import anything
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest.core.description import Description
from hamcrest.core.helpers.wrap_matcher import wrap_matcher
from hamcrest.core.matcher import Matcher
from yarl import URL

from brunns.matchers.utils import (
    append_matcher_description,
    describe_field_match,
    describe_field_mismatch,
)

logger = logging.getLogger(__name__)
ANYTHING = anything()


[docs] def is_url() -> "UrlWith": """Matches a string (or ``furl`` / ``yarl.URL`` object) as a URL. This function returns a :class:`UrlWith` matcher which can be refined using builder methods to match specific parts of the URL (e.g. ``.with_host(...)``, ``.with_query(...)``). :return: A matcher for URL components. """ return UrlWith()
[docs] class UrlWith(BaseMatcher[Union[str, URL, furl]]): """Matches specific components of a URL. The matcher parses the actual value using the ``furl`` library. :param host: Expected hostname (e.g., "google.com"). :param path: Expected path string (e.g., "/search"). :param query: Expected query parameters dictionary. :param fragment: Expected URL fragment (hash). """ def __init__( self, host: Union[str, Matcher[str]] = ANYTHING, path: Union[str, Matcher[str]] = ANYTHING, query: Union[ Mapping[str, Union[str, Matcher[str]]], Matcher[Mapping[str, Union[str, Matcher[str]]]], ] = ANYTHING, fragment: Union[str, Matcher[str]] = ANYTHING, ) -> None: super().__init__() self.scheme: Matcher[str] = ANYTHING self.username: Matcher[str] = ANYTHING self.password: Matcher[str] = ANYTHING self.host = wrap_matcher(host) self.port: Matcher[int] = ANYTHING self.path = wrap_matcher(path) self.path_segments: Matcher[Sequence[str]] = ANYTHING self.query = wrap_matcher(query) self.fragment = wrap_matcher(fragment) def _matches(self, url: Union[str, URL, furl]) -> bool: url = furl(url) return ( self.scheme.matches(url.scheme) and self.username.matches(url.username) and self.password.matches(url.password) and self.host.matches(url.host) and self.port.matches(url.port) and self.path.matches(url.path) and self.path_segments.matches(url.path.segments) and self.query.matches(url.query.params) and self.fragment.matches(url.fragment) )
[docs] def describe_to(self, description: Description) -> None: description.append_text("URL with") append_matcher_description(self.scheme, "scheme", description) append_matcher_description(self.username, "username", description) append_matcher_description(self.password, "password", description) append_matcher_description(self.host, "host", description) append_matcher_description(self.port, "port", description) append_matcher_description(self.path, "path", description) append_matcher_description(self.path_segments, "path segments", description) append_matcher_description(self.query, "query", description) append_matcher_description(self.fragment, "fragment", description)
[docs] def describe_mismatch(self, url: Union[str, URL, furl], mismatch_description: Description) -> None: url = furl(url) mismatch_description.append_text("was URL with") describe_field_mismatch(self.scheme, "scheme", url.scheme, mismatch_description) describe_field_mismatch(self.username, "username", url.username, mismatch_description) describe_field_mismatch(self.password, "password", url.password, mismatch_description) describe_field_mismatch(self.host, "host", url.host, mismatch_description) describe_field_mismatch(self.port, "port", url.port, mismatch_description) describe_field_mismatch(self.path, "path", url.path, mismatch_description) describe_field_mismatch(self.path_segments, "path segments", url.path.segments, mismatch_description) describe_field_mismatch(self.query, "query", url.query.params, mismatch_description) describe_field_mismatch(self.fragment, "fragment", url.fragment, mismatch_description)
[docs] def describe_match(self, url: Union[str, URL, furl], match_description: Description) -> None: url = furl(url) match_description.append_text("was URL with") describe_field_match(self.scheme, "scheme", url.scheme, match_description) describe_field_match(self.username, "username", url.username, match_description) describe_field_match(self.password, "password", url.password, match_description) describe_field_match(self.host, "host", url.host, match_description) describe_field_match(self.port, "port", url.port, match_description) describe_field_match(self.path, "path", url.path, match_description) describe_field_match(self.path_segments, "path segments", url.path.segments, match_description) describe_field_match(self.query, "query", url.query.params, match_description) describe_field_match(self.fragment, "fragment", url.fragment, match_description)
[docs] def with_scheme(self, scheme: Union[str, Matcher[str]]): """Matches if the URL scheme matches the given value or matcher. :param scheme: The expected scheme (e.g. "https") or matcher. :return: Self, for chaining. """ self.scheme = wrap_matcher(scheme) return self
[docs] def and_scheme(self, scheme: Union[str, Matcher[str]]): """Matches if the URL scheme matches the given value or matcher. A synonym for :meth:`with_scheme`. :param scheme: The expected scheme or matcher. :return: Self, for chaining. """ return self.with_scheme(scheme)
[docs] def with_username(self, username: Union[str, Matcher[str]]): """Matches if the URL username matches the given value or matcher. :param username: The expected username or matcher. :return: Self, for chaining. """ self.username = wrap_matcher(username) return self
[docs] def and_username(self, username: Union[str, Matcher[str]]): """Matches if the URL username matches the given value or matcher. A synonym for :meth:`with_username`. :param username: The expected username or matcher. :return: Self, for chaining. """ return self.with_username(username)
[docs] def with_password(self, password: Union[str, Matcher[str]]): """Matches if the URL password matches the given value or matcher. :param password: The expected password or matcher. :return: Self, for chaining. """ self.password = wrap_matcher(password) return self
[docs] def and_password(self, password: Union[str, Matcher[str]]): """Matches if the URL password matches the given value or matcher. A synonym for :meth:`with_password`. :param password: The expected password or matcher. :return: Self, for chaining. """ return self.with_password(password)
[docs] def with_host(self, host: Union[str, Matcher[str]]): """Matches if the URL host matches the given value or matcher. :param host: The expected hostname or matcher. :return: Self, for chaining. """ self.host = wrap_matcher(host) return self
[docs] def and_host(self, host: Union[str, Matcher[str]]): """Matches if the URL host matches the given value or matcher. A synonym for :meth:`with_host`. :param host: The expected hostname or matcher. :return: Self, for chaining. """ return self.with_host(host)
[docs] def with_port(self, port: Union[int, Matcher[int]]): """Matches if the URL port matches the given value or matcher. :param port: The expected port integer or matcher. :return: Self, for chaining. """ self.port = wrap_matcher(port) return self
[docs] def and_port(self, port: Union[int, Matcher[int]]): """Matches if the URL port matches the given value or matcher. A synonym for :meth:`with_port`. :param port: The expected port integer or matcher. :return: Self, for chaining. """ return self.with_port(port)
[docs] def with_path(self, path: Union[str, Matcher[str]]): """Matches if the URL path matches the given value or matcher. :param path: The expected path string (e.g. "/foo/bar") or matcher. :return: Self, for chaining. """ self.path = wrap_matcher(path) return self
[docs] def and_path(self, path: Union[str, Matcher[str]]): """Matches if the URL path matches the given value or matcher. A synonym for :meth:`with_path`. :param path: The expected path string or matcher. :return: Self, for chaining. """ return self.with_path(path)
[docs] def with_path_segments(self, path_segments: Union[Sequence[str], Matcher[Sequence[str]]]): """Matches if the URL path segments match the given sequence or matcher. :param path_segments: The expected sequence of path segments (e.g. ["foo", "bar"]) or matcher. :return: Self, for chaining. """ self.path_segments = wrap_matcher(path_segments) return self
[docs] def and_path_segments(self, path_segments: Union[Sequence[str], Matcher[Sequence[str]]]): """Matches if the URL path segments match the given sequence or matcher. A synonym for :meth:`with_path_segments`. :param path_segments: The expected sequence of path segments or matcher. :return: Self, for chaining. """ return self.with_path_segments(path_segments)
[docs] def with_query( self, query: Union[Mapping[str, Union[str, Matcher[str]]], Matcher[Mapping[str, Union[str, Matcher[str]]]]], ): """Matches if the URL query parameters match the given dictionary or matcher. :param query: The expected query parameters dictionary or matcher. :return: Self, for chaining. """ self.query = wrap_matcher(query) return self
[docs] def and_query( self, query: Union[Mapping[str, Union[str, Matcher[str]]], Matcher[Mapping[str, Union[str, Matcher[str]]]]], ): """Matches if the URL query parameters match the given dictionary or matcher. A synonym for :meth:`with_query`. :param query: The expected query parameters dictionary or matcher. :return: Self, for chaining. """ return self.with_query(query)
[docs] def with_fragment(self, fragment: Union[str, Matcher[str]]): """Matches if the URL fragment (hash) matches the given value or matcher. :param fragment: The expected fragment string or matcher. :return: Self, for chaining. """ self.fragment = wrap_matcher(fragment) return self
[docs] def and_fragment(self, fragment: Union[str, Matcher[str]]): """Matches if the URL fragment (hash) matches the given value or matcher. A synonym for :meth:`with_fragment`. :param fragment: The expected fragment string or matcher. :return: Self, for chaining. """ return self.with_fragment(fragment)
[docs] @deprecated(version="2.3.0", reason="Use builder style is_url()") def url_with_host(matcher: Union[str, Matcher]): # pragma: no cover """Matches URL with specific host. .. deprecated:: 2.3.0 Use ``is_url().with_host(...)`` instead. """ return UrlWith(host=matcher)
[docs] @deprecated(version="2.3.0", reason="Use builder style is_url()") def url_with_path(matcher: Union[str, Matcher]): # pragma: no cover """Matches URL with specific path. .. deprecated:: 2.3.0 Use ``is_url().with_path(...)`` instead. """ return UrlWith(path=matcher)
[docs] @deprecated(version="2.3.0", reason="Use builder style is_url()") def url_with_query(matcher: Union[Mapping[str, str], Matcher]): # pragma: no cover """Matches URL with specific query parameters. .. deprecated:: 2.3.0 Use ``is_url().with_query(...)`` instead. """ return UrlWith(query=matcher)
[docs] @deprecated(version="2.3.0", reason="Use builder style is_url()") def url_with_fragment(matcher: Union[str, Matcher]): # pragma: no cover """Matches URL with specific fragment. .. deprecated:: 2.3.0 Use ``is_url().with_fragment(...)`` instead. """ return UrlWith(fragment=matcher)
[docs] @deprecated(version="2.2.0", reason="Use builder style is_url()") def to_host(matcher: Union[str, Matcher]): # pragma: no cover """Matches URL with specific host. .. deprecated:: 2.2.0 Use ``is_url().with_host(...)`` instead. """ return url_with_host(matcher)
[docs] @deprecated(version="2.2.0", reason="Use builder style is_url()") def with_path(matcher: Union[str, Matcher]): # pragma: no cover """Matches URL with specific path. .. deprecated:: 2.2.0 Use ``is_url().with_path(...)`` instead. """ return url_with_path(matcher)
[docs] @deprecated(version="2.2.0", reason="Use builder style is_url()") def with_query(matcher: Union[Mapping[str, str], Matcher]): # pragma: no cover """Matches URL with specific query parameters. .. deprecated:: 2.2.0 Use ``is_url().with_query(...)`` instead. """ return url_with_query(matcher)
[docs] @deprecated(version="2.2.0", reason="Use builder style is_url()") def with_fragment(matcher: Union[str, Matcher]): # pragma: no cover """Matches URL with specific fragment. .. deprecated:: 2.2.0 Use ``is_url().with_fragment(...)`` instead. """ return url_with_fragment(matcher)