import functools


def decorator_with_keywords(func=None, **dkws):
    # NOTE:  ONLY ACCEPTS KW ARGS
    """
    A decorator that can handle optional keyword arguments.

    When the decorator is called with no optional arguments like this:

    @decorator
    def function ...

    The function is passed as the first argument and decorate returns the decorated function, as expected.

    If the decorator is called with one or more optional arguments like this:

    @decorator(optional_argument1='some value')
    def function ....

    Then decorator is called with the function argument with value None, so a function that decorates
    is returned, as expected.
    """

    # print('WHOOP', func, dkws)
    def _decorate(func):
        @functools.wraps(func)
        def wrapped_function(*args, **kws):
            # print('!!')
            return func(*args, **kws)

        return wrapped_function

    if func:
        return _decorate(func)

    return _decorate