示例#1
0
class UserExt(xso.XSO):
    TAG = (namespaces.xep0045_muc_user, "x")

    status_codes = xso.ChildValueList(StatusCodeList(), container_type=set)

    destroy = xso.Child([DestroyNotification])

    decline = xso.Child([Decline])

    invites = xso.ChildList([Invite])

    items = xso.ChildList([UserItem])

    password = xso.ChildText((namespaces.xep0045_muc_user, "password"),
                             default=None)

    def __init__(self,
                 status_codes=[],
                 destroy=None,
                 decline=None,
                 invites=[],
                 items=[],
                 password=None):
        super().__init__()
        self.status_codes.update(status_codes)
        self.destroy = destroy
        self.decline = decline
        self.invites.extend(invites)
        self.items.extend(items)
        self.password = password
class HashesUsedParent(xso.XSO):
    """
    Mix-in class for XSOs which use :class:`HashUsed` children.

    .. attribute:: algos

        A list of hash algorithms.
    """

    algos = xso.ChildValueList(type_=HashUsedType(), )
示例#3
0
文件: xso.py 项目: rotoql/aioxmpp
class Data(AbstractItem):
    """
    A :xep:`4` ``x`` element, that is, a Data Form.

    :param type_: Initial value for the :attr:`type_` attribute.

    .. attribute:: type_

       The ``type`` attribute of the form, represented by one of the members of
       the :class:`DataType` enumeration.

    .. attribute:: title

       The (optional) title of the form. Either a :class:`str` or :data:`None`.

    .. attribute:: instructions

       A sequence of strings which represent the instructions elements on the
       form.

    .. attribute:: fields

       If the :class:`Data` is a form, this is a sequence of :class:`Field`
       elements which represent the fields to be filled in.

       This does not make sense on :attr:`.DataType.RESULT` typed objects.

    .. attribute:: items

       If the :class:`Data` is a table, this is a sequence of :class:`Item`
       instances which represent the table rows.

       This only makes sense on :attr:`.DataType.RESULT` typed objects.

    .. attribute:: reported

       If the :class:`Data` is a table, this is a :class:`Reported` object
       representing the table header.

       This only makes sense on :attr:`.DataType.RESULT` typed objects.

    .. automethod:: get_form_type
    """

    TAG = (namespaces.xep0004_data, "x")

    type_ = xso.Attr("type", type_=xso.EnumCDataType(DataType))

    title = xso.ChildText(
        (namespaces.xep0004_data, "title"),
        default=None,
    )

    instructions = xso.ChildValueList(type_=InstructionsElement())

    items = xso.ChildList([Item])

    reported = xso.Child([Reported], required=False)

    def __init__(self, type_):
        super().__init__()
        self.type_ = type_

    def _validate_result(self):
        if self.fields:
            raise ValueError("field in report result")

        fieldvars = {field.var for field in self.reported.fields}

        if not fieldvars:
            raise ValueError("empty report header")

        for item in self.items:
            itemvars = {field.var for field in item.fields}
            if itemvars != fieldvars:
                raise ValueError("field mismatch between row and header")

    def validate(self):
        super().validate()

        if (self.type_ != DataType.RESULT
                and (self.reported is not None or self.items)):
            raise ValueError("report in non-result")

        if (self.type_ == DataType.RESULT
                and (self.reported is not None or self.items)):
            self._validate_result()

    def get_form_type(self):
        """
        Extract the ``FORM_TYPE`` from the fields.

        :return: ``FORM_TYPE`` value or :data:`None`
        :rtype: :class:`str` or :data:`None`

        Return :data:`None` if no well-formed ``FORM_TYPE`` field is found in
        the list of fields.

        .. versionadded:: 0.8
        """

        for field in self.fields:
            if field.var == "FORM_TYPE" and field.type_ == FieldType.HIDDEN:
                if len(field.values) != 1:
                    return None
                return field.values[0]
