Skip to content

Commit 4bde808

Browse files
Reject string-subclass file error messages
Co-authored-by: Shri Sukhani <shrisukhani@users.noreply.github.com>
1 parent 12c9ff8 commit 4bde808

2 files changed

Lines changed: 44 additions & 150 deletions

File tree

hyperbrowser/client/file_utils.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77

88
def _validate_error_message_text(message_value: str, *, field_name: str) -> None:
9-
if not isinstance(message_value, str):
9+
if type(message_value) is not str:
1010
raise HyperbrowserError(f"{field_name} must be a string")
1111
try:
1212
normalized_message = message_value.strip()
@@ -24,8 +24,7 @@ def _validate_error_message_text(message_value: str, *, field_name: str) -> None
2424
raise HyperbrowserError(f"{field_name} must not be empty")
2525
try:
2626
contains_control_character = any(
27-
ord(character) < 32 or ord(character) == 127
28-
for character in message_value
27+
ord(character) < 32 or ord(character) == 127 for character in message_value
2928
)
3029
except HyperbrowserError:
3130
raise

tests/test_file_utils.py

Lines changed: 42 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,27 @@ def test_ensure_existing_file_path_rejects_non_string_missing_message(tmp_path:
3434
)
3535

3636

37+
def test_ensure_existing_file_path_rejects_string_subclass_missing_message(
38+
tmp_path: Path,
39+
):
40+
class _MissingMessage(str):
41+
pass
42+
43+
file_path = tmp_path / "file.txt"
44+
file_path.write_text("content")
45+
46+
with pytest.raises(
47+
HyperbrowserError, match="missing_file_message must be a string"
48+
) as exc_info:
49+
ensure_existing_file_path(
50+
str(file_path),
51+
missing_file_message=_MissingMessage("missing"),
52+
not_file_message="not-file",
53+
)
54+
55+
assert exc_info.value.original_error is None
56+
57+
3758
def test_ensure_existing_file_path_rejects_blank_missing_message(tmp_path: Path):
3859
file_path = tmp_path / "file.txt"
3960
file_path.write_text("content")
@@ -77,6 +98,27 @@ def test_ensure_existing_file_path_rejects_non_string_not_file_message(tmp_path:
7798
)
7899

79100

101+
def test_ensure_existing_file_path_rejects_string_subclass_not_file_message(
102+
tmp_path: Path,
103+
):
104+
class _NotFileMessage(str):
105+
pass
106+
107+
file_path = tmp_path / "file.txt"
108+
file_path.write_text("content")
109+
110+
with pytest.raises(
111+
HyperbrowserError, match="not_file_message must be a string"
112+
) as exc_info:
113+
ensure_existing_file_path(
114+
str(file_path),
115+
missing_file_message="missing",
116+
not_file_message=_NotFileMessage("not-file"),
117+
)
118+
119+
assert exc_info.value.original_error is None
120+
121+
80122
def test_ensure_existing_file_path_rejects_blank_not_file_message(tmp_path: Path):
81123
file_path = tmp_path / "file.txt"
82124
file_path.write_text("content")
@@ -354,153 +396,6 @@ def __fspath__(self) -> str:
354396
assert exc_info.value.original_error is None
355397

356398

