Skip to content

excludable

Excludable dataclass

Class that keeps sets of fields to exclude and include

Source code in ormar/models/excludable.py
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
@dataclass
class Excludable:
    """
    Class that keeps sets of fields to exclude and include
    """

    include: Set = field(default_factory=set)
    exclude: Set = field(default_factory=set)

    def get_copy(self) -> "Excludable":
        """
        Return copy of self to avoid in place modifications
        :return: copy of self with copied sets
        :rtype: ormar.models.excludable.Excludable
        """
        _copy = self.__class__()
        _copy.include = {x for x in self.include}
        _copy.exclude = {x for x in self.exclude}
        return _copy

    def set_values(self, value: Set, is_exclude: bool) -> None:
        """
        Appends the data to include/exclude sets.

        :param value: set of values to add
        :type value: set
        :param is_exclude: flag if values are to be excluded or included
        :type is_exclude: bool
        """
        prop = "exclude" if is_exclude else "include"
        current_value = getattr(self, prop)
        current_value.update(value)
        setattr(self, prop, current_value)

    def is_included(self, key: str) -> bool:
        """
        Check if field in included (in set or set is {...})
        :param key: key to check
        :type key: str
        :return: result of the check
        :rtype: bool
        """
        return (... in self.include or key in self.include) if self.include else True

    def is_excluded(self, key: str) -> bool:
        """
        Check if field in excluded (in set or set is {...})
        :param key: key to check
        :type key: str
        :return: result of the check
        :rtype: bool
        """
        return (... in self.exclude or key in self.exclude) if self.exclude else False

get_copy()

Return copy of self to avoid in place modifications

Returns:

Type Description
ormar.models.excludable.Excludable

copy of self with copied sets

Source code in ormar/models/excludable.py
19
20
21
22
23
24
25
26
27
28
def get_copy(self) -> "Excludable":
    """
    Return copy of self to avoid in place modifications
    :return: copy of self with copied sets
    :rtype: ormar.models.excludable.Excludable
    """
    _copy = self.__class__()
    _copy.include = {x for x in self.include}
    _copy.exclude = {x for x in self.exclude}
    return _copy

is_excluded(key)

Check if field in excluded (in set or set is {...})

Parameters:

Name Type Description Default
key str

key to check

required

Returns:

Type Description
bool

result of the check

Source code in ormar/models/excludable.py
54
55
56
57
58
59
60
61
62
def is_excluded(self, key: str) -> bool:
    """
    Check if field in excluded (in set or set is {...})
    :param key: key to check
    :type key: str
    :return: result of the check
    :rtype: bool
    """
    return (... in self.exclude or key in self.exclude) if self.exclude else False

is_included(key)

Check if field in included (in set or set is {...})

Parameters:

Name Type Description Default
key str

key to check

required

Returns:

Type Description
bool

result of the check

Source code in ormar/models/excludable.py
44
45
46
47
48
49
50
51
52
def is_included(self, key: str) -> bool:
    """
    Check if field in included (in set or set is {...})
    :param key: key to check
    :type key: str
    :return: result of the check
    :rtype: bool
    """
    return (... in self.include or key in self.include) if self.include else True

set_values(value, is_exclude)

Appends the data to include/exclude sets.

Parameters:

Name Type Description Default
value Set

set of values to add

required
is_exclude bool

flag if values are to be excluded or included

required
Source code in ormar/models/excludable.py
30
31
32
33
34
35
36
37
38
39
40
41
42
def set_values(self, value: Set, is_exclude: bool) -> None:
    """
    Appends the data to include/exclude sets.

    :param value: set of values to add
    :type value: set
    :param is_exclude: flag if values are to be excluded or included
    :type is_exclude: bool
    """
    prop = "exclude" if is_exclude else "include"
    current_value = getattr(self, prop)
    current_value.update(value)
    setattr(self, prop, current_value)

ExcludableItems

Keeps a dictionary of Excludables by alias + model_name keys to allow quick lookup by nested models without need to travers deeply nested dictionaries and passing include/exclude around

Source code in ormar/models/excludable.py
 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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
