33
33
import warnings
34
34
import weakref
35
35
from argparse import (Action , ArgumentDefaultsHelpFormatter , ArgumentParser ,
36
- ArgumentTypeError )
36
+ ArgumentTypeError , _ArgumentGroup )
37
37
from asyncio import FIRST_COMPLETED , AbstractEventLoop , Task
38
38
from collections import UserDict , defaultdict
39
39
from collections .abc import (AsyncGenerator , Awaitable , Generator , Hashable ,
@@ -1326,23 +1326,49 @@ def add_arguments(self, actions):
1326
1326
super ().add_arguments (actions )
1327
1327
1328
1328
1329
+ class _FlexibleArgumentGroup (_ArgumentGroup ):
1330
+
1331
+ def __init__ (self , parser : FlexibleArgumentParser , * args , ** kwargs ):
1332
+ self ._parser = parser
1333
+ super ().__init__ (* args , ** kwargs )
1334
+
1335
+ def add_argument (self , * args : Any , ** kwargs : Any ):
1336
+ if sys .version_info < (3 , 13 ):
1337
+ deprecated = kwargs .pop ('deprecated' , False )
1338
+ action = super ().add_argument (* args , ** kwargs )
1339
+ object .__setattr__ (action , 'deprecated' , deprecated )
1340
+ if deprecated and action .dest not in \
1341
+ self ._parser .__class__ ._deprecated :
1342
+ self ._parser ._warning (
1343
+ _gettext ("argument '%(argument_name)s' is deprecated" ) %
1344
+ {'argument_name' : action .dest })
1345
+ self ._parser ._deprecated .add (action .dest )
1346
+ return action
1347
+
1348
+ # python>3.13
1349
+ return super ().add_argument (* args , ** kwargs )
1350
+
1351
+
1329
1352
class FlexibleArgumentParser (ArgumentParser ):
1330
1353
"""ArgumentParser that allows both underscore and dash in names."""
1331
1354
1355
+ _deprecated : set [str ] = set ()
1356
+
1332
1357
def __init__ (self , * args , ** kwargs ):
1333
1358
# Set the default 'formatter_class' to SortedHelpFormatter
1334
1359
if 'formatter_class' not in kwargs :
1335
1360
kwargs ['formatter_class' ] = SortedHelpFormatter
1336
1361
super ().__init__ (* args , ** kwargs )
1337
- self ._deprecated = set ()
1338
1362
1339
1363
def add_argument (self , * args : Any , ** kwargs : Any ):
1340
1364
# add a deprecated=True with optional deprecated_reason to signify
1341
1365
# reasons for deprecating this args
1342
1366
if sys .version_info < (3 , 13 ):
1343
1367
deprecated = kwargs .pop ('deprecated' , False )
1344
1368
action = super ().add_argument (* args , ** kwargs )
1345
- if deprecated and action .dest not in self ._deprecated :
1369
+ object .__setattr__ (action , 'deprecated' , deprecated )
1370
+ if deprecated and \
1371
+ action .dest not in FlexibleArgumentParser ._deprecated :
1346
1372
self ._warning (
1347
1373
_gettext ("argument '%(argument_name)s' is deprecated" ) %
1348
1374
{'argument_name' : action .dest })
@@ -1354,9 +1380,9 @@ def add_argument(self, *args: Any, **kwargs: Any):
1354
1380
return super ().add_argument (* args , ** kwargs )
1355
1381
1356
1382
def _warning (self , message : str ):
1357
- args = {'prog' : self .prog , 'message' : message }
1358
1383
self ._print_message (
1359
- _gettext ('%(prog)s: warning: %(message)s\n ' ) % args , sys .stderr )
1384
+ _gettext ('warning: %(message)s\n ' ) % {'message' : message },
1385
+ sys .stderr )
1360
1386
1361
1387
def parse_args ( # type: ignore[override]
1362
1388
self ,
@@ -1533,6 +1559,12 @@ def _load_config_file(self, file_path: str) -> list[str]:
1533
1559
1534
1560
return processed_args
1535
1561
1562
+ def add_argument_group (self , * args : Any ,
1563
+ ** kwargs : Any ) -> _FlexibleArgumentGroup :
1564
+ group = _FlexibleArgumentGroup (self , self , * args , ** kwargs )
1565
+ self ._action_groups .append (group )
1566
+ return group
1567
+
1536
1568
1537
1569
async def _run_task_with_lock (task : Callable , lock : asyncio .Lock , * args ,
1538
1570
** kwargs ):
0 commit comments