##// END OF EJS Templates
Merge pull request #12612 from jpavlav/pathlib_everywhere
Matthias Bussonnier -
r26139:3fdf4743 merge
parent child Browse files
Show More
@@ -1,104 +1,105 b''
1 """Implementation of packaging-related magic functions.
1 """Implementation of packaging-related magic functions.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2018 The IPython Development Team.
4 # Copyright (c) 2018 The IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 import re
11 import re
12 import shlex
12 import shlex
13 import sys
13 import sys
14 from pathlib import Path
14
15
15 from pathlib import Path
16 from pathlib import Path
16 from IPython.core.magic import Magics, magics_class, line_magic
17 from IPython.core.magic import Magics, magics_class, line_magic
17
18
18
19
19 def _is_conda_environment():
20 def _is_conda_environment():
20 """Return True if the current Python executable is in a conda env"""
21 """Return True if the current Python executable is in a conda env"""
21 # TODO: does this need to change on windows?
22 # TODO: does this need to change on windows?
22 return Path(sys.prefix, "conda-meta", "history").exists()
23 return Path(sys.prefix, "conda-meta", "history").exists()
23
24
24
25
25 def _get_conda_executable():
26 def _get_conda_executable():
26 """Find the path to the conda executable"""
27 """Find the path to the conda executable"""
27 # Check if there is a conda executable in the same directory as the Python executable.
28 # Check if there is a conda executable in the same directory as the Python executable.
28 # This is the case within conda's root environment.
29 # This is the case within conda's root environment.
29 conda = Path(sys.executable).parent / "conda"
30 conda = Path(sys.executable).parent / "conda"
30 if conda.isfile():
31 if conda.isfile():
31 return str(conda)
32 return str(conda)
32
33
33 # Otherwise, attempt to extract the executable from conda history.
34 # Otherwise, attempt to extract the executable from conda history.
34 # This applies in any conda environment.
35 # This applies in any conda environment.
35 history = Path(sys.prefix, "conda-meta", "history").read_text()
36 history = Path(sys.prefix, "conda-meta", "history").read_text()
36 match = re.search(
37 match = re.search(
37 r"^#\s*cmd:\s*(?P<command>.*conda)\s[create|install]",
38 r"^#\s*cmd:\s*(?P<command>.*conda)\s[create|install]",
38 history,
39 history,
39 flags=re.MULTILINE,
40 flags=re.MULTILINE,
40 )
41 )
41 if match:
42 if match:
42 return match.groupdict()["command"]
43 return match.groupdict()["command"]
43
44
44 # Fallback: assume conda is available on the system path.
45 # Fallback: assume conda is available on the system path.
45 return "conda"
46 return "conda"
46
47
47
48
48 CONDA_COMMANDS_REQUIRING_PREFIX = {
49 CONDA_COMMANDS_REQUIRING_PREFIX = {
49 'install', 'list', 'remove', 'uninstall', 'update', 'upgrade',
50 'install', 'list', 'remove', 'uninstall', 'update', 'upgrade',
50 }
51 }
51 CONDA_COMMANDS_REQUIRING_YES = {
52 CONDA_COMMANDS_REQUIRING_YES = {
52 'install', 'remove', 'uninstall', 'update', 'upgrade',
53 'install', 'remove', 'uninstall', 'update', 'upgrade',
53 }
54 }
54 CONDA_ENV_FLAGS = {'-p', '--prefix', '-n', '--name'}
55 CONDA_ENV_FLAGS = {'-p', '--prefix', '-n', '--name'}
55 CONDA_YES_FLAGS = {'-y', '--y'}
56 CONDA_YES_FLAGS = {'-y', '--y'}
56
57
57
58
58 @magics_class
59 @magics_class
59 class PackagingMagics(Magics):
60 class PackagingMagics(Magics):
60 """Magics related to packaging & installation"""
61 """Magics related to packaging & installation"""
61
62
62 @line_magic
63 @line_magic
63 def pip(self, line):
64 def pip(self, line):
64 """Run the pip package manager within the current kernel.
65 """Run the pip package manager within the current kernel.
65
66
66 Usage:
67 Usage:
67 %pip install [pkgs]
68 %pip install [pkgs]
68 """
69 """
69 self.shell.system(' '.join([sys.executable, '-m', 'pip', line]))
70 self.shell.system(' '.join([sys.executable, '-m', 'pip', line]))
70 print("Note: you may need to restart the kernel to use updated packages.")
71 print("Note: you may need to restart the kernel to use updated packages.")
71
72
72 @line_magic
73 @line_magic
73 def conda(self, line):
74 def conda(self, line):
74 """Run the conda package manager within the current kernel.
75 """Run the conda package manager within the current kernel.
75
76
76 Usage:
77 Usage:
77 %conda install [pkgs]
78 %conda install [pkgs]
78 """
79 """
79 if not _is_conda_environment():
80 if not _is_conda_environment():
80 raise ValueError("The python kernel does not appear to be a conda environment. "
81 raise ValueError("The python kernel does not appear to be a conda environment. "
81 "Please use ``%pip install`` instead.")
82 "Please use ``%pip install`` instead.")
82
83
83 conda = _get_conda_executable()
84 conda = _get_conda_executable()
84 args = shlex.split(line)
85 args = shlex.split(line)
85 command = args[0]
86 command = args[0]
86 args = args[1:]
87 args = args[1:]
87 extra_args = []
88 extra_args = []
88
89
89 # When the subprocess does not allow us to respond "yes" during the installation,
90 # When the subprocess does not allow us to respond "yes" during the installation,
90 # we need to insert --yes in the argument list for some commands
91 # we need to insert --yes in the argument list for some commands
91 stdin_disabled = getattr(self.shell, 'kernel', None) is not None
92 stdin_disabled = getattr(self.shell, 'kernel', None) is not None
92 needs_yes = command in CONDA_COMMANDS_REQUIRING_YES
93 needs_yes = command in CONDA_COMMANDS_REQUIRING_YES
93 has_yes = set(args).intersection(CONDA_YES_FLAGS)
94 has_yes = set(args).intersection(CONDA_YES_FLAGS)
94 if stdin_disabled and needs_yes and not has_yes:
95 if stdin_disabled and needs_yes and not has_yes:
95 extra_args.append("--yes")
96 extra_args.append("--yes")
96
97
97 # Add --prefix to point conda installation to the current environment
98 # Add --prefix to point conda installation to the current environment
98 needs_prefix = command in CONDA_COMMANDS_REQUIRING_PREFIX
99 needs_prefix = command in CONDA_COMMANDS_REQUIRING_PREFIX
99 has_prefix = set(args).intersection(CONDA_ENV_FLAGS)
100 has_prefix = set(args).intersection(CONDA_ENV_FLAGS)
100 if needs_prefix and not has_prefix:
101 if needs_prefix and not has_prefix:
101 extra_args.extend(["--prefix", sys.prefix])
102 extra_args.extend(["--prefix", sys.prefix])
102
103
103 self.shell.system(' '.join([conda, command] + extra_args + args))
104 self.shell.system(' '.join([conda, command] + extra_args + args))
104 print("\nNote: you may need to restart the kernel to use updated packages.")
105 print("\nNote: you may need to restart the kernel to use updated packages.")
@@ -1,88 +1,87 b''
1 # coding: utf-8
1 # coding: utf-8
2
2
3 # This script autogenerates `IPython.core.latex_symbols.py`, which contains a
3 # This script autogenerates `IPython.core.latex_symbols.py`, which contains a
4 # single dict , named `latex_symbols`. The keys in this dict are latex symbols,
4 # single dict , named `latex_symbols`. The keys in this dict are latex symbols,
5 # such as `\\alpha` and the values in the dict are the unicode equivalents for
5 # such as `\\alpha` and the values in the dict are the unicode equivalents for
6 # those. Most importantly, only unicode symbols that are valid identifiers in
6 # those. Most importantly, only unicode symbols that are valid identifiers in
7 # Python 3 are included.
7 # Python 3 are included.
8
8
9 #
9 #
10 # The original mapping of latex symbols to unicode comes from the `latex_symbols.jl` files from Julia.
10 # The original mapping of latex symbols to unicode comes from the `latex_symbols.jl` files from Julia.
11
11
12 import os, sys
12 from pathlib import Path
13
13
14 # Import the Julia LaTeX symbols
14 # Import the Julia LaTeX symbols
15 print('Importing latex_symbols.js from Julia...')
15 print('Importing latex_symbols.js from Julia...')
16 import requests
16 import requests
17 url = 'https://raw.githubusercontent.com/JuliaLang/julia/master/stdlib/REPL/src/latex_symbols.jl'
17 url = 'https://raw.githubusercontent.com/JuliaLang/julia/master/stdlib/REPL/src/latex_symbols.jl'
18 r = requests.get(url)
18 r = requests.get(url)
19
19
20
20
21 # Build a list of key, value pairs
21 # Build a list of key, value pairs
22 print('Building a list of (latex, unicode) key-value pairs...')
22 print('Building a list of (latex, unicode) key-value pairs...')
23 lines = r.text.splitlines()
23 lines = r.text.splitlines()
24
24
25 prefixes_line = lines.index('# "font" prefixes')
25 prefixes_line = lines.index('# "font" prefixes')
26 symbols_line = lines.index('# manual additions:')
26 symbols_line = lines.index('# manual additions:')
27
27
28 prefix_dict = {}
28 prefix_dict = {}
29 for l in lines[prefixes_line + 1: symbols_line]:
29 for l in lines[prefixes_line + 1: symbols_line]:
30 p = l.split()
30 p = l.split()
31 if not p or p[1] == 'latex_symbols': continue
31 if not p or p[1] == 'latex_symbols': continue
32 prefix_dict[p[1]] = p[3]
32 prefix_dict[p[1]] = p[3]
33
33
34 idents = []
34 idents = []
35 for l in lines[symbols_line:]:
35 for l in lines[symbols_line:]:
36 if not '=>' in l: continue #Β if it's not a def, skip
36 if not '=>' in l: continue #Β if it's not a def, skip
37 if '#' in l: l = l[:l.index('#')] #Β get rid of eol comments
37 if '#' in l: l = l[:l.index('#')] #Β get rid of eol comments
38 x, y = l.strip().split('=>')
38 x, y = l.strip().split('=>')
39 if '*' in x: #Β if a prefix is present substitute it with its value
39 if '*' in x: #Β if a prefix is present substitute it with its value
40 p, x = x.split('*')
40 p, x = x.split('*')
41 x = prefix_dict[p][:-1] + x[1:]
41 x = prefix_dict[p][:-1] + x[1:]
42 x, y = x.split('"')[1], y.split('"')[1] #Β get the values in quotes
42 x, y = x.split('"')[1], y.split('"')[1] #Β get the values in quotes
43 idents.append((x, y))
43 idents.append((x, y))
44
44
45 # Filter out non-valid identifiers
45 # Filter out non-valid identifiers
46 print('Filtering out characters that are not valid Python 3 identifiers')
46 print('Filtering out characters that are not valid Python 3 identifiers')
47
47
48 def test_ident(i):
48 def test_ident(i):
49 """Is the unicode string valid in a Python 3 identifier."""
49 """Is the unicode string valid in a Python 3 identifier."""
50 # Some characters are not valid at the start of a name, but we still want to
50 # Some characters are not valid at the start of a name, but we still want to
51 # include them. So prefix with 'a', which is valid at the start.
51 # include them. So prefix with 'a', which is valid at the start.
52 return ('a' + i).isidentifier()
52 return ('a' + i).isidentifier()
53
53
54 assert test_ident("Ξ±")
54 assert test_ident("Ξ±")
55 assert not test_ident('‴')
55 assert not test_ident('‴')
56
56
57 valid_idents = [line for line in idents if test_ident(line[1])]
57 valid_idents = [line for line in idents if test_ident(line[1])]
58
58
59 # Write the `latex_symbols.py` module in the cwd
59 # Write the `latex_symbols.py` module in the cwd
60
60
61 s = """# encoding: utf-8
61 s = """# encoding: utf-8
62
62
63 # DO NOT EDIT THIS FILE BY HAND.
63 # DO NOT EDIT THIS FILE BY HAND.
64
64
65 # To update this file, run the script /tools/gen_latex_symbols.py using Python 3
65 # To update this file, run the script /tools/gen_latex_symbols.py using Python 3
66
66
67 # This file is autogenerated from the file:
67 # This file is autogenerated from the file:
68 # https://raw.githubusercontent.com/JuliaLang/julia/master/base/latex_symbols.jl
68 # https://raw.githubusercontent.com/JuliaLang/julia/master/base/latex_symbols.jl
69 # This original list is filtered to remove any unicode characters that are not valid
69 # This original list is filtered to remove any unicode characters that are not valid
70 # Python identifiers.
70 # Python identifiers.
71
71
72 latex_symbols = {\n
72 latex_symbols = {\n
73 """
73 """
74 for line in valid_idents:
74 for line in valid_idents:
75 s += ' "%s" : "%s",\n' % (line[0], line[1])
75 s += ' "%s" : "%s",\n' % (line[0], line[1])
76 s += "}\n"
76 s += "}\n"
77
77
78 s += """
78 s += """
79
79
80 reverse_latex_symbol = { v:k for k,v in latex_symbols.items()}
80 reverse_latex_symbol = { v:k for k,v in latex_symbols.items()}
81 """
81 """
82
82
83 fn = os.path.join('..','IPython','core','latex_symbols.py')
83 fn = Path("..", "IPython", "core", "latex_symbols.py")
84 print("Writing the file: %s" % fn)
84 print("Writing the file: %s" % str(fn))
85 with open(fn, 'w', encoding='utf-8') as f:
85 fn.write_text(s, encoding="utf-8")
86 f.write(s)
87
86
88
87
General Comments 0
You need to be logged in to leave comments. Login now