class ExcludableItems:
    """
    Keeps a dictionary of Excludables by alias + model_name keys
    to allow quick lookup by nested models without need to travers
    deeply nested dictionaries and passing include/exclude around
    """

    def __init__(self) -> None:
        self.items: Dict[str, Excludable] = dict()

    @classmethod
    def from_excludable(cls, other: "ExcludableItems") -> "ExcludableItems":
        """
        Copy passed ExcludableItems to avoid inplace modifications.

        :param other: other excludable items to be copied
        :type other: ormar.models.excludable.ExcludableItems
        :return: copy of other
        :rtype: ormar.models.excludable.ExcludableItems
        """
        new_excludable = cls()
        for key, value in other.items.items():
            new_excludable.items[key] = value.get_copy()
        return new_excludable

    def include_entry_count(self) -> int:
        """
        Returns count of include items inside
        """
        count = 0
        for key in self.items.keys():
            count += len(self.items[key].include)
        return count

    def get(self, model_cls: Type["Model"], alias: str = "") -> Excludable:
        """
        Return Excludable for given model and alias.

        :param model_cls: target model to check
        :type model_cls: ormar.models.metaclass.ModelMetaclass
        :param alias: table alias from relation manager
        :type alias: str
        :return: Excludable for given model and alias
        :rtype: ormar.models.excludable.Excludable
        """
        key = f"{alias + '_' if alias else ''}{model_cls.get_name(lower=True)}"
        excludable = self.items.get(key)
        if not excludable:
            excludable = Excludable()
            self.items[key] = excludable
        return excludable

    def build(
        self,
        items: Union[List[str], str, Tuple[str], Set[str], Dict],
        model_cls: Type["Model"],
        is_exclude: bool = False,
    ) -> None:
        """
        Receives the one of the types of items and parses them as to achieve
        a end situation with one excludable per alias/model in relation.

        Each excludable has two sets of values - one to include, one to exclude.

        :param items: values to be included or excluded
        :type items: Union[List[str], str, Tuple[str], Set[str], Dict]
        :param model_cls: source model from which relations are constructed
        :type model_cls: ormar.models.metaclass.ModelMetaclass
        :param is_exclude: flag if items should be included or excluded
        :type is_exclude: bool
        """
        if isinstance(items, str):
            items = {items}

        if isinstance(items, Dict):
            self._traverse_dict(
                values=items,
                source_model=model_cls,
                model_cls=model_cls,
                is_exclude=is_exclude,
            )

        else:
            items = set(items)
            nested_items = set(x for x in items if "__" in x)
            items.difference_update(nested_items)
            self._set_excludes(
                items=items,
                model_name=model_cls.get_name(lower=True),
                is_exclude=is_exclude,
            )
            if nested_items:
                self._traverse_list(
                    values=nested_items, model_cls=model_cls, is_exclude=is_exclude
                )

    def _set_excludes(
        self, items: Set, model_name: str, is_exclude: bool, alias: str = ""
    ) -> None:
        """
        Sets set of values to be included or excluded for given key and model.

        :param items: items to include/exclude
        :type items: set
        :param model_name: name of model to construct key
        :type model_name: str
        :param is_exclude: flag if values should be included or excluded
        :type is_exclude: bool
        :param alias:
        :type alias: str
        """
        key = f"{alias + '_' if alias else ''}{model_name}"
        excludable = self.items.get(key)
        if not excludable:
            excludable = Excludable()
        excludable.set_values(value=items, is_exclude=is_exclude)
        self.items[key] = excludable

    def _traverse_dict(  # noqa: CFQ002
        self,
        values: Dict,
        source_model: Type["Model"],
        model_cls: Type["Model"],
        is_exclude: bool,
        related_items: List = None,
        alias: str = "",
    ) -> None:
        """
        Goes through dict of nested values and construct/update Excludables.

        :param values: items to include/exclude
        :type values: Dict
        :param source_model: source model from which relations are constructed
        :type source_model: ormar.models.metaclass.ModelMetaclass
        :param model_cls: model from which current relation is constructed
        :type model_cls: ormar.models.metaclass.ModelMetaclass
        :param is_exclude: flag if values should be included or excluded
        :type is_exclude: bool
        :param related_items: list of names of related fields chain
        :type related_items: List
        :param alias: alias of relation
        :type alias: str
        """
        self_fields = set()
        related_items = related_items[:] if related_items else []
        for key, value in values.items():
            if value is ...:
                self_fields.add(key)
            elif isinstance(value, set):
                (
                    table_prefix,
                    target_model,
                    _,
                    _,
                ) = get_relationship_alias_model_and_str(
                    source_model=source_model, related_parts=related_items + [key]
                )
                self._set_excludes(
                    items=value,
                    model_name=target_model.get_name(),
                    is_exclude=is_exclude,
                    alias=table_prefix,
                )
            else:
                # dict
                related_items.append(key)
                (
                    table_prefix,
                    target_model,
                    _,
                    _,
                ) = get_relationship_alias_model_and_str(
                    source_model=source_model, related_parts=related_items
                )
                self._traverse_dict(
                    values=value,
                    source_model=source_model,
                    model_cls=target_model,
                    is_exclude=is_exclude,
                    related_items=related_items,
                    alias=table_prefix,
                )
        if self_fields:
            self._set_excludes(
                items=self_fields,
                model_name=model_cls.get_name(),
                is_exclude=is_exclude,
                alias=alias,
            )

    def _traverse_list(
        self, values: Set[str], model_cls: Type["Model"], is_exclude: bool
    ) -> None:
        """
        Goes through list of values and construct/update Excludables.

        :param values: items to include/exclude
        :type values: set
        :param model_cls: model from which current relation is constructed
        :type model_cls: ormar.models.metaclass.ModelMetaclass
        :param is_exclude: flag if values should be included or excluded
        :type is_exclude: bool
        """
        # here we have only nested related keys
        for key in values:
            key_split = key.split("__")
            related_items, field_name = key_split[:-1], key_split[-1]
            (table_prefix, target_model, _, _) = get_relationship_alias_model_and_str(
                source_model=model_cls, related_parts=related_items
            )
            self._set_excludes(
                items={field_name},
                model_name=target_model.get_name(),
                is_exclude=is_exclude,
                alias=table_prefix,
            )

