(expected_target: str, actual_location: str | None)
| 180 | |
| 181 | |
| 182 | def location_matches(expected_target: str, actual_location: str | None) -> bool: |
| 183 | if actual_location is None: |
| 184 | return False |
| 185 | actual = normalize_location(actual_location) |
| 186 | if expected_target.startswith("re:"): |
| 187 | return re.fullmatch(expected_target[3:], actual or "") is not None |
| 188 | if expected_target.startswith("http://") or expected_target.startswith("https://"): |
| 189 | return actual == expected_target |
| 190 | # Relative targets may come back relative or absolute. |
| 191 | if actual == expected_target: |
| 192 | return True |
| 193 | parsed = urllib.parse.urlsplit(actual) |
| 194 | if parsed.scheme and parsed.netloc: |
| 195 | actual_path_q = urllib.parse.urlunsplit(("", "", parsed.path, parsed.query, "")) |
| 196 | return actual_path_q == expected_target |
| 197 | return False |
| 198 | |
| 199 | |
| 200 | class NoRedirectHandler(urllib.request.HTTPRedirectHandler): |
no test coverage detected