1import functools
2from .obj_dic import DotDict
3
4
5allowed_fields = [
6    "description",
7    "nres",
8    "code",
9    "chars",
10    "lines",
11    "words",
12    "md5",
13    "l",
14    "h",
15    "w",
16    "c",
17    "history",
18    "plugins",
19    "url",
20    "content",
21    "history.url",
22    "history.method",
23    "history.scheme",
24    "history.host",
25    "history.content",
26    "history.raw_content" "history.is_path",
27    "history.pstrip",
28    "history.cookies",
29    "history.headers",
30    "history.params",
31    "r",
32    "r.reqtime",
33    "r.url",
34    "r.method",
35    "r.scheme",
36    "r.host",
37    "r.content",
38    "r.raw_content" "r.is_path",
39    "r.pstrip",
40    "r.cookies.",
41    "r.headers.",
42    "r.params.",
43]
44
45
46def _check_allowed_field(attr):
47    if [field for field in allowed_fields if attr.startswith(field)]:
48        return True
49    return False
50
51
52def _get_alias(attr):
53    attr_alias = {
54        "l": "lines",
55        "h": "chars",
56        "w": "words",
57        "c": "code",
58        "r": "history",
59    }
60
61    if attr in attr_alias:
62        return attr_alias[attr]
63
64    return attr
65
66
67def rsetattr(obj, attr, new_val, operation):
68    # if not _check_allowed_field(attr):
69    #    raise AttributeError("Unknown field {}".format(attr))
70
71    pre, _, post = attr.rpartition(".")
72
73    pre_post = None
74    if len(attr.split(".")) > 3:
75        pre_post = post
76        pre, _, post = pre.rpartition(".")
77
78    post = _get_alias(post)
79
80    try:
81        obj_to_set = rgetattr(obj, pre) if pre else obj
82        prev_val = rgetattr(obj, attr)
83        if pre_post is not None:
84            prev_val = DotDict({pre_post: prev_val})
85
86        if operation is not None:
87            val = operation(prev_val, new_val)
88        else:
89            if isinstance(prev_val, DotDict):
90                val = {k: new_val for k, v in prev_val.items()}
91            else:
92                val = new_val
93
94        return setattr(obj_to_set, post, val)
95    except AttributeError:
96        raise AttributeError(
97            "rsetattr: Can't set '{}' attribute of {}.".format(
98                post, obj_to_set.__class__
99            )
100        )
101
102
103def rgetattr(obj, attr, *args):
104    def _getattr(obj, attr):
105        attr = _get_alias(attr)
106        try:
107            return getattr(obj, attr, *args)
108        except AttributeError:
109            raise AttributeError(
110                "rgetattr: Can't get '{}' attribute from '{}'.".format(
111                    attr, obj.__class__
112                )
113            )
114
115    # if not _check_allowed_field(attr):
116    # raise AttributeError("Unknown field {}".format(attr))
117
118    return functools.reduce(_getattr, [obj] + attr.split("."))
119