Coverage for src/idiap_devtools/scripts/fullenv.py: 0%

44 statements  

« prev     ^ index     » next       coverage.py v7.4.3, created at 2024-04-22 14:46 +0200

1# Copyright © 2022 Idiap Research Institute <contact@idiap.ch> 

2# 

3# SPDX-License-Identifier: BSD-3-Clause 

4 

5import pathlib 

6import sys 

7 

8import click 

9 

10from ..click import PreserveIndentCommand, validate_profile, verbosity_option 

11from ..logging import setup 

12 

13logger = setup(__name__.split(".", 1)[0]) 

14 

15 

16@click.command( 

17 cls=PreserveIndentCommand, 

18 epilog=""" 

19Examples: 

20 

21 1. Creates a development environment with all constrained packages (assumes 

22 the ``default`` profile is configured): 

23 

24 .. code:: sh 

25 

26 $ conda activate base 

27 (base) $ devtool fullenv -vv 

28 (base) $ mamba env create -n dev -f environment.yaml 

29 (base) $ conda activate dev 

30 

31 2. Creates a development environment with a specific profile: 

32 

33 .. code:: sh 

34 

35 $ conda activate base 

36 (base) $ devtool fullenv -vv -P ../profile 

37 (base) $ mamba env create -n dev -f environment.yaml 

38 (base) $ conda activate dev 

39 

40 

41 .. tip:: 

42 

43 You may hand-edit the output file ``environment.yaml`` to adjust for 

44 details, add conda or Python packages you'd like to complement your work 

45 environment. An example would be adding debuggers such as ``ipdb`` to 

46 the installation plan before calling ``mamba env create``. 

47 

48""", 

49) 

50@click.option( 

51 "-P", 

52 "--profile", 

53 default="default", 

54 show_default=True, 

55 callback=validate_profile, 

56 help="Directory containing the development profile (and a file named " 

57 "profile.toml), or the name of a configuration key pointing to the " 

58 "development profile to use", 

59) 

60@click.option( 

61 "-p", 

62 "--python", 

63 default=("%d.%d" % sys.version_info[:2]), 

64 show_default=True, 

65 help="Version of python to build the environment for", 

66) 

67@click.option( 

68 "-Y", 

69 "--only-python/--no-only-python", 

70 default=False, 

71 show_default=True, 

72 help="Only installs Python packages, and not conda packages " 

73 "(except for Python itself, and pip)", 

74) 

75@click.option( 

76 "-o", 

77 "--output", 

78 default="environment.yaml", 

79 show_default=True, 

80 help="The name of the environment plan file", 

81 type=click.Path(path_type=pathlib.Path), 

82) 

83@verbosity_option(logger=logger) 

84def fullenv( 

85 profile, 

86 python, 

87 only_python, 

88 output, 

89 **_, 

90) -> None: 

91 """Create a development environment with all constrained packages.""" 

92 

93 import shutil 

94 import typing 

95 

96 import yaml 

97 

98 from ..profile import Profile 

99 

100 the_profile = Profile(profile) 

101 

102 base_environment = dict(python=python, pip=None) 

103 

104 if only_python: 

105 conda_packages = None 

106 else: 

107 conda_packages = the_profile.conda_constraints(python) 

108 

109 if conda_packages is not None: 

110 conda_packages.update(base_environment) 

111 else: 

112 conda_packages = base_environment 

113 

114 python_packages = the_profile.python_constraints() 

115 if python_packages is None: 

116 python_packages = [] 

117 

118 # filter out all conda packages already in the list 

119 conda_to_python = the_profile.get(("conda", "to_python"), {}) 

120 python_to_conda = {v: k for k, v in conda_to_python.items() if k != "__ignore__"} 

121 python_packages = [ 

122 k 

123 for k in python_packages 

124 if python_to_conda.get(k.name, k.name) not in conda_packages 

125 ] 

126 

127 data: dict[str, typing.Any] = dict(channels=["conda-forge"]) 

128 

129 data["dependencies"] = sorted( 

130 [f"{k} {v}" if v is not None else k for k, v in conda_packages.items()] 

131 ) 

132 

133 if python_packages: 

134 data["dependencies"].append(dict(pip=sorted([str(k) for k in python_packages]))) 

135 

136 # backup previous installation plan, if one exists 

137 if output.exists(): 

138 backup = output.parent / (output.name + "~") 

139 shutil.copy(output, backup) 

140 

141 with output.open("w") as f: 

142 yaml.dump(data, f) 

143 

144 click.echo( 

145 "Run the following commands to create and prepare your development environment:" 

146 ) 

147 install_cmds = [ 

148 f"mamba env create --force -n dev -f {output}", 

149 "conda activate dev", 

150 ] 

151 for k in install_cmds: 

152 click.secho(k, fg="yellow", bold=True)