Пример #1
0
 def from_json(json_object):
     prefix = "<class 'nlglib.microplanning.struct."
     if '__class__' in json_object:
         cls = json_object['__class__']
         if cls == ("%sElement'>" % prefix):
             rv = Element.from_dict(json_object['__value__'])
         elif cls == ("%sElementList'>" % prefix):
             rv = ElementList.from_dict(json_object['__value__'])
         elif cls == ("%sString'>" % prefix):
             rv = String.from_dict(json_object['__value__'])
         elif cls == ("%sWord'>" % prefix):
             rv = Word.from_dict(json_object['__value__'])
         elif cls == ("%sVar'>" % prefix):
             rv = Var.from_dict(json_object['__value__'])
         elif cls == ("%sPhrase'>" % prefix):
             rv = Phrase.from_dict(json_object['__value__'])
         elif cls == ("%sNounPhrase'>" % prefix):
             rv = NounPhrase.from_dict(json_object['__value__'])
         elif cls == ("%sVerbPhrase'>" % prefix):
             rv = VerbPhrase.from_dict(json_object['__value__'])
         elif cls == ("%sPrepositionPhrase'>" % prefix):
             rv = PrepositionPhrase.from_dict(json_object['__value__'])
         elif cls == ("%sAdjectivePhrase'>" % prefix):
             rv = AdjectivePhrase.from_dict(json_object['__value__'])
         elif cls == ("%sAdverbPhrase'>" % prefix):
             rv = AdverbPhrase.from_dict(json_object['__value__'])
         elif cls == ("%sCoordination'>" % prefix):
             rv = Coordination.from_dict(json_object['__value__'])
         elif cls == ("%sClause'>" % prefix):
             rv = Clause.from_dict(json_object['__value__'])
         elif cls == "<class 'nlglib.features.feature.FeatureSet'>":
             rv = FeatureSet()
             rv.update(json_object['__value__'])
         else:
             raise TypeError('Unknown class "{}"'.format(cls))
         if hasattr(rv, 'update_parents'):
             rv.update_parents()
         return rv
     return json_object
Пример #2
0
class Element(object):
    """A base class representing an NLG element.
        Aside for providing a base class for other kinds of NLG elements,
        the class also implements basic functionality for elements.

    """

    category = category.ELEMENT

    def __init__(self, features=None, parent=None, id=None):
        self.features = FeatureSet()
        self.features.update(features)
        self.parent = parent
        self.id = id
        self.hash = -1

    def __copy__(self):
        rv = self.__class__(features=self.features,
                            parent=self.parent,
                            id=self.id)
        return rv

    # noinspection PyArgumentList
    def __deepcopy__(self, memo):
        rv = self.__class__(features=None, parent=None, id=self.id)
        memo[id(self)] = rv
        rv.features = deepcopy(self.features, memo=memo)
        rv.parent = memo.get(id(self.parent), None)
        return rv

    def __bool__(self):
        """Because Element is abstract, it will evaluate to false. """
        return False

    def __eq__(self, other):
        return (isinstance(other, Element) and self.id == other.id
                and self.category == other.category and comparable_features(
                    self.features) == comparable_features(other.features))

    def __hash__(self):
        if self.hash == -1:
            self.hash = hash(str(self))
        return self.hash

    def __repr__(self):
        from . import visitors
        v = visitors.ReprVisitor()
        self.accept(v)
        return str(v)

    def __str__(self):
        from . import visitors
        v = visitors.SimpleStrVisitor()
        self.accept(v)
        return str(v)

    def __contains__(self, feature_name):
        """Check if the argument feature name is contained in the element."""
        return feature_name in self.features

    def __setitem__(self, feature_name, feature_value):
        """Set the feature name/value in the element feature set."""
        self.features[feature_name] = feature_value

    def __getitem__(self, feature_name):
        """Return the value associated with the feature name, from the
        element feature set.

        If the feature name is not found in the feature dict, return None.

        """
        return self.features.get(feature_name)

    def __delitem__(self, feature_name):
        """Remove the argument feature name and its associated value from
        the element feature set.

        """
        self.features.discard(feature_name)

    def __add__(self, other):
        """Add two elements resulting in a coordination 
        if both elements are not "False" else return the "True" element.
        
        """
        if not self:
            return other
        if not other:
            return self
        return Coordination(self, other)

    @classmethod
    def from_dict(cls, dct):
        o = cls(None, None, None)
        o.__dict__.update(dct)
        return o

    @classmethod
    def from_json(cls, s):
        return json.loads(s, cls=ElementDecoder)

    def to_json(self):
        return json.dumps(self, cls=ElementEncoder)

    def to_xml(self, depth=0, headers=False):
        from . import visitors
        visitor = visitors.XmlVisitor(depth=depth)
        self.accept(visitor)
        if headers:
            return str(visitor)
        else:
            return str(visitor.xml)

    def accept(self, visitor, **kwargs):
        """Implementation of the Visitor pattern."""
        visitor_method_name = self.category.lower()
        # get the appropriate method of the visitor instance
        m = getattr(visitor, visitor_method_name)
        # ensure that the method is callable
        if not hasattr(m, '__call__'):
            msg = 'Error: cannot call undefined method: %s on visitor'
            raise ValueError(msg % visitor_method_name)
        # and finally call the callback
        return m(self, **kwargs)

    def elements(self, recursive=False, itself=None):
        """Return a generator yielding elements contained in the element

        :param bool recursive: also include sub-elements of the contained elements
        :param str itself: yield `self` as one of the elements; values in (None, 'first', 'last')

        """
        if itself or recursive and self.category != category.ELEMENT:
            yield self

    def arguments(self):
        """Return any arguments (vars) from the element as a list. """
        return [
            x for x in self.elements(recursive=True)
            if x.category == category.VAR
        ]

    def replace(self, one, another, key=lambda x: x):
        """Replace the first occurrence of `one` by `another`.

        :param one: a constituent to replace; will be raised to element
        :param another: a replacement element; will be raised to element
        :param key: a key function for comparison; default is identity
        :returns: True if replacement occurred; False otherwise
        
        """
        return False  # basic implementation does nothing

    def replace_argument(self, id, replacement):
        """Replace an argument with given `id` by `replacement`
        if such argument exists.

        """
        for a in self.arguments():
            if a.id == id:
                return self.replace(a, replacement)
        return False

    def replace_arguments(self, **kwargs):
        """Replace arguments with ids in the kwargs 
        by the corresponding values. 
        
        """
        for k, v in kwargs.items():
            self.replace_argument(k, v)

    @property
    def string(self):
        """Return the string inside the value. """
        return ''

    def update_parents(self, parent=_sentinel):
        """Re-set the `parent` attribute of nested elements."""
        if parent is not _sentinel:
            self.parent = parent
