141 lines
4.4 KiB
Python
141 lines
4.4 KiB
Python
# Copyright (c) 2009- Spyder Kernels Contributors
|
|
#
|
|
# Licensed under the terms of the MIT License
|
|
# (see spyder_kernels/__init__.py for details)
|
|
|
|
"""Utility functions."""
|
|
|
|
import ast
|
|
import os
|
|
import re
|
|
import sys
|
|
import sysconfig
|
|
|
|
|
|
def create_pathlist():
|
|
"""
|
|
Create list of Python library paths to be skipped from module
|
|
reloading and Pdb steps.
|
|
"""
|
|
# Get standard installation paths
|
|
try:
|
|
paths = sysconfig.get_paths()
|
|
standard_paths = [paths['stdlib'],
|
|
paths['purelib'],
|
|
paths['scripts'],
|
|
paths['data']]
|
|
except Exception:
|
|
standard_paths = []
|
|
|
|
# Get user installation path
|
|
# See spyder-ide/spyder#8776
|
|
try:
|
|
import site
|
|
if getattr(site, 'getusersitepackages', False):
|
|
# Virtualenvs don't have this function but
|
|
# conda envs do
|
|
user_path = [site.getusersitepackages()]
|
|
elif getattr(site, 'USER_SITE', False):
|
|
# However, it seems virtualenvs have this
|
|
# constant
|
|
user_path = [site.USER_SITE]
|
|
else:
|
|
user_path = []
|
|
except Exception:
|
|
user_path = []
|
|
|
|
return standard_paths + user_path
|
|
|
|
|
|
def path_is_library(path, initial_pathlist=None):
|
|
"""Decide if a path is in user code or a library according to its path."""
|
|
# Compute DEFAULT_PATHLIST only once and make it global to reuse it
|
|
# in any future call of this function.
|
|
if 'DEFAULT_PATHLIST' not in globals():
|
|
global DEFAULT_PATHLIST
|
|
DEFAULT_PATHLIST = create_pathlist()
|
|
|
|
if initial_pathlist is None:
|
|
initial_pathlist = []
|
|
|
|
pathlist = initial_pathlist + DEFAULT_PATHLIST
|
|
|
|
if path is None:
|
|
# Path probably comes from a C module that is statically linked
|
|
# into the interpreter. There is no way to know its path, so we
|
|
# choose to ignore it.
|
|
return True
|
|
elif any([p in path for p in pathlist]):
|
|
# We don't want to consider paths that belong to the standard
|
|
# library or installed to site-packages.
|
|
return True
|
|
elif os.name == 'nt':
|
|
if re.search(r'.*\\pkgs\\.*', path):
|
|
return True
|
|
else:
|
|
return False
|
|
elif not os.name == 'nt':
|
|
# Paths containing the strings below can be part of the default
|
|
# Linux installation, Homebrew or the user site-packages in a
|
|
# virtualenv.
|
|
patterns = [
|
|
r'^/usr/lib.*',
|
|
r'^/usr/local/lib.*',
|
|
r'^/usr/.*/dist-packages/.*',
|
|
r'^/home/.*/.local/lib.*',
|
|
r'^/Library/.*',
|
|
r'^/Users/.*/Library/.*',
|
|
r'^/Users/.*/.local/.*',
|
|
]
|
|
|
|
if [p for p in patterns if re.search(p, path)]:
|
|
return True
|
|
else:
|
|
return False
|
|
else:
|
|
return False
|
|
|
|
|
|
def capture_last_Expr(code_ast, out_varname):
|
|
"""Parse line and modify code to capture in globals the last expression."""
|
|
# Modify ast code to capture the last expression
|
|
capture_last_expression = False
|
|
if (
|
|
len(code_ast.body)
|
|
and isinstance(code_ast.body[-1], ast.Expr)
|
|
):
|
|
capture_last_expression = True
|
|
expr_node = code_ast.body[-1]
|
|
# Create new assign node
|
|
assign_node = ast.parse(
|
|
'globals()[{}] = None'.format(repr(out_varname))).body[0]
|
|
# Replace None by the value
|
|
assign_node.value = expr_node.value
|
|
# Fix line number and column offset
|
|
assign_node.lineno = expr_node.lineno
|
|
assign_node.col_offset = expr_node.col_offset
|
|
if sys.version_info[:2] >= (3, 8):
|
|
# Exists from 3.8, necessary from 3.11
|
|
assign_node.end_lineno = expr_node.end_lineno
|
|
if assign_node.lineno == assign_node.end_lineno:
|
|
# Add 'globals()[{}] = ' and remove 'None'
|
|
assign_node.end_col_offset += expr_node.end_col_offset - 4
|
|
else:
|
|
assign_node.end_col_offset = expr_node.end_col_offset
|
|
code_ast.body[-1] = assign_node
|
|
return code_ast, capture_last_expression
|
|
|
|
|
|
def canonic(filename):
|
|
"""
|
|
Return canonical form of filename.
|
|
|
|
This is a copy of bdb.canonic, so that the debugger will process
|
|
filenames in the same way
|
|
"""
|
|
if filename == "<" + filename[1:-1] + ">":
|
|
return filename
|
|
canonic = os.path.abspath(filename)
|
|
canonic = os.path.normcase(canonic)
|
|
return canonic
|