8000 Merge pull request #1125 from murrayrm/keyword_aliases-07Feb2025 · python-control/python-control@a042895 · GitHub
[go: up one dir, main page]

Skip to content

Commit a042895

Browse files
authored
Merge pull request #1125 from murrayrm/keyword_aliases-07Feb2025
Uniform processing of time response and optimization parameters
2 parents cf77f99 + 3b4e3a4 commit a042895

18 files changed

+851
-289
lines changed

control/config.py

Lines changed: 149 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# config.py - package defaults
22
# RMM, 4 Nov 2012
33
#
4-
# TODO: add ability to read/write configuration files (ala matplotlib)
4+
# TODO: add ability to read/write configuration files (a la matplotlib)
55

66
"""Functions to access default parameter values.
77
@@ -384,10 +384,13 @@ def use_legacy_defaults(version):
384384
def _process_legacy_keyword(kwargs, oldkey, newkey, newval, warn_oldkey=True):
385385
"""Utility function for processing legacy keywords.
386386
387+
.. deprecated:: 0.10.2
388+
Replace with `_process_param` or `_process_kwargs`.
389+
387390
Use this function to handle a legacy keyword that has been renamed.
388391
This function pops the old keyword off of the kwargs dictionary and
389392
issues a warning. If both the old and new keyword are present, a
390-
ControlArgument exception is raised.
393+
`ControlArgument` exception is raised.
391394
392395
Parameters
393396
----------
@@ -412,6 +415,10 @@ def _process_legacy_keyword(kwargs, oldkey, newkey, newval, warn_oldkey=True):
412415
Value of the (new) keyword.
413416
414417
"""
418+
# TODO: turn on this warning when ready to deprecate
419+
# warnings.warn(
420+
# "replace `_process_legacy_keyword` with `_process_param` "
421+
# "or `_process_kwargs`", PendingDeprecationWarning)
415422
if oldkey in kwargs:
416423
if warn_oldkey:
417424
warnings.warn(
@@ -424,3 +431,143 @@ def _process_legacy_keyword(kwargs, oldkey, newkey, newval, warn_oldkey=True):
424431
return kwargs.pop(oldkey)
425432
else:
426433
return newval
434+
435+
436+
def _process_param(name, defval, kwargs, alias_mapping, sigval=None):
437+
"""Process named parameter, checking aliases and legacy usage.
438+
439+
Helper function to process function arguments by mapping aliases to
440+
either their default keywords or to a named argument. The alias
441+
mapping is a dictionary that returns a tuple consisting of valid
442+
aliases and legacy aliases::
443+
444+
alias_mapping = {
445+
'argument_name_1': (['alias', ...], ['legacy', ...]),
446+
...}
447+
448+
If `param` is a named keyword in the function signature with default
449+
value `defval`, a typical calling sequence at the start of a function
450+
is::
451+
452+
param = _process_param('param', defval, kwargs, function_aliases)
453+
454+
If `param` is a variable keyword argument (in `kwargs`), `defval` can
455+
be passed as either None or the default value to use if `param` is not
456+
present in `kwargs`.
457+
458+
Parameters
459+
----------
460+
name : str
461+
Name of the parameter to be checked.
462+
defval : object or dict
463+
Default value for the parameter.
464+
kwargs : dict
465+
Dictionary of variable keyword arguments.
466+
alias_mapping : dict
467+
Dictionary providing aliases and legacy names.
468+
sigval : object, optional
469+
Default value specified in the function signature (default = None).
470+
If specified, an error will be generated if `defval` is different
471+
than `sigval` and an alias or legacy keyword is given.
472+
473+
Returns
474+
-------
475+
newval : object
476+
New value of the named parameter.
477+
478+
Raises
479+
------
480+
TypeError
481+
If multiple keyword aliases are used for the same parameter.
482+
483+
Warns
484+
-----
485+
PendingDeprecationWarning
486+
If legacy name is used to set the value for the variable.
487+
488+
"""
489+
# Check to see if the parameter is in the keyword list
490+
if name in kwargs:
491+
if defval != sigval:
492+
raise TypeError(f"multiple values for parameter {name}")
493+
newval = kwargs.pop(name)
494+
else:
495+
newval = defval
496+
497+
# Get the list of aliases and legacy names
498+
aliases, legacy = alias_mapping[name]
499+
500+
for kw in legacy:
501+
if kw in kwargs:
502+
warnings.warn(
503+
f"alias `{kw}` is legacy name; use `{name}` instead",
504+
PendingDeprecationWarning)
505+
kwval = kwargs.pop(kw)
506+
if newval != defval and kwval != newval:
507+
raise TypeError(
508+
f"multiple values for parameter `{name}` (via {kw})")
509+
newval = kwval
510+
511+
for kw in aliases:
512+
if kw in kwargs:
513+
kwval = kwargs.pop(kw)
514+
if newval != defval and kwval != newval:
515+
raise TypeError(
516+
f"multiple values for parameter `{name}` (via {kw})")
517+
newval = kwval
518+
519+
return newval
520+
521+
522+
def _process_kwargs(kwargs, alias_mapping):
523+
"""Process aliases and legacy keywords.
524+
525+
Helper function to process function arguments by mapping aliases to
526+
their default keywords. The alias mapping is a dictionary that returns
527+
a tuple consisting of valid aliases and legacy aliases::
528+
529+
alias_mapping = {
530+
'argument_name_1': (['alias', ...], ['legacy', ...]),
531+
...}
532+
533+
If an alias is present in the dictionary of keywords, it will be used
534+
to set the value of the argument. If a legacy keyword is used, a
535+
warning is issued.
536+
537+
Parameters
538+
----------
539+
kwargs : dict
540+
Dictionary of variable keyword arguments.
541+
alias_mapping : dict
542+
Dictionary providing aliases and legacy names.
543+
544+
Raises
545+
------
546+
TypeError
547+
If multiple keyword aliased are used for the same parameter.
548+
549+
Warns
550+
-----
551+
PendingDeprecationWarning
552+
If legacy name is used to set the value for the variable.
553+
554+
"""
555+
for name in alias_mapping or []:
556+
aliases, legacy = alias_mapping[name]
557+
558+
for kw in legacy:
559+
if kw in kwargs:
560+
warnings.warn(
561+
f"alias `{kw}` is legacy name; use `{name}` instead",
562+
PendingDeprecationWarning)
563+
if name in kwargs:
564+
raise TypeError(
565+
f"multiple values for parameter `{name}` (via {kw})")
566+
kwargs[name] = kwargs.pop(kw)
567+
568+
for kw in aliases:
569+
if kw in kwargs:
570+
if name in kwargs:
571+
raise TypeError(
572+
f"multiple values for parameter `{name}` (via {kw})")
573+
kwargs[name] = kwargs.pop(kw)

0 commit comments

Comments
 (0)
0