Пример #1
1
def main(args=None):
    import argparse

    parser = argparse.ArgumentParser(
        description="Tool to measure resources consumed"
        " by a group of processes, no matter how hard they fork."
        " Does that by creating a temp cgroup and running passed command there."
    )
    parser.add_argument("cmdline", nargs="+", help="Command to run and any arguments for it.")
    parser.add_argument(
        "-g",
        "--cgroup",
        default="bench/tmp",
        metavar="{ /path | tagged-path }",
        help="Hierarchy path to create temp-cgroup under"
        ' ("/" means root cgroup, default: %(default)s).'
        " Any missing path components will be created."
        " If relative name is specified, it will be interpreted from /tagged path.",
    )
    parser.add_argument(
        "-c",
        "--rcs",
        default="cpuacct, blkio, memory",
        metavar="rc1[,rc2,...]",
        help="Comma-separated list of rc hierarchies to get metrics from (default: %(default)s)."
        " Should have corresponding path mounted under {}.".format(cg_root),
    )
    parser.add_argument(
        "-q", "--quiet", action="store_true", help="Redirect stderr/stdout for started pid to /dev/null."
    )
    parser.add_argument("-d", "--debug", action="store_true", help="Verbose operation mode.")
    opts = parser.parse_args(sys.argv[1:] if args is None else args)

    global log
    import logging

    logging.basicConfig(level=logging.DEBUG if opts.debug else logging.INFO)
    log = logging.getLogger()

    # Check all rc tasks-file paths
    cg_subpath = "tmp.{}".format(cmd_pid)
    cg_tasks, cg_path = OrderedDict(), join("tagged", opts.cgroup).lstrip("/")
    for rc in map(bytes.strip, opts.rcs.split(",")):
        tasks = join(cg_root, rc, cg_path, cg_subpath, "tasks")
        assert "\n" not in tasks, repr(tasks)
        os.makedirs(dirname(tasks))
        assert exists(tasks), tasks
        cg_tasks[rc] = tasks

        # Append cmdline, send data to child
    data = cg_tasks.values()
    if opts.quiet:
        data.append("-")
    data = "\n".join(it.chain(data, ["\0".join(map(lambda arg: arg.encode("hex"), opts.cmdline))]))
    cmd_w.write(struct.pack(len_fmt, len(data)) + data)
    cmd_w.flush()

    # Wait for signal to start counting
    mark = cmd_start_r.read(1)
    ts0 = time()
    assert mark == ".", repr(mark)
    cmd_start_r.close()

    pid, status = os.waitpid(cmd_pid, 0)
    ts1 = time()

    err = status >> 8
    if status & 0xFF:
        print("Unclean exit of child pid due to signal: {}".format((status & 0xFF) >> 1))
        err = err or 1

        # Make sure everything finished running there
    leftovers = set()
    for tasks in cg_tasks.values():
        with open(tasks) as src:
            leftovers.update(map(int, src.read().splitlines()))
    if leftovers:
        print(
            "Main pid has finished, but cgroups have leftover threads"
            " still running: {}".format(", ".join(map(bytes, leftovers))),
            file=sys.stderr,
        )
        err = err or 1

        # Collect/print accounting data
    acct = OrderedDict()
    acct["cmd"] = " ".join(opts.cmdline)
    acct["wall_clock"] = "{:.3f}".format(ts1 - ts0)
    acct["exit_status"] = "{} {}".format(status >> 8, status & 0xFF >> 1)

    acct_srcs = OrderedDict()
    for cg_path in map(dirname, cg_tasks.viewvalues()):
        for p in os.listdir(cg_path):
            acct_srcs[p] = join(cg_path, p)

    acct_nums = OrderedDict(
        [
            ("cpuacct", ["usage", "usage_percpu"]),
            (
                "memory",
                [
                    "max_usage_in_bytes",
                    "memsw.max_usage_in_bytes",
                    "kmem.max_usage_in_bytes",
                    "kmem.tcp.max_usage_in_bytes",
                ],
            ),
        ]
    )
    for rc, metrics in acct_nums.viewitems():
        for p in metrics:
            p = "{}.{}".format(rc, p)
            if p not in acct_srcs:
                continue
            with open(acct_srcs[p]) as src:
                numbers = map(int, src.read().strip().split())
                acct[p] = " ".join(map(num_format, numbers))

    for p in "time sectors io_merged io_serviced io_wait_time".split():
        p = "blkio.{}".format(p)
        try:
            src = acct_srcs[p]
        except KeyError:
            pass
        else:
            with open(src) as src:
                src = src.read().splitlines()
            for line in src:
                line = line.split()
                if not line or line[0] == "Total":
                    continue
                t = None
                try:
                    dev, t, v = line
                except ValueError:
                    dev, v = line
                dev = dev_resolve(*map(int, dev.split(":")))
                if not dev:
                    continue
                label = "{}[{}]".format(p, dev)
                if t:
                    label += "[{}]".format(t)
                acct[label] = num_format(int(v))

    for k, v in acct.viewitems():
        print("{}: {}".format(k, v), file=sys.stderr)

        # Cleanup tmp dirs
    leftovers = set()
    for tasks in cg_tasks.values():
        tasks_dir = dirname(tasks)
        try:
            os.rmdir(tasks_dir)
        except (OSError, IOError):
            leftovers.add(tasks_dir)
    if leftovers:
        print("Leftover cgroup dirs remaining:{}\n".format("\n  ".join([""] + sorted(leftovers))), file=sys.stderr)
        err = err or 1

    return err
Пример #2
0
class GridParams(object):
    def __init__(self,
                 seq_len,
                 num_epochs=[50],
                 learning_rate=[1e-4],
                 batch_size=[24],
                 keep_prob=[0.5],
                 beta1=[0.9],
                 concat_revcom_input=[False],
                 inference_method_key=["inferenceA"]):
        '''
        Pass parameters as a with values as list
        IE: num_epochs=[50,40], learning_rate=[1e-4,1e-5]        
        '''
        self.param_dict = OrderedDict([
            ('num_epochs', set(num_epochs)),
            ('learning_rate', set(learning_rate)),
            ('batch_size', set(batch_size)),
            ('keep_prob', set(keep_prob)),
            ('beta1', set(beta1)),
            ('concat_revcom_input', set(concat_revcom_input)),
            ('inference_method_key', set(inference_method_key)),
        ])

        cartesian_prod = itertools.product(*self.param_dict.viewvalues())

        self.grid_params_list = []
        for param_tuple in cartesian_prod:
            self.grid_params_list.append(ModelParams(seq_len, *param_tuple))
        self.num_perms = len(self.grid_params_list)
Пример #3
0
 def test_repr_recursive_values(self):
     od = OrderedDict()
     od[42] = od.viewvalues()
     r = repr(od)
     # Cannot perform a stronger test, as the contents of the repr
     # are implementation-dependent.  All we can say is that we
     # want a str result, not an exception of any sort.
     self.assertIsInstance(r, str)
     od[42] = od.viewitems()
     r = repr(od)
     # Again.
     self.assertIsInstance(r, str)
 def test_repr_recursive_values(self):
     od = OrderedDict()
     od[42] = od.viewvalues()
     r = repr(od)
     # Cannot perform a stronger test, as the contents of the repr
     # are implementation-dependent.  All we can say is that we
     # want a str result, not an exception of any sort.
     self.assertIsInstance(r, str)
     od[42] = od.viewitems()
     r = repr(od)
     # Again.
     self.assertIsInstance(r, str)
Пример #5
0
class DataTable(object):

    def __init__(self, iterable=None, headers=None, value_if_missing=None):
        """
        You must pass in an iterable of:

        1. dict, where the keys will be counted as the headers ("fields"),
        2. list/tuple/generator, where the first will be assumed
           to be the fields.
        3. DataRow, from a previous DataTable.

        If your list of lists data doesn't have headers ("fields"),
        make some and pass them into the `headers` parameter.

        If your data has headers and you pass in headers anyways, headers
        acts as a filter and selects the subset of headers you want included.
        If you pass in a header that isn't in the data, there will be an error.

        ---

        If your data is CSV, TSV, or similar format, you can even copy-paste
        it the relevant script for on-the-fly DataTable construction. See
        the DataTable.fromcsvstring() method for details.
        """
        self.__data = OrderedDict()

        if iterable is None:
            # TODO: this exists so that we can create a DataTable
            # TODO: with no data, but we can make headers
            # TODO: what's the best way to address this headers issue?
            if headers is not None:
                validate_fields(headers)
                for header in headers:
                    self.__data[header] = []
            return

        if not hasattr(iterable, '__iter__'):
            raise Exception("DataTable takes an iterable and "
                            "%s is not an iterable" % type(iterable))

        iterator = iterable.__iter__()
        first_row = iterator.next()

        # also identifies OrderedDict
        if isinstance(first_row, dict):
            if not headers:
                fields = first_row.keys()
            else:
                fields = headers
            validate_fields(fields)
            for field in fields:
                self.__data[field] = [first_row[field]]
            for i, item in enumerate(iterator, 1):
                for field in self.fields:
                    try:
                        value = item[field]
                    except KeyError:
                        if value_if_missing is not None:
                            self.__data[field].append(value_if_missing)
                            continue
                        missing = self.__data.viewkeys()-item.viewkeys()
                        raise KeyError("Row %s is missing fields: %s" %
                                       (i, missing))
                    except TypeError:
                        raise TypeError("Although the first row of your data "
                                        "was a `dict`-like object, "
                                        "row %s was: %s" % (i, type(item)))
                    self.__data[field].append(value)
        elif isinstance(first_row, (list, tuple, GeneratorType)):
            # identifies namedtuples, and similar, including this library's
            # DataRow object. in their case, not only will the first row
            # not be headers, but we must access `._fields` to get
            # the header information. from then on, they should be the same.
            if isinstance(first_row, tuple) and hasattr(first_row, '_fields'):
                if not headers:
                    fields = first_row._fields
                else:
                    fields = headers
                validate_fields(fields)
                for field, value in izip(fields, first_row):
                    self.__data[field] = [value]
            else:
                if not headers:
                    fields = list(first_row)
                else:
                    fields = headers
                    iterator = chain((first_row,), iterator)
                validate_fields(fields)
                for field in fields:
                    self.__data[field] = []

            for i, item in enumerate(iterator):
                if not isinstance(item, (list, tuple, GeneratorType)):
                    raise TypeError("Although the first row of your data "
                                    "was a `list`, `tuple`, or `generator`"
                                    "-like object, row %s was: "
                                    "%s" % (i, type(item)))
                if not hasattr(item, '__len__'):
                    item = tuple(item)
                if len(self.fields) != len(item):
                    raise Exception("Row %s's length (%s) does not match "
                                    "headers' length (%s)" % (i,
                                                              len(self.fields),
                                                              len(item)))
                for field, value in izip(self.fields, item):
                    self.__data[field].append(value)
        else:
            raise Exception("Unrecognized row type: %s" % type(first_row))

    @property
    def fields(self):
        """
        A shallow copy of the list of fields in the DataTable.

        If you modify the DataTable, this list will not update.
        """
        return self.__data.keys()

    @fields.setter
    def fields(self, new_fieldnames):
        """
        Overwrite all field names with new field names. Mass renaming.
        """
        if len(new_fieldnames) != len(self.fields):
            raise Exception("Cannot replace fieldnames (len: %s) with list of "
                            "incorrect length (len: %s)" % (len(new_fieldnames),
                                                            len(self.fields)))
        for old_name, new_name in izip(self.fields, new_fieldnames):
            # use pop instead of `del` in case old_name == new_name
            self.__data[new_name] = self.__data.pop(old_name)

    @classmethod
    def fromcolumns(cls, fields, columns):
        if len(fields) != len(columns):
            raise Exception("When constructing .fromcolumns, the number of "
                            "fields (%s) must equal the number of columns (%s)"
                            % (len(fields), len(columns)))
        new_table = cls()
        for field, column in izip(fields, columns):
            new_table[field] = column
        return new_table

    @classmethod
    def fromcsv(cls, path, delimiter=",", headers=None):
        f = open(path, 'r')
        reader = UnicodeRW.UnicodeDictReader(f,
                                             delimiter=delimiter)
        new_table = cls(reader, headers=headers)
        f.close()
        return new_table

    @classmethod
    def fromcsvstring(cls, csvstring, delimiter=",", quotechar="\""):
        """
        Takes one string that represents the entire contents of the CSV
        file, or similar delimited file.

        If you have a list of lists, where the first list is the headers,
        then use the main constructor.

        If you see an excess of whitespace in the first column of your data,
        this is probably because you tried to format a triple-quoted string
        literal nicely. Don't add any padding to the left.

        NOTE: Please prefix your triple-quoted string literal with `u` or `ur`
        as necessary. For copy-pasting directly from Excel, use `ur`. For
        copy-pasting from something Python (or similar) printed, use `ur`.
        For something just dumped from Python via __repr__ or some other
        text source that displays escape characters used, use `u`.

        ---

        Implementation notes:

        This solution was inspired by UnicodeRW.
        cStringIO.StringIO turns the passed string into a file-like
        (readble) object. The string must be encoded so that StringIO
        presents encoded text.

        In UnicodeRW, codecs.getreader('utf-8') reads an encoded file object
        to product a decoded file object on the fly. We don't need this.

        We read the StringIO object line by line into csv.reader,
        which is consumes encoded text and parses the CSV format out of it.
        Then we decode each cell one by one as we pass it into the data table

        csv.QUOTE_NONE (as well as the r-prefix on r'''string''') are vital
        since we're copy-pasting directly from Excel. The string should be
        treated as "literally" ("raw") as possible.
        """
        if not isinstance(csvstring, basestring):
            raise Exception("If trying to construct a DataTable with "
                            "a list of lists, just use the main "
                            "constructor. Make sure to include a header row")

        stringio = StringIO(csvstring.encode('utf-8'))
        csv_data = csv.reader((line for line in stringio),
                              delimiter=delimiter,
                              dialect=csv.excel,
                              quotechar=quotechar,
                              quoting=csv.QUOTE_NONE)
        new_datatable = cls((s.decode('utf-8') for s in row)
                            for row in csv_data)
        for field in new_datatable.fields:
            new_datatable[field] = parse_column(new_datatable[field])
        return new_datatable

    @classmethod
    def fromdict(cls, datadict):
        """
        Constructs a new DataTable using a dictionary of the format:

        {field1: [a,b,c],
         field2: [d,e,f],
         field3: [g,h,i]}

        ... which most closely matches the internal representation
        of the DataTable. If it is an OrderedDict, the key order
        will be preserved.
        """
        new_datatable = cls()
        for field, column in datadict.items():
            new_datatable[field] = column
        return new_datatable

    @classmethod
    def fromexcel(cls, path, sheet_name_or_num=0, headers=None):
        """
        Constructs a new DataTable from an Excel file.

        Specify sheet_name_or_number to load that specific sheet.

        Headers will be inferred automatically, but if you'd prefer
        to load only a subset of all the headers, pass in a list of the
        headers you'd like as `headers`.

        ---

        Alternatively, it's quite simple to:

            reader = ExcelReader('myfile.xls')
            reader.change_sheet('default')
            data = DataTable(reader)
        """
        reader = ExcelRW.UnicodeDictReader(path, sheet_name_or_num)
        return cls(reader, headers=headers)

    def __add__(self, other_datatable):
        return self.concat(other_datatable)

    def __contains__(self, fieldname):
        return fieldname in self.__data.viewkeys()

    def __delitem__(self, key):
        del self.__data[key]

    def __eq__(self, other):
        """
        Note that there is a bug (in my opinion) where two OrderedDicts
        are considered equal even if one dict has more key-value pairs
        after the initial matching set.

        The line where we compare the length of the two DataTables and
        the number of keys is meant to protect against this bug.
        """
        if not isinstance(other, DataTable):
            raise TypeError("Cannot compare DataTables with `%s` "
                            "for equality" % type(other))
        if len(self) != len(other) or len(self.fields) != len(other.fields):
            return False
        for selfrow, otherrow in izip(self, other):
            if selfrow != otherrow:
                return False
        return True

    def __getitem__(self, item):
        """
        Pass in a fieldname to retrieve a column:
        column = dt['column_name']

        Or slice the DataTable like a list:
        sliced = dt[:30:2]
        """
        if isinstance(item, slice):
            start, stop, step = item.indices(len(self))
            sliced_table = DataTable()
            for field in self.fields:
                sliced_table[field] = self.__data[field][start:stop:step]
            return sliced_table
        elif isinstance(item, (list, tuple)):
            return [self.__getitem__(colname) for colname in item]
        elif isinstance(item, basestring):
            if item not in self:
                raise KeyError("DataTable does not have column `%s`" % item)
            return self.__data[item]
        elif isinstance(item, (int, long)):
            return self.row(item)
        else:
            raise KeyError("DataTable does not support indexing with `%s`" %
                           type(item))

    def __len__(self):
        if not self.__data:
            return 0
        else:
            return len(self.__data.viewvalues().__iter__().next())

    def __repr__(self):
        return str(self)

    def __setitem__(self, fieldname, column):
        """
        Sets a column with the specified name to the specified value:

        dt['new_column'] = [1, 2, 3]

        1. If the column name doesn't exist, it will be created.
        2. If the column value provided is a tuple, it will be cast to a list.
        3. If the column value isn't a list, tuple, or array, it will
           be assumed that you're trying to set a whole column to some scalar
           value. For example:

           dt['another_column'] = True

           ... will set the entire column, for the length of the table, equal
           to `True`.
        """
        if not isinstance(column, (list, array)):
            if isinstance(column, tuple):
                column = list(column)
            else:
                column = [column] * len(self)
        if self.__data and len(column) != len(self):
            raise Exception("New column length (%s) must match length "
                            "of table (%s)" % (len(column), len(self)))
        self.__data[fieldname] = column

    def __str__(self):
        return unicode(self).encode('utf-8')

    def __unicode__(self):
        return self.pretty

    def __print_table(self, row_delim, header_delim=None,
                      header_pad=u"", pad=u""):
        """
        row_delim         default delimiter inserted between columns of every
                          row in the table.
        header_delim      delimiter inserted within the headers. by default
                          takes the value of `row_delim`
        header_pad        put on the sides of the row of headers.
        pad               put on the sides of every row.
        """
        if header_delim is None:
            header_delim = row_delim
        num_cols = len(self.fields)
        accumulator = ((u"%s" + header_delim) * num_cols)[:-len(header_delim)]
        accumulator = ((header_pad + accumulator + header_pad + u"\n") %
                       tuple(self.fields))
        for datarow in self:
            rowstring = ((u"%s" + row_delim) * num_cols)[:-len(row_delim)]
            rowstring = (pad + rowstring + pad + u"\n") % tuple(datarow)
            accumulator += rowstring
        return accumulator[:-1]

    @property
    def html(self):
        accumulator = u"<table>"
        accumulator += u"<tr>" + u"".join([u"<th>"+field+u"</th>"
                                           for field in self.fields]) + u"</tr>"
        for datarow in self:
            accumulator += u"<tr>" + u"".join([u"<td>"+unicode(row)+u"</td>"
                                               for row in datarow]) + u"</tr>"
        return accumulator + u"</table>"

    @property
    def jira(self):
        header, row = u"||", u"|"
        return self.__print_table(row_delim=row,
                                  header_delim=header,
                                  header_pad=header,
                                  pad=row)

    # TODO: print a "prettytable" style table
    @property
    def pretty(self):
        return self.t

    @property
    def t(self):
        return self.__print_table(u"\t")

    def append(self, row):
        """
        Takes a dict, a list/tuple/generator, or a DataRow/namedtuple,
        and appends it to the "bottom" or "end" of the DataTable.

        dicts must share the same keys as the DataTable's columns.

        lists/tuples/generators are simply trusted to be in the correct order
        and of the correct type (if relevant).

        If the table being appended to is empty, the columns are inferred
        from the row being appended.

        DataRows and namedtuples' `_fields` protected class attribute is
        checked for the field names. Those are checked against the DataTable
        and then appended to the relevant columns using those field names.
        """
        if isinstance(row, dict):
            if self.fields and not set(row.keys()) == set(self.fields):
                raise Exception("Cannot append a dict to DataTable without "
                                "all keys matching (order being irrelevant).\n"
                                "dict: %s\nDataTable: %s" % (row.keys(),
                                                             self.fields))
            if not self.fields:
                for field in row.keys():
                    self.__data[field] = [row[field]]
            else:
                for field in self.fields:
                    self.__data[field].append(row[field])
        elif isinstance(row, (list, tuple, GeneratorType)):
            if isinstance(row, tuple) and hasattr(row, '_fields'):
                fieldnames = row._fields
                if self.fields and not set(fieldnames) == set(self.fields):
                    raise Exception("Cannot append a Datarow or namedtuple to "
                                    "DataTable without all fields matching "
                                    "(order being irrelevant).\n"
                                    "DataRow/namedtuple: %s\n"
                                    "DataTable: %s" % (fieldnames, self.fields))
                if not self.fields:
                    for fieldname, value in izip(fieldnames, row):
                        self.__data[fieldname] = [value]
                else:
                    for fieldname, value in izip(fieldnames, row):
                        self.__data[fieldname].append(value)
            else:
                if isinstance(row, GeneratorType):
                    row = tuple(row)
                if self.fields and not len(row) == len(self.fields):
                    raise Exception("The row being appended does not have the "
                                    "correct length. It should have a length "
                                    "of %s, but is %s" % (len(self.fields),
                                                          len(row)))
                if not self.fields:
                    raise Exception("Can't append a list/tuple/GeneratorType "
                                    "as a row if the table doesn't have "
                                    "columns defined yet.")
                # we're just going to hope that the generator's contents are
                # provided in the right order, and of the right type.
                for (_, column), element in izip(self.__data.items(), row):
                    column.append(element)
        else:
            raise Exception("Unable to append type `%s` to DataTable" %
                            type(row))

    def apply(self, func, *fields):
        """
        Applies the function, `func`, to every row in the DataTable.

        If no fields are supplied, the entire row is passed to `func`.
        If fields are supplied, the values at all of those fields
        are passed into func in that order.
        ---
        data['diff'] = data.apply(short_diff, 'old_count', 'new_count')
        """
        results = []
        for row in self:
            if not fields:
                results.append(func(row))
            else:
                if any(field not in self for field in fields):
                    for field in fields:
                        if field not in self:
                            raise Exception("Column `%s` does not exist "
                                            "in DataTable" % field)
                results.append(func(*[row[field] for field in fields]))
        return results

    def col(self, col_name_or_num):
        """
        Returns the col at index `colnum` or name `colnum`.
        """
        if isinstance(col_name_or_num, basestring):
            return self[col_name_or_num]
        elif isinstance(col_name_or_num, (int, long)):
            if col_name_or_num > len(self.fields):
                raise IndexError("Invalid column index `%s` for DataTable" %
                                 col_name_or_num)
            return self.__data[self.fields[col_name_or_num]]

    def concat(self, other_datatable, inplace=False):
        """
        Concatenates two DataTables together, as long as column names
        are identical (ignoring order). The resulting DataTable's columns
        are in the order of the table whose `concat` method was called.
        """
        if not isinstance(other_datatable, DataTable):
            raise TypeError("`concat` requires a DataTable, not a %s" %
                            type(other_datatable))

        # if the self table is empty, we can just return the other table
        # if we need to do it in place, we just copy over the columns
        if not self.fields:
            if inplace:
                for field in other_datatable.fields:
                    self[field] = other_datatable[field]
                return self
            else:
                return other_datatable
        if not other_datatable.fields:
            return self

        if set(self.fields) != set(other_datatable.fields):
            raise Exception("Columns do not match:\nself: %s\nother: %s" %
                            (self.fields, other_datatable.fields))

        if inplace:
            for field in self.fields:
                self.__data[field] = self[field] + other_datatable[field]
            return self
        else:
            new_table = DataTable()
            for field in self.fields:
                new_table[field] = self[field] + other_datatable[field]
            return new_table

    def copy(self):
        return self.fromdict(self.__data)

    def distinct(self, fieldname, key=None):
        """
        Returns the unique values seen at `fieldname`.
        """
        return tuple(unique_everseen(self[fieldname], key=key))

    def groupby(self, *groupfields):
        """
        Groups rows in this table according to the unique combinations of
        `groupfields` combined.
        """
        return GroupbyTable(self, groupfields)

    # TODO: this is a placeholder and only does a very simple left join.
    def join(self, right_table, on):
        keymap = {}
        for row in right_table:
            if row[on] in keymap:
                keymap[row[on]].append(row)
            else:
                keymap[row[on]] = [row]
        new_table = []
        for row in self:
            if row[on] in keymap:
                left_dict = dict(row.items())
                for item in keymap[row[on]]:
                    left_dict_copy = left_dict.copy()
                    left_dict_copy.update(dict(item.items()))
                    new_table.append(left_dict_copy)
        return DataTable(new_table)

    def mask(self, masklist):
        """
        `masklist` is an array of Bools or equivalent.

        This returns a new DataTable using only the rows that were True
        (or equivalent) in the mask.
        """
        if not hasattr(masklist, '__len__'):
            masklist = tuple(masklist)

        if len(masklist) != len(self):
            raise Exception("Masklist length (%s) must match length "
                            "of DataTable (%s)" % (len(masklist), len(self)))

        new_datatable = DataTable()
        for field in self.fields:
            new_datatable[field] = list(compress(self[field], masklist))
        return new_datatable

    def mutapply(self, function, fieldname):
        """
        Applies `function` in-place to the field name specified.

        In other words, `mutapply` overwrites column `fieldname`
        ith the results of applying `function` to each element of that column.
        """
        self[fieldname] = self.apply(function, fieldname)

    def rename(self, old_fieldname, new_fieldname):
        """
        Renames a specific field, and preserves the underlying order.
        """
        if old_fieldname not in self:
            raise Exception("DataTable does not have field `%s`" %
                            old_fieldname)

        if not isinstance(new_fieldname, basestring):
            raise ValueError("DataTable fields must be strings, not `%s`" %
                             type(new_fieldname))

        if old_fieldname == new_fieldname:
            return

        new_names = self.fields
        location = new_names.index(old_fieldname)
        del new_names[location]
        new_names.insert(location, new_fieldname)
        self.fields = new_names

    def reorder(self, fields_in_new_order):
        """
        Pass in field names in the order you wish them to be swapped.
        """
        if not len(fields_in_new_order) == len(self.fields):
            raise Exception("Fields to reorder with are not the same length "
                            "(%s) as the original fields (%s)" %
                            (len(fields_in_new_order), len(self.fields)))
        if not set(fields_in_new_order) == set(self.fields):
            raise Exception("Fields to reorder with should be the same "
                            "as the original fields")
        new = OrderedDict()
        for field in fields_in_new_order:
            new[field] = self.__data[field]
        self.__data = new

    def row(self, rownum):
        """
        Returns the row at index `rownum`.
        ---
        Note that the DataRow object returned that represents the data row
        is constructed on the fly and is a just a shallow copy of
        the underlying data that does not update dynamically.
        """
        if rownum > len(self):
            raise IndexError("Invalid row index `%s` for DataTable" % rownum)
        return datarow_constructor(self.fields)([self[field][rownum]
                                                 for field in self.fields])

    def sample(self, num):
        """
        Returns a new table with rows randomly sampled.

        We create a mask with `num` True bools, and fill it with False bools
        until it is the length of the table. We shuffle it, and apply that
        mask to the table.
        """
        if num > len(self):
            return self.copy()
        elif num < 0:
            raise IndexError("Cannot sample a negative number of rows "
                             "from a DataTable")

        random_row_mask = ([True] * num) + ([False] * (len(self) - num))
        shuffle(random_row_mask)

        sampled_table = self.mask(random_row_mask)
        random_col_name = 'random_sorting_column'
        while random_col_name in sampled_table:
            random_col_name = '%030x' % randrange(16**30)
        sampled_table[random_col_name] = [random()
                                          for _ in xrange(len(sampled_table))]
        sampled_table.sort(random_col_name, inplace=True)
        del sampled_table[random_col_name]
        return sampled_table

    def sort(self, fieldname, key=lambda x: x, desc=False, inplace=False):
        """
        This matches Python's built-in sorting signature closely.

        By default, a new DataTable will be returned and the original will
        not be mutated. If preferred, specify `inplace=True` in order to
        mutate the original table. Either way, a reference to the relevant
        table will be returned.
        """
        try:
            field_index = tuple(self.fields).index(fieldname)
        except ValueError:
            raise ValueError("Sorting on a field that doesn't exist: `%s`" %
                             fieldname)

        data_cols = izip(*sorted(izip(*[self.__data[field]
                                        for field in self.fields]),
                                 key=lambda row: key(row[field_index]),
                                 reverse=desc))

        target_table = self if inplace else DataTable()

        for field, data_col in izip(self.fields, data_cols):
            target_table[field] = list(data_col)

        # Note that sorting in-place still returns a reference
        # to the table being sorted, for convenience.
        return target_table

    def where(self, fieldname, value, negate=False):
        """
        Returns a new DataTable with rows only where the value at
        `fieldname` == `value`.
        """
        if negate:
            return self.mask([elem != value
                              for elem in self[fieldname]])
        else:
            return self.mask([elem == value
                              for elem in self[fieldname]])

    def wherefunc(self, func, negate=False):
        """
        Applies a function to an entire row and filters the rows based on the
        boolean output of that function.
        """
        if negate:
            return self.mask([not func(item) for item in self])
        else:
            return self.mask([func(item) for item in self])

    def wherein(self, fieldname, collection, negate=False):
        """
        Returns a new DataTable with rows only where the value at
        `fieldname` is contained within `collection`.
        """
        if negate:
            return self.mask([elem not in collection
                              for elem in self[fieldname]])
        else:
            return self.mask([elem in collection
                              for elem in self[fieldname]])

    def wheregreater(self, fieldname, value):
        """
        Returns a new DataTable with rows only where the value at
        `fieldname` > `value`.
        """
        return self.mask([elem > value for elem in self[fieldname]])

    def whereless(self, fieldname, value):
        """
        Returns a new DataTable with rows only where the value at
        `fieldname` < `value`.
        """
        return self.mask([elem < value for elem in self[fieldname]])

    def wherenot(self, fieldname, value):
        """
        Logical opposite of `where`.
        """
        return self.where(fieldname, value, negate=True)

    def wherenotfunc(self, func):
        """
        Logical opposite of `wherefunc`.
        """
        return self.wherefunc(func, negate=True)

    def wherenotin(self, fieldname, value):
        """
        Logical opposite of `wherein`.
        """
        return self.wherein(fieldname, value, negate=True)

    def writecsv(self, path, delimiter=","):
        writer = UnicodeRW.UnicodeWriter(open(path, 'wb'),
                                         self.fields,
                                         delimiter=delimiter,
                                         lineterminator=u"\n")
        writer.writerow(self.fields)
        writer.writerows(self)
        writer.close()

    def writexlsx(self, path, sheetname="default"):
        """
        Writes this table to an .xlsx file at the specified path.

        If you'd like to specify a sheetname, you may do so.

        If you'd like to write one workbook with different DataTables
        for each sheet, import the `excel` function from acrylic. You
        can see that code in `utils.py`.

        Note that the outgoing file is an .xlsx file, so it'd make sense to
        name that way.
        """
        writer = ExcelRW.UnicodeWriter(path)
        writer.set_active_sheet(sheetname)
        writer.writerow(self.fields)
        writer.writerows(self)
        writer.save()

    def __iter__(self):
        datarow = datarow_constructor(self.fields)
        for values in izip(*[self.__data[field] for field in self.fields]):
            yield datarow(values)
