-
Notifications
You must be signed in to change notification settings - Fork 0
Clone dev 11171 #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Clone dev 11171 #11
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -109,6 +109,9 @@ def split_and_match_files_list(paths: Sequence[str]) -> list[str]: | |||||||||||||||||||||||||||||||||||
expanded_paths = [] | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
for path in paths: | ||||||||||||||||||||||||||||||||||||
if not path: | ||||||||||||||||||||||||||||||||||||
continue | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
path = expand_path(path.strip()) | ||||||||||||||||||||||||||||||||||||
globbed_files = fileglob.glob(path, recursive=True) | ||||||||||||||||||||||||||||||||||||
if globbed_files: | ||||||||||||||||||||||||||||||||||||
|
@@ -318,6 +321,23 @@ def parse_config_file( | |||||||||||||||||||||||||||||||||||
print(f"{file_read}: No [mypy] section in config file", file=stderr) | ||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||
section = parser["mypy"] | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
if "files" in section: | ||||||||||||||||||||||||||||||||||||
raw_files = section["files"].strip() | ||||||||||||||||||||||||||||||||||||
files_split = [file.strip() for file in raw_files.split(",")] | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
# Remove trailing empty entry if present | ||||||||||||||||||||||||||||||||||||
if files_split and files_split[-1] == "": | ||||||||||||||||||||||||||||||||||||
files_split.pop() | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
# Raise an error if there are any remaining empty strings | ||||||||||||||||||||||||||||||||||||
if "" in files_split: | ||||||||||||||||||||||||||||||||||||
raise ValueError( | ||||||||||||||||||||||||||||||||||||
"Invalid config: Empty filenames are not allowed except for trailing commas." | ||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||
Comment on lines
+334
to
+337
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Uninformative Error MessageThe error message doesn't provide specific information about which entries are empty or their positions in the input. This violates the repository guideline that error messages should be more informative to help users debug configuration issues. Standards
|
||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
options.files = files_split | ||||||||||||||||||||||||||||||||||||
Comment on lines
+324
to
+339
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical: Bypasses existing file processing logic. This custom parsing bypasses the registered
Without these, users cannot use globs or environment variables in INI files, creating an inconsistency with TOML (line 207 uses Remove this custom parsing and let - if "files" in section:
- raw_files = section["files"].strip()
- files_split = [file.strip() for file in raw_files.split(",")]
-
- # Remove trailing empty entry if present
- if files_split and files_split[-1] == "":
- files_split.pop()
-
- # Raise an error if there are any remaining empty strings
- if "" in files_split:
- raise ValueError(
- "Invalid config: Empty filenames are not allowed except for trailing commas."
- )
-
- options.files = files_split
-
prefix = f"{file_read}: [mypy]: " If empty-string validation is needed, add it to 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
Comment on lines
+325
to
+339
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Inconsistent Validation PatternThe code performs partial cleanup before validation by removing trailing empty entries, then validates the remaining input. This violates the repository guideline to validate complete input consistently rather than special-casing positions like trailing elements. Standards
|
||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
prefix = f"{file_read}: [mypy]: " | ||||||||||||||||||||||||||||||||||||
updates, report_dirs = parse_section( | ||||||||||||||||||||||||||||||||||||
prefix, options, set_strict_flags, section, config_types, stderr | ||||||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
import os | ||
import tempfile | ||
from unittest import TestCase, main | ||
|
||
from mypy.config_parser import parse_config_file | ||
from mypy.options import Options | ||
|
||
|
||
class TestConfigParser(TestCase): | ||
def test_parse_config_file_with_single_file(self) -> None: | ||
"""A single file should be correctly parsed.""" | ||
with tempfile.TemporaryDirectory() as tmpdirname: | ||
config_path = os.path.join(tmpdirname, "test_config.ini") | ||
|
||
with open(config_path, "w") as f: | ||
f.write( | ||
""" | ||
[mypy] | ||
files = file1.py | ||
""" | ||
) | ||
|
||
options = Options() | ||
|
||
parse_config_file(options, lambda: None, config_path, stdout=None, stderr=None) | ||
|
||
self.assertEqual(options.files, ["file1.py"]) | ||
|
||
def test_parse_config_file_with_no_spaces(self) -> None: | ||
"""Files listed without spaces should be correctly parsed.""" | ||
with tempfile.TemporaryDirectory() as tmpdirname: | ||
config_path = os.path.join(tmpdirname, "test_config.ini") | ||
|
||
with open(config_path, "w") as f: | ||
f.write( | ||
""" | ||
[mypy] | ||
files =file1.py,file2.py,file3.py | ||
""" | ||
) | ||
|
||
options = Options() | ||
|
||
parse_config_file(options, lambda: None, config_path, stdout=None, stderr=None) | ||
|
||
self.assertEqual(options.files, ["file1.py", "file2.py", "file3.py"]) | ||
|
||
def test_parse_config_file_with_extra_spaces(self) -> None: | ||
"""Files with extra spaces should be correctly parsed.""" | ||
with tempfile.TemporaryDirectory() as tmpdirname: | ||
config_path = os.path.join(tmpdirname, "test_config.ini") | ||
|
||
with open(config_path, "w") as f: | ||
f.write( | ||
""" | ||
[mypy] | ||
files = file1.py , file2.py , file3.py | ||
""" | ||
) | ||
|
||
options = Options() | ||
|
||
parse_config_file(options, lambda: None, config_path, stdout=None, stderr=None) | ||
|
||
self.assertEqual(options.files, ["file1.py", "file2.py", "file3.py"]) | ||
|
||
def test_parse_config_file_with_empty_files_key(self) -> None: | ||
"""An empty files key should result in an empty list.""" | ||
with tempfile.TemporaryDirectory() as tmpdirname: | ||
config_path = os.path.join(tmpdirname, "test_config.ini") | ||
|
||
with open(config_path, "w") as f: | ||
f.write( | ||
""" | ||
[mypy] | ||
files = | ||
""" | ||
) | ||
|
||
options = Options() | ||
|
||
parse_config_file(options, lambda: None, config_path, stdout=None, stderr=None) | ||
|
||
self.assertEqual(options.files, []) | ||
|
||
def test_parse_config_file_with_only_comma(self) -> None: | ||
"""A files key with only a comma should raise an error.""" | ||
with tempfile.TemporaryDirectory() as tmpdirname: | ||
config_path = os.path.join(tmpdirname, "test_config.ini") | ||
|
||
with open(config_path, "w") as f: | ||
f.write( | ||
""" | ||
[mypy] | ||
files = , | ||
""" | ||
) | ||
|
||
options = Options() | ||
|
||
with self.assertRaises(ValueError) as cm: | ||
parse_config_file(options, lambda: None, config_path, stdout=None, stderr=None) | ||
|
||
self.assertIn("Invalid config", str(cm.exception)) | ||
|
||
def test_parse_config_file_with_only_whitespace(self) -> None: | ||
"""A files key with only whitespace should result in an empty list.""" | ||
with tempfile.TemporaryDirectory() as tmpdirname: | ||
config_path = os.path.join(tmpdirname, "test_config.ini") | ||
|
||
with open(config_path, "w") as f: | ||
f.write( | ||
""" | ||
[mypy] | ||
files = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
""" | ||
) | ||
|
||
options = Options() | ||
|
||
parse_config_file(options, lambda: None, config_path, stdout=None, stderr=None) | ||
|
||
self.assertEqual(options.files, []) | ||
|
||
def test_parse_config_file_with_mixed_valid_and_invalid_entries(self) -> None: | ||
"""Mix of valid and invalid filenames should raise an error.""" | ||
with tempfile.TemporaryDirectory() as tmpdirname: | ||
config_path = os.path.join(tmpdirname, "test_config.ini") | ||
|
||
with open(config_path, "w") as f: | ||
f.write( | ||
""" | ||
[mypy] | ||
files = file1.py, , , file2.py | ||
""" | ||
) | ||
|
||
options = Options() | ||
|
||
with self.assertRaises(ValueError) as cm: | ||
parse_config_file(options, lambda: None, config_path, stdout=None, stderr=None) | ||
|
||
self.assertIn("Invalid config", str(cm.exception)) | ||
|
||
def test_parse_config_file_with_newlines_between_files(self) -> None: | ||
"""Newlines between file entries should be correctly handled.""" | ||
with tempfile.TemporaryDirectory() as tmpdirname: | ||
config_path = os.path.join(tmpdirname, "test_config.ini") | ||
|
||
with open(config_path, "w") as f: | ||
f.write( | ||
""" | ||
[mypy] | ||
files = file1.py, | ||
file2.py, | ||
file3.py | ||
""" | ||
) | ||
|
||
options = Options() | ||
|
||
parse_config_file(options, lambda: None, config_path, stdout=None, stderr=None) | ||
|
||
self.assertEqual(options.files, ["file1.py", "file2.py", "file3.py"]) | ||
Comment on lines
+9
to
+164
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Test coverage gaps: Missing glob and path expansion validation. These tests validate the custom parsing at mypy/config_parser.py lines 324-339, but that implementation bypasses the existing
Additionally, 🤖 Prompt for AI Agents
|
||
|
||
|
||
if __name__ == "__main__": | ||
main() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check for an empty path is good, but it doesn't account for paths that consist only of whitespace. A path like
' '
will pass theif not path:
check, butpath.strip()
on the next line will turn it into an empty string, which will then be processed and likely added toexpanded_paths
.To handle this correctly, you should strip the path before checking if it's empty.