@rbac(('owner', 'user'))
    def get_trait_typenames(self, pathname, iotype=None):
        """Return names of the 'final' type (bypassing passthrough traits)
        for `pathname` using :meth:`get_dyn_trait`. Used by dynamic wrappers
        to determine the type of variable to wrap. The returned list is a
        depth-first traversal of the class hierarchy.

        pathname: str
            Pathname of the desired trait. May contain dots.

        iotype: str (optional)
            Expected iotype of the trait.
        """
        if not pathname:
            obj = self
        else:
            trait = self.get_dyn_trait(pathname, iotype=iotype)
            if trait is None:
                return []

            trait = trait.trait_type or trait.trait or trait
            if trait.target:  # PassthroughTrait, PassthroughProperty
                trait = self.get_dyn_trait(trait.target)
                try:
                    ttype = trait.trait_type
                except __HOLE__:
                    pass
                else:
                    if ttype is not None:
                        trait = ttype

            if isinstance(trait, Python):  # Container
                obj = self.get(pathname)
            else:  # Variable
                obj = trait

        names = []
        Container._bases(type(obj), names)
        return names
dataset/ETHPy150Open OpenMDAO/OpenMDAO-Framework/openmdao.main/src/openmdao/main/container.py/Container.get_trait_typenames