Move main func into dedicated function

This commit is contained in:
Swen Kooij
2020-02-29 14:56:53 +02:00
parent ada467c043
commit be90c8b9b0
9 changed files with 152 additions and 32 deletions
+28 -16
View File
@@ -1,26 +1,38 @@
import argparse
import sys
from .requirements import RequirementsEditableEntry, RequirementsRecursiveEntry
from .requirements_txt_parser import parse_requirements_txt
from .setup_py_parser import parse_setup_py
from .list import list as list_packages
def main() -> int:
input_file = sys.argv[1]
parser = argparse.ArgumentParser()
parser.add_argument(
"--recurse-recursive",
default=False,
help="recurse into -r entries",
action="store_true",
)
parser.add_argument(
"--recurse-editable",
default=False,
help="recurse into -e entries",
action="store_true",
)
parser.add_argument(
"file_paths",
nargs="+",
help="list of requirements.txt or setup.py files",
)
aggregated_entries = []
for requirement in parse_requirements_txt(input_file):
if isinstance(requirement, RequirementsRecursiveEntry):
aggregated_entries.extend(
list(parse_requirements_txt(requirement.path))
)
elif isinstance(requirement, RequirementsEditableEntry):
aggregated_entries.extend(list(parse_setup_py(requirement.path)))
else:
aggregated_entries.append(requirement)
args = parser.parse_args()
for requirement in list_packages(
args.file_paths,
recurse_recursive=args.recurse_recursive,
recurse_editable=args.recurse_editable,
):
print(requirement)
for req in aggregated_entries:
print(req.source.line, req.source.path)
return 0
@@ -0,0 +1,13 @@
import enum
class PackageListFileType(enum.Enum):
REQUIREMENTS_TXT = "requirements.txt"
SETUP_PY = "setup.py"
def identify_package_list_file_type(file_path: str) -> PackageListFileType:
if file_path.endswith("setup.py"):
return PackageListFileType.SETUP_PY
return PackageListFileType.REQUIREMENTS_TXT
+49
View File
@@ -0,0 +1,49 @@
from typing import Generator, List
from .identify_package_list_file_type import (
PackageListFileType,
identify_package_list_file_type,
)
from .requirements import (
RequirementsEditableEntry,
RequirementsEntry,
RequirementsRecursiveEntry,
)
from .requirements_txt_parser import parse_requirements_txt
from .setup_py_parser import parse_setup_py
def list(
file_paths: List[str],
recurse_recursive: bool = True,
recurse_editable: bool = True,
) -> Generator[RequirementsEntry, None, None]:
generators = []
for file_path in file_paths:
package_list_file_type = identify_package_list_file_type(file_path)
if package_list_file_type == PackageListFileType.REQUIREMENTS_TXT:
generators.append(parse_requirements_txt(file_path))
elif package_list_file_type == PackageListFileType.SETUP_PY:
generators.append(parse_setup_py(file_path))
while len(generators) > 0:
for requirement in generators[0]:
if isinstance(requirement, RequirementsRecursiveEntry):
if recurse_recursive:
generators.append(
parse_requirements_txt(requirement.absolute_path)
)
else:
yield requirement
elif isinstance(requirement, RequirementsEditableEntry):
if recurse_editable:
generators.append(
parse_setup_py(requirement.resolved_absolute_path)
)
else:
yield requirement
else:
yield requirement
generators = generators[1:]
+46 -8
View File
@@ -19,12 +19,23 @@ class RequirementsEntry:
@dataclass
class RequirementsRecursiveEntry(RequirementsEntry):
path: str
original_path: str
absolute_path: str
def __str__(self) -> str:
return f"-r {self.absolute_path}"
@dataclass
class RequirementsEditableEntry(RequirementsEntry):
path: str
original_path: str
absolute_path: str
resolved_path: str
resolved_absolute_path: str
def __str__(self) -> str:
return f"-e {self.absolute_path}"
@dataclass
@@ -33,6 +44,13 @@ class RequirementsVCSPackageEntry(RequirementsEntry):
uri: str
tag: Optional[str]
def __str__(self) -> str:
result = f"{self.vcs}+{self.uri}"
if self.tag:
result += f"#{self.tag}"
return result
@dataclass
class RequirementsPackageEntry(RequirementsEntry):
@@ -40,6 +58,9 @@ class RequirementsPackageEntry(RequirementsEntry):
operator: str
version: str
def __str__(self) -> str:
return f"{self.name}{self.operator}{self.version}"
def parse_requirements(
source: Optional[RequirementsEntrySource], lines: List[str]
@@ -63,7 +84,6 @@ def parse_requirements(
elif stripped_line.startswith("-e"):
yield parse_editable_requirements_entry(line_source, stripped_line)
# TODO: add support for other VCS's
elif re.match(r"^(.+)\+", stripped_line):
yield parse_vcs_requirements_entry(line_source, stripped_line)
else:
@@ -73,20 +93,38 @@ def parse_requirements(
def parse_recursive_requirements_entry(
source: RequirementsEntrySource, line: str
) -> RequirementsRecursiveEntry:
path = _clean_line(line.replace("-r", ""))
original_path = _clean_line(line.replace("-r", ""))
absolute_path = os.path.realpath(
os.path.join(os.path.dirname(source.path), original_path)
)
return RequirementsRecursiveEntry(
source=source,
path=os.path.realpath(os.path.join(os.path.dirname(source.path), path)),
source=source, original_path=original_path, absolute_path=absolute_path,
)
def parse_editable_requirements_entry(
source: RequirementsEntrySource, line: str
) -> RequirementsEditableEntry:
path = _clean_line(line.replace("-e", ""))
original_path = _clean_line(line.replace("-e", ""))
resolved_path = original_path
if not original_path.endswith(".py"):
resolved_path = os.path.join(original_path, "setup.py")
absolute_path = os.path.realpath(
os.path.join(os.path.dirname(source.path), original_path)
)
resolved_absolute_path = os.path.realpath(
os.path.join(os.path.dirname(source.path), resolved_path)
)
return RequirementsEditableEntry(
source=source,
path=os.path.realpath(os.path.join(os.path.dirname(source.path), path)),
original_path=original_path,
absolute_path=absolute_path,
resolved_path=resolved_path,
resolved_absolute_path=resolved_absolute_path,
)
+3 -1
View File
@@ -1,3 +1,5 @@
import os
from typing import Generator
from .requirements import (
@@ -11,7 +13,7 @@ def parse_requirements_txt(
file_path: str,
) -> Generator[RequirementsEntry, None, None]:
source = RequirementsEntrySource(
path=file_path, line=None, line_number=None
path=os.path.realpath(file_path), line=None, line_number=None
)
with open(file_path, "r") as fp:
+3 -1
View File
@@ -1,3 +1,5 @@
import os
from typing import Generator
import setuptools
@@ -21,7 +23,7 @@ def parse_setup_py(file_path: str) -> Generator[RequirementsEntry, None, None]:
exec(fp.read())
source = RequirementsEntrySource(
path=file_path, line=None, line_number=None
path=os.path.realpath(file_path), line=None, line_number=None
)
requirements = setup_kwargs.get("install_requires") or []
+6 -4
View File
@@ -27,7 +27,7 @@ def test_parse_requirements_recursive_entry(path):
assert requirements[0].source.path == source.path
assert requirements[0].source.line == line
assert requirements[0].source.line_number == 1
assert requirements[0].path == os.path.realpath(
assert requirements[0].absolute_path == os.path.realpath(
os.path.join(os.getcwd(), path)
)
@@ -43,7 +43,7 @@ def test_parse_requirements_editable_entry(path):
assert requirements[0].source.path == source.path
assert requirements[0].source.line == line
assert requirements[0].source.line_number == 1
assert requirements[0].path == os.path.realpath(
assert requirements[0].absolute_path == os.path.realpath(
os.path.join(os.getcwd(), path)
)
@@ -126,13 +126,15 @@ def test_parse_requirements_ignores_leading_and_trailing_whitespace():
assert requirements[1].source.path == source.path
assert requirements[1].source.line == "-r ./otherfile.txt"
assert requirements[1].source.line_number == 2
assert requirements[1].path == os.path.join(os.getcwd(), "otherfile.txt")
assert requirements[1].absolute_path == os.path.join(
os.getcwd(), "otherfile.txt"
)
assert isinstance(requirements[2], RequirementsEditableEntry)
assert requirements[2].source.path == source.path
assert requirements[2].source.line == "-e ../"
assert requirements[2].source.line_number == 3
assert requirements[2].path == os.path.realpath(
assert requirements[2].absolute_path == os.path.realpath(
os.path.join(os.getcwd(), "..")
)
+3 -1
View File
@@ -22,5 +22,7 @@ def test_parse_requirements_txt():
assert isinstance(requirements[3], RequirementsEditableEntry)
for index, requirement in enumerate(requirements):
assert requirement.source.path == requirements_txt_path
assert requirement.source.path == os.path.realpath(
requirements_txt_path
)
assert requirement.source.line_number == index + 1
+1 -1
View File
@@ -23,7 +23,7 @@ def test_parse_setup_py():
assert isinstance(requirements[3], RequirementsEditableEntry)
for index, requirement in enumerate(requirements):
assert requirement.source.path == setup_py_path
assert requirement.source.path == os.path.realpath(setup_py_path)
assert requirement.source.line_number == index + 1