You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			65 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			65 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Python
		
	
# Copyright (c) Jupyter Development Team.
 | 
						|
# Distributed under the terms of the Modified BSD License.
 | 
						|
 | 
						|
from pathlib import Path
 | 
						|
import sys
 | 
						|
import inspect
 | 
						|
import warnings
 | 
						|
 | 
						|
def _get_frame(level):
 | 
						|
    """Get the frame at the given stack level."""
 | 
						|
    # sys._getframe is much faster than inspect.stack, but isn't guaranteed to
 | 
						|
    # exist in all python implementations, so we fall back to inspect.stack()
 | 
						|
 | 
						|
    # We need to add one to level to account for this get_frame call.
 | 
						|
    if hasattr(sys, '_getframe'):
 | 
						|
        frame = sys._getframe(level+1)
 | 
						|
    else:
 | 
						|
        frame = inspect.stack(context=0)[level+1].frame
 | 
						|
    return frame
 | 
						|
 | 
						|
 | 
						|
# This function is from https://github.com/python/cpython/issues/67998
 | 
						|
# (https://bugs.python.org/file39550/deprecated_module_stacklevel.diff) and
 | 
						|
# calculates the appropriate stacklevel for deprecations to target the
 | 
						|
# deprecation for the caller, no matter how many internal stack frames we have
 | 
						|
# added in the process. For example, with the deprecation warning in the
 | 
						|
# __init__ below, the appropriate stacklevel will change depending on how deep
 | 
						|
# the inheritance hierarchy is.
 | 
						|
def _external_stacklevel(internal):
 | 
						|
    """Find the stacklevel of the first frame that doesn't contain any of the given internal strings
 | 
						|
 | 
						|
    The depth will be 1 at minimum in order to start checking at the caller of
 | 
						|
    the function that called this utility method.
 | 
						|
    """
 | 
						|
    # Get the level of my caller's caller
 | 
						|
    level = 2
 | 
						|
    frame = _get_frame(level)
 | 
						|
 | 
						|
    # Normalize the path separators:
 | 
						|
    normalized_internal = [str(Path(s)) for s in internal]
 | 
						|
 | 
						|
    # climb the stack frames while we see internal frames
 | 
						|
    while frame and any(s in str(Path(frame.f_code.co_filename)) for s in normalized_internal):
 | 
						|
        level +=1
 | 
						|
        frame = frame.f_back
 | 
						|
 | 
						|
    # Return the stack level from the perspective of whoever called us (i.e., one level up)
 | 
						|
    return level-1
 | 
						|
 | 
						|
def deprecation(message, internal='ipywidgets/widgets/'):
 | 
						|
    """Generate a deprecation warning targeting the first frame that is not 'internal'
 | 
						|
    
 | 
						|
    internal is a string or list of strings, which if they appear in filenames in the
 | 
						|
    frames, the frames will be considered internal. Changing this can be useful if, for examnple,
 | 
						|
    we know that ipywidgets is calling out to traitlets internally.
 | 
						|
    """
 | 
						|
    if isinstance(internal, str):
 | 
						|
        internal = [internal]
 | 
						|
 | 
						|
    # stack level of the first external frame from here
 | 
						|
    stacklevel = _external_stacklevel(internal)
 | 
						|
 | 
						|
    # The call to .warn adds one frame, so bump the stacklevel up by one
 | 
						|
    warnings.warn(message, DeprecationWarning, stacklevel=stacklevel+1)
 |