コード例 #1
0
    def intersection(self, other):
        from winnow.options import OptionsSet

        if isinstance(other, OptionNullWinnowValue):

            this_options = self._get_options()
            that_options = other._get_options()

            options = None

            if this_options is not None and that_options is not None:
                options = OptionsSet(this_options).merge(
                    OptionsSet(that_options)).store
            elif this_options is not None or that_options is not None:
                options = this_options if this_options is not None else that_options
            else:
                pass

            info = self.get_merged_info(other)
            info[u"type"] = self.type,

            if options is not None:

                info[VALUES_KEY_NAME] = {u"options": options}

            return self.__class__(info)

        if isinstance(other, OptionResourceWinnowValue) or isinstance(
                other, OptionStringWinnowValue):
            return other.intersection(self)

        return None
コード例 #2
0
ファイル: inline.py プロジェクト: paulharter/winnow
def _merge_option_dicts(source,
                        options_a,
                        options_b,
                        ref_doc_a,
                        ref_doc_b,
                        errors=[]):

    # expand the options dicts collecting their replaced refs
    ref_hashes = {}

    inline_refs(options_a, ref_doc_a, source, ref_hashes)
    inline_refs(options_b, ref_doc_b, source, ref_hashes)

    # do the merge
    set_a = OptionsSet(options_a)
    set_b = OptionsSet(options_b)

    try:
        merged_options = set_a.merge(set_b).store
    except OptionsExceptionSetWithException as e:
        merged_options = e.set.store
        for ex_info in e.exception_infos:
            key = ex_info[0]
            values = ex_info[1]

            msg = """***** Merge Error ****

Merging:

type: {type_a}
path: {path_a}

with

type: {type_b}
path: {path_b}

Gave an empty result for the key: {key}

When using these values:
{values}
        """.format(type_a=ref_doc_a.get("type"),
                   type_b=ref_doc_b.get("type"),
                   path_a=ref_doc_a.get("path"),
                   path_b=ref_doc_b.get("path"),
                   key=key,
                   values="\n".join(
                       [utils.json_dumps(v.as_json()) for v in values]))

            errors.append(msg)

    # un merge unchanged refs by looking at the ref_hashes
    restore_unchanged_refs(merged_options, ref_hashes)

    return merged_options
コード例 #3
0
ファイル: inline.py プロジェクト: paulharter/winnow
def _find_expanded_ref(reference,
                       doc,
                       source,
                       options,
                       ref_hashes,
                       default_scopes=None):

    # looks up the contents of a reference

    if u"~" in reference:
        ref, internal_path = reference.split(u"~")
    elif u"#" in reference:
        ref, internal_path = reference.split(u"#")
    else:
        ref = reference
        internal_path = None
    if ref == "":
        referenced_doc = doc
    else:
        wv = source.lookup(ref)
        if wv is None:
            raise OptionsExceptionReferenceError(
                "Winnow Reference Error: Failed to find resource %s" % ref)
        existing_doc = wv.get_doc()
        referenced_doc = deepcopy(existing_doc)
    if referenced_doc is None:
        raise OptionsExceptionReferenceError(
            "Winnow Reference Error: Cannot find reference %s as ref doc is None"
            % ref)
    else:
        if options is not None:
            # if the ref also has some options then pre merge them into the reference
            referenced_options = referenced_doc.get(u"options")
            if referenced_options is None:
                referenced_doc[u"options"] = options
            else:
                options_a = OptionsSet(referenced_options)
                options_b = OptionsSet(options)
                referenced_doc[u"options"] = _merge_option_dicts(
                    source, options_a.store, options_b.store, referenced_doc,
                    doc)

            ## TODO look again at the the default scopes thing
            # if default_scopes is not None:
            #     for k, v in referenced_doc[u"options"].iteritems():
            #         print v
            #         if v.get("scopes") is None:
            #             v["scopes"] = default_scopes

        new_doc = _extract_internal_path(
            referenced_doc, internal_path) if internal_path else referenced_doc
        # TODO revisit this use of doc as the reference doc to use
        new_doc = inline_refs(new_doc, doc, source, ref_hashes)
        return new_doc
