@@ -299,6 +299,11 @@ def has_private_name(self) -> bool:
299
299
"""Whether this object/alias has a private name."""
300
300
return self .name .startswith ("_" ) # type: ignore[attr-defined]
301
301
302
+ @property
303
+ def has_special_name (self ) -> bool :
304
+ """Whether this object/alias has a special name."""
305
+ return self .name .startswith ("__" ) and self .name .endswith ("__" ) # type: ignore[attr-defined]
306
+
302
307
@property
303
308
def is_exported (self ) -> bool :
304
309
"""Whether this object/alias is exported (listed in `__all__`)."""
@@ -365,18 +370,30 @@ def is_public(self) -> bool:
365
370
- Otherwise, the object is public.
366
371
"""
367
372
# TODO: Return regular True/False values in next version.
373
+
374
+ # Give priority to the `public` attribute if it is set.
368
375
if self .public is not None : # type: ignore[attr-defined]
369
376
return _True if self .public else _False # type: ignore[return-value,attr-defined]
377
+
378
+ # If the object is defined at the module-level and is listed in `__all__`, it is public.
379
+ # If the parent module defines `__all__` but does not list the object, it is private.
370
380
if self .parent and self .parent .is_module and bool (self .parent .exports ): # type: ignore[attr-defined]
371
381
return _True if self .name in self .parent .exports else _False # type: ignore[attr-defined,return-value]
372
- if self .has_private_name :
382
+
383
+ # Special objects are always considered public.
384
+ # Even if we don't access them directly, they are used through different *public* means
385
+ # like instantiating classes (`__init__`), using operators (`__eq__`), etc..
386
+ if self .has_private_name and not self .has_special_name :
373
387
return _False # type: ignore[return-value]
374
- # The following condition effectively filters out imported objects.
388
+
375
389
# TODO: In a future version, we will support two conventions regarding imports:
376
390
# - `from a import x as x` marks `x` as public.
377
391
# - `from a import *` marks all wildcard imported objects as public.
392
+ # The following condition effectively filters out imported objects.
378
393
if self .is_alias and not (self .inherited or (self .parent and self .parent .is_alias )): # type: ignore[attr-defined]
379
394
return _False # type: ignore[return-value]
395
+
396
+ # If we reached this point, the object is public.
380
397
return _True # type: ignore[return-value]
381
398
382
399
0 commit comments