示例#1
0
    def __init__(self, fields: Sequence[Tuple[str, BaseSedes[Any,
                                                             Any]]]) -> None:
        field_names = tuple(field_name for field_name, field_sedes in fields)
        duplicate_field_names = get_duplicates(field_names)
        if duplicate_field_names:
            raise ValueError(
                f"The following fields are duplicated {','.join(sorted(duplicate_field_names))}"
            )

        self.fields = fields
示例#2
0
    def __init__(self, fields: Sequence[Tuple[str, BaseSedes[Any,
                                                             Any]]]) -> None:
        self.fields = fields
        self.field_names = tuple(field_name for field_name, _ in self.fields)
        self.field_sedes_objects = tuple(field_sedes
                                         for _, field_sedes in self.fields)
        self.field_name_to_sedes = dict(self.fields)

        if len(fields) == 0:
            raise ValidationError("Cannot define container without any fields")

        duplicate_field_names = get_duplicates(self.field_names)
        if duplicate_field_names:
            raise ValidationError(
                f"The following fields are duplicated {','.join(sorted(duplicate_field_names))}"
            )
示例#3
0
def _validate_field_names(field_names: Sequence[str]) -> None:
    # check that field names are unique
    duplicate_field_names = get_duplicates(field_names)
    if duplicate_field_names:
        raise TypeError("The following fields are duplicated in the `fields` "
                        "declaration: "
                        "{0}".format(",".join(sorted(duplicate_field_names))))

    # check that field names are valid identifiers
    invalid_field_names = {
        field_name
        for field_name in field_names if not _is_valid_identifier(field_name)
    }
    if invalid_field_names:
        raise TypeError(
            "The following field names are not valid python identifiers: {0}".
            format(",".join("`{0}`".format(item)
                            for item in sorted(invalid_field_names))))
示例#4
0
def validate_args_and_kwargs(args, kwargs, arg_names):
    duplicate_arg_names = get_duplicates(arg_names)
    if duplicate_arg_names:
        raise ValueError("Duplicate argument names: {0}".format(sorted(duplicate_arg_names)))

    needed_arg_names = set(arg_names[len(args):])
    used_arg_names = set(arg_names[:len(args)])

    duplicate_arg_names = used_arg_names.intersection(kwargs.keys())
    if duplicate_arg_names:
        raise TypeError("Duplicate kwargs: {0}".format(sorted(duplicate_arg_names)))

    unknown_arg_names = set(kwargs.keys()).difference(arg_names)
    if unknown_arg_names:
        raise TypeError("Unknown kwargs: {0}".format(sorted(unknown_arg_names)))

    missing_arg_names = set(needed_arg_names).difference(kwargs.keys())
    if missing_arg_names:
        raise TypeError("Missing kwargs: {0}".format(sorted(missing_arg_names)))
示例#5
0
    def __new__(cls, name, bases, attrs):
        super_new = super(SerializableBase, cls).__new__

        serializable_bases = tuple(b for b in bases
                                   if isinstance(b, SerializableBase))
        has_multiple_serializable_parents = len(serializable_bases) > 1
        is_serializable_subclass = any(serializable_bases)
        declares_fields = 'fields' in attrs

        if not is_serializable_subclass:
            # If this is the original creation of the `Serializable` class,
            # just create the class.
            return super_new(cls, name, bases, attrs)
        elif not declares_fields:
            if has_multiple_serializable_parents:
                raise TypeError(
                    "Cannot create subclass from multiple parent `Serializable` "
                    "classes without explicit `fields` declaration.")
            else:
                # This is just a vanilla subclass of a `Serializable` parent class.
                parent_serializable = serializable_bases[0]

                if hasattr(parent_serializable, '_meta'):
                    fields = parent_serializable._meta.fields
                else:
                    # This is a subclass of `Serializable` which has no
                    # `fields`, likely intended for further subclassing.
                    fields = ()
        else:
            # ensure that the `fields` property is a tuple of tuples to ensure
            # immutability.
            fields = tuple(tuple(field) for field in attrs.pop('fields'))

        # split the fields into names and sedes
        if fields:
            field_names, sedes = zip(*fields)
        else:
            field_names = ()

        # check that field names are unique
        duplicate_field_names = get_duplicates(field_names)
        if duplicate_field_names:
            raise TypeError(
                "The following fields are duplicated in the `fields` "
                "declaration: "
                "{0}".format(",".join(sorted(duplicate_field_names))))

        # check that field names are valid identifiers
        invalid_field_names = {
            field_name
            for field_name in field_names
            if not _is_valid_identifier(field_name)
        }
        if invalid_field_names:
            raise TypeError(
                "The following field names are not valid python identifiers: {0}"
                .format(",".join("`{0}`".format(item)
                                 for item in sorted(invalid_field_names))))

        # extract all of the fields from parent `Serializable` classes.
        parent_field_names = {
            field_name
            for base in serializable_bases if hasattr(base, '_meta')
            for field_name in base._meta.field_names
        }

        # check that all fields from parent serializable classes are
        # represented on this class.
        missing_fields = parent_field_names.difference(field_names)
        if missing_fields:
            raise TypeError(
                "Subclasses of `Serializable` **must** contain a full superset "
                "of the fields defined in their parent classes.  The following "
                "fields are missing: "
                "{0}".format(",".join(sorted(missing_fields))))

        # the actual field values are stored in separate *private* attributes.
        # This computes attribute names that don't conflict with other
        # attributes already present on the class.
        reserved_namespace = set(attrs.keys()).union(
            attr for base in bases for parent_cls in base.__mro__
            for attr in _get_class_namespace(parent_cls))
        field_attrs = _mk_field_attrs(field_names, reserved_namespace)

        # construct the Meta object to store field information for the class
        meta_namespace = {
            'fields': fields,
            'field_attrs': field_attrs,
            'field_names': field_names,
            'container_sedes': Container(fields),
        }

        meta_base = attrs.pop('_meta', MetaBase)
        meta = type(
            'Meta',
            (meta_base, ),
            meta_namespace,
        )
        attrs['_meta'] = meta

        # construct `property` attributes for read only access to the fields.
        field_props = tuple(
            (field, _mk_field_property(field, attr))
            for field, attr in zip(meta.field_names, meta.field_attrs))

        return super_new(
            cls,
            name,
            bases,
            dict(field_props + tuple(attrs.items())),
        )