188
188
189
189
_IS_WINDOWS = os .name == "nt" # Are we running on Windows?
190
190
191
- try :
192
- import curses
193
- except ImportError as e :
194
- if not _IS_WINDOWS :
195
- raise
196
- sys .exit (
197
- """\
198
- menuconfig failed to import the standard Python 'curses' library. Try
199
- installing a package like windows-curses
200
- (https://github.com/zephyrproject-rtos/windows-curses) by running this command
201
- in cmd.exe:
202
-
203
- pip install windows-curses
204
-
205
- Starting with Kconfiglib 13.0.0, windows-curses is no longer automatically
206
- installed when installing Kconfiglib via pip on Windows (because it breaks
207
- installation on MSYS2).
208
-
209
- Exception:
210
- {}: {}""" .format (
211
- type (e ).__name__ , e
212
- )
213
- )
191
+ # Defer curses import to runtime - it will be imported by _ensure_curses()
192
+ # when menuconfig() is called. This avoids import errors in headless CI/CD
193
+ # environments where menuconfig UI is not used.
214
194
215
195
import errno
216
196
import locale
357
337
""" ,
358
338
}
359
339
360
- _NAMED_COLORS = {
361
- # Basic colors
362
- "black" : curses .COLOR_BLACK ,
363
- "red" : curses .COLOR_RED ,
364
- "green" : curses .COLOR_GREEN ,
365
- "yellow" : curses .COLOR_YELLOW ,
366
- "blue" : curses .COLOR_BLUE ,
367
- "magenta" : curses .COLOR_MAGENTA ,
368
- "cyan" : curses .COLOR_CYAN ,
369
- "white" : curses .COLOR_WHITE ,
370
- # Bright versions
371
- "brightblack" : curses .COLOR_BLACK + 8 ,
372
- "brightred" : curses .COLOR_RED + 8 ,
373
- "brightgreen" : curses .COLOR_GREEN + 8 ,
374
- "brightyellow" : curses .COLOR_YELLOW + 8 ,
375
- "brightblue" : curses .COLOR_BLUE + 8 ,
376
- "brightmagenta" : curses .COLOR_MAGENTA + 8 ,
377
- "brightcyan" : curses .COLOR_CYAN + 8 ,
378
- "brightwhite" : curses .COLOR_WHITE + 8 ,
379
- # Aliases
380
- "purple" : curses .COLOR_MAGENTA ,
381
- "brightpurple" : curses .COLOR_MAGENTA + 8 ,
382
- }
340
+ # Curses module - will be imported by _ensure_curses()
341
+ curses = None
342
+
343
+ # Named colors cache - will be initialized by _get_named_colors()
344
+ _named_colors_cache = None
345
+
346
+
347
+ def _get_named_colors ():
348
+ """Returns the named colors dictionary. Initializes it on first call."""
349
+ global _named_colors_cache
350
+ if _named_colors_cache is None :
351
+ _named_colors_cache = {
352
+ # Basic colors
353
+ "black" : curses .COLOR_BLACK ,
354
+ "red" : curses .COLOR_RED ,
355
+ "green" : curses .COLOR_GREEN ,
356
+ "yellow" : curses .COLOR_YELLOW ,
357
+ "blue" : curses .COLOR_BLUE ,
358
+ "magenta" : curses .COLOR_MAGENTA ,
359
+ "cyan" : curses .COLOR_CYAN ,
360
+ "white" : curses .COLOR_WHITE ,
361
+ # Bright versions
362
+ "brightblack" : curses .COLOR_BLACK + 8 ,
363
+ "brightred" : curses .COLOR_RED + 8 ,
364
+ "brightgreen" : curses .COLOR_GREEN + 8 ,
365
+ "brightyellow" : curses .COLOR_YELLOW + 8 ,
366
+ "brightblue" : curses .COLOR_BLUE + 8 ,
367
+ "brightmagenta" : curses .COLOR_MAGENTA + 8 ,
368
+ "brightcyan" : curses .COLOR_CYAN + 8 ,
369
+ "brightwhite" : curses .COLOR_WHITE + 8 ,
370
+ # Aliases
371
+ "purple" : curses .COLOR_MAGENTA ,
372
+ "brightpurple" : curses .COLOR_MAGENTA + 8 ,
373
+ }
374
+ return _named_colors_cache
383
375
384
376
385
377
def _rgb_to_6cube (rgb ):
@@ -594,8 +586,9 @@ def parse_color(color_def):
594
586
)
595
587
)
596
588
597
- if color_def in _NAMED_COLORS :
598
- color_num = _color_from_num (_NAMED_COLORS [color_def ])
589
+ named_colors = _get_named_colors ()
590
+ if color_def in named_colors :
591
+ color_num = _color_from_num (named_colors [color_def ])
599
592
else :
600
593
try :
601
594
color_num = _color_from_num (int (color_def , 0 ))
@@ -695,6 +688,43 @@ def _style_attr(fg_color, bg_color, attribs, color_attribs={}):
695
688
#
696
689
697
690
691
+ def _ensure_curses ():
692
+ """
693
+ Imports curses module if not already imported. This allows the module
694
+ to be imported in headless CI/CD environments without triggering import
695
+ errors, as long as menuconfig() is not called.
696
+ """
697
+ global curses
698
+ if curses is not None :
699
+ return
700
+
701
+ try :
702
+ import curses as curses_module
703
+
704
+ curses = curses_module
705
+ except ImportError as e :
706
+ if not _IS_WINDOWS :
707
+ raise
708
+ sys .exit (
709
+ """\
710
+ menuconfig failed to import the standard Python 'curses' library. Try
711
+ installing a package like windows-curses
712
+ (https://github.com/zephyrproject-rtos/windows-curses) by running this command
713
+ in cmd.exe:
714
+
715
+ pip install windows-curses
716
+
717
+ Starting with Kconfiglib 13.0.0, windows-curses is no longer automatically
718
+ installed when installing Kconfiglib via pip on Windows (because it breaks
719
+ installation on MSYS2).
720
+
721
+ Exception:
722
+ {}: {}""" .format (
723
+ type (e ).__name__ , e
724
+ )
725
+ )
726
+
727
+
698
728
def _main ():
699
729
menuconfig (standard_kconfig (__doc__ ))
700
730
@@ -706,6 +736,9 @@ def menuconfig(kconf):
706
736
kconf:
707
737
Kconfig instance to be configured
708
738
"""
739
+ # Import curses at runtime to avoid issues in headless environments
740
+ _ensure_curses ()
741
+
709
742
global _kconf
710
743
global _conf_filename
711
744
global _conf_changed
0 commit comments