コード例 #4
0
ファイル: inline.py プロジェクト: opendesk/winnow
def _merge_option_dicts(source, options_a, options_b, ref_doc_a, ref_doc_b, errors=[]):

    # expand the options dicts collecting their replaced refs
    ref_hashes = {}

    inline_refs(options_a, ref_doc_a, source, ref_hashes)
    inline_refs(options_b, ref_doc_b, source, ref_hashes)

    # do the merge
    set_a = OptionsSet(options_a)
    set_b = OptionsSet(options_b)

    try:
        merged_options = set_a.merge(set_b).store
    except OptionsExceptionSetWithException as e:
        merged_options = e.set.store
        for ex_info in e.exception_infos:
            key = ex_info[0]
            values = ex_info[1]

            msg = """***** Merge Error ****

Merging:

type: {type_a}
path: {path_a}

with

type: {type_b}
path: {path_b}

Gave an empty result for the key: {key}

When using these values:
{values}
        """.format(type_a=ref_doc_a.get("type"),
                   type_b=ref_doc_b.get("type"),
                   path_a=ref_doc_a.get("path"),
                   path_b=ref_doc_b.get("path"),
                   key=key,
                   values = "\n".join([utils.json_dumps(v.as_json()) for v in values])
                   )

            errors.append(msg)

    # un merge unchanged refs by looking at the ref_hashes
    restore_unchanged_refs(merged_options, ref_hashes)

    return merged_options
コード例 #5
0
ファイル: operations.py プロジェクト: opendesk/winnow
def default_choices(source, scopes):

    #take a copy of the options
    doc = source.get_doc()
    options_dict = deepcopy(source.get_options_dict())

    #expand it
    ref_hashes = {}
    inline.inline_refs(options_dict, doc, source, ref_hashes)

    #scope it
    _trim_out_off_scope(options_dict, set(scopes))

    # wrap it in an options set
    options_set = OptionsSet(options_dict)

    #get default options set
    default = options_set.default()

    return default.store
コード例 #6
0
def default_choices(source, scopes):

    #take a copy of the options
    doc = source.get_doc()
    options_dict = deepcopy(source.get_options_dict())

    #expand it
    ref_hashes = {}
    inline.inline_refs(options_dict, doc, source, ref_hashes)

    #scope it
    _trim_out_off_scope(options_dict, set(scopes))

    # wrap it in an options set
    options_set = OptionsSet(options_dict)

    #get default options set
    default = options_set.default()

    return default.store
コード例 #7
0
    def issubset(self, other):
        if isinstance(other, OptionNullWinnowValue):
            return True
        from winnow.options import OptionsSet
        self.check_class(other)
        other_keys = set(other.values_lookup.keys())
        self_keys = set(self.values_lookup.keys())

        ## check this values keys
        if not self_keys.issubset(other_keys):
            return False

        ## if self and other have matching values that both have have nested options check them too
        for key in self_keys:
            this_options = self.get_value_options(key)
            that_options = other.get_value_options(key)
            if this_options is not None and that_options is not None:
                if not OptionsSet(that_options).allows(
                        OptionsSet(this_options)):
                    return False
        return True
コード例 #8
0
def _patch_upstream(source, target, options_set):

    doc = source.get_doc()
    if u"upstream" in doc.keys():
        upstream_delegate = source.get_upstream()
        if upstream_delegate is None:
            raise OptionsExceptionReferenceError(
                "Winnow Reference Error: Cannot find upstream reference %s" %
                doc[u"upstream"])
    else:
        return options_set

    upstream_options = OptionsSet(upstream_delegate.get_options_dict())
    patched_options_set = options_set.patch(upstream_options)
    if target is not None:
        _add_start_if_needed(source, target)
        target.add_history_action(action=HISTORY_ACTION_PATCH,
                                  input=upstream_delegate,
                                  output_type=doc.get("type"))

    return _patch_upstream(upstream_delegate, target, patched_options_set)
コード例 #9
0
def allows(source_a, source_b):
    set_a = OptionsSet(inline.get_inlined_options(source_a))
    set_b = OptionsSet(inline.get_inlined_options(source_b))
    return set_a.allows(set_b)