Пример #6
0
class DotMap(MutableMapping, OrderedDict):
    def __init__(self, *args, **kwargs):
        self._map = OrderedDict()
        self._dynamic = True
        if kwargs:
            if "_dynamic" in kwargs:
                self._dynamic = kwargs["_dynamic"]
        if args:
            d = args[0]
            # for recursive assignment handling
            trackedIDs = {id(d): self}
            if isinstance(d, dict):
                for k, v in self.__call_items(d):
                    if isinstance(v, dict):
                        if id(v) in trackedIDs:
                            v = trackedIDs[id(v)]
                        else:
                            v = self.__class__(v, _dynamic=self._dynamic)
                            trackedIDs[id(v)] = v
                    if type(v) is list:
                        l = []
                        for i in v:
                            n = i
                            if isinstance(i, dict):
                                n = self.__class__(i, _dynamic=self._dynamic)
                            l.append(n)
                        v = l
                    self._map[k] = v
        if kwargs:
            for k, v in self.__call_items(kwargs):
                if k is not "_dynamic":
                    self._map[k] = v

    def __call_items(self, obj):
        if hasattr(obj, "iteritems") and ismethod(getattr(obj, "iteritems")):
            return obj.iteritems()
        else:
            return obj.items()

    def items(self):
        return self.iteritems()

    def iteritems(self):
        return self.__call_items(self._map)

    def __iter__(self):
        return self._map.__iter__()

    def next(self):
        return self._map.next()

    def __setitem__(self, k, v):
        self._map[k] = v

    def __getitem__(self, k):
        return self._map[k]

    def __setattr__(self, k, v):
        if k in {
                "_map",
                "_dynamic",
                "_ipython_canary_method_should_not_exist_",
        }:
            super(DotMap, self).__setattr__(k, v)
        else:
            self[k] = v

    def __getattr__(self, k):
        if k in {
                "_map",
                "_dynamic",
                "_ipython_canary_method_should_not_exist_",
        }:
            return super(DotMap, self).__getattr__(k)

        try:
            v = super(self.__class__, self).__getattribute__(k)
            return v
        except AttributeError:
            pass

        return self[k]

    def __delattr__(self, key):
        return self._map.__delitem__(key)

    def __contains__(self, k):
        return self._map.__contains__(k)

    def __add__(self, other):
        if self.empty():
            return other
        else:
            self_type = type(self).__name__
            other_type = type(other).__name__
            msg = "unsupported operand type(s) for +: '{}' and '{}'"
            raise TypeError(msg.format(self_type, other_type))

    def __str__(self):
        items = []
        for k, v in self.__call_items(self._map):
            # recursive assignment case
            if id(v) == id(self):
                items.append("{0}={1}(...)".format(k, self.__class__.__name__))
            else:
                seperator = "\n" if isinstance(v, DotMap) else " "
                attr_str = f"{k}:{seperator}{v}"
                attr_str = self._indent(attr_str, 2)
                items.append(attr_str)
        joined = "\n".join(items)
        return joined

    def __repr__(self):
        return str(self)

    def toDict(self):
        d = {}
        for k, v in self.items():
            if issubclass(type(v), DotMap):
                # bizarre recursive assignment support
                if id(v) == id(self):
                    v = d
                else:
                    v = v.toDict()
            elif type(v) in (list, tuple):
                l = []
                for i in v:
                    n = i
                    if issubclass(type(i), DotMap):
                        n = i.toDict()
                    l.append(n)
                if type(v) is tuple:
                    v = tuple(l)
                else:
                    v = l
            d[k] = v
        return d

    def pprint(self, pformat="dict"):
        if pformat == "json":
            print(dumps(self.toDict(), indent=4, sort_keys=True))
        else:
            pprint(self.toDict())

    def empty(self):
        return not any(self)

    # proper dict subclassing
    def values(self):
        return self._map.values()

    # # ipython support
    def __dir__(self):
        return self.keys()

    @classmethod
    def parseOther(self, other):
        if issubclass(type(other), DotMap):
            return other._map
        else:
            return other

    def __cmp__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__cmp__(other)

    def __eq__(self, other):
        other = DotMap.parseOther(other)
        if not isinstance(other, dict):
            return False
        return self._map.__eq__(other)

    def __ge__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__ge__(other)

    def __gt__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__gt__(other)

    def __le__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__le__(other)

    def __lt__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__lt__(other)

    def __ne__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__ne__(other)

    def __delitem__(self, key):
        return self._map.__delitem__(key)

    def __len__(self):
        return self._map.__len__()

    def clear(self):
        self._map.clear()

    def copy(self):
        return self.__class__(self)

    def __copy__(self):
        return self.copy()

    def __deepcopy__(self, memo=None):
        return self.copy()

    def get(self, key, default=None):
        return self._map.get(key, default)

    def has_key(self, key):
        return key in self._map

    def iterkeys(self):
        return self._map.iterkeys()

    def itervalues(self):
        return self._map.itervalues()

    def keys(self):
        return self._map.keys()

    def pop(self, key, default=None):
        return self._map.pop(key, default)

    def popitem(self):
        return self._map.popitem()

    def setdefault(self, key, default=None):
        return self._map.setdefault(key, default)

    def update(self, *args, **kwargs):
        if len(args) != 0:
            self._map.update(*args)
        self._map.update(kwargs)

    def viewitems(self):
        return self._map.viewitems()

    def viewkeys(self):
        return self._map.viewkeys()

    def viewvalues(self):
        return self._map.viewvalues()

    @classmethod
    def fromkeys(cls, seq, value=None):
        d = cls()
        d._map = OrderedDict.fromkeys(seq, value)
        return d

    def __getstate__(self):
        return self.__dict__

    def __setstate__(self, d):
        self.__dict__.update(d)

    # bannerStr
    def _getListStr(self, items):
        out = "["
        mid = ""
        for i in items:
            mid += "  {}\n".format(i)
        if mid != "":
            mid = "\n" + mid
        out += mid
        out += "]"
        return out

    def _getValueStr(self, k, v):
        outV = v
        multiLine = len(str(v).split("\n")) > 1
        if multiLine:
            # push to next line
            outV = "\n" + v
        if type(v) is list:
            outV = self._getListStr(v)
        out = "{} {}".format(k, outV)
        return out

    def _getSubMapDotList(self, pre, name, subMap):
        outList = []
        if pre == "":
            pre = name
        else:
            pre = "{}.{}".format(pre, name)

        def stamp(pre, k, v):
            valStr = self._getValueStr(k, v)
            return "{}.{}".format(pre, valStr)

        for k, v in subMap.items():
            if isinstance(v, DotMap) and v != DotMap():
                subList = self._getSubMapDotList(pre, k, v)
                outList.extend(subList)
            else:
                outList.append(stamp(pre, k, v))
        return outList

    def _getSubMapStr(self, name, subMap):
        outList = ["== {} ==".format(name)]
        for k, v in subMap.items():
            if isinstance(v, self.__class__) and v != self.__class__():
                # break down to dots
                subList = self._getSubMapDotList("", k, v)
                # add the divit
                # subList = ['> {}'.format(i) for i in subList]
                outList.extend(subList)
            else:
                out = self._getValueStr(k, v)
                # out = '> {}'.format(out)
                out = "{}".format(out)
                outList.append(out)
        finalOut = "\n".join(outList)
        return finalOut

    def bannerStr(self):
        lines = []
        previous = None
        for k, v in self.items():
            if previous == self.__class__.__name__:
                lines.append("-")
            out = ""
            if isinstance(v, self.__class__):
                name = k
                subMap = v
                out = self._getSubMapStr(name, subMap)
                lines.append(out)
                previous = self.__class__.__name__
            else:
                out = self._getValueStr(k, v)
                lines.append(out)
                previous = "other"
        lines.append("--")
        s = "\n".join(lines)
        return s

    def _indent(self, s_, num_spaces):
        s = s_.split("\n")
        if len(s) == 1:
            return s_
        first = s.pop(0)
        s = [(num_spaces * " ") + line for line in s]
        s = "\n".join(s)
        s = first + "\n" + s
        return s
Пример #7
0
class Reference(object):
  def __init__(self, fasta, chrom, output, prefix):      
    self.__log = False
    self.__logger = ''
    self.start_logging()

    self.__fasta = fasta
    self.__chrom = chrom
    self.__chromdict = OrderedDict()
    self.__fastadict = defaultdict(list)
    self.__output = output
    self.__prefix = prefix

  def start_logging(self):
    self.__log = True
    self.__logger = logging.getLogger('pipeline.createReference')

  def show_log(self, level, message):
    if self.__log:
      if level == 'debug':
        self.__logger.debug(message)
      elif level == 'info':
        self.__logger.info(message)
      elif level == 'warning':
        self.__logger.warning(message)
      elif level == 'error':
        self.__logger.error(message)
      elif level == 'critical':
        self.__logger.critical(message)
    else:
      print message

  def prepare_chromdict(self):
    self.show_log('info', 'chromosome which are kept and names are changed:')
    for entry in readFile_getList_withSep(self.__chrom, '\t'):
      self.show_log('info', '{0} -> {1}'.format(entry[0], entry[1]))
      if entry[0][0] != '>':
        entry[0] = '>{0}'.format(entry[0])
      if entry[1][0] != '>':
        entry[1] = '>{0}'.format(entry[1])
      self.__chromdict[entry[0]] = entry[1]

  def process_Fasta(self):
    self.show_log('info', 'Reading the fasta file')
    chromremove = set()
    linecount = 0
    chromid = ''
    with get_fileobject(self.__fasta, 'r') as filein:
      for line in filein:
        if line.startswith('>'):
          try:
            chromid = self.__chromdict[line.rstrip('\n')]
          except KeyError:
            chromid = ''
            chromremove.add(line.rstrip('\n'))
            linecount += 1
        elif chromid != '':
          self.__fastadict[chromid].append(line)
        else:
          linecount += 1

    self.show_log('info', 'chromosomes removed: {0}'.format(len(chromremove)))
    self.show_log('info', 'lines removed: {0}'.format(linecount))

  def writeFasta(self):
    self.show_log('info', 'Writing the new fasta files')
    chromfolder = '{0}chromosomes{1}'.format(self.__output, sep)
    if not create_Directory(chromfolder):
      self.show_log('error', "Can't create directory: {0}".format(chromfolder))
      exit(2)
    fastafile = '{0}{1}.fa'.format(self.__output, self.__prefix)
    self.show_log('info', 'Fasta file: {0}'.format(fastafile))
    self.show_log('info', 'Chromosome folder: {0}'.format(chromfolder))
    for chrom in self.__chromdict.viewvalues():
      if len(self.__fastadict[chrom]) != 0:
        chromfilename = '{0}{1}.fa'.format(chromfolder, chrom.lstrip('>'))
        self.show_log('info', "Writing '{0}'".format(chromfilename))
        write_list([chrom+'\n'] + self.__fastadict[chrom], chromfilename)
        write_list([chrom+'\n'] + self.__fastadict[chrom], fastafile, 'a')
Пример #8
0
class UnitModel(Q.QAbstractItemModel):
    """Unit model."""
    def __init__(self, file_descriptors, file_format=None):
        """
        Create model.

        Arguments:
            file_descriptors: File descriptors proxy object.
            file_format (Optional[str]): File format. Defaults to
                *None*.
        """
        super(UnitModel, self).__init__()
        self._file_descriptors = file_descriptors

        self._units2file = OrderedDict()
        self._units2stat = OrderedDict()
        self._emb2ext = OrderedDict()
        self._ext2emb = OrderedDict()
        self._extfiles = {}

        file_dict = {}
        for handle, info in self._file_descriptors.handle2info.viewitems():
            self._units2file[handle] = info.filename
            self._units2stat[handle] = info.embedded
            file_dict[info.filename] = handle

        unit = -10
        for fileuid in external_files(file_format):
            filename = external_file(fileuid)
            if not filename:
                continue
            self._extfiles[fileuid] = filename
            if fileuid in file_dict:
                continue
            self._units2file[unit] = fileuid
            unit = unit - 1

    def file2unit(self, filename, udefault=None, umin=None, umax=None):
        """Get unit for given file."""
        return self._file_descriptors.file2unit(filename, udefault, umin, umax)

    def addItem(self, filename, udefault=None, umin=None, umax=None):
        """
        Add item to model and units dictionary.

        Arguments:
            filename (str): File name.
            udefault (Optional[int]): Default file descriptor value.
                Defaults to *None*.
            umin (Optional[int]): Minimum file descriptor value.
                Defaults to *None*.
            umax (Optional[int]): Maximum file descriptor value.
                Defaults to *None*.

        Returns:
            int: File descriptor.

        Raises:
            ValueError: if unit can not be registered in [min, max]
            range.

        Note:
            For now, items are always added as external files.
        """
        self.beginInsertRows(Q.QModelIndex(), 0, 0)

        unit = self.file2unit(filename, udefault, umin, umax)

        self._units2file[unit] = filename

        self.endInsertRows()
        return unit

    def rowCount(self, parent=Q.QModelIndex()):
        """
        Get number of rows.

        Arguments:
            parent (Optional[QModelIndex]): Parent model index. Defaults
                to invalid model index.

        Returns:
            int: Rows count.
        """
        if parent.isValid():
            return 0

        return len(self._units2file)

    # pragma pylint: disable=unused-argument, no-self-use
    def columnCount(self, parent=Q.QModelIndex()):
        """
        Get number of columns.

        Arguments:
            parent (Optional[QModelIndex]): Parent model index. Defaults
                to invalid model index.

        Returns:
            int: Columns count.
        """
        return 1

    def index(self, row, column, parent=Q.QModelIndex()):
        """
        Get model index for given *row* *column* and *parent*.

        Arguments:
            row (int): Row index.
            column (int): Column index.
            parent (Optional[QModelIndex]): Parent model index. Defaults
                to invalid model index.

        Returns:
            QModelIndex: Corresponding model index.
        """
        return self.createIndex(row, column) if \
            self.hasIndex(row, column, parent) else Q.QModelIndex()

    def data(self, index, role=Q.Qt.DisplayRole):
        """
        Get data stored by model index for given role.

        Arguments:
            index (QModelIndex): Model index.
            role (Optional[int]): Role of the data. Defaults to
                *Qt.DisplayRole*.

        Returns:
            any: Data stored by model index.
        """
        # pragma pylint: disable=too-many-branches
        value = None
        if index.isValid():
            unit = self._units2file.keys()[index.row()]
            filename = None if unit == -1 else self._units2file[unit]

            if role in (Role.IdRole, ):
                value = unit

            elif role in (Role.ValidityRole, ):
                if unit == -1:
                    value = False
                else:
                    if filename in self._extfiles:
                        value = self._extfiles.get(filename) is not None
                    else:
                        value = filename is not None

            elif role in (Role.ReferenceRole, ):
                if unit == -1:
                    value = False
                else:
                    value = filename in self._extfiles

            elif role in (Q.Qt.DisplayRole, Q.Qt.EditRole, Q.Qt.ToolTipRole,
                          Role.CustomRole):
                undefstr = translate("DataFiles", "undefined")
                embedstr = translate("DataFiles", "embedded")

                if unit == -1:
                    value = "<{}>".format(undefstr)  # pragma pylint: disable=redefined-variable-type

                else:
                    if filename in self._extfiles:
                        # for external files 'filename' is its UID
                        if role in (Q.Qt.DisplayRole, Q.Qt.EditRole):
                            value = self._extfiles.get(filename)
                        elif role in (Q.Qt.ToolTipRole, ):
                            value = self._extfiles.get(filename) + \
                                " ({})".format(filename)
                        else:  # Role.CustomRole
                            value = filename
                    else:
                        if role in (Q.Qt.DisplayRole, Q.Qt.EditRole):
                            if filename is not None:
                                state = self._units2stat.get(unit, False)
                                value = os.path.basename(filename)
                                if state:
                                    value = value + " ({})".format(embedstr)
                            else:
                                value = undefstr
                                if unit is not None:
                                    value = "{} ".format(unit) + value
                                value = "<{}>".format(value)
                        else:  # Qt.ToolTipRole, Role.CustomRole
                            value = filename
        return value

    # pragma pylint: disable=unused-argument, no-self-use
    def parent(self, index):
        """
        Get parent model index for the given one.

        Arguments:
            index (QModelIndex): Model index.

        Returns:
            QModelIndex: Parent model index.
        """
        return Q.QModelIndex()

    def emb2ext(self, embname, extname):
        """
        Unembed file from the study.

        Arguments:
            embname (str): Source path for embedded data file.
            extname (str): Destination path to put the file to.

        Returns:
            str: New file path (external).

        Raises:
            ValueError: If external file name is already in use (except
                when it is a back conversion).
        """
        return self._conversionTemplate(embname, lambda _: extname,
                                        self._ext2emb, self._emb2ext, False)

    def ext2emb(self, extname):
        """
        Embed file to the study.

        Arguments:
            extname (str): Source path of the data file.

        Returns:
            str: New file path (embedded).

        Raises:
            ValueError: If internal file name is already in use (except
                when it is a  back conversion).
        """
        return self._conversionTemplate(extname,
                                        self._file_descriptors.ext2emb,
                                        self._emb2ext, self._ext2emb, True)

    def _conversionTemplate(self, oldname, gen_newname, register, unregister,
                            newstate):
        """
        Template for converting file from embedded to external and back.

        Arguments:
            oldname (str): Source file path.
            gen_newname (function): Used to generate new file path.
            register (dict): Dictionary where to register the resulting
                conversion.
            unregister (dict): Dictionary where to unregister a previous
                conversion.
            newstate (bool): New embedded state flag.

        Returns:
            str: New file path.

        Raises:
            ValueError: If new file path is already in use under another
                entry.
        """
        [unit] = [k for k, v in self._units2file.iteritems() if v == oldname]

        oldstate = self._units2stat.get(unit, False)
        if oldstate == newstate:
            return oldname

        newname = gen_newname(oldname)

        # if not a back conversion
        if oldname not in unregister:
            # error if the name already exists
            if newname in self._units2file.viewvalues():
                errmsg = translate(
                    "DataFiles", "File {0} is already in use elsewhere in "
                    "the study. It cannot be reused under a "
                    "different file entry.").format(newname)
                raise ValueError(errmsg)

            # register
            register[newname] = oldname

        # unregister if a back conversion
        if oldname in unregister:
            unregister.pop(oldname)

        # replace the old name by the new one in the dictionary
        self._units2file[unit] = newname
        self._units2stat[unit] = newstate
        self.modelReset.emit()

        return newname

    def transferFile(self, filename):
        """
        Called at register time when an external file is embedded
        / unembedded.

        Argument:
            filename (str): File path in its new status.

        Note:
            - From external to embedded, the file is copied.
            - From embedded to external, the file is moved.
        """
        if filename in self._ext2emb:
            assert filename not in self._emb2ext
            move_file(self._ext2emb[filename], filename)
            return

        if filename in self._emb2ext:
            assert filename not in self._ext2emb
            copy_file(self._emb2ext[filename], filename)

    def other_unit_search(self, filename):
        """
        Looks for `filename` among child and parent stages,
        but not the current stage.

        Arguments:
            filename (str): full path of the file.

        Returns:
            int: logical unit of the file if found, else *None*.
        """
        return self._file_descriptors.other_unit_search(filename)

    def unit_conflict(self, unit, filename):
        """
        Looks for a unit conflict in parent and child stages,
        i.e. two files sharing the same unit.

        Arguments:
            unit (int): logical unit to test.
            filename (str): full file path to test.

        Returns:
            bool: *True* if there is no conflict, *False* otherwise.
        """
        return self._file_descriptors.unit_conflict(unit, filename)

    def file_conflict(self, unit, filename):
        """
        Looks for a file conflict in parent and child stages,
        i.e. two different units sharing the same file.

        Arguments:
            unit (int): logical unit to test.
            filename (str): full file path to test.

        Returns:
            bool: *True* if there is no conflict, *False* otherwise.
        """
        return self._file_descriptors.file_conflict(unit, filename)

    def basename_conflict(self, filename):
        """
        Looks for a basename conflict, i.e. a file with the same
        basename in the current stage.

        Arguments:
            filename (str): file path.

        Note:
            Due to Salome launcher not supporting two files with
            the same basename, we have to forbide it for two files
            of the same stage.
        """
        return self._file_descriptors.basename_conflict(filename)
