##// END OF EJS Templates
pyflakes to avoid missing imports
Matthias Bussonnier -
Show More
@@ -0,0 +1,5 b''
1 [flake8]
2 ignore = W293,E301,E271,E265,W291,E722,E302,C901,E225,E128,E122,E226,E231
3 max-line-length = 160
4 exclude = tests/*
5 max-complexity = 10
@@ -1,30 +1,33 b''
1 1 name: Run MyPy
2 2
3 3 on:
4 4 push:
5 5 branches: [ master ]
6 6 pull_request:
7 7 branches: [ master ]
8 8
9 9 jobs:
10 10 build:
11 11
12 12 runs-on: ubuntu-latest
13 13 strategy:
14 14 matrix:
15 15 python-version: [3.8]
16 16
17 17 steps:
18 18 - uses: actions/checkout@v2
19 19 - name: Set up Python ${{ matrix.python-version }}
20 20 uses: actions/setup-python@v2
21 21 with:
22 22 python-version: ${{ matrix.python-version }}
23 23 - name: Install dependencies
24 24 run: |
25 25 python -m pip install --upgrade pip
26 pip install mypy
26 pip install mypy pyflakes flake8
27 27 - name: Lint with mypy
28 28 run: |
29 29 mypy IPython/terminal/ptutils.py
30 30 mypy IPython/core/c*.py
31 - name: Lint with pyflakes
32 run: |
33 flake8 IPython/core/magics/script.py
@@ -1,318 +1,316 b''
1 1 """Magic functions for running cells in various scripts."""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 import errno
7 7 import os
8 8 import sys
9 9 import signal
10 10 import time
11 11 import asyncio
12 12 import atexit
13 13
14 14 from subprocess import CalledProcessError
15 15
16 16 from IPython.core import magic_arguments
17 17 from IPython.core.magic import (
18 18 Magics, magics_class, line_magic, cell_magic
19 19 )
20 20 from IPython.lib.backgroundjobs import BackgroundJobManager
21 from IPython.utils import py3compat
22 21 from IPython.utils.process import arg_split
23 22 from traitlets import List, Dict, default
24 23
25 24
26 25 #-----------------------------------------------------------------------------
27 26 # Magic implementation classes
28 27 #-----------------------------------------------------------------------------
29 28
30 29 def script_args(f):
31 30 """single decorator for adding script args"""
32 31 args = [
33 32 magic_arguments.argument(
34 33 '--out', type=str,
35 34 help="""The variable in which to store stdout from the script.
36 35 If the script is backgrounded, this will be the stdout *pipe*,
37 36 instead of the stderr text itself and will not be auto closed.
38 37 """
39 38 ),
40 39 magic_arguments.argument(
41 40 '--err', type=str,
42 41 help="""The variable in which to store stderr from the script.
43 42 If the script is backgrounded, this will be the stderr *pipe*,
44 43 instead of the stderr text itself and will not be autoclosed.
45 44 """
46 45 ),
47 46 magic_arguments.argument(
48 47 '--bg', action="store_true",
49 48 help="""Whether to run the script in the background.
50 49 If given, the only way to see the output of the command is
51 50 with --out/err.
52 51 """
53 52 ),
54 53 magic_arguments.argument(
55 54 '--proc', type=str,
56 55 help="""The variable in which to store Popen instance.
57 56 This is used only when --bg option is given.
58 57 """
59 58 ),
60 59 magic_arguments.argument(
61 60 '--no-raise-error', action="store_false", dest='raise_error',
62 61 help="""Whether you should raise an error message in addition to
63 62 a stream on stderr if you get a nonzero exit code.
64 63 """
65 64 )
66 65 ]
67 66 for arg in args:
68 67 f = arg(f)
69 68 return f
70 69
71 70 @magics_class
72 71 class ScriptMagics(Magics):
73 72 """Magics for talking to scripts
74 73
75 74 This defines a base `%%script` cell magic for running a cell
76 75 with a program in a subprocess, and registers a few top-level
77 76 magics that call %%script with common interpreters.
78 77 """
79 78 script_magics = List(
80 79 help="""Extra script cell magics to define
81 80
82 81 This generates simple wrappers of `%%script foo` as `%%foo`.
83 82
84 83 If you want to add script magics that aren't on your path,
85 84 specify them in script_paths
86 85 """,
87 86 ).tag(config=True)
88 87 @default('script_magics')
89 88 def _script_magics_default(self):
90 89 """default to a common list of programs"""
91 90
92 91 defaults = [
93 92 'sh',
94 93 'bash',
95 94 'perl',
96 95 'ruby',
97 96 'python',
98 97 'python2',
99 98 'python3',
100 99 'pypy',
101 100 ]
102 101 if os.name == 'nt':
103 102 defaults.extend([
104 103 'cmd',
105 104 ])
106 105
107 106 return defaults
108 107
109 108 script_paths = Dict(
110 109 help="""Dict mapping short 'ruby' names to full paths, such as '/opt/secret/bin/ruby'
111 110
112 111 Only necessary for items in script_magics where the default path will not
113 112 find the right interpreter.
114 113 """
115 114 ).tag(config=True)
116 115
117 116 def __init__(self, shell=None):
118 117 super(ScriptMagics, self).__init__(shell=shell)
119 118 self._generate_script_magics()
120 119 self.job_manager = BackgroundJobManager()
121 120 self.bg_processes = []
122 121 atexit.register(self.kill_bg_processes)
123 122
124 123 def __del__(self):
125 124 self.kill_bg_processes()
126 125
127 126 def _generate_script_magics(self):
128 127 cell_magics = self.magics['cell']
129 128 for name in self.script_magics:
130 129 cell_magics[name] = self._make_script_magic(name)
131 130
132 131 def _make_script_magic(self, name):
133 132 """make a named magic, that calls %%script with a particular program"""
134 133 # expand to explicit path if necessary:
135 134 script = self.script_paths.get(name, name)
136 135
137 136 @magic_arguments.magic_arguments()
138 137 @script_args
139 138 def named_script_magic(line, cell):
140 139 # if line, add it as cl-flags
141 140 if line:
142 line = "%s %s" % (script, line)
141 line = "%s %s" % (script, line)
143 142 else:
144 143 line = script
145 144 return self.shebang(line, cell)
146 145
147 146 # write a basic docstring:
148 147 named_script_magic.__doc__ = \
149 148 """%%{name} script magic
150 149
151 150 Run cells with {script} in a subprocess.
152 151
153 152 This is a shortcut for `%%script {script}`
154 153 """.format(**locals())
155 154
156 155 return named_script_magic
157 156
158 157 @magic_arguments.magic_arguments()
159 158 @script_args
160 159 @cell_magic("script")
161 160 def shebang(self, line, cell):
162 161 """Run a cell via a shell command
163 162
164 163 The `%%script` line is like the #! line of script,
165 164 specifying a program (bash, perl, ruby, etc.) with which to run.
166 165
167 166 The rest of the cell is run by that program.
168 167
169 168 Examples
170 169 --------
171 170 ::
172 171
173 172 In [1]: %%script bash
174 173 ...: for i in 1 2 3; do
175 174 ...: echo $i
176 175 ...: done
177 176 1
178 177 2
179 178 3
180 179 """
181 180
182 181 async def _handle_stream(stream, stream_arg, file_object):
183 182 while True:
184 183 line = (await stream.readline()).decode("utf8")
185 184 if not line:
186 185 break
187 186 if stream_arg:
188 187 self.shell.user_ns[stream_arg] = line
189 188 else:
190 189 file_object.write(line)
191 190 file_object.flush()
192 191
193 192 async def _stream_communicate(process, cell):
194 193 process.stdin.write(cell)
195 194 process.stdin.close()
196 195 stdout_task = asyncio.create_task(
197 196 _handle_stream(process.stdout, args.out, sys.stdout)
198 197 )
199 198 stderr_task = asyncio.create_task(
200 199 _handle_stream(process.stderr, args.err, sys.stderr)
201 200 )
202 201 await asyncio.wait([stdout_task, stderr_task])
203 202
204 203 if sys.platform.startswith("win"):
205 204 asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
206 205 loop = asyncio.get_event_loop()
207 206
208 207 argv = arg_split(line, posix=not sys.platform.startswith("win"))
209 208 args, cmd = self.shebang.parser.parse_known_args(argv)
210 209 try:
211 210 p = loop.run_until_complete(
212 211 asyncio.create_subprocess_exec(
213 212 *cmd,
214 213 stdout=asyncio.subprocess.PIPE,
215 214 stderr=asyncio.subprocess.PIPE,
216 215 stdin=asyncio.subprocess.PIPE
217 216 )
218 217 )
219 218 except OSError as e:
220 219 if e.errno == errno.ENOENT:
221 220 print("Couldn't find program: %r" % cmd[0])
222 221 return
223 222 else:
224 223 raise
225 224
226 225 if not cell.endswith('\n'):
227 226 cell += '\n'
228 227 cell = cell.encode('utf8', 'replace')
229 228 if args.bg:
230 229 self.bg_processes.append(p)
231 230 self._gc_bg_processes()
232 231 to_close = []
233 232 if args.out:
234 233 self.shell.user_ns[args.out] = p.stdout
235 234 else:
236 235 to_close.append(p.stdout)
237 236 if args.err:
238 237 self.shell.user_ns[args.err] = p.stderr
239 238 else:
240 239 to_close.append(p.stderr)
241 240 self.job_manager.new(self._run_script, p, cell, to_close, daemon=True)
242 241 if args.proc:
243 242 self.shell.user_ns[args.proc] = p
244 243 return
245 244
246 245 try:
247 246 loop.run_until_complete(_stream_communicate(p, cell))
248 247 except KeyboardInterrupt:
249 248 try:
250 249 p.send_signal(signal.SIGINT)
251 250 time.sleep(0.1)
252 251 if p.returncode is not None:
253 252 print("Process is interrupted.")
254 253 return
255 254 p.terminate()
256 255 time.sleep(0.1)
257 256 if p.returncode is not None:
258 257 print("Process is terminated.")
259 258 return
260 259 p.kill()
261 260 print("Process is killed.")
262 261 except OSError:
263 262 pass
264 263 except Exception as e:
265 print("Error while terminating subprocess (pid=%i): %s" \
266 % (p.pid, e))
264 print("Error while terminating subprocess (pid=%i): %s" % (p.pid, e))
267 265 return
268 266 if args.raise_error and p.returncode!=0:
269 267 raise CalledProcessError(p.returncode, cell)
270 268
271 269 def _run_script(self, p, cell, to_close):
272 270 """callback for running the script in the background"""
273 271 p.stdin.write(cell)
274 272 p.stdin.close()
275 273 for s in to_close:
276 274 s.close()
277 275 p.wait()
278 276
279 277 @line_magic("killbgscripts")
280 278 def killbgscripts(self, _nouse_=''):
281 279 """Kill all BG processes started by %%script and its family."""
282 280 self.kill_bg_processes()
283 281 print("All background processes were killed.")
284 282
285 283 def kill_bg_processes(self):
286 284 """Kill all BG processes which are still running."""
287 285 if not self.bg_processes:
288 286 return
289 287 for p in self.bg_processes:
290 288 if p.returncode is None:
291 289 try:
292 290 p.send_signal(signal.SIGINT)
293 291 except:
294 292 pass
295 293 time.sleep(0.1)
296 294 self._gc_bg_processes()
297 295 if not self.bg_processes:
298 296 return
299 297 for p in self.bg_processes:
300 298 if p.returncode is None:
301 299 try:
302 300 p.terminate()
303 301 except:
304 302 pass
305 303 time.sleep(0.1)
306 304 self._gc_bg_processes()
307 305 if not self.bg_processes:
308 306 return
309 307 for p in self.bg_processes:
310 308 if p.returncode is None:
311 309 try:
312 310 p.kill()
313 311 except:
314 312 pass
315 313 self._gc_bg_processes()
316 314
317 315 def _gc_bg_processes(self):
318 316 self.bg_processes = [p for p in self.bg_processes if p.returncode is None]
@@ -1,46 +1,47 b''
1 1 include README.rst
2 2 include COPYING.rst
3 3 include LICENSE
4 4 include setupbase.py
5 5 include setupegg.py
6 6 include MANIFEST.in
7 7 include pytest.ini
8 8 include mypy.ini
9 9 include .mailmap
10 include .flake8
10 11
11 12 recursive-exclude tools *
12 13 exclude tools
13 14 exclude CONTRIBUTING.md
14 15 exclude .editorconfig
15 16
16 17 graft setupext
17 18
18 19 graft scripts
19 20
20 21 # Load main dir but exclude things we don't want in the distro
21 22 graft IPython
22 23
23 24 # Documentation
24 25 graft docs
25 26 exclude docs/\#*
26 27 exclude docs/man/*.1.gz
27 28
28 29 exclude .git-blame-ignore-revs
29 30
30 31 # Examples
31 32 graft examples
32 33
33 34 # docs subdirs we want to skip
34 35 prune docs/build
35 36 prune docs/gh-pages
36 37 prune docs/dist
37 38
38 39 # Patterns to exclude from any directory
39 40 global-exclude *~
40 41 global-exclude *.flc
41 42 global-exclude *.yml
42 43 global-exclude *.pyc
43 44 global-exclude *.pyo
44 45 global-exclude .dircopy.log
45 46 global-exclude .git
46 47 global-exclude .ipynb_checkpoints
General Comments 0
You need to be logged in to leave comments. Login now