8000 BUG: Make sure numpy globals keep identity after reload. by charris · Pull Request #7941 · numpy/numpy · GitHub
[go: up one dir, main page]

Skip to content

BUG: Make sure numpy globals keep identity after reload. #7941

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 20, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 8 additions & 50 deletions numpy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,56 +109,8 @@
import sys
import warnings

# Disallow reloading numpy. Doing that does nothing to change previously
# loaded modules, which would need to be reloaded separately, but it does
# change the identity of the warnings and sentinal classes defined below
# with dire consequences when checking for identity.
if '_is_loaded' in globals():
raise RuntimeError('Reloading numpy is not supported')
_is_loaded = True


# Define some global warnings and the _NoValue sentinal. Defining them here
# means that their identity will change if numpy is reloaded, hence if that is
# to be allowed they should be moved into their own, non-reloadable module.
# Note that these should be defined (or imported) before the other imports.
class ModuleDeprecationWarning(DeprecationWarning):
"""Module deprecation warning.

The nose tester turns ordinary Deprecation warnings into test failures.
That makes it hard to deprecate whole modules, because they get
imported by default. So this is a special Deprecation warning that the
nose tester will let pass without making tests fail.

"""
pass


class VisibleDeprecationWarning(UserWarning):
"""Visible deprecation warning.

By default, python will not show deprecation warnings, so this class
can be used when a very visible warning is helpful, for example because
the usage is most likely a user bug.

"""
pass


class _NoValue:
"""Special keyword value.

This class may be used as the default value assigned to a deprecated
keyword in order to check if it has been given a user defined value.
"""
pass


# oldnumeric and numarray were removed in 1.9. In case some packages import
# but do not use them, we define them here for backward compatibility.
oldnumeric = 'removed'
numarray = 'removed'

from ._globals import ModuleDeprecationWarning, VisibleDeprecationWarning
from ._globals import _NoValue

# We first need to detect if we're being called as part of the numpy setup
# procedure itself in a reliable manner.
Expand All @@ -177,6 +129,7 @@ class _NoValue:
its source directory; please exit the numpy source tree, and relaunch
your python interpreter from there."""
raise ImportError(msg)

from .version import git_revision as __git_revision__
from .version import version as __version__

Expand Down Expand Up @@ -239,3 +192,8 @@ def pkgload(*packages, **options):
warnings.filterwarnings("ignore", message="numpy.dtype size changed")
warnings.filterwarnings("ignore", message="numpy.ufunc size changed")
warnings.filterwarnings("ignore", message="numpy.ndarray size changed")

# oldnumeric and numarray were removed in 1.9. In case some packages import
# but do not use them, we define them here for backward compatibility.
oldnumeric = 'removed'
numarray = 'removed'
62 changes: 62 additions & 0 deletions numpy/_globals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""
Module defining global singleton classes.

This module raises a RuntimeError if an attempt to reload it is made. In that
way the identities of the classes defined here are fixed and will remain so
even if numpy itself is reloaded. In particular, a function like the following
will still work correctly after numpy is reloaded::

def foo(arg=np._NoValue):
if arg is np._NoValue:
...

That was not the case when the singleton classes were defined in the numpy
``__init__.py`` file. See gh-7844 for a discussion of the reload problem that
motivated this module.

"""
from __future__ import division, absolute_import, print_function


__ALL__ = [
'ModuleDeprecationWarning', 'VisibleDeprecationWarning', '_NoValue'
]


# Disallow reloading this module so as to preserve the identities of the
# classes defined here.
if '_is_loaded' in globals():
raise RuntimeError('Reloading numpy._globals is not allowed')
_is_loaded = True


class ModuleDeprecationWarning(DeprecationWarning):
"""Module deprecation warning.

The nose tester turns ordinary Deprecation warnings into test failures.
That makes it hard to deprecate whole modules, because they get
imported by default. So this is a special Deprecation warning that the
nose tester will let pass without making tests fail.

"""
pass


class VisibleDeprecationWarning(UserWarning):
"""Visible deprecation warning.

By default, python will not show deprecation warnings, so this class
can be used when a very visible warning is helpful, for example because
the usage is most likely a user bug.

"""
pass


class _NoValue:
"""Special keyword value.

This class may be used as the default value assigned to a deprecated
keyword in order to check if it has been given a user defined value.
"""
pass
14 changes: 11 additions & 3 deletions numpy/tests/test_reloading.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,29 @@

import sys

import numpy as np
from numpy.testing import assert_raises, assert_, run_module_suite

if sys.version_info[:2] >= (3, 4):
from importlib import reload
else:
from imp import reload

def test_reloading_exception():
def test_numpy_reloading():
# gh-7844. Also check that relevant globals retain their identity.
import numpy as np
import numpy._globals

_NoValue = np._NoValue
VisibleDeprecationWarning = np.VisibleDeprecationWarning
ModuleDeprecationWarning = np.ModuleDeprecationWarning

assert_raises(RuntimeError, reload, np)
reload(np)
assert_(_NoValue is np._NoValue)
assert_(ModuleDeprecationWarning is np.ModuleDeprecationWarning)
assert_(VisibleDeprecationWarning is np.VisibleDeprecationWarning)

assert_raises(RuntimeError, reload, numpy._globals)
reload(np)
assert_(_NoValue is np._NoValue)
assert_(ModuleDeprecationWarning is np.ModuleDeprecationWarning)
assert_(VisibleDeprecationWarning is np.VisibleDeprecationWarning)
Expand Down
0