示例#4
0
文件: xso.py 项目: rotoql/aioxmpp
class Field(xso.XSO):
    """
    Represent a single field in a Data Form.

    :param type_: Field type, must be one of the valid field types specified in
                  :xep:`4`.
    :type type_: :class:`FieldType`
    :param options: A mapping of values to labels defining the options in a
                    ``list-*`` field.
    :type options: :class:`dict` mapping :class:`str` to :class:`str`
    :param values: A sequence of values currently given for the field. Having
                   more than one value is only valid in ``*-multi`` fields.
    :type values: :class:`list` of :class:`str`
    :param desc: Description which can be shown in a tool-tip or similar,
                 without newlines.
    :type desc: :class:`str` or :data:`None`s
    :param label: Human-readable label to be shown next to the field input
    :type label: :class:`str` or :data:`None`
    :param required: Flag to indicate that the field is required
    :type required: :class:`bool`
    :param var: "ID" identifying the field uniquely inside the form. Only
                required for fields carrying a meaning (thus, not for
                ``fixed``).
    :type var: :class:`str` or :data:`None`

    The semantics of a :class:`Field` are different depending on where it
    occurs: in a :class:`Data`, it is a form field to be filled in, in a
    :class:`Item` it is a cell of a row and in a :class:`Reported` it
    represents a column header.

    .. attribute:: required

       A boolean flag indicating whether the field is required.

       If true, the XML serialisation will contain the corresponding
       ``<required/>`` tag.

    .. attribute:: desc

       Single line of description for the field. This attribute represents the
       ``<desc/>`` element from :xep:`4`.

    .. attribute:: values

       A sequence of strings representing the ``<value/>`` elements of the
       field, one string for each value.

       .. note::

          Since the requirements on the sequence of strings in :attr:`values`
          change depending on the :attr:`type_` attribute, validation and type
          conversion on assignment is very lax. The attribute accepts all
          sequences of strings, even if the field is for example a
          :attr:`FieldType.BOOLEAN` field, which allows for at most one string
          of a well-defined format (see the documentation there for the
          details).

          This makes it easy to inadvertendly generate invalid forms, which is
          why you should be using :class:`Form` subclasses when accessing forms
          from within normal code and some other, generic mechanism taking care
          of these details when showing forms in a UI framework to users. Note
          that devising such a mechanism is out of scope for :mod:`aioxmpp`, as
          every UI framework has different requirements.

    .. attribute:: options

       A dictionary mapping values to human-readable labels, representing the
       ``<option/>`` elements of the field.

    .. attribute:: var

       The uniquely identifying string of the (valued, that is,
       non-:attr:`FieldType.FIXED` field). Represents the ``var`` attribute of
       the field.

    .. attribute:: type_

       The type of the field. The :attr:`type_` must be a :class:`FieldType`
       enumeration value and determines restrictions and constraints on other
       attributes. See the :class:`FieldType` enumeration and :xep:`4` for
       details.

    .. attribute:: label

       The human-readable label for the field, representing the ``label``
       attribute of the field. May be :data:`None` if the label is omitted.

    """

    TAG = (namespaces.xep0004_data, "field")

    required = xso.ChildFlag((namespaces.xep0004_data, "required"), )

    desc = xso.ChildText((namespaces.xep0004_data, "desc"), default=None)

    values = xso.ChildValueList(type_=ValueElement())

    options = xso.ChildValueMap(
        type_=OptionElement(),
        mapping_type=collections.OrderedDict,
    )

    var = xso.Attr((None, "var"), default=None)

    type_ = xso.Attr(
        (None, "type"),
        type_=xso.EnumCDataType(FieldType, ),
        default=FieldType.TEXT_SINGLE,
    )

    label = xso.Attr((None, "label"), default=None)

    def __init__(self,
                 *,
                 type_=FieldType.TEXT_SINGLE,
                 options={},
                 values=[],
                 desc=None,
                 label=None,
                 required=False,
                 var=None):
        super().__init__()
        self.type_ = type_
        self.options.update(options)
        self.values[:] = values
        self.desc = desc
        self.label = label
        self.required = required
        self.var = var

    def validate(self):
        super().validate()

        if self.type_ != FieldType.FIXED and not self.var:
            raise ValueError("missing attribute var")

        if not self.type_.has_options and self.options:
            raise ValueError("unexpected option on non-list field")

        if not self.type_.is_multivalued and len(self.values) > 1:
            raise ValueError("too many values on non-multi field")

        values_list = [opt for opt in self.options.values()]
        values_set = set(values_list)

        if len(values_list) != len(values_set):
            raise ValueError("duplicate option value")
