Skip to main content

Keyword-only argument emulation for Python 2 as a decorator. Python 3 compatible.

Project description

build code quality code health coverage pypi github license: MIT

This library emulates the python3 keyword-only arguments under python2. The resulting code is python3 compatible.

Usage

Installation

pip install kwonly-args

Alternatively you can download the zipped library from https://pypi.python.org/pypi/kwonly-args

Code

With this library you can turn some or all of the default arguments of your function into keyword-only arguments.

  • Decorate your function with kwonly_args.first_kwonly_arg and select one of the default arguments of your function with the name parameter of the decorator. The selected argument along with all default arguments on its right side will be treated as keyword-only arguments.

  • All keyword-only arguments have a default value and they aren’t required args by default. You can make a keyword-only argument required by using kwonly_args.KWONLY_REQUIRED as its default value.

Your new-born keyword-only args are no longer treated as positional arguments and varargs still work if your function has *args or something like that.

from kwonly_args import first_kwonly_arg, KWONLY_REQUIRED


# This turns default1 and default2 into keyword-only arguments.
# They are no longer handled as positional arguments.
@first_kwonly_arg('default1')
def func(arg0, arg1, default0='d0', default1='d1', default2='d2', *args):
    print('arg0={} arg1={} default0={} default1={} default2={} args={}'.format(
          arg0, arg1, default0, default1, default2, args))


func(0, 1, 2, 3, 4)
# Output:
# arg0=0 arg1=1 default0=2 default1=d1 default=d2 args=(3, 4)

# The default1 and default2 args can be passed only as keyword arguments:
func(0, 1, 2, 3, 4, default1='kwonly_param')
# Output:
# arg0=0 arg1=1 default0=2 default1=kwonly_param default=d2 args=(3, 4)


# In this example all three args are keyword-only args and default1 is required.
@first_kwonly_arg('default0')
def func2(default0='d0', default1=KWONLY_REQUIRED, default2='d2'):
    ...

You can also decorate class methods (including both old and new style classes):

from kwonly_args import first_kwonly_arg


class MyClass:
    # turning d1 and d2 into keyword-only arguments
    @first_kwonly_arg('d1')
    def my_instance_method(self, a0, a1, d0='d0', d1='d1', d2='d2', *args):
        ...

    # You have to apply @first_kwonly_arg before @classmethod!
    @classmethod
    @first_kwonly_arg('d1')
    def my_class_method(cls, a0, a1, d0='d0', d1='d1', d2='d2', *args):
        ...

    # You have to apply @first_kwonly_arg before @staticmethod!
    @staticmethod
    @first_kwonly_arg('d1')
    def my_static_method(a0, a1, d0='d0', d1='d1', d2='d2', *args):
        ...

Implementation

Python 2 function signature anatomy

A python2 function argument list consists of the following optional parts. Any optional parts that are present in a function signature appear in the listed order:

  1. Positional arguments

    1. Required arguments (positional arguments without default value)

    2. Default arguments (positional arguments with default value)

    3. Keyword-only arguments (this is available only when you use this library)

  2. VarArgs (*args)

  3. VarKWArgs (**kwargs)

As you see in standard python2 your positional argument list consists of zero or more required arguments followed by zero or more default arguments. This library can turn the last N default arguments (all/some of them) into keyword-only arguments. With the help of this library you can now split the positional argument list of your python2 function signatures into 3 parts instead of the standard 2.

In python3 the keyword-only arguments reside between VarArgs and VarKWArgs but in python2 you can’t put anything between those (it would be a syntax error) so your best bet to emulate keyword-only arguments is turning some of your positional arguments into keyword-only args.

Why does this “library” exist?

The world gives birth to new things in every single moment. This is a key driver behind evolution. But anyway, you are just too naive if you think you can stop code-monkeys with this question. :-D Even a bad reimplementation can give new insights sometimes but in worst case the author learns some new things and learns to appreciate existing implementations for hiding the discovered hell/complexity.

I’ve checked out some other python2 keyword-only argument emulator code snippets and decided to roll my own just for fun and also for the following reasons:

  • Some of those implementations provide you with a decorator with which you have to specify your keyword-only arguments with their (usually zero based) index in the arg list of the function. This is error prone, I never liked the idea of identifying arguments with indexes. The only minor disadvantage of using arg names instead of arg indexes is that using arg names requires direct access to the signature of the original wrapped function. If there are other decorators between our decorator and the original function then under python2 using names isn’t really possible (because functools.update_wrapper() and decorators in general don’t have/support the __wrapped__ attribute to maintain a chain back to the originally wrapped function).

  • Some implementations allow you to pick an arbitrary set of positional arguments by specifying their indexes or names. I don’t like the idea of promoting arbitrary positional arguments into keyword-only arguments by scattering keyword-only args through the remaining positional args. It degrades code readability a lot. This is why I decided to keep positional arguments of the same type (required/default/kwonly) together in a well defined slice of the positional argument list.

  • The implementation of this solution is brief (~40 lines of logic), simple, and well tested.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kwonly-args-1.0.4.tar.gz (8.2 kB view hashes)

Uploaded Source

Built Distribution

kwonly_args-1.0.4-py3-none-any.whl (11.7 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page