Add a list of (name, mdef) tuples.

        A model definition (mdef) is structured as follows::

            {
                "ctors":(
                    ('name', 'class.path.ctor', {}, {'doc': 'The foo thing.'}),
                ),

                "types":(
                    ('name', ('basetype', {typeopts}), {info}),
                ),

                "forms":(
                    (formname, (typename, typeopts), {info}, (
                        (propname, (typename, typeopts), {info}),
                    )),
                ),
                "univs":(
                    (propname, (typename, typeopts), {info}),
                )
            }

        Args:
            mods (list):  The list of tuples.

        Returns:
            None

def addDataModels(self, mods):
        '''
        Add a list of (name, mdef) tuples.

        A model definition (mdef) is structured as follows::

            {
                "ctors":(
                    ('name', 'class.path.ctor', {}, {'doc': 'The foo thing.'}),
                ),

                "types":(
                    ('name', ('basetype', {typeopts}), {info}),
                ),

                "forms":(
                    (formname, (typename, typeopts), {info}, (
                        (propname, (typename, typeopts), {info}),
                    )),
                ),
                "univs":(
                    (propname, (typename, typeopts), {info}),
                )
            }

        Args:
            mods (list):  The list of tuples.

        Returns:
            None

        '''

        # load all the base type ctors in order...
        for modlname, mdef in mods:

            for name, ctor, opts, info in mdef.get('ctors', ()):
                item = s_dyndeps.tryDynFunc(ctor, self, name, info, opts)
                self.types[name] = item
                self._modeldef['ctors'].append((name, ctor, opts, info))

        # load all the types in order...
        for modlname, mdef in mods:

            for typename, (basename, opts), info in mdef.get('types', ()):

                base = self.types.get(basename)
                if base is None:
                    raise s_exc.NoSuchType(name=basename)

                self.types[typename] = base.extend(typename, opts, info)
                self._modeldef['types'].append((typename, (basename, opts), info))

        # Load all the universal properties
        for modlname, mdef in mods:
            for univname, typedef, univinfo in mdef.get('univs', ()):
                self.addUnivProp(univname, typedef, univinfo)

        # now we can load all the forms...
        for modlname, mdef in mods:

            for formname, forminfo, propdefs in mdef.get('forms', ()):

                if not s_syntax.isFormName(formname):
                    mesg = f'Invalid form name {formname}'
                    raise s_exc.BadFormDef(name=formname, mesg=mesg)

                _type = self.types.get(formname)
                if _type is None:
                    raise s_exc.NoSuchType(name=formname)

                self._modeldef['forms'].append((formname, forminfo, propdefs))

                form = Form(self, formname, forminfo)

                self.forms[formname] = form
                self.props[formname] = form

                for univname, typedef, univinfo in self.univs:
                    self._addFormUniv(form, univname, typedef, univinfo)

                for propdef in propdefs:

                    if len(propdef) != 3:
                        raise s_exc.BadPropDef(valu=propdef)

                    propname, typedef, propinfo = propdef

                    prop = Prop(self, form, propname, typedef, propinfo)

                    full = f'{formname}:{propname}'
                    self.props[full] = prop
                    self.props[(formname, propname)] = prop

        self._modelinfo.addDataModels(mods)