@@ -293,6 +293,39 @@ def is_implicitely_exported(self) -> bool:
293293 """
294294 return self .parent .exports is None # type: ignore[attr-defined]
295295
296+ def is_public (
297+ self ,
298+ * ,
299+ strict : bool = False ,
300+ check_name : bool = True ,
301+ ) -> bool :
302+ """Whether this object is considered public.
303+
304+ In modules, developers can mark objects as public thanks to the `__all__` variable.
305+ In classes however, there is no convention or standard to do so.
306+
307+ Therefore, to decide whether an object is public, we follow this algorithm:
308+
309+ - If the object's `public` attribute is set (boolean), return its value.
310+ - In strict mode, the object is public only if it is explicitely exported (listed in `__all__`).
311+ Strict mode should only be used for module members.
312+ - Otherwise, if name checks are enabled, the object is private if its name starts with an underscore.
313+ - Otherwise, if the object is an alias, and is neither inherited from a base class,
314+ nor a member of a parent alias, it is not public.
315+ - Otherwise, the object is public.
316+ """
317+ if self .public is not None : # type: ignore[attr-defined]
318+ return self .public # type: ignore[attr-defined]
319+ if self .is_explicitely_exported :
320+ return True
321+ if strict :
322+ return False
323+ if check_name and self .name .startswith ("_" ): # type: ignore[attr-defined]
324+ return False
325+ if self .is_alias and not (self .inherited or self .parent .is_alias ): # type: ignore[attr-defined]
326+ return False
327+ return True
328+
296329
297330class SerializationMixin :
298331 """A mixin that adds de/serialization conveniences."""
0 commit comments