build(items, model_cls, is_exclude=False)

Receives the one of the types of items and parses them as to achieve a end situation with one excludable per alias/model in relation.

Each excludable has two sets of values - one to include, one to exclude.

Parameters:

Name Type Description Default
items Union[List[str], str, Tuple[str], Set[str], Dict]

values to be included or excluded

required
model_cls Type['Model']

source model from which relations are constructed

required
is_exclude bool

flag if items should be included or excluded

False
Source code in ormar/models/excludable.py
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
def build(
    self,
    items: Union[List[str], str, Tuple[str], Set[str], Dict],
    model_cls: Type["Model"],
    is_exclude: bool = False,
) -> None:
    """
    Receives the one of the types of items and parses them as to achieve
    a end situation with one excludable per alias/model in relation.

    Each excludable has two sets of values - one to include, one to exclude.

    :param items: values to be included or excluded
    :type items: Union[List[str], str, Tuple[str], Set[str], Dict]
    :param model_cls: source model from which relations are constructed
    :type model_cls: ormar.models.metaclass.ModelMetaclass
    :param is_exclude: flag if items should be included or excluded
    :type is_exclude: bool
    """
    if isinstance(items, str):
        items = {items}

    if isinstance(items, Dict):
        self._traverse_dict(
            values=items,
            source_model=model_cls,
            model_cls=model_cls,
            is_exclude=is_exclude,
        )

    else:
        items = set(items)
        nested_items = set(x for x in items if "__" in x)
        items.difference_update(nested_items)
        self._set_excludes(
            items=items,
            model_name=model_cls.get_name(lower=True),
            is_exclude=is_exclude,
        )
        if nested_items:
            self._traverse_list(
                values=nested_items, model_cls=model_cls, is_exclude=is_exclude
            )

from_excludable(other) classmethod

Copy passed ExcludableItems to avoid inplace modifications.

Parameters:

Name Type Description Default
other 'ExcludableItems'

other excludable items to be copied

required

Returns:

Type Description
ormar.models.excludable.ExcludableItems

copy of other

Source code in ormar/models/excludable.py
75
76
77
78
79
80
81
82
83
84
85
86
87
88
@classmethod
def from_excludable(cls, other: "ExcludableItems") -> "ExcludableItems":
    """
    Copy passed ExcludableItems to avoid inplace modifications.

    :param other: other excludable items to be copied
    :type other: ormar.models.excludable.ExcludableItems
    :return: copy of other
    :rtype: ormar.models.excludable.ExcludableItems
    """
    new_excludable = cls()
    for key, value in other.items.items():
        new_excludable.items[key] = value.get_copy()
    return new_excludable

get(model_cls, alias='')

Return Excludable for given model and alias.

Parameters:

Name Type Description Default
model_cls Type['Model']

target model to check

required
alias str

table alias from relation manager

''

Returns:

Type Description
ormar.models.excludable.Excludable

Excludable for given model and alias

Source code in ormar/models/excludable.py
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
def get(self, model_cls: Type["Model"], alias: str = "") -> Excludable:
    """
    Return Excludable for given model and alias.

    :param model_cls: target model to check
    :type model_cls: ormar.models.metaclass.ModelMetaclass
    :param alias: table alias from relation manager
    :type alias: str
    :return: Excludable for given model and alias
    :rtype: ormar.models.excludable.Excludable
    """
    key = f"{alias + '_' if alias else ''}{model_cls.get_name(lower=True)}"
    excludable = self.items.get(key)
    if not excludable:
        excludable = Excludable()
        self.items[key] = excludable
    return excludable

include_entry_count()

Returns count of include items inside

Source code in ormar/models/excludable.py
90
91
92
93
94
95
96
97
def include_entry_count(self) -> int:
    """
    Returns count of include items inside
    """
    count = 0
    for key in self.items.keys():
        count += len(self.items[key].include)
    return count