Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tos-kamiya/e90c44176c82449c78e1df8b405772a6 to your computer and use it in GitHub Desktop.
Save tos-kamiya/e90c44176c82449c78e1df8b405772a6 to your computer and use it in GitHub Desktop.
Initialize attributes with keyword arguments (license: Public Domain https://creativecommons.org/publicdomain/zero/1.0/deed)
# a revised and unit-tested version has been published at https://github.com/tos-kamiya/init_attrs_with_kwargs
from typing import get_type_hints
from enum import Enum
class InitAttrsWKwArgs:
@staticmethod
def _convert_option_name_to_attr_name(name: str) -> str:
if name.startswith('--'):
ns = name[2:]
elif name.startswith('-'):
ns = name[1:]
elif name.startswith('<') and name.endswith('>'):
ns = name[1:-1]
else:
ns = name
ns = ns.replace('-', '_')
if not(len(ns) > 0 and ('a' <= ns[0] <= 'z' or 'A' <= ns[0] <= 'Z') and \
all('a' <= c <= 'z' or 'A' <= c <= 'Z' or '0' <= c <= '9' or c == '_' for c in ns)):
assert False, "the name does not seem either option or positional argument: %s" % repr(name)
return ns
def __init__(self, _cast_str_values=False, **kwargs):
attr_to_type = get_type_hints(self.__class__)
for name in kwargs:
attr = InitAttrsWKwArgs._convert_option_name_to_attr_name(name)
t = attr_to_type.get(attr)
assert t is not None, "attribute not found: %s" % attr
v = kwargs[name]
if _cast_str_values and isinstance(v, str):
try:
if issubclass(t, bool):
v = not not v
elif issubclass(t, int):
v = int(v)
elif issubclass(t, float):
v = float(v)
elif issubclass(t, Enum):
v = t[v] # conversion from str to Enum (it might not look so)
except TypeError:
pass # issubclass raises a TypeError for Union, etc.
setattr(self, attr, v)
class Hoge(InitAttrsWKwArgs):
count: int
name: str
max_length: int
# Initialize from docopt's return value (dict).
v1: Hoge = Hoge(**{'<count>': 1, '--name': "Joe", '--max-length': 100})
print("dir(v1)=%s" % repr(dir(v1)))
print("v1.count=%s" % repr(v1.count))
print("v1.name=%s" % repr(v1.name))
print("v1.max_length=%s" % repr(v1.max_length))
# Initialize with keyword argument.
v2: Hoge = Hoge(count=10, name='Jane', max_length=99)
print("dir(v2)=%s" % repr(dir(v2)))
print("v2.count=%s" % repr(v2.count))
print("v2.name=%s" % repr(v2.name))
print("v2.max_length=%s" % repr(v2.max_length))
# Initialize from docopt's return value, with casting str to int
v3: Hoge = Hoge(_cast_str_values=True, **{'<count>': '1', '--name': "Joe", '--max-length': '100'})
print("dir(v3)=%s" % repr(dir(v3)))
print("v3.count=%s" % repr(v3.count))
print("v3.name=%s" % repr(v3.name))
print("v3.max_length=%s" % repr(v3.max_length))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment