Skip to content

Commit

Permalink
Don't hide submodules explicitly, use __dir__()
Browse files Browse the repository at this point in the history
We hid submodules at the top-level katpoint namespace to aid IPython
tab completion, since it is confusing to see both the "target"
submodule and the preferred "Target" class in the list. This was done
by adding underscores to their names.

The downside is that it becomes yucky to import submodules to access
internals in the unit tests (and the module can't be reloaded FWIW).

Don't rename the submodules but cull their names from __all__ and the
output of __dir__() instead. IPython has a love/hate relationship with
__all__ (see e.g. ipython/ipykernel#129) and it is currently completely
ignored. The newer and shinier __dir__() in Python 3.7 (PEP 562) is
respected though. Customise both for good measure.

Instead of hiding submodules individually by name, cull all submodules
as a group, as well as variables starting with an underscore (except
__version__). It would have been nice to sort the output of __dir__()
in groups (say classes followed by functions etc) but that is
undermined by IPython, which simply sorts everything again at the end.
  • Loading branch information
ludwigschwardt committed Oct 19, 2020
1 parent 1685c04 commit ed7e8b9
Showing 1 changed file with 12 additions and 13 deletions.
25 changes: 12 additions & 13 deletions katpoint/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"""

import logging as _logging
from types import ModuleType as _ModuleType

import numpy as _np

Expand All @@ -52,19 +53,6 @@ def wrap_angle(angle, period=2.0 * _np.pi):
return (angle + 0.5 * period) % period - 0.5 * period


# Hide submodules in module namespace, to avoid confusion with corresponding class names
# If the module is reloaded, this will fail - ignore the resulting NameError
try:
_target, _antenna, _timestamp, _flux, _catalogue, _ephem_extra, \
_conversion, _projection, _pointing, _refraction, _delay = \
target, antenna, timestamp, flux, catalogue, ephem_extra, \
conversion, projection, pointing, refraction, delay
del target, antenna, timestamp, flux, catalogue, ephem_extra, \
conversion, projection, pointing, refraction, delay
except NameError:
pass


# Setup library logger and add a print-like handler used when no logging is configured
class _NoConfigFilter(_logging.Filter):
"""Filter which only allows event if top-level logging is not configured."""
Expand All @@ -79,6 +67,17 @@ def filter(self, record):
logger = _logging.getLogger(__name__)
logger.addHandler(_no_config_handler)

# Document the public API in __all__ / __dir__ by discarding modules and private variables
__all__ = [n for n, o in globals().items()
if not isinstance(o, _ModuleType) and not n.startswith('_')]
__all__ += ['__version__']


def __dir__():
"""IPython tab completion seems to respect this."""
return __all__


# BEGIN VERSION CHECK
# Get package version when locally imported from repo or via -e develop install
try:
Expand Down

0 comments on commit ed7e8b9

Please sign in to comment.