#-----------------------------------------------------------------------------# Copyright (c) Anaconda, Inc., and Bokeh Contributors.# All rights reserved.## The full license is in the file LICENSE.txt, distributed with this software.#-----------------------------------------------------------------------------''''''#-----------------------------------------------------------------------------# Boilerplate#-----------------------------------------------------------------------------from__future__importannotationsimportlogging# isort:skiplog=logging.getLogger(__name__)#-----------------------------------------------------------------------------# Imports#-----------------------------------------------------------------------------# Standard library importsimportosimportsysfromos.pathimport(basename,dirname,join,splitext,)fromtempfileimportNamedTemporaryFile#-----------------------------------------------------------------------------# Globals and constants#-----------------------------------------------------------------------------__all__=('default_filename','detect_current_filename','temp_filename',)#-----------------------------------------------------------------------------# General API#-----------------------------------------------------------------------------#-----------------------------------------------------------------------------# Dev API#-----------------------------------------------------------------------------
[docs]defdefault_filename(ext:str)->str:''' Generate a default filename with a given extension, attempting to use the filename of the currently running process, if possible. If the filename of the current process is not available (or would not be writable), then a temporary file with the given extension is returned. Args: ext (str) : the desired extension for the filename Returns: str Raises: RuntimeError If the extensions requested is ".py" '''ifext=="py":raiseRuntimeError("asked for a default filename with 'py' extension")filename=detect_current_filename()iffilenameisNone:returntemp_filename(ext)basedir=dirname(filename)oros.getcwd()if_no_access(basedir)or_shares_exec_prefix(basedir):returntemp_filename(ext)name,_=splitext(basename(filename))returnjoin(basedir,name+"."+ext)
[docs]defdetect_current_filename()->str|None:''' Attempt to return the filename of the currently running Python process Returns None if the filename cannot be detected. '''importinspectfilename=Noneframe=inspect.currentframe()ifframeisnotNone:try:whileframe.f_backandframe.f_globals.get('name')!='__main__':frame=frame.f_backfilename=frame.f_globals.get('__file__')finally:delframereturnfilename
[docs]deftemp_filename(ext:str)->str:''' Generate a temporary, writable filename with the given extension '''# todo: not safe - the file is deleted before being written to so another# process can generate the same filenamewithNamedTemporaryFile(suffix="."+ext)asf:returnf.name
#-----------------------------------------------------------------------------# Private API#-----------------------------------------------------------------------------def_no_access(basedir:str)->bool:''' Return True if the given base dir is not accessible or writeable '''returnnotos.access(basedir,os.W_OK|os.X_OK)def_shares_exec_prefix(basedir:str)->bool:''' Whether a give base directory is on the system exex prefix '''# XXX: exec_prefix has type str so why the check?prefix:str|None=sys.exec_prefixreturnprefixisnotNoneandbasedir.startswith(prefix)#-----------------------------------------------------------------------------# Code#-----------------------------------------------------------------------------