11#!/usr/bin/env python3
2+ # -*- coding: utf-8 -*-
3+ #
4+ # --- BEGIN_HEADER ---
5+ #
6+ # features - bootstrap tool for managing per-feature dependencies
7+ # Copyright (C) 2003-2026 The MiG Project by the Science HPC Center at UCPH
8+ #
9+ # This file is part of MiG.
10+ #
11+ # MiG is free software: you can redistribute it and/or modify
12+ # it under the terms of the GNU General Public License as published by
13+ # the Free Software Foundation; either version 2 of the License, or
14+ # (at your option) any later version.
15+ #
16+ # MiG is distributed in the hope that it will be useful,
17+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
18+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+ # GNU General Public License for more details.
20+ #
21+ # You should have received a copy of the GNU General Public License
22+ # along with this program; if not, write to the Free Software
23+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24+ #
25+ # -- END_HEADER ---
26+ #
227
328import argparse
429from collections import defaultdict
3257
3358
3459def warn (msg = '' ):
60+ """
61+ Wrapper function for printing to stderr.
62+ """
3563 print (msg , file = sys .stderr )
3664
3765
@@ -149,6 +177,9 @@ def list_enabled_features(self, return_as=list):
149177 if self ._enabled_by_feature [feature_name ]))
150178
151179 def required_package_names (self , feature_name ):
180+ """
181+ Return the set of required packages for a named feature.
182+ """
152183 return set ((Features ._strip_version_if_present (entry .requirement )
153184 for entry in self ._requirements_by_feature [feature_name ]))
154185
@@ -176,9 +207,12 @@ def _interpret_feature_definition(feature_name, feature_definition, requirements
176207
177208 @staticmethod
178209 def _is_package_present (package_name ):
210+ """
211+ Determine whether a package is available to the active interpreter.
212+ """
213+
179214 try :
180215 importlib .util .find_spec (package_name )
181-
182216 return True
183217 except ModuleNotFoundError as exc :
184218 return False
@@ -213,6 +247,11 @@ def expand_definitions(definitions, requirements_dir):
213247
214248 @classmethod
215249 def from_definitions_file (cls , features_file , requirements_dir , overrides_supported = {}):
250+ """
251+ Return a Features instance populated with the features declared
252+ within the specified definitions file.
253+ """
254+
216255 assert os .path .isabs (features_file )
217256 with open (features_file ) as thefile :
218257 definitions = ConfigParser ()
@@ -221,6 +260,13 @@ def from_definitions_file(cls, features_file, requirements_dir, overrides_suppor
221260
222261 @staticmethod
223262 def match_env_dict (features , env_dict ):
263+ """
264+ Check the supplied dictionary for env-style flags (i.e. ENABLE_<NAME>)
265+ which indicate whether the correspnding feature should be enabled and
266+ optionally - based upon the definitions - for any applicable version
267+ overrides being specified if such flags are supported.
268+ """
269+
224270 def enabled_or_fallback (feature_name ):
225271 try :
226272 enable_string = env_dict [f"ENABLE_{ feature_name .upper ()} " ]
@@ -248,6 +294,10 @@ def enabled_or_fallback(feature_name):
248294
249295 @staticmethod
250296 def match_dotenv_file (features , dotenv_file ):
297+ """
298+ Match a .env file for feature enablement and overrides.
299+ """
300+
251301 from dotenv import dotenv_values
252302
253303 assert os .path .isabs (dotenv_file )
@@ -257,6 +307,10 @@ def match_dotenv_file(features, dotenv_file):
257307
258308 @staticmethod
259309 def match_configuration_file (features , configuration_file ):
310+ """
311+ Match a .configuration file for feature enablement and overrides.
312+ """
313+
260314 from mig .shared .conf import get_configuration_object
261315 configuration = get_configuration_object (configuration_file , skip_log = True , disable_auth_log = True )
262316
@@ -271,7 +325,11 @@ def enabled_or_fallback(feature_name):
271325 return enabled_by_feature_name , {}
272326
273327
274- def main_enabled (features , args , print = print , warn = warn ):
328+ def subcommand_enabled (features , args , print = print , warn = warn ):
329+ """
330+ 'enabled' subcommand executor.
331+ """
332+
275333 if args .c :
276334 enabled_by_feature_name = Features .match_configuration_file (features , args .c )
277335 features .apply_enabled (enabled_by_feature_name )
@@ -288,7 +346,11 @@ def main_enabled(features, args, print=print, warn=warn):
288346 return 0
289347
290348
291- def main_install (features , args , print = print , warn = warn ):
349+ def subcommand_install (features , args , print = print , warn = warn ):
350+ """
351+ 'install' subcommand executor.
352+ """
353+
292354 if args .c :
293355 enabled_by_feature_name = Features .match_configuration_file (features , args .c )
294356 features .apply_enabled (enabled_by_feature_name )
@@ -313,18 +375,26 @@ def main_install(features, args, print=print, warn=warn):
313375 raise NotImplementedError ("install is not currently implemented" )
314376
315377
316- def main_show (features , args , print = print , warn = warn ):
378+ def subcommand_show (features , args , print = print , warn = warn ):
379+ """
380+ 'show' subcommand executor.
381+ """
382+
317383 print (f"available features: { ', ' .join (features .feature_names )} " )
318384
319385
320386_COMMAND_HANDLERS = dict (
321- enabled = main_enabled ,
322- install = main_install ,
323- show = main_show ,
387+ enabled = subcommand_enabled ,
388+ install = subcommand_install ,
389+ show = subcommand_show ,
324390)
325391
326392
327393def main (argv ):
394+ """
395+ Main entrypoint function.
396+ """
397+
328398 parser = argparse .ArgumentParser ()
329399 subparsers = parser .add_subparsers (dest = 'command' )
330400
@@ -351,6 +421,10 @@ def main(argv):
351421 return args_main (parser .parse_args (args = argv ))
352422
353423def args_main (args , * , print = print , warn = warn , features = None ):
424+ """
425+ Internal helper for executing the parsed arguments.
426+ """
427+
354428 features = features or Features .from_definitions_file (
355429 FEATURES_FILE ,
356430 FEATURES_REQUIREMENTS_DIR ,
0 commit comments