Skip to content

Commit

Permalink
ENH #881 add decorator
Browse files Browse the repository at this point in the history
  • Loading branch information
prjemian committed Jan 9, 2024
1 parent e5231a4 commit 9219cd3
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 0 deletions.
1 change: 1 addition & 0 deletions apstools/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from .log_utils import setup_IPython_console_logging
from .log_utils import stream_log_handler
from .memory import rss_mem
from .misc import call_signature_decorator
from .misc import cleanupText
from .misc import connect_pvlist
from .misc import count_child_devices_and_signals
Expand Down
41 changes: 41 additions & 0 deletions apstools/utils/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
.. autosummary::
~call_signature_decorator
~cleanupText
~connect_pvlist
~count_child_devices_and_signals
Expand All @@ -25,6 +26,7 @@
~unix
"""

import inspect
import logging
import pathlib
import re
Expand All @@ -35,6 +37,7 @@
import warnings
from collections import OrderedDict
from collections import defaultdict
from functools import wraps

import databroker
import ophyd
Expand All @@ -51,6 +54,44 @@
logger = logging.getLogger(__name__)


def call_signature_decorator(f):
"""
Get the names of all function parameters supplied by the caller.
This is used to differentiate user-supplied parameters from as-defined
parameters with the same value.
HOW TO USE THIS DECORATOR:
Decorate a function or method with this decorator *and* add an additional
`_call_args=None` kwarg to the function. The function can test `_call_args`
if a specific kwarg was supplied by the caller.
EXAMPLE::
@call_signature_decorator
def func1(a, b=1, c=True, _call_args=None):
if 'c' in _call_args: # Caller supplied this kwarg?
pass
.. note:: With ``call_signature_decorator``, it is not possible to get the names
of the positional arguments. Since positional parameters are not specified by
name, such capability is not expected to become a requirement.
:see: https://stackoverflow.com/questions/14749328#58166804
(how-to-check-whether-optional-function-parameter-is-set)
"""
key = "_call_args"
varnames = inspect.getfullargspec(f)[0]

@wraps(f)
def wrapper(*a, **kw):
kw[key] = set(list(varnames[: len(a)]) + list(kw.keys()))
return f(*a, **kw)

return wrapper


def cleanupText(text):
"""
convert text so it can be used as a dictionary key
Expand Down

0 comments on commit 9219cd3

Please sign in to comment.