Пример #9
0
class Config(MutableMapping, OrderedDict):
    @classmethod
    def load(cls, file_path):
        with open(file_path) as f:
            params = yaml.load(f.read(), Loader=yaml.FullLoader)

        # We expand ~ in those yaml entries with `path`
        # on their keys for making
        # config files more platform-independent
        params = {
            key: (os.path.expanduser(value)
                  if "path" in key and value is not None else value)
            for key, value in params.items()
        }

        return cls(params)

    def dump(self, file_path):
        with open(file_path, "w") as f:
            d = self.to_dict()
            f.write(yaml.dump(d))

    def __init__(self, *args, **kwargs):
        self._map = OrderedDict()

        if args:
            d = args[0]
            # for recursive assignment handling
            trackedIDs = {id(d): self}
            if isinstance(d, dict):
                for k, v in self.__call_items(d):
                    if isinstance(v, dict):
                        if id(v) in trackedIDs:
                            v = trackedIDs[id(v)]
                        else:
                            v = self.__class__(v)
                            trackedIDs[id(v)] = v
                    if type(v) is list:
                        l = []
                        for i in v:
                            n = i
                            if isinstance(i, dict):
                                n = self.__class__(i)
                            l.append(n)
                        v = l
                    self._map[k] = v
        if kwargs:
            for k, v in self.__call_items(kwargs):
                self._map[k] = v

    _path_state = list()

    def __call_items(self, obj):
        if hasattr(obj, "iteritems") and ismethod(getattr(obj, "iteritems")):
            return obj.iteritems()
        else:
            return obj.items()

    def items(self):
        return self.iteritems()

    def iteritems(self):
        return self.__call_items(self._map)

    def __iter__(self):
        return self._map.__iter__()

    def next(self):
        return self._map.next()

    def __setitem__(self, k, v):
        # print('Called __setitem__')

        if (k in self._map and not self._map[k] is None
                and not isinstance(v, type(self._map[k]))):
            if v is not None:
                raise ValueError(
                    f"Updating existing value {type(self._map[k])} "
                    f"with different type ({type(v)}).")
        split_path = k.split(".")
        current_option = self._map
        for p in split_path[:-1]:
            current_option = current_option[p]
        current_option[split_path[-1]] = v

    def __getitem__(self, k):
        split_path = k.split(".")
        current_option = self._map
        for p in split_path:
            if p not in current_option:
                raise KeyError(p)
            current_option = current_option[p]
        return current_option

    def __setattr__(self, k, v):
        if k in {"_map", "_ipython_canary_method_should_not_exist_"}:
            super(Config, self).__setattr__(k, v)
        else:
            self[k].update(v)

    def __getattr__(self, k):
        if k in {"_map", "_ipython_canary_method_should_not_exist_"}:
            return super(Config, self).__getattr__(k)

        try:
            v = super(self.__class__, self).__getattribute__(k)
            return v
        except AttributeError:
            self._path_state.append(k)
            pass

        return self[k]

    def __delattr__(self, key):
        return self._map.__delitem__(key)

    def __contains__(self, k):
        return self._map.__contains__(k)

    def __add__(self, other):
        if self.empty():
            return other
        else:
            self_type = type(self).__name__
            other_type = type(other).__name__
            msg = "unsupported operand type(s) for +: '{}' and '{}'"
            raise TypeError(msg.format(self_type, other_type))

    def __str__(self):
        items = []
        for k, v in self.__call_items(self._map):
            # recursive assignment case
            if id(v) == id(self):
                items.append("{0}={1}(...)".format(k, self.__class__.__name__))
            else:
                items.append("{0}={1}".format(k, repr(v)))
        joined = ", ".join(items)
        out = "{0}({1})".format(self.__class__.__name__, joined)
        return out

    def __repr__(self):
        return str(self)

    def to_dict(self, flatten=False, parent_key="", sep="."):
        d = {}
        for k, v in self.items():
            if issubclass(type(v), Config):
                # bizarre recursive assignment support
                if id(v) == id(self):
                    v = d
                else:
                    v = v.to_dict()
            elif type(v) in (list, tuple):
                l = []
                for i in v:
                    n = i
                    if issubclass(type(i), Config):
                        n = i.to_dict()
                    l.append(n)
                if type(v) is tuple:
                    v = tuple(l)
                else:
                    v = l
            d[k] = v

        if flatten:
            d = flatten_dict(d, parent_key=parent_key, sep=sep)

        return d

    def pprint(self, ):
        pprint(self.to_dict())

    def empty(self):
        return not any(self)

    # proper dict subclassing
    def values(self):
        return self._map.values()

    # ipython support
    def __dir__(self):
        return list(self.keys())

    def _ipython_key_completions_(self):
        return list(self.keys())

    @classmethod
    def parseOther(cls, other):
        if issubclass(type(other), Config):
            return other._map
        else:
            return other

    def __cmp__(self, other):
        other = Config.parseOther(other)
        return self._map.__cmp__(other)

    def __eq__(self, other):
        other = Config.parseOther(other)
        if not isinstance(other, dict):
            return False
        return self._map.__eq__(other)

    def __ge__(self, other):
        other = Config.parseOther(other)
        return self._map.__ge__(other)

    def __gt__(self, other):
        other = Config.parseOther(other)
        return self._map.__gt__(other)

    def __le__(self, other):
        other = Config.parseOther(other)
        return self._map.__le__(other)

    def __lt__(self, other):
        other = Config.parseOther(other)
        return self._map.__lt__(other)

    def __ne__(self, other):
        other = Config.parseOther(other)
        return self._map.__ne__(other)

    def __delitem__(self, key):
        return self._map.__delitem__(key)

    def __len__(self):
        return self._map.__len__()

    def clear(self):
        self._map.clear()

    def copy(self):
        return self.__class__(self)

    def __copy__(self):
        return self.copy()

    def __deepcopy__(self, memo=None):
        return self.copy()

    def get(self, key, default=None):
        return self._map.get(key, default)

    def has_key(self, key):
        return key in self._map

    def iterkeys(self):
        return self._map.iterkeys()

    def itervalues(self):
        return self._map.itervalues()

    def keys(self):
        return self._map.keys()

    def pop(self, key, default=None):
        return self._map.pop(key, default)

    def popitem(self):
        return self._map.popitem()

    def setdefault(self, key, default=None):
        self._map.setdefault(key, default)

    def update(self, *args, **kwargs):
        if len(args) == 1:
            for key, value in args[0].items():
                if key in self and isinstance(self[key], dict):
                    if value is None:
                        self[key] = value
                    else:
                        self[key].update(value)
                else:
                    pass
                    raise ValueError()
        elif len(args) > 1:
            raise NotImplementedError
            # self._map.update(*args)
        else:
            raise NotImplementedError

    def viewitems(self):
        return self._map.viewitems()

    def viewkeys(self):
        return self._map.viewkeys()

    def viewvalues(self):
        return self._map.viewvalues()

    @classmethod
    def fromkeys(cls, seq, value=None):
        d = cls()
        d._map = OrderedDict.fromkeys(seq, value)
        return d

    def __getstate__(self):
        return self.__dict__

    def __setstate__(self, d):
        self.__dict__.update(d)

    # bannerStr

    def _getListStr(self, items):
        out = "["
        mid = ""
        for i in items:
            mid += "  {}\n".format(i)
        if mid != "":
            mid = "\n" + mid
        out += mid
        out += "]"
        return out

    def _getValueStr(self, k, v):
        outV = v
        multiLine = len(str(v).split("\n")) > 1
        if multiLine:
            # push to next line
            outV = "\n" + v
        if type(v) is list:
            outV = self._getListStr(v)
        out = "{} {}".format(k, outV)
        return out

    def _getSubMapDotList(self, pre, name, subMap):
        outList = []
        if pre == "":
            pre = name
        else:
            pre = "{}.{}".format(pre, name)

        def stamp(pre, k, v):
            valStr = self._getValueStr(k, v)
            return "{}.{}".format(pre, valStr)

        for k, v in subMap.items():
            if isinstance(v, Config) and v != Config():
                subList = self._getSubMapDotList(pre, k, v)
                outList.extend(subList)
            else:
                outList.append(stamp(pre, k, v))
        return outList

    def _getSubMapStr(self, name, subMap):
        outList = ["== {} ==".format(name)]
        for k, v in subMap.items():
            if isinstance(v, self.__class__) and v != self.__class__():
                # break down to dots
                subList = self._getSubMapDotList("", k, v)
                # add the divit
                # subList = ['> {}'.format(i) for i in subList]
                outList.extend(subList)
            else:
                out = self._getValueStr(k, v)
                # out = '> {}'.format(out)
                out = "{}".format(out)
                outList.append(out)
        finalOut = "\n".join(outList)
        return finalOut

    def bannerStr(self):
        lines = []
        previous = None
        for k, v in self.items():
            if previous == self.__class__.__name__:
                lines.append("-")
            out = ""
            if isinstance(v, self.__class__):
                name = k
                subMap = v
                out = self._getSubMapStr(name, subMap)
                lines.append(out)
                previous = self.__class__.__name__
            else:
                out = self._getValueStr(k, v)
                lines.append(out)
                previous = "other"
        lines.append("--")
        s = "\n".join(lines)
        return s
Пример #10
0
class DotMap(MutableMapping, OrderedDict):
    def __init__(self, *args, **kwargs):
        self._map = OrderedDict()
        if args:
            assert len(args) == 1
            d = args[0]
            if isinstance(d, dict):
                for k, v in self.__call_items(d):
                    if isinstance(v, dict):
                        v = DotMap(v)
                    if isinstance(v, list):
                        l = []
                        for i in v:
                            n = i
                            if isinstance(i, dict):
                                n = DotMap(i)
                            l.append(n)
                        v = l
                    self._map[k] = v
        if kwargs:
            for k, v in self.__call_items(kwargs):
                self._map[k] = v

    def __call_items(self, obj):
        if hasattr(obj, 'iteritems') and ismethod(getattr(obj, 'iteritems')):
            return obj.iteritems()
        return obj.items()

    def items(self):
        return self.iteritems()

    def iteritems(self):
        return self.__call_items(self._map)

    def __iter__(self):
        return self._map.__iter__()

    def next(self):
        return self._map.next()

    def __setitem__(self, k, v):
        self._map[k] = v

    def __getitem__(self, k):
        if k not in self._map and k != IPYTHON_CANNARY:
            # automatically extend to new DotMap
            self[k] = DotMap()
        return self._map[k]

    def __setattr__(self, k, v):
        if k in {'_map', IPYTHON_CANNARY}:
            super(DotMap, self).__setattr__(k, v)
        else:
            self[k] = v

    def __getattr__(self, k):
        if k == {'_map', IPYTHON_CANNARY}:
            super(DotMap, self).__getattr__(k)
        else:
            return self[k]

    def __delattr__(self, key):
        return self._map.__delitem__(key)

    def __contains__(self, k):
        return self._map.__contains__(k)

    def __str__(self):
        items = []
        for k, v in self.__call_items(self._map):
            if id(v) == id(self):
                items.append('{0}=DotMap(...)'.format(k))
            else:
                items.append('{0}={1}'.format(k, repr(v)))
        joined = ', '.join(items)
        out = '{0}({1})'.format(self.__class__.__name__, joined)
        return out

    __repr__ = __str__

    def toDict(self):
        d = {}
        for k, v in self.items():
            if isinstance(v, DotMap):
                if id(v) == id(self):
                    v = d
                else:
                    v = v.toDict()
            elif isinstance(v, (list, tuple)):
                l = []
                for i in v:
                    n = i
                    if type(i) is DotMap:
                        n = i.toDict()
                    l.append(n)
                if isinstance(v, tuple):
                    v = tuple(l)
                else:
                    v = l
            d[k] = v
        return d

    def empty(self):
        return (not any(self))

    def values(self):
        return self._map.values()

    # ipython support
    def __dir__(self):
        return self.keys()

    @classmethod
    def parse_other(cls, other):
        if isinstance(other, DotMap):
            return other._map
        return other

    def __cmp__(self, other):
        other = DotMap.parse_other(other)
        return self._map.__cmp__(other)

    def __eq__(self, other):
        other = DotMap.parse_other(other)
        if not isinstance(other, dict):
            return False
        return self._map.__eq__(other)

    def __ge__(self, other):
        other = DotMap.parse_other(other)
        return self._map.__ge__(other)

    def __gt__(self, other):
        other = DotMap.parse_other(other)
        return self._map.__gt__(other)

    def __le__(self, other):
        other = DotMap.parse_other(other)
        return self._map.__le__(other)

    def __lt__(self, other):
        other = DotMap.parse_other(other)
        return self._map.__lt__(other)

    def __ne__(self, other):
        other = DotMap.parse_other(other)
        return self._map.__ne__(other)

    def __delitem__(self, key):
        return self._map.__delitem__(key)

    def __len__(self):
        return self._map.__len__()

    def clear(self):
        self._map.clear()

    def copy(self):
        return DotMap(self)

    def __copy__(self):
        return self.copy()

    def __deepcopy__(self, memo=None):
        return self.copy()

    def get(self, key, default=None):
        return self._map.get(key, default)

    def has_key(self, key):
        return key in self._map

    def iterkeys(self):
        return self._map.iterkeys()

    def itervalues(self):
        return self._map.itervalues()

    def keys(self):
        return self._map.keys()

    def pop(self, key, default=None):
        return self._map.pop(key, default)

    def popitem(self):
        return self._map.popitem()

    def setdefault(self, key, default=None):
        self._map.setdefault(key, default)

    def update(self, *args, **kwargs):
        if len(args) != 0:
            self._map.update(*args)
        self._map.update(kwargs)

    def viewitems(self):
        return self._map.viewitems()

    def viewkeys(self):
        return self._map.viewkeys()

    def viewvalues(self):
        return self._map.viewvalues()

    @classmethod
    def fromkeys(cls, seq, value=None):
        d = DotMap()
        d._map = OrderedDict.fromkeys(seq, value)
        return d

    def __getstate__(self):
        return self.__dict__

    def __setstate__(self, d):
        self.__dict__.update(d)
Пример #11
0
class DotMap(MutableMapping, OrderedDict):
    def __init__(self, *args, **kwargs):
        self._map = OrderedDict()
        self._dynamic = kwargs.pop('_dynamic', True)
        self._prevent_method_masking = kwargs.pop('_prevent_method_masking',
                                                  False)
        trackedIDs = kwargs.pop('_trackedIDs', {})

        if args:
            d = args[0]
            # for recursive assignment handling
            trackedIDs[id(d)] = self

            src = []
            if isinstance(d, MutableMapping):
                src = self.__call_items(d)
            elif isinstance(d, Iterable):
                src = d

            for k, v in src:
                if self._prevent_method_masking and k in reserved_keys:
                    raise KeyError('"{}" is reserved'.format(k))
                if isinstance(v, dict):
                    idv = id(v)
                    if idv in trackedIDs:
                        v = trackedIDs[idv]
                    else:
                        trackedIDs[idv] = v
                        v = self.__class__(v,
                                           _dynamic=self._dynamic,
                                           _prevent_method_masking=self.
                                           _prevent_method_masking,
                                           _trackedIDs=trackedIDs)
                if type(v) is list:
                    l = []
                    for i in v:
                        n = i
                        if isinstance(i, dict):
                            idi = id(i)
                            if idi in trackedIDs:
                                n = trackedIDs[idi]
                            else:
                                trackedIDs[idi] = i
                                n = self.__class__(
                                    i,
                                    _dynamic=self._dynamic,
                                    _prevent_method_masking=self.
                                    _prevent_method_masking)
                        l.append(n)
                    v = l
                self._map[k] = v
        if kwargs:
            for k, v in self.__call_items(kwargs):
                if self._prevent_method_masking and k in reserved_keys:
                    raise KeyError('"{}" is reserved'.format(k))
                self._map[k] = v

    def __call_items(self, obj):
        if hasattr(obj, 'iteritems') and ismethod(getattr(obj, 'iteritems')):
            return obj.iteritems()
        else:
            return obj.items()

    def items(self):
        return self.iteritems()

    def iteritems(self):
        return self.__call_items(self._map)

    def __iter__(self):
        return self._map.__iter__()

    def next(self):
        return self._map.next()

    def __setitem__(self, k, v):
        self._map[k] = v

    def __getitem__(self, k):
        if k not in self._map and self._dynamic and k != '_ipython_canary_method_should_not_exist_':
            # automatically extend to new DotMap
            self[k] = self.__class__()
        return self._map[k]

    def __setattr__(self, k, v):
        if k in {
                '_map', '_dynamic', '_ipython_canary_method_should_not_exist_',
                '_prevent_method_masking'
        }:
            super(DotMap, self).__setattr__(k, v)
        elif self._prevent_method_masking and k in reserved_keys:
            raise KeyError('"{}" is reserved'.format(k))
        else:
            self[k] = v

    def __getattr__(self, k):
        if k.startswith('__') and k.endswith('__'):
            raise AttributeError(k)

        if k in {
                '_map', '_dynamic', '_ipython_canary_method_should_not_exist_'
        }:
            return super(DotMap, self).__getattr__(k)

        try:
            v = super(self.__class__, self).__getattribute__(k)
            return v
        except AttributeError:
            pass

        return self[k]

    def __delattr__(self, key):
        return self._map.__delitem__(key)

    def __contains__(self, k):
        return self._map.__contains__(k)

    def __add__(self, other):
        if self.empty():
            return other
        else:
            self_type = type(self).__name__
            other_type = type(other).__name__
            msg = "unsupported operand type(s) for +: '{}' and '{}'"
            raise TypeError(msg.format(self_type, other_type))

    def __str__(self, seen=None):
        items = []
        seen = {id(self)} if seen is None else seen
        for k, v in self.__call_items(self._map):
            # circular assignment case
            if isinstance(v, self.__class__):
                if id(v) in seen:
                    items.append('{0}={1}(...)'.format(
                        k, self.__class__.__name__))
                else:
                    seen.add(id(v))
                    items.append('{0}={1}'.format(k, v.__str__(seen)))
            else:
                items.append('{0}={1}'.format(k, repr(v)))
        joined = ', '.join(items)
        out = '{0}({1})'.format(self.__class__.__name__, joined)
        return out

    def __repr__(self):
        return str(self)

    def toDict(self, seen=None):
        if seen is None:
            seen = {}

        d = {}

        seen[id(self)] = d

        for k, v in self.items():
            if issubclass(type(v), DotMap):
                idv = id(v)
                if idv in seen:
                    v = seen[idv]
                else:
                    v = v.toDict(seen=seen)
            elif type(v) in (list, tuple):
                l = []
                for i in v:
                    n = i
                    if issubclass(type(i), DotMap):
                        idv = id(n)
                        if idv in seen:
                            n = seen[idv]
                        else:
                            n = i.toDict(seen=seen)
                    l.append(n)
                if type(v) is tuple:
                    v = tuple(l)
                else:
                    v = l
            d[k] = v
        return d

    def pprint(self, pformat='dict'):
        if pformat == 'json':
            print(dumps(self.toDict(), indent=4, sort_keys=True))
        else:
            pprint(self.toDict())

    def empty(self):
        return (not any(self))

    # proper dict subclassing
    def values(self):
        return self._map.values()

    # ipython support
    def __dir__(self):
        return self.keys()

    @classmethod
    def parseOther(self, other):
        if issubclass(type(other), DotMap):
            return other._map
        else:
            return other

    def __cmp__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__cmp__(other)

    def __eq__(self, other):
        other = DotMap.parseOther(other)
        if not isinstance(other, dict):
            return False
        return self._map.__eq__(other)

    def __ge__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__ge__(other)

    def __gt__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__gt__(other)

    def __le__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__le__(other)

    def __lt__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__lt__(other)

    def __ne__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__ne__(other)

    def __delitem__(self, key):
        return self._map.__delitem__(key)

    def __len__(self):
        return self._map.__len__()

    def clear(self):
        self._map.clear()

    def copy(self):
        return self.__class__(self)

    def __copy__(self):
        return self.copy()

    def __deepcopy__(self, memo=None):
        return self.copy()

    def get(self, key, default=None):
        return self._map.get(key, default)

    def has_key(self, key):
        return key in self._map

    def iterkeys(self):
        return self._map.iterkeys()

    def itervalues(self):
        return self._map.itervalues()

    def keys(self):
        return self._map.keys()

    def pop(self, key, default=None):
        return self._map.pop(key, default)

    def popitem(self):
        return self._map.popitem()

    def setdefault(self, key, default=None):
        return self._map.setdefault(key, default)

    def update(self, *args, **kwargs):
        if len(args) != 0:
            self._map.update(*args)
        self._map.update(kwargs)

    def viewitems(self):
        return self._map.viewitems()

    def viewkeys(self):
        return self._map.viewkeys()

    def viewvalues(self):
        return self._map.viewvalues()

    @classmethod
    def fromkeys(cls, seq, value=None):
        d = cls()
        d._map = OrderedDict.fromkeys(seq, value)
        return d

    def __getstate__(self):
        return self.__dict__

    def __setstate__(self, d):
        self.__dict__.update(d)

    # bannerStr
    def _getListStr(self, items):
        out = '['
        mid = ''
        for i in items:
            mid += '  {}\n'.format(i)
        if mid != '':
            mid = '\n' + mid
        out += mid
        out += ']'
        return out

    def _getValueStr(self, k, v):
        outV = v
        multiLine = len(str(v).split('\n')) > 1
        if multiLine:
            # push to next line
            outV = '\n' + v
        if type(v) is list:
            outV = self._getListStr(v)
        out = '{} {}'.format(k, outV)
        return out

    def _getSubMapDotList(self, pre, name, subMap):
        outList = []
        if pre == '':
            pre = name
        else:
            pre = '{}.{}'.format(pre, name)

        def stamp(pre, k, v):
            valStr = self._getValueStr(k, v)
            return '{}.{}'.format(pre, valStr)

        for k, v in subMap.items():
            if isinstance(v, DotMap) and v != DotMap():
                subList = self._getSubMapDotList(pre, k, v)
                outList.extend(subList)
            else:
                outList.append(stamp(pre, k, v))
        return outList

    def _getSubMapStr(self, name, subMap):
        outList = ['== {} =='.format(name)]
        for k, v in subMap.items():
            if isinstance(v, self.__class__) and v != self.__class__():
                # break down to dots
                subList = self._getSubMapDotList('', k, v)
                # add the divit
                # subList = ['> {}'.format(i) for i in subList]
                outList.extend(subList)
            else:
                out = self._getValueStr(k, v)
                # out = '> {}'.format(out)
                out = '{}'.format(out)
                outList.append(out)
        finalOut = '\n'.join(outList)
        return finalOut

    def bannerStr(self):
        lines = []
        previous = None
        for k, v in self.items():
            if previous == self.__class__.__name__:
                lines.append('-')
            out = ''
            if isinstance(v, self.__class__):
                name = k
                subMap = v
                out = self._getSubMapStr(name, subMap)
                lines.append(out)
                previous = self.__class__.__name__
            else:
                out = self._getValueStr(k, v)
                lines.append(out)
                previous = 'other'
        lines.append('--')
        s = '\n'.join(lines)
        return s
Пример #12
0
class DotMap(OrderedDict):
    def __init__(self, *args, **kwargs):

        self._map = OrderedDict()
        self._dynamic = True    # mettendo False non funzionano più i test di default. E' normale in quanto si aspettano la creazione dinamica dei figli

            # ===================================
        if LORETO:
            global MY_DICT_TYPES  # global var per la classe
            self._dynamic = False    # mettendo False non funzionano più i test di default. E' normale in quanto si aspettano la creazione dinamica dei figli
            MY_DICT_TYPES = [dict, DotMap] # by Loreto (DEFAULT dictionary)
            # ===================================

        if kwargs:
            if '_dynamic' in kwargs:
                self._dynamic = kwargs['_dynamic']
        if args:
            d = args[0]
            if isinstance(d, dict):
                for k,v in self.__call_items(d):
                    if type(v) is dict:
                        v = DotMap(v, _dynamic=self._dynamic)
                    if type(v) is list:
                        l = []
                        for i in v:
                            n = i
                            if type(i) is dict:
                                n = DotMap(i, _dynamic=self._dynamic)
                            l.append(n)
                        v = l
                    self._map[k] = v
        if kwargs:
            for k,v in self.__call_items(kwargs):
                if k is not '_dynamic':
                    self._map[k] = v

    def __call_items(self, obj):
        if hasattr(obj, 'iteritems') and ismethod(getattr(obj, 'iteritems')):
            return obj.iteritems()
        else:
            return obj.items()

    def items(self):
        return self.iteritems()

    def iteritems(self):
        return self.__call_items(self._map)

    def __iter__(self):
        return self._map.__iter__()

    def next(self):
        return self._map.next()

    def __setitem__(self, k, v):
        self._map[k] = v
    def __getitem__(self, k):
        if k not in self._map and self._dynamic and k != '_ipython_canary_method_should_not_exist_':
            # automatically extend to new DotMap
            self[k] = DotMap()
        return self._map[k]

    def __setattr__(self, k, v):
        if k in {'_map','_dynamic', '_ipython_canary_method_should_not_exist_'}:
            super(DotMap, self).__setattr__(k,v)
        else:
            self[k] = v

    def __getattr__(self, k):
        if k == {'_map','_dynamic','_ipython_canary_method_should_not_exist_'}:
            super(DotMap, self).__getattr__(k)
        else:
            return self[k]

    def __delattr__(self, key):
        return self._map.__delitem__(key)

    def __contains__(self, k):
        return self._map.__contains__(k)

    def __str__(self):
        items = []
        for k,v in self.__call_items(self._map):
            # bizarre recursive assignment situation (why someone would do this is beyond me)
            if id(v) == id(self):
                items.append('{0}=DotMap(...)'.format(k))
            else:
                items.append('{0}={1}'.format(k, repr(v)))
        out = 'DotMap({0})'.format(', '.join(items))
        return out

    def __repr__(self):
        return str(self)

    def toDict(self):
        d = {}
        for k,v in self.items():
            if type(v) is DotMap:
                # bizarre recursive assignment support
                if id(v) == id(self):
                    v = d
                else:
                    v = v.toDict()
            elif type(v) is list:
                l = []
                for i in v:
                    n = i
                    if type(i) is DotMap:
                        n = i.toDict()
                    l.append(n)
                v = l
            d[k] = v
        return d

    def pprint(self):
        pprint(self.toDict())

        # ===================================
    if LORETO:
        # MY_DICT_TYPES = [dict, DotMap]
        def Ptr(self, listOfQualifiers, create=False):
            ptr = self
            for item in listOfQualifiers:
                if item in ptr:
                    ptr = ptr[item]
                else:
                    if create:
                        ptr[item] = DotMap()
                        ptr = ptr[item]
                    else:
                        return None

            return ptr

        def KeyTree(self, fPRINT=False):
            return DictToList.KeyTree(self, myDictTYPES=MY_DICT_TYPES, fPRINT=fPRINT)

        def KeyList(self):
            return DictToList.KeyList(self, myDictTYPES=MY_DICT_TYPES)


        def PrintTree(self, fEXIT=False, MaxLevel=10, header=None, printTYPE='LTKV', stackLevel=1):
            PrintDictionaryTree.PrintDictionary(self, myDictTYPES=MY_DICT_TYPES, printTYPE=printTYPE, fEXIT=fEXIT, MaxLevel=MaxLevel, header=header, stackLevel=stackLevel+1)

        printDict = PrintTree
        printTree = PrintTree

        def GetValue(self, listOfQualifiers=[], fPRINT=False):
            return DictToList.getValue(self, listOfQualifiers=listOfQualifiers, myDictTYPES=MY_DICT_TYPES, fPRINT=fPRINT)
        # ===================================

    def empty(self):
        return (not any(self))

    # proper dict subclassing
    def values(self):
        return self._map.values()

    # ipython support
    def __dir__(self):
        return self.keys()

    @classmethod
    def parseOther(self, other):
        if type(other) is DotMap:
            return other._map
        else:
            return other
    def __cmp__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__cmp__(other)
    def __eq__(self, other):
        other = DotMap.parseOther(other)
        if not isinstance(other, dict):
            return False
        return self._map.__eq__(other)
    def __ge__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__ge__(other)
    def __gt__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__gt__(other)
    def __le__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__le__(other)
    def __lt__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__lt__(other)
    def __ne__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__ne__(other)

    def __delitem__(self, key):
        return self._map.__delitem__(key)
    def __len__(self):
        return self._map.__len__()
    def clear(self):
        self._map.clear()
    def copy(self):
        return DotMap(self.toDict())
    def get(self, key, default=None):
        return self._map.get(key, default)
    def has_key(self, key):
        return key in self._map
    def iterkeys(self):
        return self._map.iterkeys()
    def itervalues(self):
        return self._map.itervalues()
    def keys(self):
        return self._map.keys()
    def pop(self, key, default=None):
        return self._map.pop(key, default)
    def popitem(self):
        return self._map.popitem()
    def setdefault(self, key, default=None):
        self._map.setdefault(key, default)
    def update(self, *args, **kwargs):
        if len(args) != 0:
            self._map.update(*args)
        self._map.update(kwargs)
    def viewitems(self):
        return self._map.viewitems()
    def viewkeys(self):
        return self._map.viewkeys()
    def viewvalues(self):
        return self._map.viewvalues()
    @classmethod
    def fromkeys(cls, seq, value=None):
        d = DotMap()
        d._map = OrderedDict.fromkeys(seq, value)
        return d
    def __getstate__(self): return self.__dict__
    def __setstate__(self, d): self.__dict__.update(d)
