@@ -165,6 +165,64 @@ def __init__(
165165
166166 self .should_render = should_render
167167
168+ def _assert_valid_submobjects (self , submobjects : Iterable [OpenGLMobject ]) -> Self :
169+ """Check that all submobjects are actually instances of
170+ :class:`OpenGLMobject`, and that none of them is
171+ ``self`` (an :class:`OpenGLMobject` cannot contain itself).
172+
173+ This is an auxiliary function called when adding OpenGLMobjects to the
174+ :attr:`submobjects` list.
175+
176+ This function is intended to be overridden by subclasses such as
177+ :class:`OpenGLVMobject`, which should assert that only other
178+ OpenGLVMobjects may be added into it.
179+
180+ Parameters
181+ ----------
182+ submobjects
183+ The list containing values to validate.
184+
185+ Returns
186+ -------
187+ :class:`OpenGLMobject`
188+ The OpenGLMobject itself.
189+
190+ Raises
191+ ------
192+ TypeError
193+ If any of the values in `submobjects` is not an
194+ :class:`OpenGLMobject`.
195+ ValueError
196+ If there was an attempt to add an :class:`OpenGLMobject` as its own
197+ submobject.
198+ """
199+ return self ._assert_valid_submobjects_internal (submobjects , OpenGLMobject )
200+
201+ def _assert_valid_submobjects_internal (
202+ self , submobjects : list [OpenGLMobject ], mob_class : type [OpenGLMobject ]
203+ ) -> Self :
204+ for i , submob in enumerate (submobjects ):
205+ if not isinstance (submob , mob_class ):
206+ error_message = (
207+ f"Only values of type { mob_class .__name__ } can be added "
208+ f"as submobjects of { type (self ).__name__ } , but the value "
209+ f"{ submob } (at index { i } ) is of type "
210+ f"{ type (submob ).__name__ } ."
211+ )
212+ # Intended for subclasses such as OpenGLVMobject, which
213+ # cannot have regular OpenGLMobjects as submobjects
214+ if isinstance (submob , OpenGLMobject ):
215+ error_message += (
216+ " You can try adding this value into a Group instead."
217+ )
218+ raise TypeError (error_message )
219+ if submob is self :
220+ raise ValueError (
221+ f"Cannot add { type (self ).__name__ } as a submobject of "
222+ f"itself (at index { i } )."
223+ )
224+ return self
225+
168226 @classmethod
169227 def __init_subclass__ (cls , ** kwargs ):
170228 super ().__init_subclass__ (** kwargs )
@@ -734,28 +792,33 @@ def add(
734792 >>> len(outer.submobjects)
735793 1
736794
795+ Only OpenGLMobjects can be added::
796+
797+ >>> outer.add(3)
798+ Traceback (most recent call last):
799+ ...
800+ TypeError: Only values of type OpenGLMobject can be added as submobjects of OpenGLMobject, but the value 3 (at index 0) is of type int.
801+
737802 Adding an object to itself raises an error::
738803
739804 >>> outer.add(outer)
740805 Traceback (most recent call last):
741806 ...
742- ValueError: OpenGLMobject cannot contain self
807+ ValueError: Cannot add OpenGLMobject as a submobject of itself (at index 0).
743808
744809 """
745810 if update_parent :
746811 assert len (mobjects ) == 1 , "Can't set multiple parents."
747812 mobjects [0 ].parent = self
748813
749- if self in mobjects :
750- raise ValueError ( "OpenGLMobject cannot contain self" )
814+ self . _assert_valid_submobjects ( mobjects )
815+
751816 if any (mobjects .count (elem ) > 1 for elem in mobjects ):
752817 logger .warning (
753818 "Attempted adding some Mobject as a child more than once, "
754819 "this is not possible. Repetitions are ignored." ,
755820 )
756821 for mobject in mobjects :
757- if not isinstance (mobject , OpenGLMobject ):
758- raise TypeError ("All submobjects must be of type OpenGLMobject" )
759822 if mobject not in self .submobjects :
760823 self .submobjects .append (mobject )
761824 if self not in mobject .parents :
@@ -784,11 +847,7 @@ def insert(self, index: int, mobject: OpenGLMobject, update_parent: bool = False
784847 if update_parent :
785848 mobject .parent = self
786849
787- if mobject is self :
788- raise ValueError ("OpenGLMobject cannot contain self" )
789-
790- if not isinstance (mobject , OpenGLMobject ):
791- raise TypeError ("All submobjects must be of type OpenGLMobject" )
850+ self ._assert_valid_submobjects ([mobject ])
792851
793852 if mobject not in self .submobjects :
794853 self .submobjects .insert (index , mobject )
@@ -880,10 +939,12 @@ def add_to_back(self, *mobjects: OpenGLMobject) -> OpenGLMobject:
880939 :meth:`add`
881940
882941 """
942+ self ._assert_valid_submobjects (mobjects )
883943 self .submobjects = list_update (mobjects , self .submobjects )
884944 return self
885945
886946 def replace_submobject (self , index , new_submob ):
947+ self ._assert_valid_submobjects ([new_submob ])
887948 old_submob = self .submobjects [index ]
888949 if self in old_submob .parents :
889950 old_submob .parents .remove (self )
@@ -2734,8 +2795,6 @@ def throw_error_if_no_points(self):
27342795
27352796class OpenGLGroup (OpenGLMobject ):
27362797 def __init__ (self , * mobjects , ** kwargs ):
2737- if not all (isinstance (m , OpenGLMobject ) for m in mobjects ):
2738- raise Exception ("All submobjects must be of type OpenGLMobject" )
27392798 super ().__init__ (** kwargs )
27402799 self .add (* mobjects )
27412800
0 commit comments