コード例 #10
0
    def test_wildcard(self):

        options_1 = {
            u"colour": {
                u"type": VALUE_TYPE_SET_STRING,
                u"name": u"colour",
                u"description": u"please choose one of the colours",
                VALUES_KEY_NAME: [
                    {
                        u"type": VALUE_TYPE_SET_STRING,
                        u"name": u"red",
                        u"description": u"the colour red",
                        u"image_uri": u"http://something.com/khgfdkyg.png",
                        u"value": u"red",
                        u"options":{
                            u"apples":{
                                u"type": VALUE_TYPE_SET_STRING,
                                u"values": [u"cox", u"jazz", u"bramley"]
                            }
                        }
                    },
                    {
                        u"type": VALUE_TYPE_SET_STRING,
                        u"name": u"blue",
                        u"description": u"the colour blue",
                        u"image_uri": u"http://something.com/khgfdkyg.png",
                        u"value": u"blue"
                    }
                ]
            }
        }

        options_2 = {
            u"*/apples": [u"cox", u"jazz"]
        }

        set1 = OptionsSet(options_1)
        set2 = OptionsSet(options_2)

        self.assertEqual(set1.matcher.options.keys(), [u"colour", u"colour/apples"])
        self.assertEqual(set2.matcher.options.keys(), [u"*/apples"])

        mega_store_1 = set1.mega_store(set2)
        mega_store_2 = set2.mega_store(set1)

        self.assertEqual(mega_store_1.keys(), [u"colour"])

        merged = set1.merge(set2).store

        expected = [
            {
                "description": "the colour blue",
                "image_uri": "http://something.com/khgfdkyg.png",
                "name": "blue",
                "type": "set::string",
                "value": "blue"
            },
            {
                "description": "the colour red",
                "image_uri": "http://something.com/khgfdkyg.png",
                "name": "red",
                "options": {
                    "apples": [
                        "cox",
                        "jazz"
                    ]
                },
                "type": "set::string",
                "value": "red"
            }
        ]

        self.assertEqual(expected, merged["colour"]["values"])
コード例 #11
0
ファイル: operations.py プロジェクト: opendesk/winnow
def disallowed_keys(source_a, source_b):
    set_a = OptionsSet(inline.get_inlined_options(source_a))
    set_b = OptionsSet(inline.get_inlined_options(source_b))
    return set_b.disallowed_keys(set_a)
コード例 #12
0
    def intersection(self, other):

        # print " "
        # print "****************  resource intersection ******************"
        # print "self keys", self.values_lookup.keys()

        from winnow.options import OptionsSet

        self.check_class(other)

        values = []

        if type(other) == OptionNullWinnowValue:

            # print "a null resource"

            other_options = other._get_options()
            if other_options is None:
                return self

            self_keys = list(self.values_lookup.keys())

            for value_id in self_keys:
                this_value = self.values_lookup.get(value_id)
                if isinstance(this_value, dict):
                    new_value = deepcopy(this_value)
                    this_options = self.get_value_options(value_id)
                else:
                    raise Exception("This shouldn't ever happen")

                # if this_options is not None:
                #
                #     new_value[u"options"] = OptionsSet(this_options).merge(OptionsSet(other_options)).store
                #
                # values.append(new_value)
                #
                #
                #
                #

                if this_options is not None:
                    try:
                        new_value[u"options"] = OptionsSet(this_options).merge(
                            OptionsSet(other_options)).store
                    except OptionsExceptionSetWithException as e:
                        new_value = None

                if new_value is not None:
                    values.append(new_value)

        elif type(other) == OptionStringWinnowValue:
            raise OptionsExceptionIncompatibleTypes(
                "You cannot merge and resource with a string: %s" % other)

        else:

            # take a cope of the the possible values in a lookup table keyed by path
            all_values = deepcopy(self.values_lookup)

            all_values.update(deepcopy(other.values_lookup))

            # prune and child nodes from each set

            other_paths = list(other.values_lookup.keys())
            self_paths = list(self.values_lookup.keys())

            other_paths_pruned = self._prune_child_nodes(other_paths)
            self_paths_pruned = self._prune_child_nodes(self_paths)

            # then add values if it or parent is in other
            intersecting_paths = self._intersection_of_path_sets(
                other_paths_pruned, self_paths_pruned)

            # for each intersecting path find the most specific option set on each side and merge them
            values = []

            for path in intersecting_paths:
                # find best fit values to get merged options
                this_value = self.values_lookup[self._nearest_match(
                    path, self_paths)]
                other_value = other.values_lookup[self._nearest_match(
                    path, other_paths)]

                merged_value = self.munge_values(this_value, other_value)

                # and then add these options to a copy of the origional value from all_values
                new_value = all_values[path]
                if "options" in merged_value:
                    new_value["options"] = merged_value["options"]

                values.append(new_value)

        ## if there is no intersection return None
        if len(values) == 0:
            return None

        info = self.get_merged_info(other)
        info[u"type"] = self.type,
        info[VALUES_KEY_NAME] = values

        return self.__class__(info)