Пример #13
0
class DebugVariableViewer(object):
    """
    Class that implements a generic viewer that display a list of variable values
    This class has to be inherited to effectively display variable values
    """
    def __init__(self, window, items=None):
        """
        Constructor
        @param window: Reference to the Debug Variable Panel
        @param items: List of DebugVariableItem displayed by Viewer
        """
        self.ParentWindow = window
        items = [] if items is None else items
        self.ItemsDict = OrderedDict([(item.GetVariable(), item)
                                      for item in items])
        self.Items = self.ItemsDict.viewvalues()

        # Variable storing current highlight displayed in Viewer
        self.Highlight = HIGHLIGHT_NONE
        # List of buttons
        self.Buttons = []
        self.InitHighlightPensBrushes()

    def __del__(self):
        """
        Destructor
        """
        # Remove reference to Debug Variable Panel
        self.ParentWindow = None

    def InitHighlightPensBrushes(self):
        """
        Init global pens and brushes
        """
        if not HIGHLIGHT:
            HIGHLIGHT['DROP_PEN'] = wx.Pen(wx.Colour(0, 128, 255))
            HIGHLIGHT['DROP_BRUSH'] = wx.Brush(wx.Colour(0, 128, 255, 128))
            HIGHLIGHT['RESIZE_PEN'] = wx.Pen(wx.Colour(200, 200, 200))
            HIGHLIGHT['RESIZE_BRUSH'] = wx.Brush(wx.Colour(200, 200, 200))

    def GetIndex(self):
        """
        Return position of Viewer in Debug Variable Panel
        @return: Position of Viewer
        """
        return self.ParentWindow.GetViewerIndex(self)

    def GetItem(self, variable):
        """
        Return item storing values of a variable
        @param variable: Variable path
        @return: Item storing values of this variable
        """
        return self.ItemsDict.get(variable, None)

    def GetItems(self):
        """
        Return items displayed by Viewer
        @return: List of items displayed in Viewer
        """
        return self.ItemsDict.values()

    def AddItem(self, item):
        """
        Add an item to the list of items displayed by Viewer
        @param item: Item to add to the list
        """
        self.ItemsDict[item.GetVariable()] = item

    def RemoveItem(self, item):
        """
        Remove an item from the list of items displayed by Viewer
        @param item: Item to remove from the list
        """
        self.ItemsDict.pop(item.GetVariable(), None)

    def ClearItems(self):
        """
        Clear list of items displayed by Viewer
        """
        # Unsubscribe every items of the list
        for item in self.Items:
            self.ParentWindow.RemoveDataConsumer(item)

        # Clear list
        self.ItemsDict.clear()

    def ItemsIsEmpty(self):
        """
        Return if list of items displayed by Viewer is empty
        @return: True if list is empty
        """
        return len(self.Items) == 0

    def SubscribeAllDataConsumers(self):
        """
        Function that unsubscribe and remove every item that store values of
        a variable that doesn't exist in PLC anymore
        """
        for item in self.ItemsDict.values()[:]:
            iec_path = item.GetVariable()

            # Check that variablepath exist in PLC
            if self.ParentWindow.GetDataType(iec_path) is None:
                # If not, unsubscribe and remove it
                self.ParentWindow.RemoveDataConsumer(item)
                self.RemoveItem(item)
            else:
                # If it exist, resubscribe and refresh data type
                self.ParentWindow.AddDataConsumer(iec_path.upper(), item, True)
                item.RefreshVariableType()

    def ResetItemsData(self):
        """
        Reset data stored in every items displayed in Viewer
        """
        for item in self.Items:
            item.ResetData()

    def GetItemsMinCommonTick(self):
        """
        Return the minimum tick common to all iems displayed in Viewer
        @return: Minimum common tick between items
        """
        return reduce(max, [
            item.GetData()[0, 0]
            for item in self.Items if len(item.GetData()) > 0
        ], 0)

    def RefreshViewer(self):
        """
        Method that refresh the content displayed by Viewer
        Need to be overridden by inherited classes
        """
        pass

    def SetHighlight(self, highlight):
        """
        Set Highlight type displayed in Viewer
        @return: True if highlight has changed
        """
        # Return immediately if highlight don't change
        if self.Highlight == highlight:
            return False

        self.Highlight = highlight
        return True

    def GetButtons(self):
        """
        Return list of buttons defined in Viewer
        @return: List of buttons
        """
        return self.Buttons

    def IsOverButton(self, x, y):
        """
        Return if point is over one button of Viewer
        @param x: X coordinate of point
        @param y: Y coordinate of point
        @return: button where point is over
        """
        for button in self.GetButtons():
            if button.HitTest(x, y):
                return button
        return None

    def HandleButton(self, x, y):
        """
        Search for the button under point and if found execute associated
        callback
        @param x: X coordinate of point
        @param y: Y coordinate of point
        @return: True if a button was found and callback executed
        """
        button = self.IsOverButton(x, y)
        if button is None:
            return False

        button.ProcessCallback()
        return True

    def ShowButtons(self, show):
        """
        Set display state of buttons in Viewer
        @param show: Display state (True if buttons must be displayed)
        """
        # Change display of every buttons
        for button in self.Buttons:
            button.Show(show)

        # Refresh button positions
        self.RefreshButtonsPosition()
        self.RefreshViewer()

    def RefreshButtonsPosition(self):
        """
        Function that refresh buttons position in Viewer
        """
        # Get Viewer size
        width, _height = self.GetSize()

        # Buttons are align right so we calculate buttons positions in
        # reverse order
        buttons = self.Buttons[:]
        buttons.reverse()

        # Position offset on x coordinate
        x_offset = 0
        for button in buttons:
            # Buttons are stacked right, removing those that are not active
            if button.IsEnabled():
                # Update button position according to button width and offset
                # on x coordinate
                w, _h = button.GetSize()
                button.SetPosition(width - 5 - w - x_offset, 5)
                # Update offset on x coordinate
                x_offset += w + 2

    def DrawCommonElements(self, dc, buttons=None):
        """
        Function that draw common graphics for every Viewers
        @param dc: wx.DC object corresponding to Device context where drawing
        common graphics
        @param buttons: List of buttons to draw if different from default
        (default None)
        """
        # Get Viewer size
        width, height = self.GetSize()

        # Set dc styling for drop before or drop after highlight
        dc.SetPen(HIGHLIGHT['DROP_PEN'])
        dc.SetBrush(HIGHLIGHT['DROP_BRUSH'])

        # Draw line at upper side of Viewer if highlight is drop before
        if self.Highlight == HIGHLIGHT_BEFORE:
            dc.DrawLine(0, 1, width - 1, 1)

        # Draw line at lower side of Viewer if highlight is drop before
        elif self.Highlight == HIGHLIGHT_AFTER:
            dc.DrawLine(0, height - 1, width - 1, height - 1)

        # If no specific buttons are defined, get default buttons
        if buttons is None:
            buttons = self.Buttons
        # Draw buttons
        for button in buttons:
            button.Draw(dc)

        # If graph dragging is processing
        if self.ParentWindow.IsDragging():
            destBBox = self.ParentWindow.GetDraggingAxesClippingRegion(self)
            srcPos = self.ParentWindow.GetDraggingAxesPosition(self)
            if destBBox.width > 0 and destBBox.height > 0:
                srcPanel = self.ParentWindow.DraggingAxesPanel
                srcBBox = srcPanel.GetAxesBoundingBox()

                srcX = srcBBox.x - (srcPos.x if destBBox.x == 0 else 0)
                srcY = srcBBox.y - (srcPos.y if destBBox.y == 0 else 0)

                srcBmp = _convert_agg_to_wx_bitmap(srcPanel.get_renderer(),
                                                   None)
                srcDC = wx.MemoryDC()
                srcDC.SelectObject(srcBmp)

                dc.Blit(destBBox.x, destBBox.y, int(destBBox.width),
                        int(destBBox.height), srcDC, srcX, srcY)

    def OnEnter(self, event):
        """
        Function called when entering Viewer
        @param event: wx.MouseEvent
        """
        # Display buttons
        self.ShowButtons(True)
        event.Skip()

    def OnLeave(self, event):
        """
        Function called when leaving Viewer
        @param event: wx.MouseEvent
        """
        # Hide buttons
        self.ShowButtons(False)
        event.Skip()

    def OnCloseButton(self):
        """
        Function called when Close button is pressed
        """
        wx.CallAfter(self.ParentWindow.DeleteValue, self)

    def OnForceButton(self):
        """
        Function called when Force button is pressed
        """
        self.ForceValue(self.ItemsDict.values()[0])

    def OnReleaseButton(self):
        """
        Function called when Release button is pressed
        """
        self.ReleaseValue(self.ItemsDict.values()[0])

    def OnMouseDragging(self, x, y):
        """
        Function called when mouse is dragged over Viewer
        @param x: X coordinate of mouse pointer
        @param y: Y coordinate of mouse pointer
        """
        xw, yw = self.GetPosition()
        # Refresh highlight in Debug Variable Panel (highlight can be displayed
        # in another Viewer
        self.ParentWindow.RefreshHighlight(x + xw, y + yw)

    def RefreshHighlight(self, x, y):
        """
        Function called by Debug Variable Panel asking Viewer to refresh
        highlight according to mouse position
        @param x: X coordinate of mouse pointer
        @param y: Y coordinate of mouse pointer
        """
        # Get Viewer size
        _width, height = self.GetSize()

        # Mouse is in the first half of Viewer
        if y < height / 2:
            # If Viewer is the upper one, draw drop before highlight
            if self.ParentWindow.IsViewerFirst(self):
                self.SetHighlight(HIGHLIGHT_BEFORE)

            # Else draw drop after highlight in previous Viewer
            else:
                self.SetHighlight(HIGHLIGHT_NONE)
                self.ParentWindow.HighlightPreviousViewer(self)

        # Mouse is in the second half of Viewer, draw drop after highlight
        else:
            self.SetHighlight(HIGHLIGHT_AFTER)

    def OnEraseBackground(self, event):
        """
        Function called when Viewer background is going to be erase
        @param event: wx.EraseEvent
        """
        # Prevent flicker on Windows
        pass

    def OnResize(self, event):
        """
        Function called when Viewer size changed
        @param event: wx.ResizeEvent
        """
        # Refresh button positions
        self.RefreshButtonsPosition()
        self.ParentWindow.ForceRefresh()
        event.Skip()

    def ForceValue(self, item):
        """
        Force value of item given
        @param item: Item to force value
        """
        # Check variable data type
        iec_path = item.GetVariable()
        iec_type = self.ParentWindow.GetDataType(iec_path)
        # Return immediately if not found
        if iec_type is None:
            return

        # Open a dialog to enter varaible forced value
        dialog = ForceVariableDialog(self, iec_type, str(item.GetValue()))
        if dialog.ShowModal() == wx.ID_OK:
            self.ParentWindow.ForceDataValue(iec_path.upper(),
                                             dialog.GetValue())

    def ReleaseValue(self, item):
        """
        Release value of item given
        @param item: Item to release value
        """
        self.ParentWindow.ReleaseDataValue(item.GetVariable().upper())
Пример #14
0
class BaseCache(object):
    """
    BaseCache is a class that saves and operates on an OrderedDict. It has a
    certain capacity, stored in the attribute `maxsize`. Whether this
    capacity is reached, can be checked by using the boolean property
    `is_full`. To implement a custom cache, inherit from this class and
    override the methods ``__getitem__`` and ``__setitem__``.
    Call the method `sunpy.database.caching.BaseCache.callback` as soon
    as an item from the cache is removed.
    """
    __metaclass__ = ABCMeta

    def __init__(self, maxsize=float('inf')):
        self.maxsize = maxsize
        self._dict = OrderedDict()

    def get(self, key, default=None):  # pragma: no cover
        """Return the corresponding value to `key` if `key` is in the cache,
        `default` otherwise. This method has no side-effects, multiple calls
        with the same cache and the same passed key must always return the same
        value.

        """
        try:
            return self._dict[key]
        except KeyError:
            return default

    @abstractmethod
    def __getitem__(self, key):
        """abstract method: this method must be overwritten by inheriting
        subclasses. It defines what happens if an item from the cache is
        attempted to be accessed.

        """
        return  # pragma: no cover

    @abstractmethod
    def __setitem__(self, key, value):
        """abstract method: this method must be overwritten by inheriting
        subclasses. It defines what happens if a new value should be assigned
        to the given key. If the given key does already exist in the cache or
        not must be checked by the person who implements this method.
        """

    @abstractproperty
    def to_be_removed(self):
        """The item that will be removed on the next
        :meth:`sunpy.database.caching.BaseCache.remove` call.

        """

    @abstractmethod
    def remove(self):
        """Call this method to manually remove one item from the cache. Which
        item is removed, depends on the implementation of the cache. After the
        item has been removed, the callback method is called.

        """

    def callback(self, key, value):
        """This method should be called (by convention) if an item is removed
        from the cache because it is full. The passed key and value are the
        ones that are removed. By default this method does nothing, but it
        can be customized in a custom cache that inherits from this base class.

        """

    @property
    def is_full(self):
        """True if the number of items in the cache equals :attr:`maxsize`,
        False otherwise.

        """
        return len(self._dict) == self.maxsize

    def __delitem__(self, key):
        self._dict.__delitem__(key)

    def __contains__(self, key):
        return key in self._dict.keys()

    def __len__(self):
        return len(self._dict)

    def __iter__(self):
        for key in self._dict.__iter__():
            yield key

    def __reversed__(self):  # pragma: no cover
        for key in self._dict.__reversed__():
            yield key

    def clear(self):  # pragma: no cover
        return self._dict.clear()

    def keys(self):  # pragma: no cover
        return self._dict.keys()

    def values(self):  # pragma: no cover
        return self._dict.values()

    def items(self):  # pragma: no cover
        return self._dict.items()

    def iterkeys(self):  # pragma: no cover
        return self._dict.iterkeys()

    def itervalues(self):  # pragma: no cover
        for value in self._dict.itervalues():
            yield value

    def iteritems(self):  # pragma: no cover
        for key, value in six.iteritems(self._dict):
            yield key, value

    def update(self, *args, **kwds):  # pragma: no cover
        self._dict.update(*args, **kwds)

    def pop(self, key, default=MutableMapping._MutableMapping__marker):  # pragma: no cover
        return self._dict.pop(key, default)

    def setdefault(self, key, default=None):  # pragma: no cover
        return self._dict.setdefault(key, default)

    def popitem(self, last=True):  # pragma: no cover
        return self._dict.popitem(last)

    def __reduce__(self):  # pragma: no cover
        return self._dict.__reduce__()

    def copy(self):  # pragma: no cover
        return self._dict.copy()

    def __eq__(self, other):  # pragma: no cover
        return self._dict.__eq__(other)

    def __ne__(self, other):  # pragma: no cover
        return self._dict.__ne__(other)

    def viewkeys(self):  # pragma: no cover
        return self._dict.viewkeys()

    def viewvalues(self):  # pragma: no cover
        return self._dict.viewvalues()

    def viewitems(self):  # pragma: no cover
        return self._dict.viewitems()

    @classmethod
    def fromkeys(cls, iterable, value=None):  # pragma: no cover
        return OrderedDict.fromkeys(iterable, value)

    def __repr__(self):  # pragma: no cover
        return '{0}({1!r})'.format(self.__class__.__name__, dict(self._dict))
Пример #15
0
class DotMap(MutableMapping, OrderedDict):
    def __init__(self, *args, **kwargs):
        self._map = OrderedDict()
        self._dynamic = True
        if kwargs:
            if '_dynamic' in kwargs:
                self._dynamic = kwargs['_dynamic']
        if args:
            d = args[0]
            if isinstance(d, dict):
                for k, v in self.__call_items(d):
                    if isinstance(v, dict):
                        v = DotMap(v, _dynamic=self._dynamic)
                    if type(v) is list:
                        l = []
                        for i in v:
                            n = i
                            if type(i) is dict:
                                n = DotMap(i, _dynamic=self._dynamic)
                            l.append(n)
                        v = l
                    self._map[k] = v
        if kwargs:
            for k, v in self.__call_items(kwargs):
                if k is not '_dynamic':
                    self._map[k] = v

    def __call_items(self, obj):
        if hasattr(obj, 'iteritems') and ismethod(getattr(obj, 'iteritems')):
            return obj.iteritems()
        else:
            return obj.items()

    def items(self):
        return self.iteritems()

    def iteritems(self):
        return self.__call_items(self._map)

    def __iter__(self):
        return self._map.__iter__()

    def next(self):
        return self._map.next()

    def __setitem__(self, k, v):
        self._map[k] = v

    def __getitem__(self, k):
        if k not in self._map and self._dynamic and k != '_ipython_canary_method_should_not_exist_':
            # automatically extend to new DotMap
            self[k] = DotMap()
        return self._map[k]

    def __setattr__(self, k, v):
        if k in {
                '_map', '_dynamic', '_ipython_canary_method_should_not_exist_'
        }:
            super(DotMap, self).__setattr__(k, v)
        else:
            self[k] = v

    def __getattr__(self, k):
        if k in {
                '_map', '_dynamic', '_ipython_canary_method_should_not_exist_'
        }:
            super(DotMap, self).__getattr__(k)
        else:
            return self[k]

    def __delattr__(self, key):
        return self._map.__delitem__(key)

    def __contains__(self, k):
        return self._map.__contains__(k)

    def __str__(self):
        items = []
        for k, v in self.__call_items(self._map):
            # bizarre recursive assignment situation (why someone would do this is beyond me)
            if id(v) == id(self):
                items.append('{0}=DotMap(...)'.format(k))
            else:
                items.append('{0}={1}'.format(k, repr(v)))
        joined = ', '.join(items)
        out = '{0}({1})'.format(self.__class__.__name__, joined)
        return out

    def __repr__(self):
        return str(self)

    def toDict(self):
        d = {}
        for k, v in self.items():
            if type(v) is DotMap:
                # bizarre recursive assignment support
                if id(v) == id(self):
                    v = d
                else:
                    v = v.toDict()
            elif type(v) in (list, tuple):
                l = []
                for i in v:
                    n = i
                    if type(i) is DotMap:
                        n = i.toDict()
                    l.append(n)
                if type(v) is tuple:
                    v = tuple(l)
                else:
                    v = l
            d[k] = v
        return d

    def pprint(self, pformat='dict'):
        if pformat == 'json':
            print(dumps(self.toDict(), indent=4, sort_keys=True))
        else:
            pprint(self.toDict())

    def empty(self):
        return (not any(self))

    # proper dict subclassing
    def values(self):
        return self._map.values()

    # ipython support
    def __dir__(self):
        return self.keys()

    @classmethod
    def parseOther(self, other):
        if type(other) is DotMap:
            return other._map
        else:
            return other

    def __cmp__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__cmp__(other)

    def __eq__(self, other):
        other = DotMap.parseOther(other)
        if not isinstance(other, dict):
            return False
        return self._map.__eq__(other)

    def __ge__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__ge__(other)

    def __gt__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__gt__(other)

    def __le__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__le__(other)

    def __lt__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__lt__(other)

    def __ne__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__ne__(other)

    def __delitem__(self, key):
        return self._map.__delitem__(key)

    def __len__(self):
        return self._map.__len__()

    def clear(self):
        self._map.clear()

    def copy(self):
        return DotMap(self)

    def __copy__(self):
        return self.copy()

    def __deepcopy__(self, memo=None):
        return self.copy()

    def get(self, key, default=None):
        return self._map.get(key, default)

    def has_key(self, key):
        return key in self._map

    def iterkeys(self):
        return self._map.iterkeys()

    def itervalues(self):
        return self._map.itervalues()

    def keys(self):
        return self._map.keys()

    def pop(self, key, default=None):
        return self._map.pop(key, default)

    def popitem(self):
        return self._map.popitem()

    def setdefault(self, key, default=None):
        self._map.setdefault(key, default)

    def update(self, *args, **kwargs):
        if len(args) != 0:
            self._map.update(*args)
        self._map.update(kwargs)

    def viewitems(self):
        return self._map.viewitems()

    def viewkeys(self):
        return self._map.viewkeys()

    def viewvalues(self):
        return self._map.viewvalues()

    @classmethod
    def fromkeys(cls, seq, value=None):
        d = DotMap()
        d._map = OrderedDict.fromkeys(seq, value)
        return d

    def __getstate__(self):
        return self.__dict__

    def __setstate__(self, d):
        self.__dict__.update(d)

    # bannerStr
    def _getListStr(self, items):
        out = '['
        mid = ''
        for i in items:
            mid += '  {}\n'.format(i)
        if mid != '':
            mid = '\n' + mid
        out += mid
        out += ']'
        return out

    def _getValueStr(self, k, v):
        outV = v
        multiLine = len(str(v).split('\n')) > 1
        if multiLine:
            # push to next line
            outV = '\n' + v
        if type(v) is list:
            outV = self._getListStr(v)
        out = '{} {}'.format(k, outV)
        return out

    def _getSubMapDotList(self, pre, name, subMap):
        outList = []
        if pre == '':
            pre = name
        else:
            pre = '{}.{}'.format(pre, name)

        def stamp(pre, k, v):
            valStr = self._getValueStr(k, v)
            return '{}.{}'.format(pre, valStr)

        for k, v in subMap.items():
            if isinstance(v, DotMap) and v != DotMap():
                subList = self._getSubMapDotList(pre, k, v)
                outList.extend(subList)
            else:
                outList.append(stamp(pre, k, v))
        return outList

    def _getSubMapStr(self, name, subMap):
        outList = ['== {} =='.format(name)]
        for k, v in subMap.items():
            if isinstance(v, DotMap) and v != DotMap():
                # break down to dots
                subList = self._getSubMapDotList('', k, v)
                # add the divit
                # subList = ['> {}'.format(i) for i in subList]
                outList.extend(subList)
            else:
                out = self._getValueStr(k, v)
                # out = '> {}'.format(out)
                out = '{}'.format(out)
                outList.append(out)
        finalOut = '\n'.join(outList)
        return finalOut

    def bannerStr(self):
        lines = []
        previous = None
        for k, v in self.items():
            if previous == 'DotMap':
                lines.append('-')
            out = ''
            if isinstance(v, DotMap):
                name = k
                subMap = v
                out = self._getSubMapStr(name, subMap)
                lines.append(out)
                previous = 'DotMap'
            else:
                out = self._getValueStr(k, v)
                lines.append(out)
                previous = 'other'
        lines.append('--')
        s = '\n'.join(lines)
        return s
Пример #16
0
class DotMap(OrderedDict):

	def __init__(self, *args, **kwargs):
		self._map = OrderedDict()
		if args:
			d = args[0]
			if type(d) is dict:
				for k,v in self.__call_items(d):
					if type(v) is dict:
						v = DotMap(v)
					self._map[k] = v
		if kwargs:
			for k,v in self.__call_items(kwargs):
				self._map[k] = v

	def __call_items(self, obj):
		if hasattr(obj, 'iteritems') and ismethod(getattr(obj, 'iteritems')):
			return obj.iteritems()
		else:
			return obj.items()

	def items(self):
		return self.iteritems()

	def iteritems(self):
		return self.__call_items(self._map)

	def __iter__(self):
		return self._map.__iter__()

	def next(self):
		return self._map.next()

	def __setitem__(self, k, v):
		self._map[k] = v
	def __getitem__(self, k):
		if k not in self._map:
			# automatically extend to new DotMap
			self[k] = DotMap()
		return self._map[k]

	def __setattr__(self, k, v):
		if k == '_map':
			super(DotMap, self).__setattr__(k,v)
		else:
			self[k] = v

	def __getattr__(self, k):
		if k == '_map':
			super(DotMap, self).__getattr__(k)
		else:
			return self[k]

	def __delattr__(self, key):
		return self._map.__delitem__(key)

	def __contains__(self, k):
		return self._map.__contains__(k)

	def __str__(self):
		items = []
		for k,v in self.__call_items(self._map):
			items.append('{0}={1}'.format(k, repr(v)))
		out = 'DotMap({0})'.format(', '.join(items))
		return out

	def __repr__(self):
		return str(self)

	def toDict(self):
		d = {}
		for k,v in self.items():
			if type(v) is DotMap:
				v = v.toDict()
			d[k] = v
		return d

	def pprint(self):
		pprint(self.toDict())

	# proper dict subclassing
	def values(self):
		return self._map.values()

	@classmethod
	def parseOther(self, other):
		if type(other) is DotMap:
			return other._map
		else:
			return other	
	def __cmp__(self, other):
		other = DotMap.parseOther(other)
		return self._map.__cmp__(other)
	def __eq__(self, other):
		other = DotMap.parseOther(other)
		if not isinstance(other, dict):
			return False
		return self._map.__eq__(other)
	def __ge__(self, other):
		other = DotMap.parseOther(other)
		return self._map.__ge__(other)
	def __gt__(self, other):
		other = DotMap.parseOther(other)
		return self._map.__gt__(other)
	def __le__(self, other):
		other = DotMap.parseOther(other)
		return self._map.__le__(other)
	def __lt__(self, other):
		other = DotMap.parseOther(other)
		return self._map.__lt__(other)
	def __ne__(self, other):
		other = DotMap.parseOther(other)
		return self._map.__ne__(other)

	def __delitem__(self, key):
		return self._map.__delitem__(key)
	def __len__(self):
		return self._map.__len__()
	def clear(self):
		self._map.clear()
	def copy(self):
		return self
	def get(self, key, default=None):
		return self._map.get(key, default)
	def has_key(self, key):
		return key in self._map
	def iterkeys(self):
		return self._map.iterkeys()
	def itervalues(self):
		return self._map.itervalues()
	def keys(self):
		return self._map.keys()
	def pop(self, key, default=None):
		return self._map.pop(key, default)
	def popitem(self):
		return self._map.popitem()
	def setdefault(self, key, default=None):
		self._map.setdefault(key, default)
	def update(self, *args, **kwargs):
		if len(args) != 0:
			self._map.update(*args)
		self._map.update(kwargs)
	def viewitems(self):
		return self._map.viewitems()
	def viewkeys(self):
		return self._map.viewkeys()
	def viewvalues(self):
		return self._map.viewvalues()
	@classmethod
	def fromkeys(cls, seq, value=None):
		d = DotMap()
		d._map = OrderedDict.fromkeys(seq, value)
		return d
