Skip to content

Create new config option 'config_names' #42

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

Merged
merged 2 commits into from
Jan 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ Configuration
``dmypy_status_file`` (Default is ``.dmypy.json``) specifies which status file dmypy should use.
This modifies the ``--status-file`` option passed to ``dmypy`` given ``dmypy`` is active.

``config_sub_paths`` (default is ``[]``) specifies sub paths under which the mypy configuration file may be found.
For each directory searched for the mypy config file, this also searches the sub paths specified here

This project supports the use of ``pyproject.toml`` for configuration. It is in fact the preferred way. Using that your configuration could look like this:

::
Expand Down Expand Up @@ -91,6 +94,15 @@ With ``dmypy_status_file`` your config could look like this:
"dmypy_status_file": ".custom_dmypy_status_file.json"
}

With ``config_sub_paths`` your config could look like this:

::

{
"enabled": True,
"config_sub_paths": [".config"]
}

Developing
-------------

Expand Down
53 changes: 30 additions & 23 deletions pylsp_mypy/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ def init(workspace: str) -> Dict[str, str]:

configuration = {}
path = findConfigFile(
workspace, ["pylsp-mypy.cfg", "mypy-ls.cfg", "mypy_ls.cfg", "pyproject.toml"], False
workspace, [], ["pylsp-mypy.cfg", "mypy-ls.cfg", "mypy_ls.cfg", "pyproject.toml"], False
)
if path:
if "pyproject.toml" in path:
Expand All @@ -367,16 +367,19 @@ def init(workspace: str) -> Dict[str, str]:
with open(path) as file:
configuration = ast.literal_eval(file.read())

configSubPaths = configuration.get("config_sub_paths", [])
mypyConfigFile = findConfigFile(
workspace, ["mypy.ini", ".mypy.ini", "pyproject.toml", "setup.cfg"], True
workspace, configSubPaths, ["mypy.ini", ".mypy.ini", "pyproject.toml", "setup.cfg"], True
)
mypyConfigFileMap[workspace] = mypyConfigFile

log.info("mypyConfigFile = %s configuration = %s", mypyConfigFile, configuration)
return configuration


def findConfigFile(path: str, names: List[str], mypy: bool) -> Optional[str]:
def findConfigFile(
path: str, configSubPaths: List[str], names: List[str], mypy: bool
) -> Optional[str]:
"""
Search for a config file.

Expand All @@ -387,6 +390,8 @@ def findConfigFile(path: str, names: List[str], mypy: bool) -> Optional[str]:
----------
path : str
The path where the search starts.
configSubPaths : List[str]
Additional sub search paths in which mypy configs might be located
names : List[str]
The file to be found (or alternative names).
mypy : bool
Expand All @@ -401,26 +406,28 @@ def findConfigFile(path: str, names: List[str], mypy: bool) -> Optional[str]:
start = Path(path).joinpath(names[0]) # the join causes the parents to include path
for parent in start.parents:
for name in names:
file = parent.joinpath(name)
if file.is_file():
if file.name in ["mypy-ls.cfg", "mypy_ls.cfg"]:
raise NameError(
f"{str(file)}: {file.name} is no longer supported, you should rename your "
"config file to pylsp-mypy.cfg or preferably use a pyproject.toml instead."
)
if file.name == "pyproject.toml":
configPresent = (
toml.load(file).get("tool", {}).get("mypy" if mypy else "pylsp-mypy")
is not None
)
if not configPresent:
continue
if file.name == "setup.cfg":
config = ConfigParser()
config.read(str(file))
if "mypy" not in config:
continue
return str(file)
for subPath in [""] + configSubPaths:
file = parent.joinpath(subPath).joinpath(name)
if file.is_file():
if file.name in ["mypy-ls.cfg", "mypy_ls.cfg"]:
raise NameError(
f"{str(file)}: {file.name} is no longer supported, you should rename "
"your config file to pylsp-mypy.cfg or preferably use a pyproject.toml "
"instead."
)
if file.name == "pyproject.toml":
configPresent = (
toml.load(file).get("tool", {}).get("mypy" if mypy else "pylsp-mypy")
is not None
)
if not configPresent:
continue
if file.name == "setup.cfg":
config = ConfigParser()
config.read(str(file))
if "mypy" not in config:
continue
return str(file)
# No config file found in the whole directory tree
# -> check mypy default locations for mypy config
if mypy:
Expand Down
36 changes: 34 additions & 2 deletions test/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from pylsp_mypy import plugin

# TODO using these file as a document is a bad idea as tests can break by adding new tests
DOC_URI = f"file:/{Path(__file__)}"
DOC_TYPE_ERR = """{}.append(3)
"""
Expand Down Expand Up @@ -69,8 +70,7 @@ def test_plugin(workspace, last_diagnostics_monkeypatch):


def test_parse_full_line(workspace):
doc = Document(DOC_URI, workspace)
diag = plugin.parse_line(TEST_LINE, doc)
diag = plugin.parse_line(TEST_LINE) # TODO parse a document here
assert diag["message"] == '"Request" has no attribute "id"'
assert diag["range"]["start"] == {"line": 278, "character": 7}
assert diag["range"]["end"] == {"line": 278, "character": 8}
Expand Down Expand Up @@ -253,3 +253,35 @@ def test_dmypy_status_file(tmpdir, last_diagnostics_monkeypatch, workspace):
)

assert statusFile.exists()


def test_config_sub_paths(tmpdir, last_diagnostics_monkeypatch):
DOC_SOURCE = """
def foo():
return
unreachable = 1
"""
DOC_ERR_MSG = "Statement is unreachable [unreachable]"

config_sub_paths = [".config"]

# Initialize workspace.
ws = Workspace(uris.from_fs_path(str(tmpdir)), Mock())
ws._config = Config(ws.root_uri, {}, 0, {})

# Create configuration file for workspace.
plugin_config = tmpdir.join("pyproject.toml")
plugin_config.write(f"[tool.pylsp-mypy]\nenabled = true\nconfig_sub_paths = {config_sub_paths}")
config_dir = tmpdir.mkdir(".config")
mypy_config = config_dir.join("mypy.ini")
mypy_config.write("[mypy]\nwarn_unreachable = True\ncheck_untyped_defs = True")

# Update settings for workspace.
plugin.pylsp_settings(ws._config)

# Test document to make sure it uses .config/mypy.ini configuration.
doc = Document(DOC_URI, ws, DOC_SOURCE)
diags = plugin.pylsp_lint(ws._config, ws, doc, is_saved=False)
assert len(diags) == 1
diag = diags[0]
assert diag["message"] == DOC_ERR_MSG