コード例 #13
0
    def intersection(self, other):
        #
        #
        # print "++++++++++++++++++++++++++++++++++++++  me  +++++++++++++++++++++++++++++++++++++++++++"
        # print self.values_lookup.keys()
        #

        from winnow.options import OptionsSet

        self.check_class(other)

        values = []

        default = None

        if type(other) == OptionResourceWinnowValue:
            msg = "You cannot merge a string with a resource: self: %s\n other: %s" % (
                self, other)
            raise OptionsExceptionIncompatibleTypes(msg)

        elif isinstance(other, OptionNullWinnowValue):

            other_options = other._get_options()
            if other_options is None:
                return self

            self_keys = list(self.values_lookup.keys())

            for value_id in self_keys:
                this_value = self.values_lookup.get(value_id)
                if isinstance(this_value, dict):
                    new_value = deepcopy(this_value)
                    this_options = self.get_value_options(value_id)
                elif isinstance(this_value, unicode):
                    new_value = {"type": u"string", "value": this_value}
                    this_options = None
                else:
                    raise Exception("This shouldn't ever happen")

                if this_options is not None:
                    try:
                        new_value[u"options"] = OptionsSet(this_options).merge(
                            OptionsSet(other_options)).store
                    except OptionsExceptionSetWithException as e:
                        new_value = None

                default = self._default
                if new_value is not None:
                    values.append(new_value)

        else:
            other_keys = list(other.values_lookup.keys())
            # self_keys = list(self.values_lookup.keys())
            other_keys.sort()

            this_default_allowed = False
            that_default_allowed = False

            # find matching values

            # get the one to use

            # add them to the list

            ## when putting together the intersecting values perform a merge on their nested options
            for value_id in other_keys:

                this_value = self.values_lookup.get(value_id)
                if this_value is None:
                    continue
                other_value = other.values_lookup[value_id]

                if self._default == value_id:
                    this_default_allowed = True

                if other._default == value_id:
                    that_default_allowed = True

                ## if they are both unicode just add the value
                if isinstance(other_value, unicode) and isinstance(
                        this_value, unicode):
                    values.append(this_value)
                elif isinstance(other_value, unicode) and isinstance(
                        this_value, dict):
                    values.append(deepcopy(this_value))
                elif isinstance(other_value, dict) and isinstance(
                        this_value, unicode):
                    values.append(deepcopy(other_value))
                elif isinstance(other_value, dict) and isinstance(
                        this_value, dict):
                    new_value = self.munge_values(this_value, other_value)
                    values.append(new_value)
                else:
                    raise Exception("this should never happen")

                if this_default_allowed and that_default_allowed:
                    default = self._default
                elif this_default_allowed:
                    default = self._default
                elif that_default_allowed:
                    default = other._default
                else:
                    default = None

        ## if there is no intersection return None
        if len(values) == 0:
            return None

        info = self.get_merged_info(other)
        info[u"type"] = self.type,
        info[VALUES_KEY_NAME] = values
        if default is not None:
            info[u"default"] = default

        return self.__class__(info)
