Skip to content

Commit

Permalink
release 4.22.21108
Browse files Browse the repository at this point in the history
  • Loading branch information
klahnakoski committed Apr 18, 2021
2 parents 8f45b9f + f4f600a commit 6ba6bc5
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 25 deletions.
68 changes: 47 additions & 21 deletions mo_kwargs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@
import sys
from functools import update_wrapper

from mo_dots import get_logger, is_data, to_data
from mo_dots import get_logger, is_data, to_data, is_many
from mo_future import (
get_function_arguments,
get_function_defaults,
get_function_name,
text,
is_text)
is_text,
)

KWARGS = str("kwargs")

Expand Down Expand Up @@ -54,17 +55,18 @@ def raise_error(e, a, k):
packed.update(dict(zip(params, a)))
err = text(e)
if err.startswith(func_name) and (
"takes at least" in err
or "takes exactly " in err
or "required positional argument" in err
"takes at least" in err
or "takes exactly " in err
or "required positional argument" in err
):
missing = [p for p in params if str(p) not in packed]
given = [p for p in params if str(p) in packed]
if not missing:
raise e
else:
get_logger().error(
"Problem calling {{func_name}}: Expecting parameter {{missing}}, given {{given}}",
"Problem calling {{func_name}}: Expecting parameter"
" {{missing}}, given {{given}}",
func_name=func_name,
missing=missing,
given=given,
Expand All @@ -78,7 +80,9 @@ def raise_error(e, a, k):
def wo_kwargs(*given_args, **given_kwargs):
settings = given_kwargs.get(kwargs, {})
ordered_params = dict(zip(params, given_args))
a, k = params_pack(params, defaults, settings, given_kwargs, ordered_params)
a, k = params_pack(
params, defaults, settings, given_kwargs, ordered_params
)
try:
return func(*a, **k)
except TypeError as e:
Expand All @@ -89,22 +93,36 @@ def wo_kwargs(*given_args, **given_kwargs):
elif func_name in ("__init__", "__new__") or params[0] in ("self", "cls"):

def w_bound_method(*given_args, **given_kwargs):
if len(given_args) == 2 and len(given_kwargs) == 0 and is_data(given_args[1]):
if (
len(given_args) == 2
and len(given_kwargs) == 0
and is_data(given_args[1])
):
# ASSUME SECOND UNNAMED PARAM IS kwargs
a, k = params_pack(
params, defaults, given_args[1], {params[0]: given_args[0]}, given_kwargs
params,
defaults,
given_args[1],
{params[0]: given_args[0]},
given_kwargs,
)
elif kwargs in given_kwargs and is_data(given_kwargs[kwargs]):
# PUT args INTO given_kwargs
a, k = params_pack(
params, defaults, given_kwargs[kwargs], dict(zip(params, given_args)), given_kwargs
params,
defaults,
given_kwargs[kwargs],
dict(zip(params, given_args)),
given_kwargs,
)
else:
a, k = params_pack(params, defaults, dict(zip(params, given_args)), given_kwargs)
a, k = params_pack(
params, defaults, dict(zip(params, given_args)), given_kwargs
)
try:
return func(*a, **k)
except TypeError as e:
tb = getattr(e, '__traceback__', None)
tb = getattr(e, "__traceback__", None)
if tb is not None:
trace = _parse_traceback(tb)
else:
Expand All @@ -116,17 +134,27 @@ def w_bound_method(*given_args, **given_kwargs):
else:

def w_kwargs(*given_args, **given_kwargs):
if len(given_args) == 1 and len(given_kwargs) == 0 and is_data(given_args[0]):
if (
len(given_args) == 1
and len(given_kwargs) == 0
and is_data(given_args[0])
):
# ASSUME SINGLE PARAMETER IS kwargs
a, k = params_pack(params, defaults, given_args[0])
elif kwargs in given_kwargs and is_data(given_kwargs[kwargs]):
# PUT given_args INTO given_kwargs
a, k = params_pack(
params, defaults, given_kwargs[kwargs], dict(zip(params, given_args)), given_kwargs
params,
defaults,
given_kwargs[kwargs],
dict(zip(params, given_args)),
given_kwargs,
)
else:
# PULL kwargs OUT INTO PARAMS
a, k = params_pack(params, defaults, dict(zip(params, given_args)), given_kwargs)
a, k = params_pack(
params, defaults, dict(zip(params, given_args)), given_kwargs
)
try:
return func(*a, **k)
except TypeError as e:
Expand Down Expand Up @@ -159,10 +187,7 @@ def params_pack(params, *args):
{k: settings[k] for k in params[1:] if k in settings},
)
else:
return (
[],
{k: settings[k] for k in params if k in settings}
)
return ([], {k: settings[k] for k in params if k in settings})

if is_text(kwargs):
# COMPLEX VERSION @override(kwargs="other")
Expand All @@ -188,15 +213,16 @@ def get_traceback(start):


def _parse_traceback(tb):
if is_many(tb):
get_logger().error("Expecting a tracback object, not a list")
trace = []
while tb is not None:
f = tb.tb_frame
trace.append({
"file": f.f_code.co_filename,
"line": tb.tb_lineno,
"method": f.f_code.co_name
"method": f.f_code.co_name,
})
tb = tb.tb_next
trace.reverse()
return trace

