11#!/usr/bin/env python
22#
3- # SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
3+ # SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
44#
55# SPDX-License-Identifier: Apache-2.0
66#
77# 'idf.py' is a top-level config/build command line tool for ESP-IDF
88#
99# You don't have to use idf.py, you can use cmake directly
1010# (or use cmake in an IDE)
11-
1211# WARNING: we don't check for Python build-time dependencies until
1312# check_environment() function below. If possible, avoid importing
1413# any external libraries here - put in external script, or import in
1514# their specific function instead.
1615import codecs
1716import json
1817import locale
19- import os
2018import os .path
2119import shlex
2220import subprocess
2321import sys
24- from collections import Counter , OrderedDict , _OrderedDictKeysView
22+ from collections import Counter
23+ from collections import OrderedDict
24+ from collections .abc import KeysView
2525from importlib import import_module
2626from pkgutil import iter_modules
27- from typing import Any , Callable , Dict , List , Optional , Union
27+ from typing import Any
28+ from typing import Callable
29+ from typing import Dict
30+ from typing import List
31+ from typing import Optional
32+ from typing import Union
2833
2934# pyc files remain in the filesystem when switching between branches which might raise errors for incompatible
3035# idf.py extensions. Therefore, pyc file generation is turned off:
3944 if os .getenv ('IDF_COMPONENT_MANAGER' ) != '0' :
4045 from idf_component_manager import idf_extensions
4146except ImportError as e :
42- # For example, importing click could cause this.
43- print (( f'Cannot import module " { e . name } ". This usually means that "idf.py" was not '
47+ print (( f' { e } \n '
48+ f' This usually means that "idf.py" was not '
4449 f'spawned within an ESP-IDF shell environment or the python virtual '
4550 f'environment used by "idf.py" is corrupted.\n '
4651 f'Please use idf.py only in an ESP-IDF shell environment. If problem persists, '
4752 f'please try to install ESP-IDF tools again as described in the Get Started guide.' ),
4853 file = sys .stderr )
54+ if e .name is None :
55+ # The ImportError or ModuleNotFoundError might be raised without
56+ # specifying a module name. In this not so common situation, re-raise
57+ # the exception to print all the information that could assist in
58+ # identifying the problem.
59+ raise
4960
5061 sys .exit (1 )
5162
@@ -128,7 +139,7 @@ def _safe_relpath(path: str, start: Optional[str]=None) -> str:
128139 return os .path .abspath (path )
129140
130141
131- def init_cli (verbose_output : List = None ) -> Any :
142+ def init_cli (verbose_output : Optional [ List ] = None ) -> Any :
132143 # Click is imported here to run it after check_environment()
133144 import click
134145
@@ -194,7 +205,7 @@ def __init__(self, callback: Callable, name: str, aliases: List, dependencies: O
194205 self .action_args = action_args
195206 self .aliases = aliases
196207
197- def __call__ (self , context : click .core .Context , global_args : PropertyDict , action_args : Dict = None ) -> None :
208+ def __call__ (self , context : click .core .Context , global_args : PropertyDict , action_args : Optional [ Dict ] = None ) -> None :
198209 if action_args is None :
199210 action_args = self .action_args
200211
@@ -295,7 +306,7 @@ class Scope(object):
295306
296307 SCOPES = ('default' , 'global' , 'shared' )
297308
298- def __init__ (self , scope : Union ['Scope' , str ]= None ) -> None : # noqa: F821
309+ def __init__ (self , scope : Optional [ Union ['Scope' , str ] ]= None ) -> None : # noqa: F821
299310 if scope is None :
300311 self ._scope = 'default'
301312 elif isinstance (scope , str ) and scope in self .SCOPES :
@@ -318,7 +329,7 @@ def __str__(self) -> str:
318329
319330 class Option (click .Option ):
320331 """Option that knows whether it should be global"""
321- def __init__ (self , scope : Union [Scope , str ]= None , deprecated : Union [Dict , str , bool ]= False , hidden : bool = False , ** kwargs : str ) -> None :
332+ def __init__ (self , scope : Optional [ Union [Scope , str ] ]= None , deprecated : Union [Dict , str , bool ]= False , hidden : bool = False , ** kwargs : str ) -> None :
322333 """
323334 Keyword arguments additional to Click's Option class:
324335
@@ -356,7 +367,7 @@ def get_help_record(self, ctx: click.core.Context) -> Any:
356367
357368 class CLI (click .MultiCommand ):
358369 """Action list contains all actions with options available for CLI"""
359- def __init__ (self , all_actions : Dict = None , verbose_output : List = None , help : str = None ) -> None :
370+ def __init__ (self , all_actions : Optional [ Dict ] = None , verbose_output : Optional [ List ] = None , help : Optional [ str ] = None ) -> None :
360371 super (CLI , self ).__init__ (
361372 chain = True ,
362373 invoke_without_command = True ,
@@ -440,7 +451,7 @@ def get_command(self, ctx: click.core.Context, name: str) -> Optional[Action]:
440451 return Action (name = name , callback = callback .unwrapped_callback )
441452 return None
442453
443- def _print_closing_message (self , args : PropertyDict , actions : _OrderedDictKeysView ) -> None :
454+ def _print_closing_message (self , args : PropertyDict , actions : KeysView ) -> None :
444455 # print a closing message of some kind,
445456 # except if any of the following actions were requested
446457 if any (t in str (actions ) for t in ('flash' , 'dfu' , 'uf2' , 'uf2-app' , 'qemu' )):
@@ -578,7 +589,7 @@ def execute_tasks(self, tasks: List, **kwargs: str) -> OrderedDict:
578589
579590 dependecies_processed = True
580591
581- # If task have some dependecies they have to be executed before the task.
592+ # If task have some dependencies they have to be executed before the task.
582593 for dep in task .dependencies :
583594 if dep not in tasks_to_run .keys ():
584595 # If dependent task is in the list of unprocessed tasks move to the front of the list
@@ -711,11 +722,11 @@ def parse_project_dir(project_dir: str) -> Any:
711722 return CLI (help = cli_help , verbose_output = verbose_output , all_actions = all_actions )
712723
713724
714- def main (argv : List [Any ] = None ) -> None :
725+ def main (argv : Optional [ List [Any ] ] = None ) -> None :
715726 # Check the environment only when idf.py is invoked regularly from command line.
716727 checks_output = None if SHELL_COMPLETE_RUN else check_environment ()
717728
718- # Check existance of the current working directory to prevent exceptions from click cli.
729+ # Check existence of the current working directory to prevent exceptions from click cli.
719730 try :
720731 os .getcwd ()
721732 except FileNotFoundError as e :
0 commit comments