Coverage for src/iso_freeze/pin_requirements.py: 80%

25 statements  

« prev     ^ index     » next       coverage.py v6.4.2, created at 2022-08-01 11:38 +0200

1"""Write *requirements.txt file.""" 

2 

3from pathlib import Path 

4 

5from iso_freeze.lib import PyPackage 

6 

7 

8def pin_requirements( 

9 requirements: list[PyPackage], hashes: bool, output_file: Path 

10) -> None: 

11 """Write *requirements.txt file. 

12 

13 Arguments: 

14 requirements -- List of packages to pin (list[PyPackage]) 

15 hashes -- Whether to include hashes (bool) 

16 output_file -- Path to file that should be created (Path) 

17 """ 

18 output_file_contents: list[str] = build_reqirements_file_contents( 

19 requirements=requirements, hashes=hashes 

20 ) 

21 write_requirements_file(output_file=output_file, file_contents=output_file_contents) 

22 print(f"Pinned specified requirements in {output_file}") 

23 

24 

25def build_reqirements_file_contents( 

26 requirements: list[PyPackage], hashes: bool 

27) -> list[str]: 

28 """Build contents of requirements file as a list. 

29 

30 Display top level dependencies on top, similar to pip freeze -r requirements_file. 

31 

32 Arguments: 

33 requirements -- Dependencies listed in pip install --report (list[dict[str]]) 

34 hashes -- Whether to include hashes (bool) 

35 

36 Returns: 

37 Contents of requirements file (list[str]) 

38 """ 

39 # For easier formatting we create separate lists for top level requirements 

40 # and their dependencies 

41 top_level_requirements: list[str] = [] 

42 dependency_requirements: list[str] = [] 

43 for package in requirements: 

44 pinned_format: str = f"{package.name}=={package.version}" 

45 if hashes: 

46 pinned_format += f" \\\n --hash={package.hash}" 

47 # If requested == True, the package is a top level requirement 

48 if package.requested: 

49 top_level_requirements.append(pinned_format) 

50 else: 

51 dependency_requirements.append(pinned_format) 

52 # Sort pinned packages alphabetically before writing to file 

53 # (case-insensitively thanks to key=str.lower) 

54 top_level_requirements.sort(key=str.lower) 

55 # Combine lists and add comments 

56 requirements_file_content: list[str] = [ 

57 "# Top level requirements", 

58 *top_level_requirements, 

59 ] 

60 if dependency_requirements: 

61 dependency_requirements.sort(key=str.lower) 

62 requirements_file_content.extend( 

63 ["# Dependencies of top level requirements", *dependency_requirements] 

64 ) 

65 return requirements_file_content 

66 

67 

68def write_requirements_file(output_file: Path, file_contents: list[str]) -> None: 

69 """Write requirements file. 

70 

71 Arguments: 

72 output_file -- Path to and name of requirements.txt file (Path) 

73 file_contents -- Contents to to written to a file (list[str]) 

74 """ 

75 with output_file.open(mode="w", encoding="utf=8") as f: 

76 f.writelines(f"{package}\n" for package in file_contents)