コード例 #14
0
class OptionStringWinnowValue(OptionWinnowValue):

    type = VALUE_TYPE_SET_STRING

    def validate_single_value(self, value):
        if not isinstance(value, unicode):
            raise Exception("should be unicode %s" % value)

    def __str__(self):
        return str(self.as_json())

    def _set_value_list(self, value_list):

        self.values_lookup = {}
        for v in value_list:
            single_value = v if isinstance(v, unicode) else v[u"value"]
            self.validate_single_value(single_value)
            self.values_lookup[single_value] = v

    @property
    def default(self):
        first = self.values_lookup.keys()[0]
        if self._default is None:
            return first
        if not self._default in self.values_lookup:
            return first
        return self._default

    #
    # @property
    # def default(self):
    #     from winnow.options import OptionsSet
    #
    #     default_key = self.get_default_key()
    #     default_value = self.values_lookup[default_key]
    #     new_value = deepcopy(default_value)
    #
    #     value_options = new_value.get(u"options") if hasattr(new_value, 'get') else None
    #     if value_options is None or value_options == {}:
    #         return self.get_default()
    #
    #     new_value[u"options"] = OptionsSet(value_options).default().store
    #
    #     info = self.get_merged_info(self)
    #     info[u"type"] = self.type,
    #     info[VALUES_KEY_NAME] = [new_value]
    #
    #     return self.__class__(info).as_json()

    def isdisjoint(self, other):
        if isinstance(other, OptionNullWinnowValue):
            return False
        self.check_class(other)
        other_keys = set(other.values_lookup.keys())
        self_keys = set(self.values_lookup.keys())
        return self_keys.isdisjoint(other_keys)

    def issubset(self, other):
        if isinstance(other, OptionNullWinnowValue):
            return True
        from winnow.options import OptionsSet
        self.check_class(other)
        other_keys = set(other.values_lookup.keys())
        self_keys = set(self.values_lookup.keys())

        ## check this values keys
        if not self_keys.issubset(other_keys):
            return False

        ## if self and other have matching values that both have have nested options check them too
        for key in self_keys:
            this_options = self.get_value_options(key)
            that_options = other.get_value_options(key)
            if this_options is not None and that_options is not None:
                if not OptionsSet(that_options).allows(
                        OptionsSet(this_options)):
                    return False
        return True

    def intersection(self, other):
        #
        #
        # print "++++++++++++++++++++++++++++++++++++++  me  +++++++++++++++++++++++++++++++++++++++++++"
        # print self.values_lookup.keys()
        #

        from winnow.options import OptionsSet

        self.check_class(other)

        values = []

        default = None

        if type(other) == OptionResourceWinnowValue:
            msg = "You cannot merge a string with a resource: self: %s\n other: %s" % (
                self, other)
            raise OptionsExceptionIncompatibleTypes(msg)

        elif isinstance(other, OptionNullWinnowValue):

            other_options = other._get_options()
            if other_options is None:
                return self

            self_keys = list(self.values_lookup.keys())

            for value_id in self_keys:
                this_value = self.values_lookup.get(value_id)
                if isinstance(this_value, dict):
                    new_value = deepcopy(this_value)
                    this_options = self.get_value_options(value_id)
                elif isinstance(this_value, unicode):
                    new_value = {"type": u"string", "value": this_value}
                    this_options = None
                else:
                    raise Exception("This shouldn't ever happen")

                if this_options is not None:
                    try:
                        new_value[u"options"] = OptionsSet(this_options).merge(
                            OptionsSet(other_options)).store
                    except OptionsExceptionSetWithException as e:
                        new_value = None

                default = self._default
                if new_value is not None:
                    values.append(new_value)

        else:
            other_keys = list(other.values_lookup.keys())
            # self_keys = list(self.values_lookup.keys())
            other_keys.sort()

            this_default_allowed = False
            that_default_allowed = False

            # find matching values

            # get the one to use

            # add them to the list

            ## when putting together the intersecting values perform a merge on their nested options
            for value_id in other_keys:

                this_value = self.values_lookup.get(value_id)
                if this_value is None:
                    continue
                other_value = other.values_lookup[value_id]

                if self._default == value_id:
                    this_default_allowed = True

                if other._default == value_id:
                    that_default_allowed = True

                ## if they are both unicode just add the value
                if isinstance(other_value, unicode) and isinstance(
                        this_value, unicode):
                    values.append(this_value)
                elif isinstance(other_value, unicode) and isinstance(
                        this_value, dict):
                    values.append(deepcopy(this_value))
                elif isinstance(other_value, dict) and isinstance(
                        this_value, unicode):
                    values.append(deepcopy(other_value))
                elif isinstance(other_value, dict) and isinstance(
                        this_value, dict):
                    new_value = self.munge_values(this_value, other_value)
                    values.append(new_value)
                else:
                    raise Exception("this should never happen")

                if this_default_allowed and that_default_allowed:
                    default = self._default
                elif this_default_allowed:
                    default = self._default
                elif that_default_allowed:
                    default = other._default
                else:
                    default = None

        ## if there is no intersection return None
        if len(values) == 0:
            return None

        info = self.get_merged_info(other)
        info[u"type"] = self.type,
        info[VALUES_KEY_NAME] = values
        if default is not None:
            info[u"default"] = default

        return self.__class__(info)

    def _get_options(self, value):
        if isinstance(value, unicode):
            return None
        return value.get(u"options")

    def munge_values(self, this_value, other_value):
        #WTF is this really meant to do!!!!!

        from winnow.options import OptionsSet

        try:
            new_value = deepcopy(other_value)
            new_value.update(deepcopy(this_value))
        except Exception, e:
            print "this_value", this_value
            print "other_value", other_value
            raise e

        ## and then merge their options
        this_options = self._get_options(this_value)
        that_options = self._get_options(other_value)

        if this_options is not None and that_options is not None:
            new_value[u"options"] = OptionsSet(this_options).merge(
                OptionsSet(that_options)).store
        elif this_options is not None or that_options is not None:
            new_value[
                u"options"] = this_options if this_options is not None else that_options
        else:
            pass

        return new_value
