File: edit_subset_mode.py

package info (click to toggle)
glueviz 0.9.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 17,180 kB
  • ctags: 6,728
  • sloc: python: 37,111; makefile: 134; sh: 60
file content (121 lines) | stat: -rw-r--r-- 4,562 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
116
117
118
119
120
121
"""These classes define the behavior of how new subset states affect
    the edit_subset of a Data object.

   The EditSubsetMode is universal in Glue -- all datasets and clients
   share the same mode. This is enforced by making the base
   EditSubsetMode object a singleton.
"""
# pylint: disable=I0011, R0903

from __future__ import absolute_import, division, print_function

import logging

from glue.core.contracts import contract
from glue.core.data_collection import DataCollection
from glue.core.data import Data
from glue.core.decorators import singleton
from glue.utils import as_list


@singleton
class EditSubsetMode(object):

    """ Implements how new SubsetStates modify the edit_subset state """

    def __init__(self):
        self.mode = ReplaceMode
        self.data_collection = None

    def _combine_data(self, data, new_state, add_if_empty=False):
        """ Dispatches to the combine method of mode attribute.

        The behavior is dependent on the mode it dispatches to.
        By default, the method uses ReplaceMode, which overwrites
        the edit_subsets' subset_state with new_state

        :param edit_subset: The current edit_subset
        :param new_state: The new SubsetState
        :param add_if_empty: If True and a data set has no subsets,
                             a new one will be added and assigned
                             using new-state
        """
        empty = data.edit_subset is None or data.edit_subset == []
        if add_if_empty and empty:
            if self.data_collection is None:
                raise RuntimeError("Must set data_collection before "
                                   "calling update")
            data.edit_subset = self.data_collection.new_subset_group()
        if empty and not add_if_empty:
            logging.getLogger(__name__).info("Ignoring subset update")
            return
        subs = data.edit_subset
        for s in as_list(subs):
            self.mode(s, new_state)

    @contract(d='inst($DataCollection, $Data)',
              new_state='isinstance(SubsetState)',
              focus_data='inst($Data)|None')
    def update(self, d, new_state, focus_data=None):
        """ Apply a new subset state to editable subsets within a
        :class:`~glue.core.data.Data` or
        :class:`~glue.core.data_collection.DataCollection` instance

        :param d: Data or Collection to act upon
        :type d: Data or DataCollection

        :param new_state: Subset state to combine with
        :type new_state: :class:`~glue.core.subset.SubsetState`

        :param focus_data: The main data set in focus by the client,
        if relevant. If a data set is in focus and has no subsets,
        a new one will be created using new_state.
        """
        logging.getLogger(__name__).debug("Update subset for %s", d)

        if isinstance(d, Data):
            self._combine_data(d, new_state, add_if_empty=d is focus_data)
        elif isinstance(d, DataCollection):
            no_editable = all(data.edit_subset is None or
                              data.edit_subset == []
                              for data in d)
            for data in d:
                doadd = data is focus_data and no_editable
                self._combine_data(data, new_state, add_if_empty=doadd)
        else:
            raise TypeError("input must be a Data or DataCollection: %s" %
                            type(d))


def ReplaceMode(edit_subset, new_state):
    """ Replaces edit_subset.subset_state with new_state """
    logging.getLogger(__name__).debug("Replace %s", edit_subset)
    edit_subset.subset_state = new_state.copy()


def AndMode(edit_subset, new_state):
    """ Edit_subset.subset state is and-combined with new_state """
    new_state.parent = edit_subset
    state = new_state & edit_subset.subset_state
    edit_subset.subset_state = state


def OrMode(edit_subset, new_state):
    """ Edit_subset.subset state is or-combined with new_state """
    new_state.parent = edit_subset
    state = new_state | edit_subset.subset_state
    edit_subset.subset_state = state


def XorMode(edit_subset, new_state):
    """ Edit_subset.subset state is xor-combined with new_state """
    new_state.parent = edit_subset
    state = new_state ^ edit_subset.subset_state
    edit_subset.subset_state = state


def AndNotMode(edit_subset, new_state):
    """ Edit_subset.subset state is and-not-combined with new_state """
    new_state.parent = edit_subset
    state = edit_subset.subset_state & (~new_state)
    edit_subset.subset_state = state