Пример #17
0
class ConfigMap(MutableMapping, OrderedDict):

    def __init__(self, *args, **kwargs):
        self._map = OrderedDict()
        # todo: simplify
        self._dynamic = True
        if kwargs:
            if '_dynamic' in kwargs:
                self._dynamic = kwargs['_dynamic']
                del kwargs['_dynamic']
        self._evaluate = True
        if kwargs:
            if '_evaluate' in kwargs:
                self._evaluate = kwargs['_evaluate']
                del kwargs['_evaluate']
        self._evaluated = False
        if kwargs:
            if '_evaluated' in kwargs:
                self._evaluated = kwargs['_evaluated']
                del kwargs['_evaluated']
        if args:
            d = args[0]
            if isinstance(d, dict):
                for k, v in self.__call_items(d):
                    if isinstance(v, dict):
                        v = ConfigMap(v, _dynamic=self._dynamic, _evaluate=self._evaluate, _evaluated=self._evaluated)
                    if type(v) is list:
                        l = []
                        for i in v:
                            n = i
                            if type(i) is dict:
                                n = ConfigMap(i, _dynamic=self._dynamic, _evaluate=self._evaluate,
                                              _evaluated=self._evaluated)
                            l.append(n)
                        v = l
                    self._map[k] = v
        if kwargs:
            for k, v in self.__call_items(kwargs):
                self._map[k] = v

    def __call_items(self, obj):
        if hasattr(obj, 'iteritems') and ismethod(getattr(obj, 'iteritems')):
            return obj.iteritems()
        else:
            return obj.items()

    def items(self):
        return self.iteritems()

    def iteritems(self):
        return self.__call_items(self._map)

    def __iter__(self):
        return self._map.__iter__()

    def next(self):
        return self._map.next()

    def __setitem__(self, k, v):
        self._map[k] = v

    def __getitem__(self, k, evaluate=None):
        if evaluate is None:
            evaluate = self._evaluate

        if k not in self._map:
            if k == '_ipython_canary_method_should_not_exist_':
                raise KeyError

            if self._dynamic:
                # automatically extend to new ConfigMap
                self[k] = ConfigMap()
            else:
                # todo: display full recursive path?
                raise KeyError("'%s' does not exist" % k)

        var = self._map[k]

        if evaluate:
            if isinstance(var, ConfigMethod):
                var = var.evaluate()
                # todo: return instead to avoid second config map eval?

            if isinstance(var, ConfigMap):
                var = var.evaluate()

        return var

    def __setattr__(self, k, v):
        if k in ['_map', '_dynamic', '_ipython_canary_method_should_not_exist_', '_evaluate', '_evaluated']:
            super(ConfigMap, self).__setattr__(k, v)
        else:
            self[k] = v

    def __getattr__(self, k):
        if k in ['_map', '_dynamic', '_ipython_canary_method_should_not_exist_', '_evaluate', '_evaluated']:
            return self.__getattribute__(k)
        else:
            return self[k]

    def __delattr__(self, key):
        return self._map.__delitem__(key)

    def __contains__(self, k):
        return self._map.__contains__(k)

    def __str__(self):
        items = []
        for k, v in self.__call_items(self._map):
            # bizarre recursive assignment situation (why someone would do this is beyond me)
            if id(v) == id(self):
                items.append('{0}=ConfigMap(...)'.format(k))
            else:
                items.append('{0}={1}'.format(k, repr(v)))
        joined = ', '.join(items)
        out = '{0}({1})'.format(self.__class__.__name__, joined)
        return out

    def __repr__(self):
        return str(self)

    def toDict(self, evaluate=None, with_hidden=True):
        if evaluate is None:
            evaluate = bool(self._evaluate)

        d = {}
        for k, v in self.items():
            if evaluate and isinstance(v, ConfigMethod):
                v = v.evaluate()
            if isinstance(v, ConfigMap):
                v = v.toDict(evaluate=evaluate, with_hidden=with_hidden) if id(v) != id(self) else d
            elif isinstance(v, list):
                v = [i.toDict(evaluate=evaluate, with_hidden=with_hidden) if isinstance(i, ConfigMap) else i for i in v]
            elif isinstance(v, tuple):
                v = (i.toDict(evaluate=evaluate, with_hidden=with_hidden) if isinstance(i, ConfigMap) else i for i in v)

            if with_hidden is False \
                    and (isinstance(k, str) and
                         ((k.startswith('_') and not k.endswith('_')) or k.startswith('~'))):
                continue

            d[k] = v

        return d

    def evaluate(self):
        if self._evaluated:
            return self

        # TODO: case where config method access a key of the config that is just being evaluated.
        #  shouldn't give an endless loop

        # todo: make more efficient
        return ConfigMap(self.toDict(evaluate=True), _dynamic=False, _evaluated=True)

    def pprint(self, pformat='json'):
        if pformat == 'json':
            print(dumps(self.toDict(), indent=4, sort_keys=True, default=str))
        else:
            pprint(self.toDict())

    def empty(self):
        return not any(self)

        # proper dict subclassing

    def values(self):
        return self._map.values()

        # ipython support

    def __dir__(self):
        return self.keys()

    @classmethod
    def parseOther(self, other):
        if type(other) is ConfigMap:
            return other._map
        else:
            return other

    def __cmp__(self, other):
        other = ConfigMap.parseOther(other)
        return self._map.__cmp__(other)

    def __eq__(self, other):
        other = ConfigMap.parseOther(other)
        if not isinstance(other, dict):
            return False
        return self._map.__eq__(other)

    def __ge__(self, other):
        other = ConfigMap.parseOther(other)
        return self._map.__ge__(other)

    def __gt__(self, other):
        other = ConfigMap.parseOther(other)
        return self._map.__gt__(other)

    def __le__(self, other):
        other = ConfigMap.parseOther(other)
        return self._map.__le__(other)

    def __lt__(self, other):
        other = ConfigMap.parseOther(other)
        return self._map.__lt__(other)

    def __ne__(self, other):
        other = ConfigMap.parseOther(other)
        return self._map.__ne__(other)

    def __delitem__(self, key):
        return self._map.__delitem__(key)

    def __len__(self):
        return self._map.__len__()

    def clear(self):
        self._map.clear()

    def copy(self):
        return ConfigMap(self, _dynamic=self._dynamic, _evaluate=self._evaluate, _evaluated=self._evaluated)

    def __copy__(self):
        return self.copy()

    def __deepcopy__(self, memo=None):
        return self.copy()

    def get(self, key, default=None):
        return self._map.get(key, default)

    def has_key(self, key):
        return key in self._map

    def iterkeys(self):
        return self._map.iterkeys()

    def itervalues(self):
        return self._map.itervalues()

    def keys(self):
        return self._map.keys()

    def pop(self, key, default=None):
        return self._map.pop(key, default)

    def popitem(self):
        return self._map.popitem()

    def setdefault(self, key, default=None):
        self._map.setdefault(key, default)

    def update(self, *args, **kwargs):
        if len(args) != 0:
            self._map.update(*args)
        self._map.update(kwargs)

    def viewitems(self):
        return self._map.viewitems()

    def viewkeys(self):
        return self._map.viewkeys()

    def viewvalues(self):
        return self._map.viewvalues()

    @classmethod
    def fromkeys(cls, seq, value=None):
        d = ConfigMap(_dynamic=False)
        d._map = OrderedDict.fromkeys(seq, value)
        return d

    def __getstate__(self):
        return self.__dict__

    def __setstate__(self, d):
        self.__dict__.update(d)

    # bannerStr
    def _getListStr(self, items):
        out = '['
        mid = ''
        for i in items:
            mid += '  {}\n'.format(i)
        if mid != '':
            mid = '\n' + mid
        out += mid
        out += ']'
        return out

    def _getValueStr(self, k, v):
        outV = v
        multiLine = len(str(v).split('\n')) > 1
        if multiLine:
            # push to next line
            outV = '\n' + v
        if type(v) is list:
            outV = self._getListStr(v)
        out = '{} {}'.format(k, outV)
        return out

    def _getSubMapDotList(self, pre, name, subMap):
        outList = []
        if pre == '':
            pre = name
        else:
            pre = '{}.{}'.format(pre, name)

        def stamp(pre, k, v):
            valStr = self._getValueStr(k, v)
            return '{}.{}'.format(pre, valStr)

        for k, v in subMap.items():
            if isinstance(v, ConfigMap) and v != ConfigMap():
                subList = self._getSubMapDotList(pre, k, v)
                outList.extend(subList)
            else:
                outList.append(stamp(pre, k, v))
        return outList

    def _getSubMapStr(self, name, subMap):
        outList = ['== {} =='.format(name)]
        for k, v in subMap.items():
            if isinstance(v, ConfigMap) and v != ConfigMap():
                # break down to dots
                subList = self._getSubMapDotList('', k, v)
                # add the divit
                # subList = ['> {}'.format(i) for i in subList]
                outList.extend(subList)
            else:
                out = self._getValueStr(k, v)
                # out = '> {}'.format(out)
                out = '{}'.format(out)
                outList.append(out)
        finalOut = '\n'.join(outList)
        return finalOut

    def bannerStr(self):
        lines = []
        previous = None
        for k, v in self.items():
            if previous == 'ConfigMap':
                lines.append('-')
            out = ''
            if isinstance(v, ConfigMap):
                name = k
                subMap = v
                out = self._getSubMapStr(name, subMap)
                lines.append(out)
                previous = 'ConfigMap'
            else:
                out = self._getValueStr(k, v)
                lines.append(out)
                previous = 'other'
        lines.append('--')
        s = '\n'.join(lines)

        return s
Пример #18
0
class BaseCache(object):
    """
    BaseCache is a class that saves and operates on an OrderedDict. It has a
    certain capacity, stored in the attribute `maxsize`. Whether this
    capacity is reached, can be checked by using the boolean property
    `is_full`. To implement a custom cache, inherit from this class and
    override the methods ``__getitem__`` and ``__setitem__``.
    Call the method `sunpy.database.caching.BaseCache.callback` as soon
    as an item from the cache is removed.
    """
    __metaclass__ = ABCMeta

    def __init__(self, maxsize=float('inf')):
        self.maxsize = maxsize
        self._dict = OrderedDict()

    def get(self, key, default=None):  # pragma: no cover
        """Return the corresponding value to `key` if `key` is in the cache,
        `default` otherwise. This method has no side-effects, multiple calls
        with the same cache and the same passed key must always return the same
        value.

        """
        try:
            return self._dict[key]
        except KeyError:
            return default

    @abstractmethod
    def __getitem__(self, key):
        """abstract method: this method must be overwritten by inheriting
        subclasses. It defines what happens if an item from the cache is
        attempted to be accessed.

        """
        return  # pragma: no cover

    @abstractmethod
    def __setitem__(self, key, value):
        """abstract method: this method must be overwritten by inheriting
        subclasses. It defines what happens if a new value should be assigned
        to the given key. If the given key does already exist in the cache or
        not must be checked by the person who implements this method.
        """

    @abstractproperty
    def to_be_removed(self):
        """The item that will be removed on the next
        :meth:`sunpy.database.caching.BaseCache.remove` call.

        """

    @abstractmethod
    def remove(self):
        """Call this method to manually remove one item from the cache. Which
        item is removed, depends on the implementation of the cache. After the
        item has been removed, the callback method is called.

        """

    def callback(self, key, value):
        """This method should be called (by convention) if an item is removed
        from the cache because it is full. The passed key and value are the
        ones that are removed. By default this method does nothing, but it
        can be customized in a custom cache that inherits from this base class.

        """

    @property
    def is_full(self):
        """True if the number of items in the cache equals :attr:`maxsize`,
        False otherwise.

        """
        return len(self._dict) == self.maxsize

    def __delitem__(self, key):
        self._dict.__delitem__(key)

    def __contains__(self, key):
        return key in self._dict.keys()

    def __len__(self):
        return len(self._dict)

    def __iter__(self):
        for key in self._dict.__iter__():
            yield key

    def __reversed__(self):  # pragma: no cover
        for key in self._dict.__reversed__():
            yield key

    def clear(self):  # pragma: no cover
        return self._dict.clear()

    def keys(self):  # pragma: no cover
        return self._dict.keys()

    def values(self):  # pragma: no cover
        return self._dict.values()

    def items(self):  # pragma: no cover
        return self._dict.items()

    def iterkeys(self):  # pragma: no cover
        return self._dict.iterkeys()

    def itervalues(self):  # pragma: no cover
        for value in self._dict.itervalues():
            yield value

    def iteritems(self):  # pragma: no cover
        for key, value in self._dict.iteritems():
            yield key, value

    def update(self, *args, **kwds):  # pragma: no cover
        self._dict.update(*args, **kwds)

    def pop(self, key, default=MutableMapping._MutableMapping__marker):  # pragma: no cover
        return self._dict.pop(key, default)

    def setdefault(self, key, default=None):  # pragma: no cover
        return self._dict.setdefault(key, default)

    def popitem(self, last=True):  # pragma: no cover
        return self._dict.popitem(last)

    def __reduce__(self):  # pragma: no cover
        return self._dict.__reduce__()

    def copy(self):  # pragma: no cover
        return self._dict.copy()

    def __eq__(self, other):  # pragma: no cover
        return self._dict.__eq__(other)

    def __ne__(self, other):  # pragma: no cover
        return self._dict.__ne__(other)

    def viewkeys(self):  # pragma: no cover
        return self._dict.viewkeys()

    def viewvalues(self):  # pragma: no cover
        return self._dict.viewvalues()

    def viewitems(self):  # pragma: no cover
        return self._dict.viewitems()

    @classmethod
    def fromkeys(cls, iterable, value=None):  # pragma: no cover
        return OrderedDict.fromkeys(iterable, value)

    def __repr__(self):  # pragma: no cover
        return '{0}({1!r})'.format(self.__class__.__name__, dict(self._dict))
Пример #19
0
class DotMap(OrderedDict):
    def __init__(self, *args, **kwargs):

        self._map = OrderedDict()
        self._dynamic = True  # mettendo False non funzionano più i test di default. E' normale in quanto si aspettano la creazione dinamica dei figli

        # ===================================
        if LORETO:
            global MY_DICT_TYPES  # global var per la classe
            self._dynamic = False  # mettendo False non funzionano più i test di default. E' normale in quanto si aspettano la creazione dinamica dei figli
            MY_DICT_TYPES = [dict, DotMap,
                             OrderedDict]  # by Loreto (DEFAULT dictionary)
            # ===================================

        if kwargs:
            if '_dynamic' in kwargs:
                self._dynamic = kwargs['_dynamic']
        if args:
            d = args[0]
            if isinstance(d, dict):
                for k, v in self.__call_items(d):
                    if type(v) is dict:
                        v = DotMap(v, _dynamic=self._dynamic)
                    if type(v) is list:
                        l = []
                        for i in v:
                            n = i
                            if type(i) is dict:
                                n = DotMap(i, _dynamic=self._dynamic)
                            l.append(n)
                        v = l
                    self._map[k] = v
        if kwargs:
            for k, v in self.__call_items(kwargs):
                if k is not '_dynamic':
                    self._map[k] = v

    def __call_items(self, obj):
        if hasattr(obj, 'iteritems') and ismethod(getattr(obj, 'iteritems')):
            return obj.iteritems()
        else:
            return obj.items()

    def items(self):
        return self.iteritems()

    def iteritems(self):
        return self.__call_items(self._map)

    def __iter__(self):
        return self._map.__iter__()

    def next(self):
        return self._map.next()

    def __setitem__(self, k, v):
        self._map[k] = v

    def __getitem__(self, k):
        if k not in self._map and self._dynamic and k != '_ipython_canary_method_should_not_exist_':
            # automatically extend to new DotMap
            self[k] = DotMap()
        return self._map[k]

    def __setattr__(self, k, v):
        if k in {
                '_map', '_dynamic', '_ipython_canary_method_should_not_exist_'
        }:
            super(DotMap, self).__setattr__(k, v)
        else:
            self[k] = v

    def __getattr__(self, k):
        if k == {
                '_map', '_dynamic', '_ipython_canary_method_should_not_exist_'
        }:
            super(DotMap, self).__getattr__(k)
        else:
            return self[k]

    def __delattr__(self, key):
        return self._map.__delitem__(key)

    def __contains__(self, k):
        return self._map.__contains__(k)

    def __str__(self):
        items = []
        for k, v in self.__call_items(self._map):
            # bizarre recursive assignment situation (why someone would do this is beyond me)
            if id(v) == id(self):
                items.append('{0}=DotMap(...)'.format(k))
            else:
                items.append('{0}={1}'.format(k, repr(v)))
        out = 'DotMap({0})'.format(', '.join(items))
        return out

    def __repr__(self):
        return str(self)

    def toDict(self):
        d = {}
        for k, v in self.items():
            if type(v) is DotMap:
                # bizarre recursive assignment support
                if id(v) == id(self):
                    v = d
                else:
                    v = v.toDict()
            elif type(v) is list:
                l = []
                for i in v:
                    n = i
                    if type(i) is DotMap:
                        n = i.toDict()
                    l.append(n)
                v = l
            d[k] = v
        return d

    def pprint(self):
        pprint(self.toDict())

        # ===================================

    if LORETO:
        # MY_DICT_TYPES = [dict, DotMap]
        def Ptr(self, listOfQualifiers, create=False):
            ptr = self
            for item in listOfQualifiers:
                if item in ptr:
                    ptr = ptr[item]
                else:
                    if create:
                        ptr[item] = DotMap()
                        ptr = ptr[item]
                    else:
                        return None

            return ptr

        def KeyTree(self, fPRINT=False):
            return DictToList.KeyTree(self,
                                      myDictTYPES=MY_DICT_TYPES,
                                      fPRINT=fPRINT)

        def KeyList(self):
            return DictToList.KeyList(self, myDictTYPES=MY_DICT_TYPES)

        def PrintTree(self,
                      fEXIT=False,
                      maxDepth=10,
                      header=None,
                      whatPrint='LTKV',
                      stackLevel=1):
            PrintDictionaryTree.PrintDictionary(self,
                                                myDictTYPES=MY_DICT_TYPES,
                                                whatPrint=whatPrint,
                                                fEXIT=fEXIT,
                                                maxDepth=maxDepth,
                                                header=header,
                                                stackLevel=stackLevel + 1)

        printDict = PrintTree
        printTree = PrintTree

        def GetValue(self, listOfQualifiers=[], fPRINT=False):
            return DictToList.getValue(self,
                                       listOfQualifiers=listOfQualifiers,
                                       myDictTYPES=MY_DICT_TYPES,
                                       fPRINT=fPRINT)

        # ===================================

    def empty(self):
        return (not any(self))

    # proper dict subclassing
    def values(self):
        return self._map.values()

    # ipython support
    def __dir__(self):
        return self.keys()

    @classmethod
    def parseOther(self, other):
        if type(other) is DotMap:
            return other._map
        else:
            return other

    def __cmp__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__cmp__(other)

    def __eq__(self, other):
        other = DotMap.parseOther(other)
        if not isinstance(other, dict):
            return False
        return self._map.__eq__(other)

    def __ge__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__ge__(other)

    def __gt__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__gt__(other)

    def __le__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__le__(other)

    def __lt__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__lt__(other)

    def __ne__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__ne__(other)

    def __delitem__(self, key):
        return self._map.__delitem__(key)

    def __len__(self):
        return self._map.__len__()

    def clear(self):
        self._map.clear()

    def copy(self):
        return DotMap(self.toDict())

    def get(self, key, default=None):
        return self._map.get(key, default)

    def has_key(self, key):
        return key in self._map

    def iterkeys(self):
        return self._map.iterkeys()

    def itervalues(self):
        return self._map.itervalues()

    def keys(self):
        return self._map.keys()

    def pop(self, key, default=None):
        return self._map.pop(key, default)

    def popitem(self):
        return self._map.popitem()

    def setdefault(self, key, default=None):
        self._map.setdefault(key, default)

    def update(self, *args, **kwargs):
        if len(args) != 0:
            self._map.update(*args)
        self._map.update(kwargs)

    def viewitems(self):
        return self._map.viewitems()

    def viewkeys(self):
        return self._map.viewkeys()

    def viewvalues(self):
        return self._map.viewvalues()

    @classmethod
    def fromkeys(cls, seq, value=None):
        d = DotMap()
        d._map = OrderedDict.fromkeys(seq, value)
        return d

    def __getstate__(self):
        return self.__dict__

    def __setstate__(self, d):
        self.__dict__.update(d)
Пример #20
0
class DebugVariableViewer:
    
    def __init__(self, window, items=[]):
        """
        Constructor
        @param window: Reference to the Debug Variable Panel
        @param items: List of DebugVariableItem displayed by Viewer
        """
        self.ParentWindow = window
        self.ItemsDict = OrderedDict([(item.GetVariable(), item)
                                      for item in items])
        self.Items = self.ItemsDict.viewvalues()
        
        # Variable storing current highlight displayed in Viewer
        self.Highlight = HIGHLIGHT_NONE
        # List of buttons
        self.Buttons = []
    
    def __del__(self):
        """
        Destructor
        """
        # Remove reference to Debug Variable Panel
        self.ParentWindow = None
    
    def GetIndex(self):
        """
        Return position of Viewer in Debug Variable Panel
        @return: Position of Viewer
        """
        return self.ParentWindow.GetViewerIndex(self)
    
    def GetItem(self, variable):
        """
        Return item storing values of a variable
        @param variable: Variable path
        @return: Item storing values of this variable
        """
        return self.ItemsDict.get(variable, None)
    
    def GetItems(self):
        """
        Return items displayed by Viewer
        @return: List of items displayed in Viewer
        """
        return self.ItemsDict.values()
    
    def AddItem(self, item):
        """
        Add an item to the list of items displayed by Viewer
        @param item: Item to add to the list
        """
        self.ItemsDict[item.GetVariable()] = item
        
    def RemoveItem(self, item):
        """
        Remove an item from the list of items displayed by Viewer
        @param item: Item to remove from the list
        """
        self.ItemsDict.pop(item.GetVariable(), None)
    
    def ClearItems(self):
        """
        Clear list of items displayed by Viewer
        """
        # Unsubscribe every items of the list
        for item in self.Items:
            self.ParentWindow.RemoveDataConsumer(item)
        
        # Clear list
        self.ItemsDict.clear()
        
    def ItemsIsEmpty(self):
        """
        Return if list of items displayed by Viewer is empty
        @return: True if list is empty
        """
        return len(self.Items) == 0
    
    def SubscribeAllDataConsumers(self):
        """
        Function that unsubscribe and remove every item that store values of
        a variable that doesn't exist in PLC anymore
        """
        for item in self.ItemsDict.values()[:]:
            iec_path = item.GetVariable()
            
            # Check that variablepath exist in PLC
            if self.ParentWindow.GetDataType(iec_path) is None:
                # If not, unsubscribe and remove it
                self.ParentWindow.RemoveDataConsumer(item)
                self.RemoveItem(item)
            else:
                # If it exist, resubscribe and refresh data type
                self.ParentWindow.AddDataConsumer(iec_path.upper(), item, True)
                item.RefreshVariableType()
    
    def ResetItemsData(self):
        """
        Reset data stored in every items displayed in Viewer
        """
        for item in self.Items:
            item.ResetData()
    
    def GetItemsMinCommonTick(self):
        """
        Return the minimum tick common to all iems displayed in Viewer
        @return: Minimum common tick between items
        """
        return reduce(max, [item.GetData()[0, 0] 
                            for item in self.Items
                            if len(item.GetData()) > 0], 0)
    
    def RefreshViewer(self):
        """
        Method that refresh the content displayed by Viewer
        Need to be overridden by inherited classes
        """
        pass
    
    def SetHighlight(self, highlight):
        """
        Set Highlight type displayed in Viewer
        @return: True if highlight has changed
        """
        # Return immediately if highlight don't change
        if self.Highlight == highlight:
            return False
        
        self.Highlight = highlight
        return True
    
    def GetButtons(self):
        """
        Return list of buttons defined in Viewer
        @return: List of buttons
        """
        return self.Buttons
    
    def IsOverButton(self, x, y):
        """
        Return if point is over one button of Viewer
        @param x: X coordinate of point
        @param y: Y coordinate of point
        @return: button where point is over
        """
        for button in self.GetButtons():
            if button.HitTest(x, y):
                return button
        return None
    
    def HandleButton(self, x, y):
        """
        Search for the button under point and if found execute associated
        callback
        @param x: X coordinate of point
        @param y: Y coordinate of point
        @return: True if a button was found and callback executed
        """
        button = self.IsOverButton(x, y)
        if button is None:
            return False
        
        button.ProcessCallback()
        return True
    
    def ShowButtons(self, show):
        """
        Set display state of buttons in Viewer
        @param show: Display state (True if buttons must be displayed)
        """
        # Change display of every buttons
        for button in self.Buttons:
            button.Show(show)
        
        # Refresh button positions
        self.RefreshButtonsPosition()
        self.RefreshViewer()
    
    def RefreshButtonsPosition(self):
        """
        Function that refresh buttons position in Viewer
        """
        # Get Viewer size
        width, height = self.GetSize()
        
        # Buttons are align right so we calculate buttons positions in
        # reverse order
        buttons = self.Buttons[:]
        buttons.reverse()
        
        # Position offset on x coordinate
        x_offset = 0
        for button in buttons:
            # Buttons are stacked right, removing those that are not active 
            if button.IsEnabled():
                # Update button position according to button width and offset
                # on x coordinate
                w, h = button.GetSize()
                button.SetPosition(width - 5 - w - x_offset, 5)
                # Update offset on x coordinate
                x_offset += w + 2
    
    def DrawCommonElements(self, dc, buttons=None):
        """
        Function that draw common graphics for every Viewers
        @param dc: wx.DC object corresponding to Device context where drawing
        common graphics
        @param buttons: List of buttons to draw if different from default
        (default None)
        """
        # Get Viewer size
        width, height = self.GetSize()
        
        # Set dc styling for drop before or drop after highlight
        dc.SetPen(HIGHLIGHT_DROP_PEN)
        dc.SetBrush(HIGHLIGHT_DROP_BRUSH)
        
        # Draw line at upper side of Viewer if highlight is drop before
        if self.Highlight == HIGHLIGHT_BEFORE:
            dc.DrawLine(0, 1, width - 1, 1)
        
        # Draw line at lower side of Viewer if highlight is drop before
        elif self.Highlight == HIGHLIGHT_AFTER:
            dc.DrawLine(0, height - 1, width - 1, height - 1)
        
        # If no specific buttons are defined, get default buttons
        if buttons is None:
            buttons = self.Buttons
        # Draw buttons
        for button in buttons:
            button.Draw(dc)
        
        # If graph dragging is processing
        if self.ParentWindow.IsDragging():
            destBBox = self.ParentWindow.GetDraggingAxesClippingRegion(self)
            srcPos = self.ParentWindow.GetDraggingAxesPosition(self)
            if destBBox.width > 0 and destBBox.height > 0:
                srcPanel = self.ParentWindow.DraggingAxesPanel
                srcBBox = srcPanel.GetAxesBoundingBox()
                
                srcX = srcBBox.x - (srcPos.x if destBBox.x == 0 else 0)
                srcY = srcBBox.y - (srcPos.y if destBBox.y == 0 else 0)
                
                srcBmp = _convert_agg_to_wx_bitmap(
                            srcPanel.get_renderer(), None)
                srcDC = wx.MemoryDC()
                srcDC.SelectObject(srcBmp)
                
                dc.Blit(destBBox.x, destBBox.y, 
                        int(destBBox.width), int(destBBox.height), 
                        srcDC, srcX, srcY)
    
    def OnEnter(self, event):
        """
        Function called when entering Viewer
        @param event: wx.MouseEvent 
        """
        # Display buttons
        self.ShowButtons(True)
        event.Skip()
        
    def OnLeave(self, event):
        """
        Function called when leaving Viewer
        @param event: wx.MouseEvent 
        """
        # Hide buttons
        self.ShowButtons(False)
        event.Skip()
    
    def OnCloseButton(self):
        """
        Function called when Close button is pressed
        """
        wx.CallAfter(self.ParentWindow.DeleteValue, self)
    
    def OnForceButton(self):
        """
        Function called when Force button is pressed
        """
        self.ForceValue(self.ItemsDict.values()[0])
        
    def OnReleaseButton(self):
        """
        Function called when Release button is pressed
        """
        self.ReleaseValue(self.ItemsDict.values()[0])
    
    def OnMouseDragging(self, x, y):
        """
        Function called when mouse is dragged over Viewer
        @param x: X coordinate of mouse pointer
        @param y: Y coordinate of mouse pointer
        """
        xw, yw = self.GetPosition()
        # Refresh highlight in Debug Variable Panel (highlight can be displayed
        # in another Viewer
        self.ParentWindow.RefreshHighlight(x + xw, y + yw)
    
    def RefreshHighlight(self, x, y):
        """
        Function called by Debug Variable Panel asking Viewer to refresh
        highlight according to mouse position
        @param x: X coordinate of mouse pointer
        @param y: Y coordinate of mouse pointer
        """
        # Get Viewer size
        width, height = self.GetSize()
        
        # Mouse is in the first half of Viewer
        if y < height / 2:
            # If Viewer is the upper one, draw drop before highlight
            if self.ParentWindow.IsViewerFirst(self):
                self.SetHighlight(HIGHLIGHT_BEFORE)
            
            # Else draw drop after highlight in previous Viewer
            else:
                self.SetHighlight(HIGHLIGHT_NONE)
                self.ParentWindow.HighlightPreviousViewer(self)
        
        # Mouse is in the second half of Viewer, draw drop after highlight 
        else:
            self.SetHighlight(HIGHLIGHT_AFTER)
    
    def OnEraseBackground(self, event):
        """
        Function called when Viewer background is going to be erase
        @param event: wx.EraseEvent
        """
        # Prevent flicker on Windows
        pass
    
    def OnResize(self, event):
        """
        Function called when Viewer size changed
        @param event: wx.ResizeEvent
        """
        # Refresh button positions
        self.RefreshButtonsPosition()
        self.ParentWindow.ForceRefresh()
        event.Skip()
    
    def ForceValue(self, item):
        """
        Force value of item given
        @param item: Item to force value
        """
        # Check variable data type
        iec_path = item.GetVariable()
        iec_type = self.ParentWindow.GetDataType(iec_path)
        # Return immediately if not found
        if iec_type is None:
            return
        
        # Open a dialog to enter varaible forced value
        dialog = ForceVariableDialog(self, iec_type, str(item.GetValue()))
        if dialog.ShowModal() == wx.ID_OK:
            self.ParentWindow.ForceDataValue(iec_path.upper(),
                                             dialog.GetValue())
    
    def ReleaseValue(self, item):
        """
        Release value of item given
        @param item: Item to release value
        """
        self.ParentWindow.ReleaseDataValue(
                item.GetVariable().upper())