コード例 #15
0
def disallowed_keys(source_a, source_b):
    set_a = OptionsSet(inline.get_inlined_options(source_a))
    set_b = OptionsSet(inline.get_inlined_options(source_b))
    return set_b.disallowed_keys(set_a)
コード例 #16
0
    def test_wildcard(self):

        options_1 = {
            u"colour": {
                u"type":
                VALUE_TYPE_SET_STRING,
                u"name":
                u"colour",
                u"description":
                u"please choose one of the colours",
                VALUES_KEY_NAME: [{
                    u"type": VALUE_TYPE_SET_STRING,
                    u"name": u"red",
                    u"description": u"the colour red",
                    u"image_uri": u"http://something.com/khgfdkyg.png",
                    u"value": u"red",
                    u"options": {
                        u"apples": {
                            u"type": VALUE_TYPE_SET_STRING,
                            u"values": [u"cox", u"jazz", u"bramley"]
                        }
                    }
                }, {
                    u"type": VALUE_TYPE_SET_STRING,
                    u"name": u"blue",
                    u"description": u"the colour blue",
                    u"image_uri": u"http://something.com/khgfdkyg.png",
                    u"value": u"blue"
                }]
            }
        }

        options_2 = {u"*/apples": [u"cox", u"jazz"]}

        set1 = OptionsSet(options_1)
        set2 = OptionsSet(options_2)

        self.assertEqual(set1.matcher.options.keys(),
                         [u"colour", u"colour/apples"])
        self.assertEqual(set2.matcher.options.keys(), [u"*/apples"])

        mega_store_1 = set1.mega_store(set2)
        mega_store_2 = set2.mega_store(set1)

        self.assertEqual(mega_store_1.keys(), [u"colour"])

        merged = set1.merge(set2).store

        expected = [{
            "description": "the colour blue",
            "image_uri": "http://something.com/khgfdkyg.png",
            "name": "blue",
            "type": "set::string",
            "value": "blue"
        }, {
            "description": "the colour red",
            "image_uri": "http://something.com/khgfdkyg.png",
            "name": "red",
            "options": {
                "apples": ["cox", "jazz"]
            },
            "type": "set::string",
            "value": "red"
        }]

        self.assertEqual(expected, merged["colour"]["values"])
コード例 #17
0
ファイル: operations.py プロジェクト: opendesk/winnow
def allows(source_a, source_b):
    set_a = OptionsSet(inline.get_inlined_options(source_a))
    set_b = OptionsSet(inline.get_inlined_options(source_b))
    return set_a.allows(set_b)