4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
classifiers=["Development Status :: 4 - Beta","Topic :: Software Development :: Libraries","Topic :: Software Development :: Libraries :: Python Modules","License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)","Programming Language :: Python :: 2.7","Programming Language :: Python :: 3.6","Programming Language :: Python :: 3.7","Programming Language :: Python :: 3.8"],
description='More KWARGS! Let call parameters override kwargs',
include_package_data=True,
install_requires=["mo-dots>=3.93.20259","mo-future>=3.89.20246"],
install_requires=["mo-dots==4.22.21108","mo-future==3.147.20327"],
license='MPL 2.0',
long_description='\n# More KWARGS!\n\n|Branch |Status |\n|------------|---------|\n|master | [![Build Status](https://travis-ci.org/klahnakoski/mo-kwargs.svg?branch=master)](https://travis-ci.org/klahnakoski/mo-kwargs) |\n|dev | [![Build Status](https://travis-ci.org/klahnakoski/mo-kwargs.svg?branch=dev)](https://travis-ci.org/klahnakoski/mo-kwargs) [![Coverage Status](https://coveralls.io/repos/github/klahnakoski/mo-kwargs/badge.svg?branch=dev)](https://coveralls.io/github/klahnakoski/mo-kwargs?branch=dev) |\n\n\n\n## Motivation\n\nExtensive use of dependency injection, plus managing the configuration for each of the components being injected, can result in some spectacularly complex system configuration. One way to reduce the complexity is to use configuration templates that contain useful defaults, and then overwrite the properties that need to be changed for the desired configuration. \n\n`@override` has been created to provide this templating system for Python function calls. It is mostly used for class constructors, but any method can benefit. The `@overrides` decorator adds a `kwargs` parameter which can be given a template of default parameters; but unlike `**kwargs`, it will not raise duplicate key exceptions.\n\n## Provide default values\n\nWe decorate the `login()` function with `@override`. In this case, `username` is a required parameter, and `password` will default to `None`. \n\n @override\n def login(username, password=None):\n pass\n\nDefine some `dicts` for use with our `kwargs` parameter:\n\n creds = {"userame": "ekyle", "password": "password123"}\n alt_creds = {"username": "klahnakoski"}\n\n\nThe simplest case is when we use `kwargs` with no overrides\n\n login(kwargs=creds)\n # SAME AS\n login(**creds)\n # SAME AS\n login(username="ekyle", password="password123")\n\nYou may override any property in `kwargs`: In this case it is `password`\n\n login(password="123", kwargs=creds)\n # SAME AS\n login(username="ekyle", password="123")\n\nThere is no problem with overriding everything in `kwargs`:\n\n login(username="klahnakoski", password="asd213", kwargs=creds)\n # SAME AS\n login(username="klahnakoski", password="asd213")\n\nYou may continue to use `**kwargs`; which provides a way to overlay one parameter template (`creds`) with another (`alt_creds`)\n\n login(kwargs=creds, **alt_creds)\n # SAME AS\n login(username="klahnakoski", password="password123")\n\n## Handle too many parameters\n\nSometimes your method parameters come from a configuration file, or some other outside source which is outside your control. There may be more parameters than your method is willing to accept. \n\n creds = {"username": "ekyle", "password": "password123", "port":9000}\n def login(username, password=None):\n print(kwargs.get("port"))\n\nWithout `mo-kwargs`, passing the `creds` dictionary directly to `login()` would raise a key error\n\n >>> login(**creds)\n Traceback (most recent call last):\n File "<stdin>", line 1, in <module>\n TypeError: login() got an unexpected keyword argument \'port\'\n \nThe traditional solution is to pass the parameters explicitly:\n\n login(username=creds.username, password=creds.password)\n\nbut that can get get tedious when done often, or the parameter list get long. `mo-kwargs` allows you to pass the whole dictionary to the `kwargs` parameter; only the parameters used by the method are used:\n\n @override\n def login(username, password=None):\n pass\n \n login(kwargs=creds)\n # SAME AS\n login(**creds)\n\n## Package all parameters\n\nYour method can accept `kwargs` as a parameter. If it does, ensure it defaults to `None` so that it\'s not required.\n\n @override\n def login(username, password=None, kwargs=None):\n print(kwargs.get("username"))\n print(kwargs.get("port"))\n\n`kwargs` will always be a dict, possibly empty, with the full set of parameters. This is different from using `**kwargs` which contains only the remainder of the keyword parameters.\n\n >>> creds = {"username": "ekyle", "password": "password123", "port":9000}\n >>> login(**creds)\n ekyle\n 9000\n',
long_description_content_type='text/markdown',
name='mo-kwargs',
packages=["mo_kwargs"],
url='https://github.com/klahnakoski/mo-kwargs',
version='3.93.20259',
version='4.22.21108',
zip_safe=False
)
4 changes: 2 additions & 2 deletions setuptools.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
],
"description": "More KWARGS! Let call parameters override kwargs",
"include_package_data": true,
"install_requires": ["mo-dots>=3.93.20259", "mo-future>=3.89.20246"],
"install_requires": ["mo-dots==4.22.21108", "mo-future==3.147.20327"],
"license": "MPL 2.0",
"long_description": {
"$concat": [
Expand Down Expand Up @@ -125,6 +125,6 @@
"name": "mo-kwargs",
"packages": ["mo_kwargs"],
"url": "https://github.com/klahnakoski/mo-kwargs",
"version": "3.93.20259",
"version": "4.22.21108",
"zip_safe": false
}

0 comments on commit 6ba6bc5

Please sign in to comment.