Пример #21
0
class NotificationDisplay(object):
    '''Interface to display notification stack.
		Should have "display(note, cb_dismiss=None) -> nid(UInt32, >0)", "close(nid)"
			methods and NoWindowError(nid) exception, raised on erroneous nid's in close().
		Current implementation based on notipy: git://github.com/the-isz/notipy.git'''

    window = namedtuple('Window', 'gobj event_boxes')
    base_css = b'''
		#notification { background: transparent; }
		#notification #frame { background-color: #d4ded8; padding: 3px; }
		#notification #hs { background-color: black; }

		#notification #critical { background-color: #ffaeae; }
		#notification #normal { background-color: #f0ffec; }
		#notification #low { background-color: #bee3c6; }

		#notification #summary {
			padding-left: 5px;
			font-size: 1.2em;
			text-shadow: 1px 1px 0px gray;
		}
		#notification #body { font-size: 1em; }
		#notification #body * { background-color: #d4ded8; }
	'''
    base_css_min = b'#notification * { font-size: 8; }'  # simpliest fallback

    def __init__(self,
                 layout_margin,
                 layout_anchor,
                 layout_direction,
                 icon_scale=dict(),
                 markup_default=False,
                 markup_warn=False,
                 markup_strip=False):
        self.margins = dict(
            it.chain.from_iterable(
                map(
                    lambda ax: ((2**ax, layout_margin),
                                (-2**ax, layout_margin)), xrange(2))))
        self.layout_anchor = layout_anchor
        self.layout_direction = layout_direction
        self.icon_scale = icon_scale
        self.markup_default = markup_default
        self.markup_warn, self.markup_strip = markup_warn, markup_strip

        self._windows = OrderedDict()

        self._default_style = self._get_default_css()
        Gtk.StyleContext.add_provider_for_screen(
            Gdk.Screen.get_default(), self._default_style,
            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)

    def _pango_markup_parse(self, text, _err_mark='[TN82u8] '):
        success = True
        try:
            _, attr_list, text, _ = Pango.parse_markup(text, -1, '\0')
        except GLib.GError as err:
            if self.markup_warn:
                msg_start = '{}Pango formatting failed'.format(_err_mark)
                if msg_start not in text:  # detect and avoid possible feedback loops
                    log.warn('%s (%s) for text, stripping markup: %r',
                             msg_start, err, text)
                else:
                    text = xml_escape(
                        text)  # escape message so it'd render bugged part
            if self.markup_strip: text = strip_markup(text)
            try:
                _, attr_list, text, _ = Pango.parse_markup(text, -1, '\0')
            except GLib.GError:
                attr_list = None
            success = False
        return success, text, attr_list

    def _pango_markup_to_gtk(
            self,
            text,
            attr_list=None,
            _pango_classes={
                'SIZE': Pango.AttrInt,
                'WEIGHT': Pango.AttrInt,
                'UNDERLINE': Pango.AttrInt,
                'STRETCH': Pango.AttrInt,
                'VARIANT': Pango.AttrInt,
                'STYLE': Pango.AttrInt,
                'SCALE': Pango.AttrFloat,
                'FAMILY': Pango.AttrString,
                'FONT_DESC': Pango.AttrFontDesc,
                'STRIKETHROUGH': Pango.AttrInt,
                'BACKGROUND': Pango.AttrColor,
                'FOREGROUND': Pango.AttrColor,
                'RISE': Pango.AttrInt
            },
            _pango_to_gtk={'font_desc': 'font'}):
        # See https://bugzilla.gnome.org/show_bug.cgi?id=59390 for why it is necessary
        # And doesn't work with GI anyway because of
        #  https://bugzilla.gnome.org/show_bug.cgi?id=646788
        #  "Behdad Esfahbod [pango developer]: I personally have no clue how to fix this"
        # Workaround from https://github.com/matasbbb/pitivit/commit/da815339e
        # TODO: fix when AttrList.get_iterator will be accessible via GI or textbuffer gets set_markup()
        if attr_list is None:
            _, text, attr_list = self._pango_markup_parse(text)
            if attr_list is None:
                yield (text, None)
                raise StopIteration

        gtk_tags = defaultdict(dict)

        def parse_attr(attr, _data):
            gtk_attr = attr.klass.type.value_nick
            if gtk_attr in _pango_to_gtk: gtk_attr = _pango_to_gtk[gtk_attr]
            pango_attr, span = attr.klass.type.value_name, (attr.start_index,
                                                            attr.end_index)
            assert pango_attr.startswith('PANGO_ATTR_'), pango_attr
            attr.__class__ = _pango_classes[
                pango_attr[11:]]  # allows to access attr.value
            for k in 'value', 'ink_rect', 'logical_rect', 'desc', 'color':
                if not hasattr(attr, k): continue
                val = getattr(attr, k)
                if k == 'color':
                    val = '#' + ''.join(
                        '{:02x}'.format(v / 256)
                        for v in [val.red, val.green, val.blue])
                gtk_tags[span][gtk_attr] = val
                break
            else:
                raise KeyError(
                    'Failed to extract value for pango attribute: {}'.format(
                        pango_attr))
            return False

        attr_list.filter(parse_attr, None)

        pos = 0
        for (a, b), props in sorted(gtk_tags.viewitems()):
            if a > pos: yield (text[pos:a], None)
            yield (text[a:b], props)
            pos = b
        if text[pos:]: yield (text[pos:], None)

    def _get_default_css(self):
        css, base_css = Gtk.CssProvider(), self.base_css
        for attempt in xrange(6):
            try:
                css.load_from_data(base_css)
            except GLib.GError as err:
                log.warn('Failed to load default CSS style (try %s): %s',
                         attempt + 1, err)
                # print(base_css)
            else:
                break
            # Try to work around https://bugzilla.gnome.org/show_bug.cgi?id=678876 and similar issues
            if attempt == 0:
                base_css = re.sub(br'\b(background-color:)\s*rgba\([^;]+;',
                                  br'\1 white;', base_css)
            elif attempt == 1:
                base_css = re.sub(br'\b(font-size:)\s*(\d+)px\s*;', br'\1 \2;',
                                  base_css)
            elif attempt == 2:
                base_css = re.sub(br'\b(text-shadow:)[^;]+;',
                                  br'\1 1 1 0 gray;', base_css)
            elif attempt == 3:
                base_css = re.sub(br'\btext-shadow:[^;]+;', b'', base_css)
            elif attempt == 4:
                base_css = self.base_css_min  # last resort before no-css-at-all
            else:
                break  # don't load any css
        return css

    def _update_layout(self):
        # Get the coordinates of the "anchor" corner (screen corner +/- margins)
        base = tuple(map(
         lambda ax, gdk_dim=('width', 'height'):\
          (getattr(Gdk.Screen, gdk_dim[ax])() - self.margins[2**ax])\
           if 2**ax & self.layout_anchor else self.margins[-2**ax], xrange(2) ))
        # Iterate over windows in order, placing each one starting from a "base" corner
        for win in map(op.attrgetter('gobj'), self._windows.viewvalues()):
            win.move(*map(
                lambda ax: base[ax] - (win.get_size()[ax] if 2**ax & self.
                                       layout_anchor else 0), xrange(2)))
            margin = self.margins[(2 * (
                (2**self.layout_direction)
                & self.layout_anchor) / 2**self.layout_direction - 1) *
                                  2**self.layout_direction]
            base = tuple(map(
             lambda ax: base[ax] if self.layout_direction != ax else\
              base[ax] + (margin + win.get_size()[ax])\
               * (2 * (2**ax ^ (2**ax & self.layout_anchor)) / 2**ax - 1), xrange(2) ))

    def _get_icon(self, icon, remote=False):
        widget_icon = None

        if icon is not None:
            if isinstance(icon, types.StringTypes):
                icon_path = os.path.expanduser(urllib.url2pathname(icon))
                if icon_path.startswith('file://'): icon_path = icon_path[7:]
                if os.path.isfile(icon_path):
                    widget_icon = GdkPixbuf.Pixbuf.new_from_file(icon_path)
                else:
                    # Available names: Gtk.IconTheme.get_default().list_icons(None)
                    theme = Gtk.IconTheme.get_default()
                    icon_size = any(self.icon_scale.get('fixed', list())) or 32
                    widget_icon = theme.lookup_icon(
                        icon, icon_size, Gtk.IconLookupFlags.USE_BUILTIN)
                    if widget_icon: widget_icon = widget_icon.load_icon()
                    else:
                        # Msgs from remote hosts natually can have non-local icon paths in them
                        (
                            log.warn if not remote else log.debug
                        )('Provided icon info seem to be neither valid icon file nor'
                          ' a name in a freedesktop.org-compliant icon theme (or current theme'
                          ' does not have that one), ignoring it: %r',
                          core.format_trunc(icon))
            else:
                w, h, rowstride, has_alpha, bits_per_sample, channels, data = icon
                data = bytes(bytearray(data))
                widget_icon = GdkPixbuf.Pixbuf.new_from_data(
                    data, GdkPixbuf.Colorspace.RGB, bool(has_alpha),
                    int(bits_per_sample), int(w), int(h), int(rowstride))
                widget_icon._data = data  # must be preserved from gc

        if widget_icon:
            if any(it.chain.from_iterable(
                    self.icon_scale.values())):  # scale icon
                w, h = widget_icon.get_width(), widget_icon.get_height()
                for k in 'fixed', 'min', 'max':
                    box_w, box_h = self.icon_scale.get(k, (0, 0))
                    if not any([box_w, box_h]): continue
                    if k == 'min' and not ((box_w and w < box_w) or
                                           (box_h and h < box_h)):
                        continue
                    if k == 'max' and not ((box_w and w > box_w) or
                                           (box_h and h > box_h)):
                        continue
                    scale_down = (box_w and w > box_w) or (box_h and h > box_h)
                    if scale_down:
                        scale = min  # factor<1, unspec=1, must fit on both dimensions
                    elif box_w and box_h:
                        scale = min  # factor>1, but still pick min to fit on both
                    else:
                        scale = max  # ignore unspec=1 and scale to max possible factor
                    scale = scale(float(box_w or w) / w, float(box_h or h) / h)
                    box_w, box_h = w * scale, h * scale
                    log.debug(
                        'Scaling image (%s, criteria: %s) by a factor of'
                        ' %.3f: %dx%d -> %dx%d', ['up', 'down'][scale_down], k,
                        scale, w, h, box_w, box_h)
                    widget_icon = widget_icon.scale_simple(
                        box_w, box_h, GdkPixbuf.InterpType.BILINEAR)
                    if k == 'fixed':
                        break  # no need to apply min/max after that
            widget_icon, pixbuf = Gtk.Image(), widget_icon
            widget_icon.set_from_pixbuf(pixbuf)

        return widget_icon

    def _set_visual(self, win, ev=None):
        visual = win.get_screen().get_rgba_visual()
        if visual: win.set_visual(visual)

    def _create_win(self,
                    summary,
                    body,
                    icon=None,
                    urgency_label=None,
                    markup=False,
                    remote=None):
        log.debug(
            'Creating window with parameters: %s',
            core.repr_trunc_rec(
                dict(summary=summary,
                     body=body,
                     icon=icon,
                     urgency=urgency_label,
                     markup=markup)))

        win = Gtk.Window(name='notification', type=Gtk.WindowType.POPUP)
        win.set_default_size(400, 20)
        win.connect('screen-changed', self._set_visual)
        self._set_visual(win)
        ev_boxes = [win]

        frame = Gtk.Box(name='frame')
        win.add(frame)

        try:
            widget_icon = self._get_icon(icon, remote=remote)
        except Exception:  # Gdk may raise errors for some images/formats
            log.exception('Failed to set notification icon')
            widget_icon = None

        box_margin = 3
        v_box = Gtk.VBox(spacing=box_margin, expand=False)
        if widget_icon is not None:
            h_box = Gtk.HBox(spacing=box_margin * 2)
            frame.pack_start(h_box, True, True, 0)
            h_box.pack_start(widget_icon, False, False, 0)
            h_box.pack_start(v_box, True, True, 0)
            ev_boxes.append(h_box)
        else:
            frame.pack_start(v_box, True, True, 0)

        widget_summary = Gtk.Label(name='summary')

        # Sanitize tags through pango first, so set_markup won't produce empty label
        summary_markup, summary_text, summary\
         = self.get_display_summary(summary, markup)
        if summary_markup: widget_summary.set_markup(summary)
        else: widget_summary.set_text(summary)

        widget_summary.set_alignment(0, 0)
        if urgency_label:
            summary_box = Gtk.EventBox(name=urgency_label)
            summary_box.add(widget_summary)
        else:
            summary_box = widget_summary
        v_box.pack_start(summary_box, False, False, 0)
        ev_boxes.append(summary_box)

        v_box.pack_start(Gtk.HSeparator(name='hs'), False, False, 0)

        widget_body = Gtk.TextView(name='body',
                                   wrap_mode=Gtk.WrapMode.WORD_CHAR,
                                   cursor_visible=False,
                                   editable=False)
        widget_body_buffer = widget_body.get_buffer()

        body_markup, body_text, body_attrs = self.get_display_body(
            body, markup)
        if not body_markup: widget_body_buffer.set_text(body_text)
        else:
            # This buffer uses pango markup, even though GtkTextView does not support it
            # Most magic is in pango_markup_to_gtk(), there doesn't seem to be any cleaner way
            def get_tag(props,
                        _tag_id=iter(xrange(2**31 - 1)),
                        _tag_table=dict()):
                k = tuple(sorted(props.viewitems()))
                if k not in _tag_table:
                    _tag_table[k] = widget_body_buffer\
                     .create_tag('x{}'.format(next(_tag_id)), **props)
                return _tag_table[k]

            pos = widget_body_buffer.get_end_iter()
            for text, props in body_attrs:
                if props:
                    widget_body_buffer.insert_with_tags(
                        pos, text, get_tag(props))
                else:
                    widget_body_buffer.insert(pos, text)

        v_box.pack_start(widget_body, True, True, 0)
        ev_boxes.append(widget_body)

        # Make sure the window is initially drawn off-screen, because it can't be
        #  placed properly until it's size is known, and it's size is unknown until it's
        #  actually handled by window manager and then drawn by X
        # Proper placement is done on update_layout() call
        win.move(-2000, -2000)

        win.show_all()
        return self.window(win, ev_boxes)

    def get_display_summary(self, summary, markup):
        if markup:
            success, text, _ = self._pango_markup_parse(summary)
            if not success: markup, summary = False, text
        else: text = summary
        return markup, text, summary

    def get_display_body(self, body, markup):
        if markup:
            _, text, attr_list = self._pango_markup_parse(body)
            if attr_list is None: markup, body_attrs = False, [(text, None)]
            else: body_attrs = self._pango_markup_to_gtk(text, attr_list)
        else: text, body_attrs = body, [(body, None)]
        return markup, text, body_attrs

    def get_note_markup(self, note):
        return note.hints.get('x-nt-markup', self.markup_default)

    def get_note_text(self, note):
        'Returns note text, stripped of all markup, if any (and if enabled).'
        markup = self.get_note_markup(note)
        _, summary_text, _ = self.get_display_summary(note.summary, markup)
        _, body_text, _ = self.get_display_body(note.body, markup)
        return summary_text, body_text

    def display(self, note, cb_dismiss=None, cb_hover=None, cb_leave=None):
        try:
            # Priorities for icon sources:
            #  image{-,_}data: hint. raw image data structure of signature (iiibiiay)
            #  image{-,_}path: hint. either an URI (file://...) or a name in a f.o-compliant icon theme
            #  app_icon: parameter. same as image-path
            #  icon_data: hint. same as image-data
            # image_* is a deprecated hints from 1.1 spec, 1.2 is preferred
            #  (don't seem to be even mentioned in 1.2 spec icon priorities section)
            hints = note.hints.copy()
            k = '__app_icon'  # to avoid clobbering anything
            hints[k] = note.icon
            for k in 'image-data', 'image_data',\
              'image-path', 'image_path', k, 'icon_data':
                image = hints.get(k)
                if image:
                    log.debug('Got icon image from hint: %s', k)
                    break

            urgency = note.hints.get('urgency')
            if urgency is not None:
                urgency = core.urgency_levels.by_id(int(urgency))
            markup = self.get_note_markup(note)

            win = self._create_win(note.summary,
                                   note.body,
                                   image,
                                   urgency,
                                   markup=markup,
                                   remote=note.hints.get('x-nt-from-remote'))

            for eb in win.event_boxes:
                eb.add_events(Gdk.EventMask.BUTTON_PRESS_MASK
                              | Gdk.EventMask.POINTER_MOTION_MASK
                              | Gdk.EventMask.LEAVE_NOTIFY_MASK)
                for ev, cb in [('button-press-event', cb_dismiss),
                               ('motion-notify-event', cb_hover),
                               ('leave-notify-event', cb_leave)]:
                    if cb:
                        eb.connect(ev, lambda w, ev, cb, nid: cb(nid), cb,
                                   note.id)
            if cb_dismiss and win.event_boxes:
                # Connect only to window object (or first eventbox in the list)
                win.event_boxes[0].connect('destroy',
                                           lambda w, cb, nid: cb(nid),
                                           cb_dismiss, note.id)

            # update_layout() *must* be delayed until window "configure-event", because
            #  actual window size is unknown until it's resized by window manager and drawn by X
            # See the list of caveats here:
            #  http://developer.gnome.org/gtk3/unstable/GtkWindow.html#gtk-window-get-size
            win.gobj.connect('configure-event',
                             lambda w, void: self._update_layout())
            self._windows[note.id] = win

        except:
            log.exception('Failed to create notification window')

    class NoWindowError(Exception):
        pass

    def _close(self, nid):
        try:
            win = self._windows.pop(nid).gobj
        except KeyError:
            raise self.NoWindowError(nid)
        win.hide(), win.destroy()

    def close(self, nid):
        self._close(nid)
        self._update_layout()
class DotMap(OrderedDict):
    def __init__(self, *args, **kwargs):
        self._map = OrderedDict()
        if args:
            d = args[0]
            if type(d) is dict:
                for k, v in self.__call_items(d):
                    if type(v) is dict:
                        v = DotMap(v)
                    self._map[k] = v
        if kwargs:
            for k, v in self.__call_items(kwargs):
                self._map[k] = v

    def __call_items(self, obj):
        if hasattr(obj, 'iteritems') and ismethod(getattr(obj, 'iteritems')):
            return obj.iteritems()
        else:
            return obj.items()

    def items(self):
        return self.iteritems()

    def iteritems(self):
        return self.__call_items(self._map)

    def __iter__(self):
        return self._map.__iter__()

    def next(self):
        return self._map.next()

    def __setitem__(self, k, v):
        self._map[k] = v

    def __getitem__(self, k):
        if k not in self._map:
            # DON'T automatically extend to new DotMap
            # self[k] = DotMap()
            raise AttributeError('%s is not defined in DotMap' % k)
        return self._map[k]

    def __setattr__(self, k, v):
        if k == '_map':
            super(DotMap, self).__setattr__(k, v)
        else:
            self[k] = v

    def __getattr__(self, k):
        if k == '_map':
            super(DotMap, self).__getattr__(k)
        else:
            return self[k]

    def __delattr__(self, key):
        return self._map.__delitem__(key)

    def __contains__(self, k):
        return self._map.__contains__(k)

    def __str__(self):
        items = []
        for k, v in self.__call_items(self._map):
            items.append('{0}={1}'.format(k, repr(v)))
        out = 'DotMap({0})'.format(', '.join(items))
        return out

    def __repr__(self):
        return str(self)

    def toDict(self):
        d = {}
        for k, v in self.items():
            if type(v) is DotMap:
                v = v.toDict()
            d[k] = v
        return d

    def pprint(self):
        pprint(self.toDict())

    # proper dict subclassing
    def values(self):
        return self._map.values()

    @classmethod
    def parseOther(self, other):
        if type(other) is DotMap:
            return other._map
        else:
            return other

    def __cmp__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__cmp__(other)

    def __eq__(self, other):
        other = DotMap.parseOther(other)
        if not isinstance(other, dict):
            return False
        return self._map.__eq__(other)

    def __ge__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__ge__(other)

    def __gt__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__gt__(other)

    def __le__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__le__(other)

    def __lt__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__lt__(other)

    def __ne__(self, other):
        other = DotMap.parseOther(other)
        return self._map.__ne__(other)

    def __delitem__(self, key):
        return self._map.__delitem__(key)

    def __len__(self):
        return self._map.__len__()

    def clear(self):
        self._map.clear()

    def copy(self):
        return self

    def get(self, key, default=None):
        return self._map.get(key, default)

    def has_key(self, key):
        return key in self._map

    def iterkeys(self):
        return self._map.iterkeys()

    def itervalues(self):
        return self._map.itervalues()

    def keys(self):
        return self._map.keys()

    def pop(self, key, default=None):
        return self._map.pop(key, default)

    def popitem(self):
        return self._map.popitem()

    def setdefault(self, key, default=None):
        self._map.setdefault(key, default)

    def update(self, *args, **kwargs):
        if len(args) != 0:
            self._map.update(*args)
        self._map.update(kwargs)

    def viewitems(self):
        return self._map.viewitems()

    def viewkeys(self):
        return self._map.viewkeys()

    def viewvalues(self):
        return self._map.viewvalues()

    @classmethod
    def fromkeys(cls, seq, value=None):
        d = DotMap()
        d._map = OrderedDict.fromkeys(seq, value)
        return d