357-
def test_ensure_existing_file_path_wraps_missing_message_strip_runtime_errors(
358-
tmp_path: Path,
359-
):
360-
class _BrokenMissingMessage(str):
361-
def strip(self, chars=None): # type: ignore[override]
362-
_ = chars
363-
raise RuntimeError("missing message strip exploded")
364-
365-
file_path = tmp_path / "file.txt"
366-
file_path.write_text("content")
367-
368-
with pytest.raises(
369-
HyperbrowserError, match="Failed to normalize missing_file_message"
370-
) as exc_info:
371-
ensure_existing_file_path(
372-
str(file_path),
373-
missing_file_message=_BrokenMissingMessage("missing"),
374-
not_file_message="not-file",
375-
)
376-
377-
assert isinstance(exc_info.value.original_error, RuntimeError)
378-
379-
380-
def test_ensure_existing_file_path_wraps_missing_message_string_subclass_strip_results(
381-
tmp_path: Path,
382-
):
383-
class _BrokenMissingMessage(str):
384-
class _NormalizedMessage(str):
385-
pass
386-
387-
def strip(self, chars=None): # type: ignore[override]
388-
_ = chars
389-
return self._NormalizedMessage("missing")
390-
391-
file_path = tmp_path / "file.txt"
392-
file_path.write_text("content")
393-
394-
with pytest.raises(
395-
HyperbrowserError, match="Failed to normalize missing_file_message"
396-
) as exc_info:
397-
ensure_existing_file_path(
398-
str(file_path),
399-
missing_file_message=_BrokenMissingMessage("missing"),
400-
not_file_message="not-file",
401-
)
402-
403-
assert isinstance(exc_info.value.original_error, TypeError)
404-
405-
406-
def test_ensure_existing_file_path_wraps_missing_message_character_validation_failures(
407-
tmp_path: Path,
408-
):
409-
class _BrokenMissingMessage(str):
410-
def strip(self, chars=None): # type: ignore[override]
411-
_ = chars
412-
return "missing"
413-
414-
def __iter__(self):
415-
raise RuntimeError("missing message iteration exploded")
416-
417-
file_path = tmp_path / "file.txt"
418-
file_path.write_text("content")
419-
420-
with pytest.raises(
421-
HyperbrowserError, match="Failed to validate missing_file_message characters"
422-
) as exc_info:
423-
ensure_existing_file_path(
424-
str(file_path),
425-
missing_file_message=_BrokenMissingMessage("missing"),
426-
not_file_message="not-file",
427-
)
428-
429-
assert isinstance(exc_info.value.original_error, RuntimeError)
430-
431-
432-
def test_ensure_existing_file_path_preserves_hyperbrowser_missing_message_strip_errors(
433-
tmp_path: Path,
434-
):
435-
class _BrokenMissingMessage(str):
436-
def strip(self, chars=None): # type: ignore[override]
437-
_ = chars
438-
raise HyperbrowserError("custom missing message strip failure")
439-
440-
file_path = tmp_path / "file.txt"
441-
file_path.write_text("content")
442-
443-
with pytest.raises(
444-
HyperbrowserError, match="custom missing message strip failure"
445-
) as exc_info:
446-
ensure_existing_file_path(
447-
str(file_path),
448-
missing_file_message=_BrokenMissingMessage("missing"),
449-
not_file_message="not-file",
450-
)
451-
452-
assert exc_info.value.original_error is None
453-
454-
455-
def test_ensure_existing_file_path_wraps_not_file_message_strip_runtime_errors(
456-
tmp_path: Path,
457-
):
458-
class _BrokenNotFileMessage(str):
459-
def strip(self, chars=None): # type: ignore[override]
460-
_ = chars
461-
raise RuntimeError("not-file message strip exploded")
462-
463-
file_path = tmp_path / "file.txt"
464-
file_path.write_text("content")
465-
466-
with pytest.raises(
467-
HyperbrowserError, match="Failed to normalize not_file_message"
468-
) as exc_info:
469-
ensure_existing_file_path(
470-
str(file_path),
471-
missing_file_message="missing",
472-
not_file_message=_BrokenNotFileMessage("not-file"),
473-
)
474-
475-
assert isinstance(exc_info.value.original_error, RuntimeError)
476-
477-
478-
def test_ensure_existing_file_path_wraps_not_file_message_string_subclass_strip_results(
479-
tmp_path: Path,
480-
):
481-
class _BrokenNotFileMessage(str):
482-
class _NormalizedMessage(str):
483-
pass
484-
485-
def strip(self, chars=None): # type: ignore[override]
486-
_ = chars
487-
return self._NormalizedMessage("not-file")
488-
489-
file_path = tmp_path / "file.txt"
490-
file_path.write_text("content")
491-
492-
with pytest.raises(
493-
HyperbrowserError, match="Failed to normalize not_file_message"
494-
) as exc_info:
495-
ensure_existing_file_path(
496-
str(file_path),
497-
missing_file_message="missing",
498-
not_file_message=_BrokenNotFileMessage("not-file"),
499-
)
500-
501-
assert isinstance(exc_info.value.original_error, TypeError)
502-
503-
504399
def test_ensure_existing_file_path_rejects_string_subclass_path_inputs_before_strip():
505400
class _BrokenPath(str):
506401
def strip(self, chars=None): # type: ignore[override]

0 commit comments

Comments
 (0)