Пример #3
0
class ElementList(collections.UserList):
    category = category.ELEMENT_LIST

    def __init__(self, lst=None, parent=None, features=FeatureSet()):
        super().__init__()
        self.parent = parent
        self.features = FeatureSet()
        self.features.update(features)
        for o in lst or []:
            self.append(o)

    def append(self, item):
        item = raise_to_element(item)
        item.parent = self.parent
        item.features.update(self.features)
        super().append(item)

    def insert(self, i, item):
        item = raise_to_element(item)
        item.parent = self.parent
        item.features.update(self.features)
        super().insert(i, item)

    def remove(self, item):
        raised_item = raise_to_element(item)
        super().remove(raised_item)

    def __contains__(self, item):
        raised_item = raise_to_element(item)
        return super().__contains__(raised_item)

    def __iadd__(self, other):
        if isinstance(other, (ElementList, list, tuple)):
            for x in other:
                self.append(x)
        else:
            self.append(other)
        return self

    def __add__(self, other):
        rv = ElementList(self, parent=self.parent, features=self.features)
        rv += other
        return rv

    def __setitem__(self, i, value):
        value = raise_to_element(value)
        value.parent = self.parent
        value.features.update(self.features)
        super().__setitem__(i, value)

    # noinspection PyArgumentList
    def __deepcopy__(self, memo):
        rv = self.__class__()
        memo[id(self)] = rv
        rv.parent = memo.get(id(self.parent), None)
        rv.features = deepcopy(self.features, memo)
        for o in self:
            rv.append(deepcopy(o, memo))
        return rv

    @classmethod
    def from_dict(cls, dct):
        o = cls()
        o.__dict__.update(dct)
        return o

    @classmethod
    def from_json(cls, s):
        return json.loads(s, cls=ElementDecoder)

    def to_json(self):
        return json.dumps(self, cls=ElementEncoder)

    def elements(self, recursive=False, itself=None):
        """Return a generator yielding elements contained in the element

        Note that ElementList is a pseudo-element so it doesn't return
        itself even if the param is specified.

        :param bool recursive: also include sub-elements of the contained elements
        :param str itself: yield `self` as one of the elements; values in (None, 'first', 'last')

        """
        if recursive:
            for e in self:
                yield from e.elements(recursive, itself)
        else:
            for e in self:
                yield e

    def update_parents(self, parent=_sentinel):
        if parent is not _sentinel:
            self.parent = parent
        for x in self:
            x.update_parents(parent=parent)