Пример #23
0
class NotificationDisplay(object):
	'''Interface to display notification stack.
		Should have "display(note, cb_dismiss=None) -> nid(UInt32, >0)", "close(nid)"
			methods and NoWindowError(nid) exception, raised on erroneous nid's in close().
		Current implementation based on notipy: git://github.com/the-isz/notipy.git'''

	window = namedtuple('Window', 'gobj event_boxes')
	base_css = b'''
		#notification { background: transparent; }
		#notification #frame { padding: 3px; background-color: #d4ded8; }
		#notification #hs { background-color: black; }

		#notification #critical { background-color: #ffaeae; }
		#notification #normal { background-color: #f0ffec; }
		#notification #low { background-color: #bee3c6; }

		#notification #summary {
			padding-left: 5px;
			font-size: 10px;
			text-shadow: 1px 1px 0px gray;
		}
		#notification #body { font-size: 8px; }
		#notification #body * { background-color: #d4ded8; }
	'''
	base_css_min = b'#notification * { font-size: 8; }' # simpliest fallback


	def __init__( self, layout_margin,
			layout_anchor, layout_direction, icon_width, icon_height,
			markup_default=False, markup_warn=False, markup_strip=False ):
		self.margins = dict(it.chain.from_iterable(map(
			lambda ax: ( (2**ax, layout_margin),
				(-2**ax, layout_margin) ), xrange(2) )))
		self.layout_margin = layout_margin
		self.layout_anchor = layout_anchor
		self.layout_direction = layout_direction
		self.icon_width = icon_width
		self.icon_height = icon_height
		self.markup_default = markup_default
		self.markup_warn, self.markup_strip = markup_warn, markup_strip

		self._windows = OrderedDict()

		self._default_style = self._get_default_css()
		Gtk.StyleContext.add_provider_for_screen(
			Gdk.Screen.get_default(), self._default_style,
			Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION )


	def _pango_markup_parse(self, text, _err_mark='[TN82u8] '):
		success = True
		try: _, attr_list, text, _ = Pango.parse_markup(text, -1, '\0')
		except GLib.GError as err:
			if self.markup_warn:
				msg_start = '{}Pango formatting failed'.format(_err_mark)
				if msg_start not in text: # detect and avoid possible feedback loops
					log.warn('%s (%s) for text, stripping markup: %r', msg_start, err, text)
				else: text = xml_escape(text) # escape message so it'd render bugged part
			if self.markup_strip: text = strip_markup(text)
			try: _, attr_list, text, _ = Pango.parse_markup(text, -1, '\0')
			except GLib.GError: attr_list = None
			success = False
		return success, text, attr_list

	def _pango_markup_to_gtk( self, text, attr_list=None,
			_pango_classes={
				'SIZE': Pango.AttrInt,
				'WEIGHT': Pango.AttrInt,
				'UNDERLINE': Pango.AttrInt,
				'STRETCH': Pango.AttrInt,
				'VARIANT': Pango.AttrInt,
				'STYLE': Pango.AttrInt,
				'SCALE': Pango.AttrFloat,
				'FAMILY': Pango.AttrString,
				'FONT_DESC': Pango.AttrFontDesc,
				'STRIKETHROUGH': Pango.AttrInt,
				'BACKGROUND': Pango.AttrColor,
				'FOREGROUND': Pango.AttrColor,
				'RISE': Pango.AttrInt },
			_pango_to_gtk={'font_desc': 'font'} ):
		# See https://bugzilla.gnome.org/show_bug.cgi?id=59390 for why it is necessary
		# And doesn't work with GI anyway because of
		#  https://bugzilla.gnome.org/show_bug.cgi?id=646788
		#  "Behdad Esfahbod [pango developer]: I personally have no clue how to fix this"
		# Workaround from https://github.com/matasbbb/pitivit/commit/da815339e
		# TODO: fix when AttrList.get_iterator will be accessible via GI or textbuffer gets set_markup()
		if attr_list is None:
			_, text, attr_list = self._pango_markup_parse(text)
			if attr_list is None:
				yield (text, None)
				raise StopIteration

		gtk_tags = defaultdict(dict)
		def parse_attr(attr, _data):
			gtk_attr = attr.klass.type.value_nick
			if gtk_attr in _pango_to_gtk: gtk_attr = _pango_to_gtk[gtk_attr]
			pango_attr, span = attr.klass.type.value_name, (attr.start_index, attr.end_index)
			assert pango_attr.startswith('PANGO_ATTR_'), pango_attr
			attr.__class__ = _pango_classes[pango_attr[11:]] # allows to access attr.value
			for k in 'value', 'ink_rect', 'logical_rect', 'desc', 'color':
				if not hasattr(attr, k): continue
				val = getattr(attr, k)
				if k == 'color':
					val = '#' + ''.join('{:02x}'.format(v/256) for v in [val.red, val.green, val.blue])
				gtk_tags[span][gtk_attr] = val
				break
			else:
				raise KeyError('Failed to extract value for pango attribute: {}'.format(pango_attr))
			return False
		attr_list.filter(parse_attr, None)

		pos = 0
		for (a, b), props in sorted(gtk_tags.viewitems()):
			if a > pos: yield (text[pos:a], None)
			yield (text[a:b], props)
			pos = b
		if text[pos:]: yield (text[pos:], None)


	def _get_default_css(self):
		css, base_css = Gtk.CssProvider(), self.base_css
		for attempt in xrange(6):
			try: css.load_from_data(base_css)
			except GLib.GError as err:
				log.warn('Failed to load default CSS style (try %s): %s', attempt+1, err)
				# print(base_css)
			else: break
			# Try to work around https://bugzilla.gnome.org/show_bug.cgi?id=678876 and similar issues
			if attempt == 0:
				base_css = re.sub(br'\b(background-color:)\s*rgba\([^;]+;', br'\1 white;', base_css)
			elif attempt == 1:
				base_css = re.sub(br'\b(font-size:)\s*(\d+)px\s*;', br'\1 \2;', base_css)
			elif attempt == 2:
				base_css = re.sub(br'\b(text-shadow:)[^;]+;', br'\1 1 1 0 gray;', base_css)
			elif attempt == 3: base_css = re.sub(br'\btext-shadow:[^;]+;', b'', base_css)
			elif attempt == 4: base_css = self.base_css_min # last resort before no-css-at-all
			else: break # don't load any css
		return css


	def _update_layout(self):
		# Get the coordinates of the "anchor" corner (screen corner +/- margins)
		base = tuple(map(
			lambda ax, gdk_dim=('width', 'height'):\
				(getattr(Gdk.Screen, gdk_dim[ax])() - self.margins[2**ax])\
					if 2**ax & self.layout_anchor else self.margins[-2**ax], xrange(2) ))
		# Iterate over windows in order, placing each one starting from a "base" corner
		for win in map(op.attrgetter('gobj'), self._windows.viewvalues()):
			win.move(*map(lambda ax: base[ax] - ( win.get_size()[ax]
				if 2**ax & self.layout_anchor else 0 ), xrange(2)))
			margin = self.margins[(2 * ( (2**self.layout_direction)
				& self.layout_anchor ) / 2**self.layout_direction - 1) * 2**self.layout_direction]
			base = tuple(map(
				lambda ax: base[ax] if self.layout_direction != ax else\
					base[ax] + (margin + win.get_size()[ax])\
						* (2 * (2**ax ^ (2**ax & self.layout_anchor)) / 2**ax - 1), xrange(2) ))


	def _get_icon(self, icon):
		widget_icon = None

		if icon is not None:
			if isinstance(icon, types.StringTypes):
				icon_path = os.path.expanduser(urllib.url2pathname(icon))
				if icon_path.startswith('file://'): icon_path = icon_path[7:]
				if os.path.isfile(icon_path):
					widget_icon = GdkPixbuf.Pixbuf.new_from_file(icon_path)
				else:
					# Available names: Gtk.IconTheme.get_default().list_icons(None)
					theme = Gtk.IconTheme.get_default()
					icon_size = self.icon_width or self.icon_height or 32
					widget_icon = theme.lookup_icon(
						icon, icon_size, Gtk.IconLookupFlags.USE_BUILTIN )
					if widget_icon: widget_icon = widget_icon.load_icon()
					else:
						log.warn( '"%s" seems to be neither a valid icon file nor'
							' a name in a freedesktop.org-compliant icon theme (or your theme'
							' doesnt have that name). Ignoring.', icon )
			else:
				widget_icon = GdkPixbuf.Pixbuf.new_from_data(
					bytearray(icon[6]), GdkPixbuf.Colorspace.RGB, icon[3], icon[4],
					icon[0], icon[1], icon[2], lambda x, y: None, None )

		if widget_icon:
			if self.icon_width or self.icon_height: # scale icon
				w, h = widget_icon.get_width(), widget_icon.get_height()
				# Use max (among w/h) factor on scale-up and min on scale-down,
				#  so resulting icon will always fit in a specified box,
				#  and will match it by (at least) w or h (ideally - both)
				scale = (self.icon_width and w > self.icon_width)\
					or (self.icon_height and h > self.icon_height) # True if it's a scale-up
				scale = (min if bool(scale) ^ bool(
						self.icon_width and self.icon_height ) else max)\
					(float(self.icon_width or w) / w, float(self.icon_height or h) / h)
				widget_icon = widget_icon.scale_simple(
					w * scale, h * scale, GdkPixbuf.InterpType.BILINEAR )
			widget_icon, pixbuf = Gtk.Image(), widget_icon
			widget_icon.set_from_pixbuf(pixbuf)

		return widget_icon


	def _set_visual(self, win, ev=None):
		visual = win.get_screen().get_rgba_visual()
		if visual: win.set_visual(visual)

	def _create_win(self, summary, body, icon=None, urgency_label=None, markup=False):
		log.debug( 'Creating window with parameters: %s',
			dict(summary=summary, body=body, icon=icon, urgency=urgency_label, markup=markup) )

		win = Gtk.Window(name='notification', type=Gtk.WindowType.POPUP)
		win.set_default_size(400, 20)
		win.connect('screen-changed', self._set_visual)
		self._set_visual(win)
		ev_boxes = [win]

		frame = Gtk.Frame(name='frame', shadow_type=Gtk.ShadowType.ETCHED_OUT)
		win.add(frame)

		try: widget_icon = self._get_icon(icon)
		except Exception: # Gdk may raise errors for some images/formats
			log.exception('Failed to set notification icon')
			widget_icon = None

		v_box = Gtk.VBox(spacing=self.layout_margin, expand=False)
		if widget_icon is not None:
			h_box = Gtk.HBox(spacing=self.layout_margin * 2)
			frame.add(h_box)
			h_box.pack_start(widget_icon, False, False, 0)
			h_box.pack_start(v_box, True, True, 0)
			ev_boxes.append(h_box)
		else: frame.add(v_box)

		widget_summary = Gtk.Label(name='summary')

		# Sanitize tags through pango first, so set_markup won't produce empty label
		summary_markup, summary_text, summary\
			= self.get_display_summary(summary, markup)
		if summary_markup: widget_summary.set_markup(summary)
		else: widget_summary.set_text(summary)

		widget_summary.set_alignment(0, 0)
		if urgency_label:
			summary_box = Gtk.EventBox(name=urgency_label)
			summary_box.add(widget_summary)
		else: summary_box = widget_summary
		v_box.pack_start(summary_box, False, False, 0)
		ev_boxes.append(summary_box)

		v_box.pack_start(Gtk.HSeparator(name='hs'), False, False, 0)

		widget_body = Gtk.TextView( name='body',
			wrap_mode=Gtk.WrapMode.WORD_CHAR,
			cursor_visible=False, editable=False )
		widget_body_buffer = widget_body.get_buffer()

		body_markup, body_text, body_attrs = self.get_display_body(body, markup)
		if not body_markup: widget_body_buffer.set_text(body_text)
		else:
			# This buffer uses pango markup, even though GtkTextView does not support it
			# Most magic is in pango_markup_to_gtk(), there doesn't seem to be any cleaner way
			def get_tag(props, _tag_id=iter(xrange(2**31-1)), _tag_table=dict()):
				k = tuple(sorted(props.viewitems()))
				if k not in _tag_table:
					_tag_table[k] = widget_body_buffer\
						.create_tag('x{}'.format(next(_tag_id)), **props)
				return _tag_table[k]
			pos = widget_body_buffer.get_end_iter()
			for text, props in body_attrs:
				if props: widget_body_buffer.insert_with_tags(pos, text, get_tag(props))
				else: widget_body_buffer.insert(pos, text)

		v_box.pack_start(widget_body, False, False, 0)
		ev_boxes.append(widget_body)

		# Make sure the window is initially drawn off-screen, because it can't be
		#  placed properly until it's size is known, and it's size is unknown until it's
		#  actually handled by window manager and then drawn by X
		# Proper placement is done on update_layout() call
		win.move(-2000, -2000)

		win.show_all()
		return self.window(win, ev_boxes)


	def get_display_summary(self, summary, markup):
		if markup:
			success, text, _ = self._pango_markup_parse(summary)
			if not success: markup, summary = False, text
		else: text = summary
		return markup, text, summary

	def get_display_body(self, body, markup):
		if markup:
			_, text, attr_list = self._pango_markup_parse(body)
			if attr_list is None: markup, body_attrs = False, [(text, None)]
			else: body_attrs = self._pango_markup_to_gtk(text, attr_list)
		else: text = body
		return markup, text, body_attrs

	def get_note_markup(self, note):
		return note.hints.get('x-nt-markup', self.markup_default)

	def get_note_text(self, note):
		'Returns note text, stripped of all markup, if any (and if enabled).'
		markup = self.get_note_markup(note)
		_, summary_text, _ = self.get_display_summary(note.summary, markup)
		_, body_text, _ = self.get_display_body(note.body, markup)
		return summary_text, body_text


	def display(self, note, cb_dismiss=None, cb_hover=None, cb_leave=None):
		try:
			# Priorities for icon sources:
			#  image{-,_}data: hint. raw image data structure of signature (iiibiiay)
			#  image{-,_}path: hint. either an URI (file://...) or a name in a f.o-compliant icon theme
			#  app_icon: parameter. same as image-path
			#  icon_data: hint. same as image-data
			# image_* is a deprecated hints from 1.1 spec, 1.2 is preferred
			#  (don't seem to be even mentioned in 1.2 spec icon priorities section)
			hints = note.hints.copy()
			k = '__app_icon' # to avoid clobbering anything
			hints[k] = note.icon
			for k in 'image-data', 'image_data',\
					'image-path', 'image_path', k, 'icon_data':
				image = hints.get(k)
				if image:
					log.debug('Got icon image from hint: %s', k)
					break

			urgency = note.hints.get('urgency')
			if urgency is not None: urgency = urgency_levels.by_id(int(urgency))
			markup = self.get_note_markup(note)

			win = self._create_win(note.summary, note.body, image, urgency, markup=markup)

			for eb in win.event_boxes:
				eb.add_events(
					Gdk.EventMask.BUTTON_PRESS_MASK
					| Gdk.EventMask.POINTER_MOTION_MASK
					| Gdk.EventMask.LEAVE_NOTIFY_MASK )
				for ev,cb in [
						('button-press-event', cb_dismiss),
						('motion-notify-event', cb_hover),
						('leave-notify-event', cb_leave) ]:
					if cb: eb.connect(ev, lambda w,ev,cb,nid: cb(nid), cb, note.id)
			if cb_dismiss and win.event_boxes:
				# Connect only to window object (or first eventbox in the list)
				win.event_boxes[0].connect( 'destroy',
					lambda w,cb,nid: cb(nid), cb_dismiss, note.id )

			# update_layout() *must* be delayed until window "configure-event", because
			#  actual window size is unknown until it's resized by window manager and drawn by X
			# See the list of caveats here:
			#  http://developer.gnome.org/gtk3/unstable/GtkWindow.html#gtk-window-get-size
			win.gobj.connect('configure-event', lambda w,void: self._update_layout())
			self._windows[note.id] = win

		except: log.exception('Failed to create notification window')


	class NoWindowError(Exception): pass

	def _close(self, nid):
		try: win = self._windows.pop(nid).gobj
		except KeyError: raise self.NoWindowError(nid)
		win.hide(), win.destroy()

	def close(self, nid):
		self._close(nid)
		self._update_layout()
Пример #24
0
class NotificationDisplay(object):
    '''Interface to display notification stack.
		Should have "display(note, cb_dismiss=None) -> nid(UInt32, >0)", "close(nid)"
			methods and NoWindowError(nid) exception, raised on erroneous nid's in close().
		Current implementation based on notipy: git://github.com/the-isz/notipy.git'''
    window = namedtuple('Window', 'gobj event_boxes')

    def __init__(self, layout_margin, layout_anchor, layout_direction, img_w,
                 img_h):
        self.margins = dict(
            it.chain.from_iterable(
                map(
                    lambda ax: ((2**ax, layout_margin),
                                (-2**ax, layout_margin)), xrange(2))))
        self.layout_margin = layout_margin
        self.layout_anchor = layout_anchor
        self.layout_direction = layout_direction
        self.img_w = img_w
        self.img_h = img_h

        self._windows = OrderedDict()

        self._default_style = Gtk.CssProvider()
        self._default_style.load_from_data(b'''
			#notification { background-color: white; }
			#notification #hs { background-color: black; }

			#notification #critical { background-color: #ffaeae; }
			#notification #normal { background-color: #f0ffec; }
			#notification #low { background-color: #bee3c6; }

			#notification #summary {
				font-size: 10;
				text-shadow: 1 1 0 gray;
			}
			#notification #body { font-size: 8; }''')
        Gtk.StyleContext.add_provider_for_screen(
            Gdk.Screen.get_default(), self._default_style,
            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)

    def _update_layout(self):
        # Yep, I was SMOKING CRACK here, and it all made sense at the time
        base = tuple(map(
         lambda ax, gdk_dim=('width', 'height'):\
          (getattr(Gdk.Screen, gdk_dim[ax])() - self.margins[2**ax])\
           if 2**ax & self.layout_anchor else self.margins[-2**ax], xrange(2) ))
        for win in map(op.attrgetter('gobj'), self._windows.viewvalues()):
            win.move(*map(
                lambda ax: base[ax] - (win.get_size()[ax] if 2**ax & self.
                                       layout_anchor else 0), xrange(2)))
            margin = self.margins[(2 * (
                (2**self.layout_direction)
                & self.layout_anchor) / 2**self.layout_direction - 1) *
                                  2**self.layout_direction]
            base = tuple(map(
             lambda ax: base[ax] if self.layout_direction != ax else\
              base[ax] + (margin + win.get_size()[ax])\
               * (2 * (2**ax ^ (2**ax & self.layout_anchor)) / 2**ax - 1), xrange(2) ))

    def _create_win(self, summary, body, icon=None, urgency_label=None):
        log.debug( 'Creating window with parameters: {}'\
         .format(', '.join(map(unicode, [summary, body, icon, urgency_label]))) )

        win = Gtk.Window(name='notification', type=Gtk.WindowType.POPUP)
        win.set_default_size(400, 20)
        ev_boxes = [win]

        frame = Gtk.Frame(shadow_type=Gtk.ShadowType.ETCHED_OUT)
        win.add(frame)

        widget_icon = None
        if icon is not None:
            if isinstance(icon, unicode):
                icon_path = os.path.expanduser(urllib.url2pathname(icon))
                if icon_path.startswith('file://'): icon_path = icon_path[7:]
                if os.path.isfile(icon_path):
                    widget_icon = Gtk.Image()
                    if self.img_w != -1 or self.img_h != -1:
                        pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                            icon_path, self.img_w, self.img_h)
                        #scaled_buf = pixbuf.scale_simple(self.img_w, self.img_h, gtk.gdk.INTERP_BILINEAR)
                        widget_icon.set_from_pixbuf(pixbuf)
                    else:
                        widget_icon.set_from_file(icon_path)
                else:
                    # available names: Gtk.IconTheme.get_default().list_icons(None)
                    theme = Gtk.IconTheme.get_default()
                    if theme.has_icon(icon):
                        widget_icon = Gtk.Image()
                        widget_icon.set_from_icon_name(
                            icon, Gtk.IconSize.DND)  # XXX: why this IconSize?
                    else:
                        log.warn((
                            '"{}" seems to be neither a valid icon file nor'
                            ' a name in a freedesktop.org-compliant icon theme (or your theme'
                            ' doesnt have that name). Ignoring.').format(icon))
            else:
                # For image-data and icon_data, image should look like this:
                # dbus.Struct(
                #  (dbus.Int32, # width
                #   dbus.Int32, # height
                #   dbus.Int32, # rowstride
                #   dbus.Boolean, # has alpha
                #   dbus.Int32, # bits per sample
                #   dbus.Int32, # channels
                #   dbus.Array([dbus.Byte, ...])) # image data
                # )
                # data, colorspace, has_alpha, bits_per_sample,
                #  width, height, rowstride, destroy_fn, destroy_fn_data
                # XXX: Do I need to free the image via a function callback?
                pixbuf = GdkPixbuf.Pixbuf.new_from_data(
                    bytearray(icon[6]), GdkPixbuf.Colorspace.RGB, icon[3],
                    icon[4], icon[0], icon[1], icon[2], lambda x, y: None,
                    None)
                widget_icon = Gtk.Image()
                widget_icon.set_from_pixbuf(pixbuf)

        v_box = Gtk.VBox(spacing=self.layout_margin, expand=False)
        if widget_icon is not None:
            h_box = Gtk.HBox(spacing=self.layout_margin * 2)
            frame.add(h_box)
            h_box.pack_start(widget_icon, False, False, 0)
            h_box.pack_start(v_box, True, True, 0)
        else:
            frame.add(v_box)

        widget_summary = Gtk.Label(name='summary', label=summary)
        widget_summary.set_alignment(0, 0)
        if urgency_label:
            summary_box = Gtk.EventBox(name=urgency_label)
            summary_box.add(widget_summary)
        else:
            summary_box = widget_summary
        v_box.pack_start(summary_box, False, False, 0)

        v_box.pack_start(Gtk.HSeparator(name='hs'), False, False, 0)

        widget_body = Gtk.TextView(name='body',
                                   wrap_mode=Gtk.WrapMode.WORD_CHAR)
        widget_body_buffer = widget_body.get_buffer()
        widget_body_buffer.set_text(body)
        v_box.pack_start(widget_body, False, False, 0)
        ev_boxes.append(widget_body)

        win.show_all()
        return self.window(win, ev_boxes)

    def display(self, note, cb_dismiss=None, cb_hover=None, cb_leave=None):
        try:
            # Priorities for icon sources:
            #  image{-,_}data: hint. raw image data structure of signature (iiibiiay)
            #  image{-,_}path: hint. either an URI (file://...) or a name in a f.o-compliant icon theme
            #  app_icon: parameter. same as image-path
            #  icon_data: hint. same as image-data
            # image_* is a deprecated hints from 1.1 spec, 1.2 is preferred
            #  (don't seem to be even mentioned in 1.2 spec icon priorities section)
            hints = note.hints.copy()
            k = '__app_icon'  # to avoid clobbering anything
            hints[k] = note.icon
            for k in 'image-data', 'image_data',\
              'image-path', 'image_path', k, 'icon_data':
                image = hints.get(k)
                if image:
                    log.debug('Got icon image from hint: {}'.format(k))
                    break

            urgency = note.hints.get('urgency')
            if urgency is not None:
                urgency = urgency_levels.by_id(int(urgency))
            win = self._create_win(note.summary, note.body, image, urgency)
            for eb in win.event_boxes:
                eb.add_events(Gdk.EventMask.BUTTON_PRESS_MASK
                              | Gdk.EventMask.POINTER_MOTION_MASK
                              | Gdk.EventMask.LEAVE_NOTIFY_MASK)
                for ev, cb in [('button-press-event', cb_dismiss),
                               ('motion-notify-event', cb_hover),
                               ('leave-notify-event', cb_leave)]:
                    if cb:
                        eb.connect(ev, lambda w, ev, cb, nid: cb(nid), cb,
                                   note.id)
            if cb_dismiss and win.event_boxes:
                # Connect only to window object (or first eventbox in the list)
                win.event_boxes[0].connect('destroy',
                                           lambda w, cb, nid: cb(nid),
                                           cb_dismiss, note.id)

            self._windows[note.id] = win
            self._update_layout()

        except:
            log.exception('Failed to create notification window')

    class NoWindowError(Exception):
        pass

    def _close(self, nid):
        try:
            win = self._windows.pop(nid).gobj
        except KeyError:
            raise self.NoWindowError(nid)
        win.hide(), win.destroy()

    def close(self, nid):
        self._close(nid)
        self._update_layout()
Пример #25
0
class DotMap(OrderedDict):

	def __init__(self, *args, **kwargs):
		self._map = OrderedDict()
		self._dynamic = True
		if kwargs:
			if '_dynamic' in kwargs:
				self._dynamic = kwargs['_dynamic']
		if args:
			d = args[0]
			if isinstance(d, dict):
				for k,v in self.__call_items(d):
					if type(v) is dict:
						v = DotMap(v, _dynamic=self._dynamic)
					if type(v) is list:
						l = []
						for i in v:
							n = i
							if type(i) is dict:
								n = DotMap(i, _dynamic=self._dynamic)
							l.append(n)
						v = l
					self._map[k] = v
		if kwargs:
			for k,v in self.__call_items(kwargs):
				if k is not '_dynamic':
					self._map[k] = v

	def __call_items(self, obj):
		if hasattr(obj, 'iteritems') and ismethod(getattr(obj, 'iteritems')):
			return obj.iteritems()
		else:
			return obj.items()

	def items(self):
		return self.iteritems()

	def iteritems(self):
		return self.__call_items(self._map)

	def __iter__(self):
		return self._map.__iter__()

	def next(self):
		return self._map.next()

	def __setitem__(self, k, v):
		self._map[k] = v
	def __getitem__(self, k):
		if k not in self._map and self._dynamic and k != '_ipython_canary_method_should_not_exist_':
			# automatically extend to new DotMap
			self[k] = DotMap()
		return self._map[k]

	def __setattr__(self, k, v):
		if k in {'_map','_dynamic', '_ipython_canary_method_should_not_exist_'}:
			super(DotMap, self).__setattr__(k,v)
		else:
			self[k] = v

	def __getattr__(self, k):
		if k == {'_map','_dynamic','_ipython_canary_method_should_not_exist_'}:
			super(DotMap, self).__getattr__(k)
		else:
			return self[k]

	def __delattr__(self, key):
		return self._map.__delitem__(key)

	def __contains__(self, k):
		return self._map.__contains__(k)

	def __str__(self):
		items = []
		for k,v in self.__call_items(self._map):
			# bizarre recursive assignment situation (why someone would do this is beyond me)
			if id(v) == id(self):
				items.append('{0}=DotMap(...)'.format(k))
			else:
				items.append('{0}={1}'.format(k, repr(v)))
		out = 'DotMap({0})'.format(', '.join(items))
		return out

	def __repr__(self):
		return str(self)

	def toDict(self):
		d = {}
		for k,v in self.items():
			if type(v) is DotMap:
				# bizarre recursive assignment support
				if id(v) == id(self):
					v = d
				else:
					v = v.toDict()
			elif type(v) is list:
				l = []
				for i in v:
					n = i
					if type(i) is DotMap:
						n = i.toDict()
					l.append(n)
				v = l
			d[k] = v
		return d

	def pprint(self):
		pprint(self.toDict())

	def empty(self):
		return (not any(self))

	# proper dict subclassing
	def values(self):
		return self._map.values()

	# ipython support
	def __dir__(self):
		return self.keys()

	@classmethod
	def parseOther(self, other):
		if type(other) is DotMap:
			return other._map
		else:
			return other	
	def __cmp__(self, other):
		other = DotMap.parseOther(other)
		return self._map.__cmp__(other)
	def __eq__(self, other):
		other = DotMap.parseOther(other)
		if not isinstance(other, dict):
			return False
		return self._map.__eq__(other)
	def __ge__(self, other):
		other = DotMap.parseOther(other)
		return self._map.__ge__(other)
	def __gt__(self, other):
		other = DotMap.parseOther(other)
		return self._map.__gt__(other)
	def __le__(self, other):
		other = DotMap.parseOther(other)
		return self._map.__le__(other)
	def __lt__(self, other):
		other = DotMap.parseOther(other)
		return self._map.__lt__(other)
	def __ne__(self, other):
		other = DotMap.parseOther(other)
		return self._map.__ne__(other)

	def __delitem__(self, key):
		return self._map.__delitem__(key)
	def __len__(self):
		return self._map.__len__()
	def clear(self):
		self._map.clear()
	def copy(self):
		return DotMap(self.toDict())
	def get(self, key, default=None):
		return self._map.get(key, default)
	def has_key(self, key):
		return key in self._map
	def iterkeys(self):
		return self._map.iterkeys()
	def itervalues(self):
		return self._map.itervalues()
	def keys(self):
		return self._map.keys()
	def pop(self, key, default=None):
		return self._map.pop(key, default)
	def popitem(self):
		return self._map.popitem()
	def setdefault(self, key, default=None):
		self._map.setdefault(key, default)
	def update(self, *args, **kwargs):
		if len(args) != 0:
			self._map.update(*args)
		self._map.update(kwargs)
	def viewitems(self):
		return self._map.viewitems()
	def viewkeys(self):
		return self._map.viewkeys()
	def viewvalues(self):
		return self._map.viewvalues()
	@classmethod
	def fromkeys(cls, seq, value=None):
		d = DotMap()
		d._map = OrderedDict.fromkeys(seq, value)
		return d
	def __getstate__(self): return self.__dict__
	def __setstate__(self, d): self.__dict__.update(d)
