utils.py
184 lines
| 5.3 KiB
| text/x-python
|
PythonLexer
|
r19005 | """Notebook related utilities""" | ||
|
r10642 | |||
|
r19005 | # Copyright (c) IPython Development Team. | ||
# Distributed under the terms of the Modified BSD License. | ||||
|
r10642 | |||
|
r15097 | from __future__ import print_function | ||
|
r21155 | import errno | ||
|
r13054 | import os | ||
|
r15097 | import stat | ||
|
r21155 | import sys | ||
|
r21175 | from distutils.version import LooseVersion | ||
|
r15097 | |||
|
r13389 | try: | ||
from urllib.parse import quote, unquote | ||||
except ImportError: | ||||
from urllib import quote, unquote | ||||
|
r13054 | |||
|
r13131 | from IPython.utils import py3compat | ||
|
r15097 | # UF_HIDDEN is a stat flag not defined in the stat module. | ||
# It is used by BSD to indicate hidden files. | ||||
UF_HIDDEN = getattr(stat, 'UF_HIDDEN', 32768) | ||||
|
r10642 | |||
def url_path_join(*pieces): | ||||
"""Join components of url into a relative url | ||||
Use to prevent double slash when joining subpath. This will leave the | ||||
initial and final / in place | ||||
""" | ||||
initial = pieces[0].startswith('/') | ||||
final = pieces[-1].endswith('/') | ||||
|
r13054 | stripped = [s.strip('/') for s in pieces] | ||
result = '/'.join(s for s in stripped if s) | ||||
|
r10642 | if initial: result = '/' + result | ||
if final: result = result + '/' | ||||
|
r10644 | if result == '//': result = '/' | ||
|
r10642 | return result | ||
|
r13054 | |||
def path2url(path): | ||||
"""Convert a local file path to a URL""" | ||||
|
r13182 | pieces = [ quote(p) for p in path.split(os.sep) ] | ||
|
r13054 | # preserve trailing / | ||
if pieces[-1] == '': | ||||
pieces[-1] = '/' | ||||
url = url_path_join(*pieces) | ||||
return url | ||||
def url2path(url): | ||||
"""Convert a URL to a local file path""" | ||||
pieces = [ unquote(p) for p in url.split('/') ] | ||||
path = os.path.join(*pieces) | ||||
return path | ||||
|
r13068 | def url_escape(path): | ||
"""Escape special characters in a URL path | ||||
Turns '/foo bar/' into '/foo%20bar/' | ||||
""" | ||||
|
r19922 | parts = py3compat.unicode_to_str(path, encoding='utf8').split('/') | ||
|
r13131 | return u'/'.join([quote(p) for p in parts]) | ||
|
r13068 | |||
def url_unescape(path): | ||||
"""Unescape special characters in a URL path | ||||
Turns '/foo%20bar/' into '/foo bar/' | ||||
""" | ||||
|
r13131 | return u'/'.join([ | ||
|
r19922 | py3compat.str_to_unicode(unquote(p), encoding='utf8') | ||
for p in py3compat.unicode_to_str(path, encoding='utf8').split('/') | ||||
|
r13131 | ]) | ||
|
r13068 | |||
|
r15108 | def is_hidden(abs_path, abs_root=''): | ||
|
r15420 | """Is a file hidden or contained in a hidden directory? | ||
|
r15097 | |||
|
r15108 | This will start with the rightmost path element and work backwards to the | ||
given root to see if a path is hidden or in a hidden directory. Hidden is | ||||
determined by either name starting with '.' or the UF_HIDDEN flag as | ||||
reported by stat. | ||||
|
r15097 | |||
Parameters | ||||
---------- | ||||
|
r15108 | abs_path : unicode | ||
The absolute path to check for hidden directories. | ||||
abs_root : unicode | ||||
The absolute path of the root directory in which hidden directories | ||||
|
r15109 | should be checked for. | ||
|
r15097 | """ | ||
|
r15108 | if not abs_root: | ||
abs_root = abs_path.split(os.sep, 1)[0] + os.sep | ||||
inside_root = abs_path[len(abs_root):] | ||||
|
r15097 | if any(part.startswith('.') for part in inside_root.split(os.sep)): | ||
return True | ||||
|
r15904 | |||
# check that dirs can be listed | ||||
# may fail on Windows junctions or non-user-readable dirs | ||||
if os.path.isdir(abs_path): | ||||
try: | ||||
os.listdir(abs_path) | ||||
except OSError: | ||||
return True | ||||
|
r15097 | |||
# check UF_HIDDEN on any location up to root | ||||
|
r15108 | path = abs_path | ||
while path and path.startswith(abs_root) and path != abs_root: | ||||
|
r17537 | if not os.path.exists(path): | ||
path = os.path.dirname(path) | ||||
continue | ||||
|
r15810 | try: | ||
# may fail on Windows junctions | ||||
st = os.stat(path) | ||||
|
r15904 | except OSError: | ||
|
r15810 | return True | ||
|
r15097 | if getattr(st, 'st_flags', 0) & UF_HIDDEN: | ||
return True | ||||
path = os.path.dirname(path) | ||||
return False | ||||
|
r15420 | def to_os_path(path, root=''): | ||
"""Convert an API path to a filesystem path | ||||
If given, root will be prepended to the path. | ||||
root must be a filesystem path already. | ||||
""" | ||||
parts = path.strip('/').split('/') | ||||
parts = [p for p in parts if p != ''] # remove duplicate splits | ||||
path = os.path.join(root, *parts) | ||||
return path | ||||
|
r19005 | |||
def to_api_path(os_path, root=''): | ||||
"""Convert a filesystem path to an API path | ||||
|
r15420 | |||
|
r19005 | If given, root will be removed from the path. | ||
root must be a filesystem path already. | ||||
""" | ||||
if os_path.startswith(root): | ||||
os_path = os_path[len(root):] | ||||
parts = os_path.strip(os.path.sep).split(os.path.sep) | ||||
parts = [p for p in parts if p != ''] # remove duplicate splits | ||||
path = '/'.join(parts) | ||||
return path | ||||
|
r21155 | |||
|
r21175 | def check_version(v, check): | ||
"""check version string v >= check | ||||
If dev/prerelease tags result in TypeError for string-number comparison, | ||||
it is assumed that the dependency is satisfied. | ||||
Users on dev branches are responsible for keeping their own packages up to date. | ||||
""" | ||||
try: | ||||
return LooseVersion(v) >= LooseVersion(check) | ||||
except TypeError: | ||||
return True | ||||
|
r21155 | # Copy of IPython.utils.process.check_pid: | ||
def _check_pid_win32(pid): | ||||
import ctypes | ||||
# OpenProcess returns 0 if no such process (of ours) exists | ||||
# positive int otherwise | ||||
return bool(ctypes.windll.kernel32.OpenProcess(1,0,pid)) | ||||
def _check_pid_posix(pid): | ||||
"""Copy of IPython.utils.pro""" | ||||
try: | ||||
os.kill(pid, 0) | ||||
except OSError as err: | ||||
if err.errno == errno.ESRCH: | ||||
return False | ||||
elif err.errno == errno.EPERM: | ||||
# Don't have permission to signal the process - probably means it exists | ||||
return True | ||||
raise | ||||
else: | ||||
return True | ||||
if sys.platform == 'win32': | ||||
check_pid = _check_pid_win32 | ||||
else: | ||||
check_pid = _check_pid_posix | ||||