Skip to content
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

Add some helpful flake8 plugins #136

Merged
merged 6 commits into from
Sep 28, 2022
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
4 changes: 4 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ repos:
rev: "5.0.4"
hooks:
- id: flake8
additional_dependencies:
- flake8-bugbear==22.9.23
- flake8-comprehensions==3.10.0
- flake8-simplify==0.19.3
18 changes: 9 additions & 9 deletions deptry/dependency_getter/pyproject_toml.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import contextlib
import logging
from typing import Any, Dict, List, Union

Expand Down Expand Up @@ -25,7 +26,7 @@ def get(self) -> List[Dependency]:
dependencies = []
for dep, spec in pyproject_toml_dependencies.items():
# dep is the dependency name, spec is the version specification, e.g. "^0.2.2" or {"*", optional = true}
if not dep == "python":
if dep != "python":
optional = self._is_optional(dep, spec)
conditional = self._is_conditional(dep, spec)
dependencies.append(Dependency(dep, conditional=conditional, optional=optional))
Expand All @@ -49,14 +50,13 @@ def _get_pyproject_toml_dev_dependencies(self) -> Dict[str, Any]:
"""
dev_dependencies: Dict[str, str] = {}
pyproject_data = load_pyproject_toml()
try:

with contextlib.suppress(KeyError):
dev_dependencies = {**pyproject_data["tool"]["poetry"]["dev-dependencies"], **dev_dependencies}
except KeyError:
pass
try:

with contextlib.suppress(KeyError):
dev_dependencies = {**pyproject_data["tool"]["poetry"]["group"]["dev"]["dependencies"], **dev_dependencies}
except KeyError:
pass

return dev_dependencies

def _log_dependencies(self, dependencies: List[Dependency]) -> None:
Expand All @@ -68,13 +68,13 @@ def _log_dependencies(self, dependencies: List[Dependency]) -> None:
@staticmethod
def _is_optional(dep: str, spec: Union[str, dict]) -> bool:
# if of the shape `isodate = {version = "*", optional = true}` mark as optional`
if isinstance(spec, dict) and "optional" in spec.keys() and spec["optional"]:
if isinstance(spec, dict) and "optional" in spec and spec["optional"]:
return True
return False

@staticmethod
def _is_conditional(dep: str, spec: Union[str, dict]) -> bool:
# if of the shape `tomli = { version = "^2.0.1", python = "<3.11" }`, mark as conditional.
if isinstance(spec, dict) and "python" in spec.keys() and "version" in spec.keys():
if isinstance(spec, dict) and "python" in spec and "version" in spec:
return True
return False
12 changes: 6 additions & 6 deletions deptry/dependency_getter/requirements_txt.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging
import os
import re
from typing import List, Optional, Tuple, Union
from typing import List, Optional, Tuple

from deptry.dependency import Dependency

Expand Down Expand Up @@ -62,7 +62,7 @@ def _get_dependencies_from_requirements_file(self, file_name: str) -> List[Depen

return dependencies

def _extract_dependency_from_line(self, line: str) -> Union[Dependency, None]:
def _extract_dependency_from_line(self, line: str) -> Optional[Dependency]:
"""
Extract a dependency from a single line of a requirements.txt file.
"""
Expand All @@ -77,7 +77,7 @@ def _extract_dependency_from_line(self, line: str) -> Union[Dependency, None]:
else:
return None

def _find_dependency_name_in(self, line: str) -> Union[str, None]:
def _find_dependency_name_in(self, line: str) -> Optional[str]:
"""
Find the dependency name of a dependency specified according to the pip-standards for requirement.txt
"""
Expand All @@ -99,11 +99,11 @@ def _remove_newlines_from(line: str) -> str:

@staticmethod
def _check_if_dependency_is_optional(line: str) -> bool:
return True if re.findall(r"\[([a-zA-Z0-9-]+?)\]", line) else False
return bool(re.findall(r"\[([a-zA-Z0-9-]+?)\]", line))

@staticmethod
def _check_if_dependency_is_conditional(line: str) -> bool:
return True if ";" in line else False
return ";" in line

def _log_dependencies(self, dependencies: List[Dependency]) -> None:
logging.debug(f"The project contains the following {'dev-' if self.dev else ''}dependencies:")
Expand All @@ -116,7 +116,7 @@ def _line_is_url(line: str) -> Optional[re.Match]:
return re.search("^(http|https|git\+https)", line)

@staticmethod
def _extract_name_from_url(line: str) -> Union[str, None]:
def _extract_name_from_url(line: str) -> Optional[str]:

# Try to find egg, for url like git+https://github.com/xxxxx/package@xxxxx#egg=package
match = re.search("egg=([a-zA-Z0-9-_]*)", line)
Expand Down
20 changes: 9 additions & 11 deletions deptry/import_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def get_imported_modules_for_list_of_files(self, list_of_files: List[Path]) -> L
logging.info(f"Scanning {len(list_of_files)} files...")
modules_per_file = [self.get_imported_modules_from_file(file) for file in list_of_files]
all_modules = self._flatten_list(modules_per_file)
unique_modules = sorted(list(set(all_modules)))
unique_modules = sorted(set(all_modules))
unique_modules = self._filter_exceptions(unique_modules)
logging.debug(f"All imported modules: {unique_modules}\n")
return unique_modules
Expand All @@ -34,7 +34,7 @@ def get_imported_modules_from_file(self, path_to_file: Path) -> List[str]:
modules = self._get_imported_modules_from_ipynb(path_to_file)
else:
modules = self._get_imported_modules_from_py(path_to_file)
modules = sorted(list(set(modules)))
modules = sorted(set(modules))
logging.debug(f"Found the following imports in {str(path_to_file)}: {modules}")
except AttributeError as e:
logging.warning(f"Warning: Parsing imports for file {str(path_to_file)} failed.")
Expand Down Expand Up @@ -84,7 +84,7 @@ def _get_import_nodes_from(
for node in ast.iter_child_nodes(root):
if any([isinstance(node, recursion_type) for recursion_type in RECURSION_TYPES]):
imports += self._get_import_nodes_from(node)
elif isinstance(node, ast.Import) or isinstance(node, ast.ImportFrom):
elif isinstance(node, (ast.Import, ast.ImportFrom)):
imports += [node]
return imports

Expand All @@ -94,11 +94,9 @@ def _get_import_modules_from(nodes: List[Union[ast.Import, ast.ImportFrom]]) ->
for node in nodes:
if isinstance(node, ast.Import):
modules += [x.name.split(".")[0] for x in node.names]
elif isinstance(node, ast.ImportFrom):
if (
node.module and node.level == 0
): # nodes for imports like `from . import foo` do not have a module attribute.
modules.append(node.module.split(".")[0])
# nodes for imports like `from . import foo` do not have a module attribute.
elif isinstance(node, ast.ImportFrom) and node.module and node.level == 0:
modules.append(node.module.split(".")[0])
return modules

@staticmethod
Expand All @@ -117,10 +115,10 @@ def _filter_exceptions(modules: List[str]) -> List[str]:
for exception in exceptions:
if exception in modules:
logging.debug(f"Found module {exception} to be imported, omitting from the list of modules.")
modules = [module for module in modules if not module == exception]
modules = [module for module in modules if module != exception]
return modules

@staticmethod
def _get_file_encoding(file_name: Union[str, Path]) -> str:
rawdata = open(file_name, "rb").read()
return chardet.detect(rawdata)["encoding"]
with open(file_name, "rb") as f:
return chardet.detect(f.read())["encoding"]
5 changes: 2 additions & 3 deletions deptry/issue_finders/misplaced_dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,8 @@ def find(self) -> List[str]:
for module in self.imported_modules:
logging.debug(f"Scanning module {module.name}...")
corresponding_package_name = self._get_package_name(module)
if corresponding_package_name:
if self._is_development_dependency(module, corresponding_package_name):
misplaced_dev_dependencies.append(corresponding_package_name)
if corresponding_package_name and self._is_development_dependency(module, corresponding_package_name):
misplaced_dev_dependencies.append(corresponding_package_name)
return misplaced_dev_dependencies

def _is_development_dependency(self, module: Module, corresponding_package_name: str) -> bool:
Expand Down
11 changes: 8 additions & 3 deletions deptry/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,12 @@ def __str__(self) -> str:


class ModuleBuilder:
def __init__(self, name: str, dependencies: List[Dependency] = [], dev_dependencies: List[Dependency] = []) -> None:
def __init__(
self,
name: str,
dependencies: Optional[List[Dependency]] = None,
dev_dependencies: Optional[List[Dependency]] = None,
) -> None:
"""
Create a Module object that represents an imported module.

Expand All @@ -58,8 +63,8 @@ def __init__(self, name: str, dependencies: List[Dependency] = [], dev_dependenc
dev-dependencies: A list of the project's development dependencies
"""
self.name = name
self.dependencies = dependencies
self.dev_dependencies = dev_dependencies
self.dependencies = dependencies or []
self.dev_dependencies = dev_dependencies or []

def build(self) -> Module:
"""
Expand Down