Пример #26
0
class Maps(MutableMapping):
    """
    Converts a dictionary of key:value pairs into a dotted
    representation of those keys. Normal string representation of
    keys is still accessible via normal dictionary indexing.

    Note:
        If a key contains non-alphanumeric characters
        (!@#$%, etc, including spaces), they will be replaced with
        an underscore (_).

    Examples:
        >>> # Normal usage
        >>> test = {"hello": "world"}
        >>> print(Maps(test))

        Output: Maps(hello="world")

        >>> test = {"hello": "world"}
        >>> maps = Maps(test)
        >>> print(maps.hello)

        Output: "world"

        >>> test = {"hello": "world"}
        >>> maps = Maps(test)
        >>> print(maps["hello"])

        Output: "world"

        >>> # If a dictionary key has non-alphanumeric characters
        >>> # Notice how a series of special characters is replaced
        >>> # by only a single underscore
        >>> test = {"hello joh*&^n": "hi computer"}
        >>> maps = Maps(test)
        >>> print(maps)

        Output: Maps(hello_joh_n="hi computer")

    Raises:
        ValueError:
            An argument is of a legal type but is, or contains, an
            illegal value.
    """

    # Class-level variables
    _dynamic: bool
    _map: OrderedDict

    def __init__(self, *args, **kwargs) -> None:
        super().__init__()

        self._dynamic = True
        self._map = OrderedDict()

        if kwargs:
            for key, value in self._get_items(kwargs):
                key = re.sub('[^0-9a-zA-Z]+', '_', key)
                if key != '_dynamic':
                    self._map[key] = value
                else:
                    self._dynamic = value

        if args:
            dictionary = args[0]

            if not isinstance(dictionary, dict):
                raise ValueError(
                    "object passed to constructor must be of type 'dict': "
                    f"'{type(dictionary).__name__}'")

            # Recursive handling
            tracked_ids = {id(dictionary): self}
            for key, value in self._get_items(dictionary):
                if isinstance(key, str):
                    key = re.sub('[^0-9a-zA-Z]+', '_', key)

                value_id = id(value)
                if isinstance(value, dict):
                    if value_id in tracked_ids:
                        value = tracked_ids[value_id]
                    else:
                        value = self.__class__(value, _dynamic=self._dynamic)
                        tracked_ids[value_id] = value

                if isinstance(value, list):
                    listed_items = []

                    for item in value:
                        temp_item = item
                        if isinstance(item, dict):
                            temp_item = self.__class__(item,
                                                       _dynamic=self._dynamic)
                        listed_items.append(temp_item)

                    value = listed_items
                try:
                    self._map[key] = ast.literal_eval(value)
                except NameError:
                    if value.lower() == "false":
                        self._map[key] = False
                    elif value.lower() == "true":
                        self._map[key] = True
                    else:
                        self._map[key] = value
                except (SyntaxError, ValueError):
                    # Cannot eval this value
                    self._map[key] = value

    # Dunder methods

    def __add__(self, value: object) -> Union[Any, NoReturn]:
        if self.empty():
            return value
        else:
            self_type = type(self).__name__
            value_type = type(value).__name__
            raise TypeError(
                f"unsupported operand type(s) for +: '{self_type}' and '{value_type}'"
            )

    def __cmp__(self, value: object) -> Any:
        value = Maps.parse_value(value)
        return self._map.__cmp__(value)

    def __contains__(self, name: str) -> bool:
        return self._map.__contains__(name)

    def __copy__(self) -> Maps:
        return self.__class__(self)

    def __deepcopy__(self) -> Maps:
        return self.copy()

    def __delitem__(
            self,
            key: str,
            dict_delitem: Optional[Callable[...,
                                            Any]] = dict.__delitem__) -> Any:
        return self._map.__delitem__(key, dict_delitem=dict_delitem)

    def __dir__(self) -> Iterable:
        return self.keys()

    def __eq__(self, value: Any) -> bool:
        value = Maps.parse_value(value)
        if not isinstance(value, dict):
            return False
        return self._map.__eq__(value)

    def __ge__(self, value: Any) -> bool:
        value = Maps.parse_value(value)
        return self._map.__ge__(value)

    def __gt__(self, value: Any) -> bool:
        value = Maps.parse_value(value)
        return self._map.__gt__(value)

    def __iter__(self) -> Iterable:
        return self._map.__iter__()

    def __le__(self, value: Any) -> bool:
        value = Maps.parse_value(value)
        return self._map.__le__(value)

    def __len__(self) -> int:
        return self._map.__len__()

    def __lt__(self, value: Any) -> bool:
        value = Maps.parse_value(value)
        return self._map.__lt__(value)

    def __ne__(self, value: Any) -> bool:
        value = Maps.parse_value(value)
        return self._map.__ne__(value)

    def __repr__(self) -> str:
        return str(self)

    def __str__(self) -> str:
        items = []

        for key, value in self._get_items(self._map):

            # Recursive assignment case
            if id(value) == id(self):
                items.append("{0}={1}(...)".format(key,
                                                   self.__class__.__name__))
            else:
                items.append("{0}={1}".format(key, repr(value)))

        joined = ", ".join(items)
        return "{0}({1})".format(self.__class__.__name__, joined)

    def __delattr__(self, name: str) -> None:
        self._map.__delitem__(name)

    def __getattr__(self, name: str) -> Any:
        if name in ('_map', '_dynamic',
                    "_ipython_canary_method_should_not_exist_"):
            return super().__getattr__(name)

        try:
            return super(self.__class__, self).__getattribute__(name)
        except AttributeError:
            pass

        return self[name]

    def __setattr__(self, name: str, value: Any) -> None:
        if name in ('_map', '_dynamic',
                    "_ipython_canary_method_should_not_exist_"):
            super().__setattr__(name, value)
        else:
            self[name] = value

    def __getitem__(self, name: str) -> Union[Any, Maps]:
        if (name not in self._map and self._dynamic
                and name != "_ipython_canary_method_should_not_exist_"):
            self[name] = self.__class__()

        return self._map[name]

    def __setitem__(self, name: str, value: Any) -> None:
        self._map[name] = value

    def __getstate__(self) -> dict:
        return self.__dict__

    def __setstate__(self, value: dict) -> None:
        self.__dict__.update(value)

    # Internal methods

    def _get_items(self, item: Any) -> Iterable:
        if hasattr(item, 'iteritems') and ismethod(getattr(item, 'iteritems')):
            return item.iteritems()
        else:
            return item.items()

    # Public methods

    def clear(self) -> None:
        """Remove all items from the Maps object."""

        self._map.clear()

    def copy(self) -> Maps:
        """Makes a copy of the Maps object in memory."""

        return self.__copy__()

    def empty(self) -> bool:
        """Returns whether the Maps object is empty."""

        return (not any(self))

    @classmethod
    def fromkeys(cls,
                 iterable: Iterable,
                 value: Optional[Any] = None) -> Iterable:
        """Returns a new :obj:`Maps` object with keys supplied from an
        iterable setting each key in the object with :term:`value`.

        Args:
            iterable (:obj:`Iterable`):
                Any iterable.
            value (:obj:`obj`, optional):
                The value to set for the keys.
                Default is :obj:`None`.

        Returns:
            Maps:
                The :obj:`Maps` object.
        """

        maps = cls()
        maps.map = OrderedDict.fromkeys(iterable, value)

        return maps

    def get(self, key: str, default: Optional[Any] = None) -> Any:
        """
        Returns the value of 'key'.

        If :term:`key` does not exist, :term:default` is returned
        instead.

        Args:
            key (:obj:`str`):
                The key to get the value needed from the dict.
            default (:obj:`obj`, optional):
                The value to return if :term:`key` does not exist.

        Returns:
            Any:
                The value at :term:`key` or :term:default`.
        """

        return self._map.get(key, default)

    def has_key(self, key: str) -> bool:
        return key in self._map

    def items(self) -> Generator[Tuple[str, Any]]:
        """Returns a generator yielding a (key, value) pair."""

        return self._get_items(self._map)

    def iteritems(self) -> Iterator:
        """
        Returns an iterator over the Maps oject's (key, value)
        pairs.
        """

        return self.items()

    def iterkeys(self) -> Iterator:
        """Returns an iterator over the Maps object's keys."""

        return self._map.iterkeys()

    def itervalues(self) -> Iterator:
        """Returns an iterator over the Maps object's values."""

        return self._map.itervalues()

    def keys(self) -> Iterable:
        """Returns the keys of the Maps object."""

        return self._map.keys()

    def next(self) -> str:
        """Returns the next key in the dictionary."""

        return self._map.next()

    @classmethod
    def parse_ini(cls,
                  ini_dict: ConfigParser,
                  to_maps=False) -> Union[dict, Maps]:
        """
        Converts the values from an INI file from all strings to their
        actual Python base-types (i.e. int, float, bool, etc).

        If the value cannot be converted, it is kept as a string.
        If a value of the key:value pairs is not a string, its type is
        maintained.

        Note:
            Any meant-to-be-bool values in the key:value pairs that are
            not exactly 'False' or 'True', but are similar like 'false'
            or 'tRue' for example, will be converted to bools.

        Args:
            ini_dict (:obj:`ConfigParser`):
                The dictionary returned by configparser when an INI file
                is loaded.
            to_maps (:obj:`bool`):
                Return a :obj:`Maps` object instead of a :obj:`dict`.

        Returns:
            dict or Maps:
                A dictionary maintaining the same key:value pairs as the
                input dictionary; however, the values are their Python
                base-types. If :obj:`to_maps` is :obj:`True`, return a
                :obj:`Maps` object.

        Raises:
            TypeError:
                An argument is of an illegal type.
        """

        # Check for dict because of recursion; ini_dict is only meant
        # to be a dict when the function recursively converts the values
        # from a ConfigParser
        if not isinstance(ini_dict, (dict, ConfigParser)):
            raise TypeError(
                "argument 'ini_dict' must be of type 'ConfigParser': "
                f"{type(ini_dict).__name__}")
        if isinstance(ini_dict, ConfigParser):
            ini_dict_ = {}
            for section in ini_dict.sections():
                ini_dict_[section] = {}
                for option in ini_dict.options(section):
                    # Parse using configparser
                    option_value = ini_dict.get(section, option)

                    # Parse using os environ
                    matches = [(m.start(0), m.end(0))
                               for m in re.finditer("&", option_value)]
                    if len(matches) > 0 and len(matches) % 2 == 0:
                        i = 0
                        while True:
                            try:
                                index_end = matches.pop(i + 1)[1]
                                index_start = matches.pop(i)[0]
                                sub = option_value[index_start:index_end]
                                sub_replace = os.environ[sub[1:-1]]
                                option_value = option_value.replace(
                                    sub, sub_replace)
                            except IndexError:
                                break
                            except KeyError:
                                pass
                    ini_dict_[section][option] = option_value
            ini_dict = ini_dict_

        for key, value in ini_dict.items():
            if isinstance(value, dict):
                # Recursively parse dict
                ini_dict[key] = Maps.parse_ini(value, to_maps=to_maps)
            else:
                if not isinstance(value, str):
                    continue
                try:
                    ini_dict[key] = ast.literal_eval(value)
                except NameError:
                    if value.lower() == "false":
                        ini_dict[key] = False
                    elif value.lower() == "true":
                        ini_dict[key] = True
                    else:
                        ini_dict[key] = value
                except (SyntaxError, ValueError):
                    # Cannot eval this value
                    ini_dict[key] = value
        return Maps(ini_dict) if to_maps else ini_dict

    @classmethod
    def parse_value(cls, value: Any) -> Any:
        """
        Checks if :term:`value` subclasses :obj:`Maps`. If so, it
        returns the :obj:`Maps` object; otherwise the :term:`value`
        itself.

        Args:
            value (:obj:`Any`):
                The value to parse.

        Returns:
            Any:
                :obj:`OrderedDict` if :term:`value` subclasses
                :obj:`Maps`, otherwise :term:`value`.
        """

        if issubclass(type(value), Maps):
            return value.map
        else:
            return value

    def pop(self,
            key: str,
            default: Optional[Any] = None) -> Union[Any, NoReturn]:
        """
        Removes and returns the value in the Maps object at 'key'. If
        'key' does not exist, then 'default' is returned.

        Args:
            key (:obj:`str`):
                The key to use to remove a value from the Maps object.
            default (:obj:`obj`, optional):
                The value to return if :term:`key` does not exist in the
                :obj:`Maps` object.

        Returns:
            Any:
                The value at :term:`key`, otherwise :term:`default`.
        """

        return self._map.pop()

    def popitem(self) -> Any:
        """Removes and returns an arbitrary (key, value) pair from the
        :obj:`Maps` object.

        Returns:
            Any:
                The arbitrary (key, value) pair.

        Raises:
            KeyError:
                The :obj:`Maps` object is empty.
        """

        return self._map.popitem()

    def setdefault(self, key: str, default=None) -> Any:
        """
        Returns a value of the 'key' in the Maps object.

        If 'key' is not found, then 'default' is inserted at 'key' into
        the Maps object and then returns that value.

        Args:
            key: The key to return the value of.
            default (:obj:`obj`, optional): The value to insert if 'key'
                                            does not exist. Defaults to
                                            none.

        Returns:
            object: The object at 'key' in the Maps object, default'
                    otherwise.
        """

        return self._map.setdefault(key, default)

    def to_dict(self) -> Union[dict, NoReturn]:
        """Converts the :obj:`Maps` object to a stdlib dictionary.

        Returns:
            dict:
                The converted :obj:`Maps` object as a dictionary.
        """

        new_dict = {}

        for key, value in self.items():
            if issubclass(type(value), Maps):
                if id(value) == id(self):
                    value = new_dict
                else:
                    value = value.to_dict()
            elif isinstance(value, (tuple, list)):
                new_list = []

                for item in value:
                    temp_item = item
                    if issubclass(type(item), Maps):
                        temp_item = item.to_dict()
                    new_list.append(temp_item)

                if isinstance(value, tuple):
                    value = tuple(new_list)
                else:
                    value = new_list

            new_dict[key] = value
        return new_dict

    def update(self, *args, **kwargs) -> None:
        """Adds or changes existing values using a dictionary or
        iterator of key:value pairs."""

        if len(args) != 0:
            self._map.update(*args)
        self._map.update(kwargs)

    def values(self) -> Any:
        """Returns the values of the :obj:`Maps` object."""

        return self._map.values()

    def viewitems(self) -> Any:
        """Returns a new view of the :obj:`Maps` object's items
        (key:value pairs)."""

        return self._map.viewitems()

    def viewkeys(self) -> Any:
        """Returns a new view of the :obj:`Maps` object's keys."""

        return self._map.viewkeys()

    def viewvalues(self) -> Any:
        """Returns a new view of the :obj:`Maps` object's values."""

        return self._map.viewvalues()
class SortedDotDict(object):
    def __init__(self, *args, **kwargs):
        super(SortedDotDict, self).__init__(*args, **kwargs)
        self._dict = SortedDict()

    def __contains__(self, *args, **kwargs):
        return self._dict.__contains__(*args, **kwargs)

    def __eq__(self, *args, **kwargs):
        return self._dict.__eq__(*args, **kwargs)

    def __format__(self, *args, **kwargs):
        return self._dict.__format__(*args, **kwargs)

    def __ge__(self, *args, **kwargs):
        return self._dict.__ge__(*args, **kwargs)

    def __getattr__(self, key):
        try:
            return self._dict[key]
        except:
            raise AttributeError(key)

    def __iter__(self):
        vals = list(self.values())
        for k in vals:
            yield k

    def __getitem__(self, key):
        return self._dict[key]

    def __setitem__(self, key, value):
        self._dict[key] = value

    def __delitem__(self, key):
        del self._dict[key]

    def keys(self):
        return list(self._dict.keys())

    def values(self):
        vals = list(self._dict.values())
        vals = [v for v in vals if isinstance(v, (ConfigurationGroup, Value))]
        vals.sort()
        return vals

    def items(self):
        return list(self._dict.items())

    def iterkeys(self):
        return iter(self._dict.keys())

    def itervalues(self):
        return iter(self._dict.values())

    def iteritems(self):
        return iter(self._dict.items())

    def get(self, *args, **kwargs):
        return self._dict.get(*args, **kwargs)

    def clear(self):
        return self._dict.clear()

    def copy(self):
        s = SortedDotDict()
        s._dict = self._dict.copy()
        return s

    def fromkeys(self):
        return self._dict.fromkeys()

    def has_key(self, key):
        return key in self._dict

    def pop(self, *args, **kwargs):
        return self._dict.pop(*args, **kwargs)

    def popitem(self, *args, **kwargs):
        return self._dict.popitem(*args, **kwargs)

    def setdefault(self, key, default):
        return self._dict.setdefault(key, default)

    def update(self, d):
        return self._dict.update(d)

    def viewitems(self, *args, **kwargs):
        return self._dict.viewitems(*args, **kwargs)

    def viewvalues(self, *args, **kwargs):
        return self._dict.viewvalues(*args, **kwargs)
Пример #28
0
    def __init__(self, vmid, timestamp):
        self.vm_id = vmid
        self.timestamp = timestamp


replicas_dict = OrderedDict()
ordered_replicas_dict = OrderedDict()

for vm_id in range(21, 30):
    if vm_id % 3 == 0:
        replicas_dict[vm_id] = VM('a' + str(vm_id), -vm_id**vm_id)
    else:
        replicas_dict[vm_id] = VM('a' + str(vm_id), vm_id + vm_id)

replicas_dict.popitem()
print "Normal"
for vm in replicas_dict.viewvalues():
    print vm.timestamp

ordered_replicas_dict = OrderedDict()
for vm in (sorted(replicas_dict.values(),
                  key=operator.attrgetter('timestamp'),
                  reverse=True)):
    ordered_replicas_dict[vm.vm_id] = vm

print "In order:"
for vm in ordered_replicas_dict.viewvalues():
    print vm.timestamp

x = ordered_replicas_dict.popitem()
print "pop:", x[1].timestamp
Пример #29
0
class SortedDotDict(object):
    def __init__(self, *args, **kwargs):
        super(SortedDotDict, self).__init__(*args, **kwargs)
        self._dict = SortedDict()

    def __contains__(self, *args, **kwargs):
        return self._dict.__contains__(*args, **kwargs)

    def __eq__(self, *args, **kwargs):
        return self._dict.__eq__(*args, **kwargs)

    def __format__(self, *args, **kwargs):
        return self._dict.__format__(*args, **kwargs)

    def __ge__(self, *args, **kwargs):
        return self._dict.__ge__(*args, **kwargs)

    def __getattr__(self, key):
        try:
            return self._dict[key]
        except:
            raise AttributeError(key)

    def __iter__(self):
        vals = list(self.values())
        for k in vals:
            yield k

    def __getitem__(self, key):
        return self._dict[key]

    def __setitem__(self, key, value):
        self._dict[key] = value

    def __delitem__(self, key):
        del self._dict[key]

    def keys(self):
        return list(self._dict.keys())

    def values(self):
        vals = list(self._dict.values())
        vals = [v for v in vals if isinstance(v, (ConfigurationGroup, Value))]
        vals.sort()
        return vals

    def items(self):
        return list(self._dict.items())

    def iterkeys(self):
        return iter(self._dict.keys())

    def itervalues(self):
        return iter(self._dict.values())

    def iteritems(self):
        return iter(self._dict.items())

    def get(self, *args, **kwargs):
        return self._dict.get(*args, **kwargs)

    def clear(self):
        return self._dict.clear()

    def copy(self):
        s = SortedDotDict()
        s._dict = self._dict.copy()
        return s

    def fromkeys(self):
        return self._dict.fromkeys()

    def has_key(self, key):
        return key in self._dict

    def pop(self, *args, **kwargs):
        return self._dict.pop(*args, **kwargs)

    def popitem(self, *args, **kwargs):
        return self._dict.popitem(*args, **kwargs)

    def setdefault(self, key, default):
        return self._dict.setdefault(key, default)

    def update(self, d):
        return self._dict.update(d)

    def viewitems(self, *args, **kwargs):
        return self._dict.viewitems(*args, **kwargs)

    def viewvalues(self, *args, **kwargs):
        return self._dict.viewvalues(*args, **kwargs)
Пример #30
0
class PartiePT(Partie):
    __tablename__ = "partie_pestuse"
    __mapper_args__ = {'polymorphic_identity': 'pestuse'}
    partie_id = Column(Integer, ForeignKey('parties.id'), primary_key=True)
    repetitions = relationship('RepetitionsPT')

    def __init__(self, le2mserv, joueur):
        super(PartiePT, self).__init__("pestuse", "PT")
        self._le2mserv = le2mserv
        self.joueur = joueur
        self._texte_recapitulatif = u""
        self._texte_final = u""
        # self.PT_gain_ecus = 0
        #        self.PT_gain_euros = 0
        self._histo_build = OrderedDict()
        self._histo_build[le2mtrans(u"Period")] = "PT_period"
        self._histo_build[le2mtrans(u"DecisionY")] = "PT_decisionY"
        self._histo_build[le2mtrans(u"DecisionZ")] = "PT_decisionZ"
        self._histo_build[le2mtrans(u"NbAteliersY")] = "PT_nbAteliersY"
        self._histo_build[le2mtrans(u"NbAteliersZ")] = "PT_nbAteliersZ"
        self._histo_build[le2mtrans(u"RendementY")] = "PT_rendementY"
        self._histo_build[le2mtrans(u"RendementZ")] = "PT_rendementZ"
        self._histo_build[le2mtrans(u"ProfitY")] = "PT_profitY"
        self._histo_build[le2mtrans(u"ProfitZ")] = "PT_profitZ"
        self._histo_build[le2mtrans(u"Tirage_de")] = "PT_tirage_de"
        self._histo_build[le2mtrans(u"GainY")] = "PT_gainY"
        self._histo_build[le2mtrans(u"GainZ")] = "PT_gainZ"
        self._histo_build[le2mtrans(u"Period\npayoff")] = "PT_periodpayoff"
        self._histo_build[le2mtrans(u"Cumulative\npayoff")] = "PT_cumulativepayoff"
        self._histo_content = [list(self._histo_build.viewkeys())]
        #        self.periods = {}
        self._currentperiod = None

    @defer.inlineCallbacks
    def display_QC(self, type_partie):
        """
        Display the comprehension questionnaire screen on the remote
        Get back the decision
        :return:
        """
        if type_partie == "BEN":
            QC = list(pms.QCBEN)
        elif type_partie == "WEX":
            QC = list(pms.QCWEX)
        elif type_partie == "WEA":
            QC = list(pms.QCWEA)
        elif type_partie == "WIN":
            QC = list(pms.QCWIN)
        elif type_partie == "WEI":
            QC = list(pms.QCWEI)
        elif type_partie == "WIE":
            QC = list(pms.QCWIE)
        QC_NbQuest = len(QC)
        reponses_fausse = []
        for i_QC_NbQuest in range(0, QC_NbQuest):
            logger.debug(u"{} Decision".format(self.joueur))
            debut_QC = datetime.now()
            self.PT_decision_QC = yield (self.remote.callRemote(
                "display_QC", i_QC_NbQuest, type_partie))
            self.PT_decisiontime_QC = (datetime.now() - debut_QC).seconds
            indice_bonne_reponse = QC[i_QC_NbQuest][1].index(QC[i_QC_NbQuest][2][0])
            if self.PT_decision_QC != indice_bonne_reponse:
                reponses_fausse.append(i_QC_NbQuest)
            # self.joueur.info(u"{}".format(self.PT_decision_QC))
            self.joueur.remove_waitmode()
        self.joueur.info(u"Faute(s) {}".format(reponses_fausse))

    @property
    def currentperiod(self):
        return self._currentperiod

    @defer.inlineCallbacks
    def configure(self):
        logger.debug(u"{} Configure".format(self.joueur))
        yield (self.remote.callRemote("configure", get_module_attributes(pms)))
        self.joueur.info(u"Ok")

    @defer.inlineCallbacks
    def newperiod(self, period):
        """
        Create a new period and inform the remote
        If this is the first period then empty the historic
        :param periode:
        :return:
        """
        logger.debug(u"{} New Period".format(self.joueur))
        if period == 1:
            del self._histo_content[1:]
        self._currentperiod = RepetitionsPT(period)
        self._le2mserv.gestionnaire_base.ajouter(self.currentperiod)
        self.repetitions.append(self.currentperiod)
        yield (self.remote.callRemote("newperiod", period))
        logger.info(u"{} Ready for period {}".format(self.joueur, period))

    @defer.inlineCallbacks
    def display_decision(self, type_partie):
        """
        Display the decision screen on the remote
        Get back the decision
        :return:
        """
        logger.debug(u"{} Decision".format(self.joueur))
        debut = datetime.now()
        les_decisions = yield (self.remote.callRemote(
            "display_decision", self._histo_content, type_partie))
        self.currentperiod.PT_decisionY = les_decisions[0]
        self.currentperiod.PT_decisionZ = les_decisions[1]
        self.currentperiod.PT_nbAteliersY = les_decisions[2]
        self.currentperiod.PT_nbAteliersZ = 10 - les_decisions[2]
        self.currentperiod.PT_type_partie = type_partie
        self.currentperiod.PT_decisiontime = (datetime.now() - debut).seconds
        self.joueur.info(u"{} {} {} {}".format(self.currentperiod.PT_nbAteliersY, self.currentperiod.PT_nbAteliersZ,
                                               self.currentperiod.PT_decisionY, self.currentperiod.PT_decisionZ))
        self.joueur.remove_waitmode()

    @defer.inlineCallbacks
    def lance_de(self, type_partie):
        """
        Lancement du de
        :return:
        """
        logger.debug(u"{} tirage du dé".format(self.joueur))
        debut_de = datetime.now()
        self.currentperiod.PT_tirage_de = yield (self.remote.callRemote(
            "tirage_de", type_partie))
        self.currentperiod.PT_decisiontime_de = (datetime.now() - debut_de).seconds
        self.joueur.info(u"{}".format(self.currentperiod.PT_tirage_de))
        self.joueur.remove_waitmode()

    @defer.inlineCallbacks
    def affichage_result(self, type_partie, indice_part_pestuse, tirage_part_pestuse_gain, tirage_periode_pestuse_gain):
        """
        Affichage des resultat de la periode
        :return:
        """
        decision_pour_Y = self.currentperiod.PT_decisionY
        decision_pour_Z = self.currentperiod.PT_decisionZ
        nbAtelierY = self.currentperiod.PT_nbAteliersY
        nbAtelierZ = self.currentperiod.PT_nbAteliersZ
        tirage_du_de = self.currentperiod.PT_tirage_de
        logger.debug(u"{} Affichage des résultats de la période".format(self.joueur))
        debut_ar = datetime.now()
        les_retours = yield (self.remote.callRemote(
            "affichage_result", decision_pour_Y, decision_pour_Z, tirage_du_de, type_partie, nbAtelierY, nbAtelierZ))
        self.currentperiod.PT_rendementY = les_retours[0]
        self.currentperiod.PT_rendementZ = les_retours[1]
        self.currentperiod.PT_profitY = les_retours[2]
        self.currentperiod.PT_profitZ = les_retours[3]
        self.currentperiod.PT_tirage_de = les_retours[4]
        self.currentperiod.PT_gainY = les_retours[5]
        self.currentperiod.PT_gainZ = les_retours[6]
        # On met la valeur des gains si on est sur la partie pestuse tiree au sort et la bonne periode
        self.currentperiod.PT_periodpayoff = 0
        # print "indice_part_pestuse = ",  indice_part_pestuse
        #        print "tirage_part_pestuse_gain = ",  tirage_part_pestuse_gain
        #        print "\n"
        #        print "self.currentperiod.PT_period = ", self.currentperiod.PT_period
        #        print "tirage_periode_pestuse_gain",  tirage_periode_pestuse_gain
        if indice_part_pestuse == tirage_part_pestuse_gain and self.currentperiod.PT_period == tirage_periode_pestuse_gain:
            self.currentperiod.PT_periodpayoff = les_retours[5] + les_retours[6]
            self.PT_gain_ecus = les_retours[5] + les_retours[6]
            self.PT_gain_euros = \
                float(self.PT_gain_ecus) * float(pms.TAUX_CONVERSION)
        #            print "JE PASSE et self.currentperiod.PT_periodpayoff = ", self.currentperiod.PT_periodpayoff
        #            print " Et self.PT_gain_ecus = ",  self.PT_gain_ecus
        resu_payoff = self.currentperiod.PT_periodpayoff
        self.currentperiod.PT_indice_part_pestuse = indice_part_pestuse
        self.currentperiod.PT_tirage_part_pestuse_gain = tirage_part_pestuse_gain
        self.currentperiod.PT_tirage_periode_pestuse_gain = tirage_periode_pestuse_gain
        # On remplit l historique
        self._histo_content.append(
            [getattr(self.currentperiod, e) for e
             in self._histo_build.viewvalues()])
        self.currentperiod.PT_decisiontime_ar = (datetime.now() - debut_ar).seconds
        self.joueur.info(u"{}".format(self.currentperiod.PT_tirage_ar))
        self.joueur.remove_waitmode()

        yield resu_payoff

    def compute_periodpayoff(self):
        """
        Compute the payoff for the period
        :return:
        """
        logger.debug(u"{} Period Payoff".format(self.joueur))
        # self.currentperiod.PT_periodpayoff = 0

        # cumulative payoff since the first period
        if self.currentperiod.PT_period < 2:
            self.currentperiod.PT_cumulativepayoff = \
                self.currentperiod.PT_periodpayoff
        else:
            previousperiod = self.periods[self.currentperiod.PT_period - 1]
            self.currentperiod.PT_cumulativepayoff = \
                previousperiod.PT_cumulativepayoff + \
                self.currentperiod.PT_periodpayoff

        # we store the period in the self.periodes dictionnary
        self.periods[self.currentperiod.PT_period] = self.currentperiod

        logger.debug(u"{} Period Payoff {}".format(
            self.joueur,
            self.currentperiod.PT_periodpayoff))

    @defer.inlineCallbacks
    def display_summary(self, *args):
        """
        Create the summary (txt and historic) and then display it on the
        remote
        :param args:
        :return:
        """
        logger.debug(u"{} Summary".format(self.joueur))
        self._texte_recapitulatif = texts.get_recapitulatif(self.currentperiod)
        self._histo_content.append(
            [getattr(self.currentperiod, e) for e
             in self._histo_build.viewvalues()])
        yield (self.remote.callRemote(
            "display_summary", self._texte_recapitulatif, self._histo_content))
        self.joueur.info("Ok")
        self.joueur.remove_waitmode()

    def compute_partpayoff(self, tirage_part_pestuse_gain, tirage_periode_pestuse_gain):
        """
        Compute the payoff of the part
        :return:
        """
        logger.debug(u"{} Part Payoff".format(self.joueur))
        # gain partie
        self.PT_gain_ecus = self.currentperiod.PT_cumulativepayoff
        self.PT_gain_euros = \
            float(self.PT_gain_ecus) * float(pms.TAUX_CONVERSION)

        # texte final
        self._texte_final = texts.get_texte_final(
            self.PT_gain_ecus,
            self.PT_gain_euros,
            tirage_part_pestuse_gain,
            tirage_periode_pestuse_gain
        )

        logger.debug(u"{} Final text {}".format(self.joueur, self._texte_final))
        logger.info(u'{} Payoff ecus {} Payoff euros {:.2f}'.format(
            self.joueur, self.PT_gain_ecus, self.PT_gain_euros))