File: attrs.py

package info (click to toggle)
pyinfra 0.2.2%2Bgit20161227.ec708ef-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 11,804 kB
  • ctags: 677
  • sloc: python: 5,944; sh: 71; makefile: 11
file content (115 lines) | stat: -rw-r--r-- 2,679 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# pyinfra
# File: pyinfra/api/attrs.py
# Desc: helpers to manage "wrapped attributes"

'''
This file contains helpers/classes which allow us to have base type (``str``, ``int``, etc)
like operation arguments while also being able to keep track of the original reference (ie
the ``x`` in ``host.data.x``). This means we can generate one operation hash based on an
argument ``host.data.x`` where ``host.data.x`` changes between hosts. The same logic is
applied to facts.
'''

import six


def wrap_attr_data(key, attr):
    '''
    Wraps an object (hopefully) as a AttrBase item.
    '''

    if isinstance(attr, bool):
        return AttrDataBool(key, attr)

    if isinstance(attr, six.string_types):
        return AttrDataStr(key, attr)

    if isinstance(attr, int):
        return AttrDataInt(key, attr)

    return attr


class AttrBase:
    '''
    Subclasses of this represent core Python types with an extra 'host_key' attribute.
    '''

    pyinfra_attr_key = None


class AttrDataStr(AttrBase, six.text_type):
    def __new__(cls, key, obj):
        obj = super(AttrDataStr, cls).__new__(cls, obj)
        setattr(obj, 'pyinfra_attr_key', key)
        return obj


class AttrDataInt(AttrBase, int):
    def __new__(cls, key, obj):
        obj = super(AttrDataInt, cls).__new__(cls, obj)
        setattr(obj, 'pyinfra_attr_key', key)
        return obj


class AttrDataBool(AttrBase, int):
    def __new__(cls, key, obj):
        obj = super(AttrDataBool, cls).__new__(cls, bool(obj))
        setattr(obj, 'pyinfra_attr_key', key)
        return obj


class AttrData(object):
    '''
    Dict with attribute access and AttrBase wrappers.
    '''

    def __init__(self, attrs):
        self.attrs = attrs

    def __getitem__(self, key):
        return self.get(key)

    def __getattr__(self, key):
        return self.get(key)

    def __contains__(self, key):
        return key in self.attrs

    def __str__(self):
        return six.text_type(self.attrs)

    def get(self, key):
        return wrap_attr_data(key, self.attrs.get(key))

    def dict(self):
        return self.attrs


class FallbackAttrData(object):
    '''
    Combines multiple AttrData's to search for attributes.
    '''

    def __init__(self, *datas):
        self.datas = datas

    def __getattr__(self, key):
        for data in self.datas:
            if key in data:
                return data[key]

    def __str__(self):
        return six.text_type(self.datas)

    def dict(self):
        out = {}

        # Copy and reverse data objects
        datas = list(self.datas)
        datas.reverse()

        for data in datas:
            out.update(data.dict())

        return out