Skip to content

Commit

Permalink
ENH: Set __module__ attribute on exported functions (Fixes #968)
Browse files Browse the repository at this point in the history
This causes the functions to show up under the proper namespace, rather
than the original module, when printed in IPython/notebook.
  • Loading branch information
dopplershift committed Jun 21, 2021
1 parent 4acc25b commit fe0a7f9
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 1 deletion.
3 changes: 3 additions & 0 deletions src/metpy/calc/__init__.py
Expand Up @@ -10,6 +10,7 @@
from .thermo import * # noqa: F403
from .tools import * # noqa: F403
from .turbulence import * # noqa: F403
from ..package_tools import set_module

__all__ = basic.__all__[:] # pylint: disable=undefined-variable
__all__.extend(cross_sections.__all__) # pylint: disable=undefined-variable
Expand All @@ -18,3 +19,5 @@
__all__.extend(thermo.__all__) # pylint: disable=undefined-variable
__all__.extend(tools.__all__) # pylint: disable=undefined-variable
__all__.extend(turbulence.__all__) # pylint: disable=undefined-variable

set_module(globals())
3 changes: 3 additions & 0 deletions src/metpy/interpolate/__init__.py
Expand Up @@ -8,9 +8,12 @@
from .points import * # noqa: F403
from .slices import * # noqa: F403
from .tools import * # noqa: F403
from ..package_tools import set_module

__all__ = grid.__all__[:] # pylint: disable=undefined-variable
__all__.extend(one_dimension.__all__) # pylint: disable=undefined-variable
__all__.extend(points.__all__) # pylint: disable=undefined-variable
__all__.extend(slices.__all__) # pylint: disable=undefined-variable
__all__.extend(tools.__all__) # pylint: disable=undefined-variable

set_module(globals())
3 changes: 3 additions & 0 deletions src/metpy/io/__init__.py
Expand Up @@ -11,7 +11,10 @@
from .gini import * # noqa: F403
from .metar import * # noqa: F403
from .nexrad import * # noqa: F403
from ..package_tools import set_module
from .station_data import * # noqa: F403

__all__ = gini.__all__[:] # pylint: disable=undefined-variable
__all__.extend(nexrad.__all__) # pylint: disable=undefined-variable

set_module(globals())
24 changes: 23 additions & 1 deletion src/metpy/package_tools.py
@@ -1,4 +1,4 @@
# Copyright (c) 2015,2019 MetPy Developers.
# Copyright (c) 2015,2018,2019 MetPy Developers.
# Distributed under the terms of the BSD 3-Clause License.
# SPDX-License-Identifier: BSD-3-Clause
"""Collection of tools for managing the package."""
Expand Down Expand Up @@ -37,3 +37,25 @@ def __exit__(self, exc_type, exc_val, exc_tb):
"""Exit the instance tracking block."""
self.exports.extend(set(self.globls) - self.start_vars)
del self.start_vars


def set_module(globls):
"""Set the module for all functions in ``__all__``.
This sets the ``__module__`` attribute of all items within the ``__all__`` list
for the calling module.
This supports our hoisting of functions out of individual modules, which are
considered implementation details, into the namespace of the top-level subpackage.
Parameters
----------
globls : Dict[str, object]
Mapping of all global variables for the module. This contains all needed
python special ("dunder") variables needed to be modified.
"""
for item in globls['__all__']:
obj = globls[item]
if hasattr(obj, '__module__'):
obj.__module__ = globls['__name__']
3 changes: 3 additions & 0 deletions src/metpy/plots/__init__.py
Expand Up @@ -14,6 +14,7 @@
from .skewt import * # noqa: F403
from .station_plot import * # noqa: F403
from .wx_symbols import * # noqa: F403
from ..package_tools import set_module

logger = logging.getLogger(__name__)

Expand All @@ -29,3 +30,5 @@
__all__.extend(['USCOUNTIES', 'USSTATES'])
except ImportError:
logger.warning('Cannot import USCOUNTIES and USSTATES without Cartopy installed.')

set_module(globals())
17 changes: 17 additions & 0 deletions tests/units/test_packaging.py
@@ -0,0 +1,17 @@
# Copyright (c) 2018 MetPy Developers.
# Distributed under the terms of the BSD 3-Clause License.
# SPDX-License-Identifier: BSD-3-Clause
"""Test packaging details."""

from metpy.calc import tke
from metpy.interpolate import interpolate
from metpy.io import Level2File
from metpy.plots import StationPlot


def test_modules_set():
"""Test that functions from each subpackage have correct module set."""
assert Level2File.__module__ == 'metpy.io'
assert StationPlot.__module__ == 'metpy.plots'
assert interpolate.__module__ == 'metpy.interpolate'
assert tke.__module__ == 'metpy.calc'

0 comments on commit fe0a7f9

Please sign in to comment.