示例#5
0
class InfoQuery(xso.CapturingXSO):
    """
    A query for features and identities of an entity. The keyword arguments to
    the constructor can be used to initialize the attributes. Note that
    `identities` and `features` must be iterables of :class:`Identity` and
    :class:`Feature`, respectively; these iterables are evaluated and the items
    are stored in the respective attributes.

    .. attribute:: node

       The node at which the query is directed.

    .. attribute:: identities

       The identities of the entity, as :class:`Identity` instances. Each
       entity has at least one identity.

    .. attribute:: features

       The features of the entity, as a set of strings. Each string represents
       a :class:`Feature` instance with the corresponding :attr:`~.Feature.var`
       attribute.

    .. attribute:: captured_events

       If the object was created by parsing an XML stream, this attribute holds
       a list of events which were used when parsing it.

       Otherwise, this is :data:`None`.

       .. versionadded:: 0.5

    .. automethod:: to_dict

    """
    __slots__ = ("captured_events", )

    TAG = (namespaces.xep0030_info, "query")

    node = xso.Attr(tag="node", default=None)

    identities = xso.ChildList([Identity])

    features = xso.ChildValueList(FeatureSet(), container_type=set)

    exts = xso.ChildList([forms_xso.Data])

    def __init__(self, *, identities=(), features=(), node=None):
        super().__init__()
        self.captured_events = None
        self.identities.extend(identities)
        self.features.update(features)
        if node is not None:
            self.node = node

    def to_dict(self):
        """
        Convert the query result to a normalized JSON-like
        representation.

        The format is a subset of the format used by the `capsdb`__. Obviously,
        the node name and hash type are not included; otherwise, the format is
        identical.

        __ https://github.com/xnyhps/capsdb
        """
        identities = []
        for identity in self.identities:
            identity_dict = {
                "category": identity.category,
                "type": identity.type_,
            }
            if identity.lang is not None:
                identity_dict["lang"] = identity.lang.match_str
            if identity.name is not None:
                identity_dict["name"] = identity.name
            identities.append(identity_dict)

        features = sorted(self.features)

        forms = []
        for form in self.exts:
            forms.append({
                field.var: list(field.values)
                for field in form.fields if field.var is not None
            })

        result = {
            "identities": identities,
            "features": features,
            "forms": forms
        }

        return result

    def _set_captured_events(self, events):
        self.captured_events = events
示例#6
0
class Field(xso.XSO):
    TAG = (namespaces.xep0004_data, "field")

    required = xso.ChildTag(
        tags=[
            (namespaces.xep0004_data, "required"),
        ],
        allow_none=True)

    desc = xso.ChildText(
        (namespaces.xep0004_data, "desc"),
        default=None
    )

    values = xso.ChildValueList(
        type_=ValueElement()
    )

    options = xso.ChildValueMap(
        type_=OptionElement()
    )

    var = xso.Attr(
        (None, "var"),
        default=None
    )

    type_ = xso.Attr(
        (None, "type"),
        validator=xso.RestrictToSet([
            "boolean",
            "fixed",
            "hidden",
            "jid-multi",
            "jid-single",
            "list-multi",
            "list-single",
            "text-multi",
            "text-private",
            "text-single",
        ]),
        default="text-single"
    )

    label = xso.Attr(
        (None, "label"),
        default=None
    )

    def __init__(self, *,
                 type_="text-single",
                 options={},
                 values=[],
                 desc=None,
                 label=None,
                 required=False,
                 var=None):
        super().__init__()
        self.type_ = type_
        self.options.update(options)
        self.values[:] = values
        self.desc = desc
        self.label = label
        if required:
            self.required = (namespaces.xep0004_data, "required")
        self.var = var

    def validate(self):
        super().validate()

        if self.type_ != "fixed" and not self.var:
            raise ValueError("missing attribute var")

        if not self.type_.startswith("list-") and self.options:
            raise ValueError("unexpected option on non-list field")

        if not self.type_.endswith("-multi") and len(self.values) > 1:
            raise ValueError("too many values on non-multi field")

        values_list = [opt for opt in self.options.values()]
        values_set = set(values_list)

        if len(values_list) != len(values_set):
            raise ValueError("duplicate option value")