Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature/dictable kwargs #54

Merged
merged 5 commits into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 50 additions & 2 deletions autoconf/dictable.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import numpy as np
from pathlib import Path
from typing import Union, Callable
from typing import Union, Callable, Set

from autoconf.class_path import get_class_path, get_class

Expand Down Expand Up @@ -93,12 +93,55 @@ def to_dict(obj):
return obj


def get_arguments(obj) -> Set[str]:
"""
Get the arguments of a class. This is done by inspecting the constructor.

If the constructor has a **kwargs parameter, the arguments of the base classes are also included.

Parameters
----------
obj
The class to get the arguments of.

Returns
-------
A set of the arguments of the class.
"""
args_spec = inspect.getfullargspec(obj.__init__)
args = set(args_spec.args[1:])
if args_spec.varkw:
for base in obj.__bases__:
if base is object:
continue
args |= get_arguments(base)
return args


def instance_as_dict(obj):
arguments = set(inspect.getfullargspec(obj.__init__).args[1:])
"""
Convert an instance of a class to a dictionary representation.

Serialises any children of the object which are given as constructor arguments
or included in the __identifier_fields__ attribute.

Sets any fields in the __nullify_fields__ attribute to None.

Parameters
----------
obj
The instance of the class to be converted to a dictionary representation.

Returns
-------
A dictionary representation of the instance.
"""
arguments = get_arguments(type(obj))
try:
arguments |= set(obj.__identifier_fields__)
except (AttributeError, TypeError):
pass

argument_dict = {
arg: getattr(obj, arg)
for arg in arguments
Expand All @@ -107,6 +150,11 @@ def instance_as_dict(obj):
getattr(obj, arg),
)
}
try:
for field in obj.__nullify_fields__:
argument_dict[field] = None
except (AttributeError, TypeError):
pass

return {
"type": "instance",
Expand Down
30 changes: 30 additions & 0 deletions test_autoconf/test_dictable.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,33 @@ def test_serialise_path():
path = Path("/path/to/file.json")
path_dict = to_dict(path)
assert from_dict(path_dict) == path


class Parent:
def __init__(self, parent_arg):
self.parent_arg = parent_arg


class Child(Parent):
def __init__(self, child_arg, **kwargs):
super().__init__(**kwargs)
self.child_arg = child_arg


def test_serialise_kwargs():
child = Child(
child_arg="child",
parent_arg="parent",
)
child_dict = to_dict(child)
assert child_dict == {
"arguments": {
"child_arg": "child",
"parent_arg": "parent",
},
"class_path": "test_autoconf.test_dictable.Child",
"type": "instance",
}
new_child = from_dict(child_dict)
assert new_child.child_arg == "child"
assert new_child.parent_arg == "parent"
Loading