##// END OF EJS Templates
Run black on all files that would lead to 3 lines changes or less
Matthias Bussonnier -
Show More
@@ -1,4 +1,4 b''
1 # coding: iso-8859-5
1 # coding: iso-8859-5
2 # (Unlikely to be the default encoding for most testers.)
2 # (Unlikely to be the default encoding for most testers.)
3 # ������������������� <- Cyrillic characters
3 # ������������������� <- Cyrillic characters
4 u = '����'
4 u = "����"
@@ -1,11 +1,14 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 from IPython.testing import decorators as dec
2 from IPython.testing import decorators as dec
3
3
4
4 def test_import_backgroundjobs():
5 def test_import_backgroundjobs():
5 from IPython.lib import backgroundjobs
6 from IPython.lib import backgroundjobs
6
7
8
7 def test_import_deepreload():
9 def test_import_deepreload():
8 from IPython.lib import deepreload
10 from IPython.lib import deepreload
9
11
12
10 def test_import_demo():
13 def test_import_demo():
11 from IPython.lib import demo
14 from IPython.lib import demo
@@ -1,63 +1,62 b''
1 """
1 """
2 Inputhook for running the original asyncio event loop while we're waiting for
2 Inputhook for running the original asyncio event loop while we're waiting for
3 input.
3 input.
4
4
5 By default, in IPython, we run the prompt with a different asyncio event loop,
5 By default, in IPython, we run the prompt with a different asyncio event loop,
6 because otherwise we risk that people are freezing the prompt by scheduling bad
6 because otherwise we risk that people are freezing the prompt by scheduling bad
7 coroutines. E.g., a coroutine that does a while/true and never yield back
7 coroutines. E.g., a coroutine that does a while/true and never yield back
8 control to the loop. We can't cancel that.
8 control to the loop. We can't cancel that.
9
9
10 However, sometimes we want the asyncio loop to keep running while waiting for
10 However, sometimes we want the asyncio loop to keep running while waiting for
11 a prompt.
11 a prompt.
12
12
13 The following example will print the numbers from 1 to 10 above the prompt,
13 The following example will print the numbers from 1 to 10 above the prompt,
14 while we are waiting for input. (This works also because we use
14 while we are waiting for input. (This works also because we use
15 prompt_toolkit`s `patch_stdout`)::
15 prompt_toolkit`s `patch_stdout`)::
16
16
17 In [1]: import asyncio
17 In [1]: import asyncio
18
18
19 In [2]: %gui asyncio
19 In [2]: %gui asyncio
20
20
21 In [3]: async def f():
21 In [3]: async def f():
22 ...: for i in range(10):
22 ...: for i in range(10):
23 ...: await asyncio.sleep(1)
23 ...: await asyncio.sleep(1)
24 ...: print(i)
24 ...: print(i)
25
25
26
26
27 In [4]: asyncio.ensure_future(f())
27 In [4]: asyncio.ensure_future(f())
28
28
29 """
29 """
30 from prompt_toolkit import __version__ as ptk_version
30 from prompt_toolkit import __version__ as ptk_version
31
31
32 from IPython.core.async_helpers import get_asyncio_loop
32 from IPython.core.async_helpers import get_asyncio_loop
33
33
34 PTK3 = ptk_version.startswith('3.')
34 PTK3 = ptk_version.startswith("3.")
35
36
35
37
36
38 def inputhook(context):
37 def inputhook(context):
39 """
38 """
40 Inputhook for asyncio event loop integration.
39 Inputhook for asyncio event loop integration.
41 """
40 """
42 # For prompt_toolkit 3.0, this input hook literally doesn't do anything.
41 # For prompt_toolkit 3.0, this input hook literally doesn't do anything.
43 # The event loop integration here is implemented in `interactiveshell.py`
42 # The event loop integration here is implemented in `interactiveshell.py`
44 # by running the prompt itself in the current asyncio loop. The main reason
43 # by running the prompt itself in the current asyncio loop. The main reason
45 # for this is that nesting asyncio event loops is unreliable.
44 # for this is that nesting asyncio event loops is unreliable.
46 if PTK3:
45 if PTK3:
47 return
46 return
48
47
49 # For prompt_toolkit 2.0, we can run the current asyncio event loop,
48 # For prompt_toolkit 2.0, we can run the current asyncio event loop,
50 # because prompt_toolkit 2.0 uses a different event loop internally.
49 # because prompt_toolkit 2.0 uses a different event loop internally.
51
50
52 # get the persistent asyncio event loop
51 # get the persistent asyncio event loop
53 loop = get_asyncio_loop()
52 loop = get_asyncio_loop()
54
53
55 def stop():
54 def stop():
56 loop.stop()
55 loop.stop()
57
56
58 fileno = context.fileno()
57 fileno = context.fileno()
59 loop.add_reader(fileno, stop)
58 loop.add_reader(fileno, stop)
60 try:
59 try:
61 loop.run_forever()
60 loop.run_forever()
62 finally:
61 finally:
63 loop.remove_reader(fileno)
62 loop.remove_reader(fileno)
@@ -1,58 +1,60 b''
1 # Code borrowed from python-prompt-toolkit examples
1 # Code borrowed from python-prompt-toolkit examples
2 # https://github.com/jonathanslenders/python-prompt-toolkit/blob/77cdcfbc7f4b4c34a9d2f9a34d422d7152f16209/examples/inputhook.py
2 # https://github.com/jonathanslenders/python-prompt-toolkit/blob/77cdcfbc7f4b4c34a9d2f9a34d422d7152f16209/examples/inputhook.py
3
3
4 # Copyright (c) 2014, Jonathan Slenders
4 # Copyright (c) 2014, Jonathan Slenders
5 # All rights reserved.
5 # All rights reserved.
6 #
6 #
7 # Redistribution and use in source and binary forms, with or without modification,
7 # Redistribution and use in source and binary forms, with or without modification,
8 # are permitted provided that the following conditions are met:
8 # are permitted provided that the following conditions are met:
9 #
9 #
10 # * Redistributions of source code must retain the above copyright notice, this
10 # * Redistributions of source code must retain the above copyright notice, this
11 # list of conditions and the following disclaimer.
11 # list of conditions and the following disclaimer.
12 #
12 #
13 # * Redistributions in binary form must reproduce the above copyright notice, this
13 # * Redistributions in binary form must reproduce the above copyright notice, this
14 # list of conditions and the following disclaimer in the documentation and/or
14 # list of conditions and the following disclaimer in the documentation and/or
15 # other materials provided with the distribution.
15 # other materials provided with the distribution.
16 #
16 #
17 # * Neither the name of the {organization} nor the names of its
17 # * Neither the name of the {organization} nor the names of its
18 # contributors may be used to endorse or promote products derived from
18 # contributors may be used to endorse or promote products derived from
19 # this software without specific prior written permission.
19 # this software without specific prior written permission.
20 #
20 #
21 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
24 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
25 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
28 # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
31
32 """
32 """
33 PyGTK input hook for prompt_toolkit.
33 PyGTK input hook for prompt_toolkit.
34
34
35 Listens on the pipe prompt_toolkit sets up for a notification that it should
35 Listens on the pipe prompt_toolkit sets up for a notification that it should
36 return control to the terminal event loop.
36 return control to the terminal event loop.
37 """
37 """
38
38
39 import gtk, gobject
39 import gtk, gobject
40
40
41 # Enable threading in GTK. (Otherwise, GTK will keep the GIL.)
41 # Enable threading in GTK. (Otherwise, GTK will keep the GIL.)
42 gtk.gdk.threads_init()
42 gtk.gdk.threads_init()
43
43
44
44 def inputhook(context):
45 def inputhook(context):
45 """
46 """
46 When the eventloop of prompt-toolkit is idle, call this inputhook.
47 When the eventloop of prompt-toolkit is idle, call this inputhook.
47
48
48 This will run the GTK main loop until the file descriptor
49 This will run the GTK main loop until the file descriptor
49 `context.fileno()` becomes ready.
50 `context.fileno()` becomes ready.
50
51
51 :param context: An `InputHookContext` instance.
52 :param context: An `InputHookContext` instance.
52 """
53 """
54
53 def _main_quit(*a, **kw):
55 def _main_quit(*a, **kw):
54 gtk.main_quit()
56 gtk.main_quit()
55 return False
57 return False
56
58
57 gobject.io_add_watch(context.fileno(), gobject.IO_IN, _main_quit)
59 gobject.io_add_watch(context.fileno(), gobject.IO_IN, _main_quit)
58 gtk.main()
60 gtk.main()
@@ -1,12 +1,14 b''
1 """prompt_toolkit input hook for GTK 3
1 """prompt_toolkit input hook for GTK 3
2 """
2 """
3
3
4 from gi.repository import Gtk, GLib
4 from gi.repository import Gtk, GLib
5
5
6
6 def _main_quit(*args, **kwargs):
7 def _main_quit(*args, **kwargs):
7 Gtk.main_quit()
8 Gtk.main_quit()
8 return False
9 return False
9
10
11
10 def inputhook(context):
12 def inputhook(context):
11 GLib.io_add_watch(context.fileno(), GLib.PRIORITY_DEFAULT, GLib.IO_IN, _main_quit)
13 GLib.io_add_watch(context.fileno(), GLib.PRIORITY_DEFAULT, GLib.IO_IN, _main_quit)
12 Gtk.main()
14 Gtk.main()
@@ -1,2 +1,2 b''
1 x = 1
1 x = 1
2 print('x is:',x)
2 print("x is:", x)
@@ -1,2 +1,2 b''
1 # GENERATED BY setup.py
1 # GENERATED BY setup.py
2 commit = u""
2 commit = ""
@@ -1,67 +1,66 b''
1 from IPython.utils.dir2 import dir2
1 from IPython.utils.dir2 import dir2
2
2
3 import pytest
3 import pytest
4
4
5
5
6 class Base(object):
6 class Base(object):
7 x = 1
7 x = 1
8 z = 23
8 z = 23
9
9
10
10
11 def test_base():
11 def test_base():
12 res = dir2(Base())
12 res = dir2(Base())
13 assert "x" in res
13 assert "x" in res
14 assert "z" in res
14 assert "z" in res
15 assert "y" not in res
15 assert "y" not in res
16 assert "__class__" in res
16 assert "__class__" in res
17 assert res.count("x") == 1
17 assert res.count("x") == 1
18 assert res.count("__class__") == 1
18 assert res.count("__class__") == 1
19
19
20
20
21 def test_SubClass():
21 def test_SubClass():
22
23 class SubClass(Base):
22 class SubClass(Base):
24 y = 2
23 y = 2
25
24
26 res = dir2(SubClass())
25 res = dir2(SubClass())
27 assert "y" in res
26 assert "y" in res
28 assert res.count("y") == 1
27 assert res.count("y") == 1
29 assert res.count("x") == 1
28 assert res.count("x") == 1
30
29
31
30
32 def test_SubClass_with_trait_names_attr():
31 def test_SubClass_with_trait_names_attr():
33 # usecase: trait_names is used in a class describing psychological classification
32 # usecase: trait_names is used in a class describing psychological classification
34
33
35 class SubClass(Base):
34 class SubClass(Base):
36 y = 2
35 y = 2
37 trait_names = 44
36 trait_names = 44
38
37
39 res = dir2(SubClass())
38 res = dir2(SubClass())
40 assert "trait_names" in res
39 assert "trait_names" in res
41
40
42
41
43 def test_misbehaving_object_without_trait_names():
42 def test_misbehaving_object_without_trait_names():
44 # dir2 shouldn't raise even when objects are dumb and raise
43 # dir2 shouldn't raise even when objects are dumb and raise
45 # something other than AttribteErrors on bad getattr.
44 # something other than AttribteErrors on bad getattr.
46
45
47 class MisbehavingGetattr:
46 class MisbehavingGetattr:
48 def __getattr__(self, attr):
47 def __getattr__(self, attr):
49 raise KeyError("I should be caught")
48 raise KeyError("I should be caught")
50
49
51 def some_method(self):
50 def some_method(self):
52 return True
51 return True
53
52
54 class SillierWithDir(MisbehavingGetattr):
53 class SillierWithDir(MisbehavingGetattr):
55 def __dir__(self):
54 def __dir__(self):
56 return ['some_method']
55 return ["some_method"]
57
56
58 for bad_klass in (MisbehavingGetattr, SillierWithDir):
57 for bad_klass in (MisbehavingGetattr, SillierWithDir):
59 obj = bad_klass()
58 obj = bad_klass()
60
59
61 assert obj.some_method()
60 assert obj.some_method()
62
61
63 with pytest.raises(KeyError):
62 with pytest.raises(KeyError):
64 obj.other_method()
63 obj.other_method()
65
64
66 res = dir2(obj)
65 res = dir2(obj)
67 assert "some_method" in res
66 assert "some_method" in res
@@ -1,354 +1,354 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 This module defines the things that are used in setup.py for building IPython
3 This module defines the things that are used in setup.py for building IPython
4
4
5 This includes:
5 This includes:
6
6
7 * The basic arguments to setup
7 * The basic arguments to setup
8 * Functions for finding things like packages, package data, etc.
8 * Functions for finding things like packages, package data, etc.
9 * A function for checking dependencies.
9 * A function for checking dependencies.
10 """
10 """
11
11
12 # Copyright (c) IPython Development Team.
12 # Copyright (c) IPython Development Team.
13 # Distributed under the terms of the Modified BSD License.
13 # Distributed under the terms of the Modified BSD License.
14
14
15 import os
15 import os
16 import re
16 import re
17 import sys
17 import sys
18 from glob import glob
18 from glob import glob
19 from logging import log
19 from logging import log
20
20
21 from setuptools import Command
21 from setuptools import Command
22 from setuptools.command.build_py import build_py
22 from setuptools.command.build_py import build_py
23
23
24 from setuptools.command.install import install
24 from setuptools.command.install import install
25 from setuptools.command.install_scripts import install_scripts
25 from setuptools.command.install_scripts import install_scripts
26
26
27
27
28 #-------------------------------------------------------------------------------
28 #-------------------------------------------------------------------------------
29 # Useful globals and utility functions
29 # Useful globals and utility functions
30 #-------------------------------------------------------------------------------
30 #-------------------------------------------------------------------------------
31
31
32 # A few handy globals
32 # A few handy globals
33 isfile = os.path.isfile
33 isfile = os.path.isfile
34 pjoin = os.path.join
34 pjoin = os.path.join
35 repo_root = os.path.dirname(os.path.abspath(__file__))
35 repo_root = os.path.dirname(os.path.abspath(__file__))
36
36
37 def execfile(fname, globs, locs=None):
37 def execfile(fname, globs, locs=None):
38 locs = locs or globs
38 locs = locs or globs
39 with open(fname, encoding="utf-8") as f:
39 with open(fname, encoding="utf-8") as f:
40 exec(compile(f.read(), fname, "exec"), globs, locs)
40 exec(compile(f.read(), fname, "exec"), globs, locs)
41
41
42 # A little utility we'll need below, since glob() does NOT allow you to do
42 # A little utility we'll need below, since glob() does NOT allow you to do
43 # exclusion on multiple endings!
43 # exclusion on multiple endings!
44 def file_doesnt_endwith(test,endings):
44 def file_doesnt_endwith(test,endings):
45 """Return true if test is a file and its name does NOT end with any
45 """Return true if test is a file and its name does NOT end with any
46 of the strings listed in endings."""
46 of the strings listed in endings."""
47 if not isfile(test):
47 if not isfile(test):
48 return False
48 return False
49 for e in endings:
49 for e in endings:
50 if test.endswith(e):
50 if test.endswith(e):
51 return False
51 return False
52 return True
52 return True
53
53
54 #---------------------------------------------------------------------------
54 #---------------------------------------------------------------------------
55 # Basic project information
55 # Basic project information
56 #---------------------------------------------------------------------------
56 #---------------------------------------------------------------------------
57
57
58 # release.py contains version, authors, license, url, keywords, etc.
58 # release.py contains version, authors, license, url, keywords, etc.
59 execfile(pjoin(repo_root, 'IPython','core','release.py'), globals())
59 execfile(pjoin(repo_root, 'IPython','core','release.py'), globals())
60
60
61 # Create a dict with the basic information
61 # Create a dict with the basic information
62 # This dict is eventually passed to setup after additional keys are added.
62 # This dict is eventually passed to setup after additional keys are added.
63 setup_args = dict(
63 setup_args = dict(
64 author = author,
64 author = author,
65 author_email = author_email,
65 author_email = author_email,
66 license = license,
66 license = license,
67 )
67 )
68
68
69
69
70 #---------------------------------------------------------------------------
70 #---------------------------------------------------------------------------
71 # Find packages
71 # Find packages
72 #---------------------------------------------------------------------------
72 #---------------------------------------------------------------------------
73
73
74 def find_packages():
74 def find_packages():
75 """
75 """
76 Find all of IPython's packages.
76 Find all of IPython's packages.
77 """
77 """
78 excludes = ['deathrow', 'quarantine']
78 excludes = ['deathrow', 'quarantine']
79 packages = []
79 packages = []
80 for directory, subdirs, files in os.walk("IPython"):
80 for directory, subdirs, files in os.walk("IPython"):
81 package = directory.replace(os.path.sep, ".")
81 package = directory.replace(os.path.sep, ".")
82 if any(package.startswith("IPython." + exc) for exc in excludes):
82 if any(package.startswith("IPython." + exc) for exc in excludes):
83 # package is to be excluded (e.g. deathrow)
83 # package is to be excluded (e.g. deathrow)
84 continue
84 continue
85 if '__init__.py' not in files:
85 if '__init__.py' not in files:
86 # not a package
86 # not a package
87 continue
87 continue
88 packages.append(package)
88 packages.append(package)
89 return packages
89 return packages
90
90
91 #---------------------------------------------------------------------------
91 #---------------------------------------------------------------------------
92 # Find package data
92 # Find package data
93 #---------------------------------------------------------------------------
93 #---------------------------------------------------------------------------
94
94
95 def find_package_data():
95 def find_package_data():
96 """
96 """
97 Find IPython's package_data.
97 Find IPython's package_data.
98 """
98 """
99 # This is not enough for these things to appear in an sdist.
99 # This is not enough for these things to appear in an sdist.
100 # We need to muck with the MANIFEST to get this to work
100 # We need to muck with the MANIFEST to get this to work
101
101
102 package_data = {
102 package_data = {
103 'IPython.core' : ['profile/README*'],
103 'IPython.core' : ['profile/README*'],
104 'IPython.core.tests' : ['*.png', '*.jpg', 'daft_extension/*.py'],
104 'IPython.core.tests' : ['*.png', '*.jpg', 'daft_extension/*.py'],
105 'IPython.lib.tests' : ['*.wav'],
105 'IPython.lib.tests' : ['*.wav'],
106 'IPython.testing.plugin' : ['*.txt'],
106 'IPython.testing.plugin' : ['*.txt'],
107 }
107 }
108
108
109 return package_data
109 return package_data
110
110
111
111
112 def check_package_data(package_data):
112 def check_package_data(package_data):
113 """verify that package_data globs make sense"""
113 """verify that package_data globs make sense"""
114 print("checking package data")
114 print("checking package data")
115 for pkg, data in package_data.items():
115 for pkg, data in package_data.items():
116 pkg_root = pjoin(*pkg.split('.'))
116 pkg_root = pjoin(*pkg.split('.'))
117 for d in data:
117 for d in data:
118 path = pjoin(pkg_root, d)
118 path = pjoin(pkg_root, d)
119 if '*' in path:
119 if '*' in path:
120 assert len(glob(path)) > 0, "No files match pattern %s" % path
120 assert len(glob(path)) > 0, "No files match pattern %s" % path
121 else:
121 else:
122 assert os.path.exists(path), "Missing package data: %s" % path
122 assert os.path.exists(path), "Missing package data: %s" % path
123
123
124
124
125 def check_package_data_first(command):
125 def check_package_data_first(command):
126 """decorator for checking package_data before running a given command
126 """decorator for checking package_data before running a given command
127
127
128 Probably only needs to wrap build_py
128 Probably only needs to wrap build_py
129 """
129 """
130 class DecoratedCommand(command):
130 class DecoratedCommand(command):
131 def run(self):
131 def run(self):
132 check_package_data(self.package_data)
132 check_package_data(self.package_data)
133 command.run(self)
133 command.run(self)
134 return DecoratedCommand
134 return DecoratedCommand
135
135
136
136
137 #---------------------------------------------------------------------------
137 #---------------------------------------------------------------------------
138 # Find data files
138 # Find data files
139 #---------------------------------------------------------------------------
139 #---------------------------------------------------------------------------
140
140
141 def find_data_files():
141 def find_data_files():
142 """
142 """
143 Find IPython's data_files.
143 Find IPython's data_files.
144
144
145 Just man pages at this point.
145 Just man pages at this point.
146 """
146 """
147
147
148 if "freebsd" in sys.platform:
148 if "freebsd" in sys.platform:
149 manpagebase = pjoin('man', 'man1')
149 manpagebase = pjoin('man', 'man1')
150 else:
150 else:
151 manpagebase = pjoin('share', 'man', 'man1')
151 manpagebase = pjoin('share', 'man', 'man1')
152
152
153 # Simple file lists can be made by hand
153 # Simple file lists can be made by hand
154 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
154 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
155 if not manpages:
155 if not manpages:
156 # When running from a source tree, the manpages aren't gzipped
156 # When running from a source tree, the manpages aren't gzipped
157 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
157 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
158
158
159 # And assemble the entire output list
159 # And assemble the entire output list
160 data_files = [ (manpagebase, manpages) ]
160 data_files = [ (manpagebase, manpages) ]
161
161
162 return data_files
162 return data_files
163
163
164
164
165 # The two functions below are copied from IPython.utils.path, so we don't need
165 # The two functions below are copied from IPython.utils.path, so we don't need
166 # to import IPython during setup, which fails on Python 3.
166 # to import IPython during setup, which fails on Python 3.
167
167
168 def target_outdated(target,deps):
168 def target_outdated(target,deps):
169 """Determine whether a target is out of date.
169 """Determine whether a target is out of date.
170
170
171 target_outdated(target,deps) -> 1/0
171 target_outdated(target,deps) -> 1/0
172
172
173 deps: list of filenames which MUST exist.
173 deps: list of filenames which MUST exist.
174 target: single filename which may or may not exist.
174 target: single filename which may or may not exist.
175
175
176 If target doesn't exist or is older than any file listed in deps, return
176 If target doesn't exist or is older than any file listed in deps, return
177 true, otherwise return false.
177 true, otherwise return false.
178 """
178 """
179 try:
179 try:
180 target_time = os.path.getmtime(target)
180 target_time = os.path.getmtime(target)
181 except os.error:
181 except os.error:
182 return 1
182 return 1
183 for dep in deps:
183 for dep in deps:
184 dep_time = os.path.getmtime(dep)
184 dep_time = os.path.getmtime(dep)
185 if dep_time > target_time:
185 if dep_time > target_time:
186 #print "For target",target,"Dep failed:",dep # dbg
186 #print "For target",target,"Dep failed:",dep # dbg
187 #print "times (dep,tar):",dep_time,target_time # dbg
187 #print "times (dep,tar):",dep_time,target_time # dbg
188 return 1
188 return 1
189 return 0
189 return 0
190
190
191
191
192 def target_update(target,deps,cmd):
192 def target_update(target,deps,cmd):
193 """Update a target with a given command given a list of dependencies.
193 """Update a target with a given command given a list of dependencies.
194
194
195 target_update(target,deps,cmd) -> runs cmd if target is outdated.
195 target_update(target,deps,cmd) -> runs cmd if target is outdated.
196
196
197 This is just a wrapper around target_outdated() which calls the given
197 This is just a wrapper around target_outdated() which calls the given
198 command if target is outdated."""
198 command if target is outdated."""
199
199
200 if target_outdated(target,deps):
200 if target_outdated(target,deps):
201 os.system(cmd)
201 os.system(cmd)
202
202
203 #---------------------------------------------------------------------------
203 #---------------------------------------------------------------------------
204 # Find scripts
204 # Find scripts
205 #---------------------------------------------------------------------------
205 #---------------------------------------------------------------------------
206
206
207 def find_entry_points():
207 def find_entry_points():
208 """Defines the command line entry points for IPython
208 """Defines the command line entry points for IPython
209
209
210 This always uses setuptools-style entry points. When setuptools is not in
210 This always uses setuptools-style entry points. When setuptools is not in
211 use, our own build_scripts_entrypt class below parses these and builds
211 use, our own build_scripts_entrypt class below parses these and builds
212 command line scripts.
212 command line scripts.
213
213
214 Each of our entry points gets a plain name, e.g. ipython, a name
214 Each of our entry points gets a plain name, e.g. ipython, a name
215 suffixed with the Python major version number, e.g. ipython3, and
215 suffixed with the Python major version number, e.g. ipython3, and
216 a name suffixed with the Python major.minor version number, eg. ipython3.8.
216 a name suffixed with the Python major.minor version number, eg. ipython3.8.
217 """
217 """
218 ep = [
218 ep = [
219 'ipython%s = IPython:start_ipython',
219 'ipython%s = IPython:start_ipython',
220 ]
220 ]
221 major_suffix = str(sys.version_info[0])
221 major_suffix = str(sys.version_info[0])
222 minor_suffix = ".".join([str(sys.version_info[0]), str(sys.version_info[1])])
222 minor_suffix = ".".join([str(sys.version_info[0]), str(sys.version_info[1])])
223 return (
223 return (
224 [e % "" for e in ep]
224 [e % "" for e in ep]
225 + [e % major_suffix for e in ep]
225 + [e % major_suffix for e in ep]
226 + [e % minor_suffix for e in ep]
226 + [e % minor_suffix for e in ep]
227 )
227 )
228
228
229 class install_lib_symlink(Command):
229 class install_lib_symlink(Command):
230 user_options = [
230 user_options = [
231 ('install-dir=', 'd', "directory to install to"),
231 ('install-dir=', 'd', "directory to install to"),
232 ]
232 ]
233
233
234 def initialize_options(self):
234 def initialize_options(self):
235 self.install_dir = None
235 self.install_dir = None
236
236
237 def finalize_options(self):
237 def finalize_options(self):
238 self.set_undefined_options('symlink',
238 self.set_undefined_options('symlink',
239 ('install_lib', 'install_dir'),
239 ('install_lib', 'install_dir'),
240 )
240 )
241
241
242 def run(self):
242 def run(self):
243 if sys.platform == 'win32':
243 if sys.platform == 'win32':
244 raise Exception("This doesn't work on Windows.")
244 raise Exception("This doesn't work on Windows.")
245 pkg = os.path.join(os.getcwd(), 'IPython')
245 pkg = os.path.join(os.getcwd(), 'IPython')
246 dest = os.path.join(self.install_dir, 'IPython')
246 dest = os.path.join(self.install_dir, 'IPython')
247 if os.path.islink(dest):
247 if os.path.islink(dest):
248 print('removing existing symlink at %s' % dest)
248 print('removing existing symlink at %s' % dest)
249 os.unlink(dest)
249 os.unlink(dest)
250 print('symlinking %s -> %s' % (pkg, dest))
250 print('symlinking %s -> %s' % (pkg, dest))
251 os.symlink(pkg, dest)
251 os.symlink(pkg, dest)
252
252
253 class unsymlink(install):
253 class unsymlink(install):
254 def run(self):
254 def run(self):
255 dest = os.path.join(self.install_lib, 'IPython')
255 dest = os.path.join(self.install_lib, 'IPython')
256 if os.path.islink(dest):
256 if os.path.islink(dest):
257 print('removing symlink at %s' % dest)
257 print('removing symlink at %s' % dest)
258 os.unlink(dest)
258 os.unlink(dest)
259 else:
259 else:
260 print('No symlink exists at %s' % dest)
260 print('No symlink exists at %s' % dest)
261
261
262 class install_symlinked(install):
262 class install_symlinked(install):
263 def run(self):
263 def run(self):
264 if sys.platform == 'win32':
264 if sys.platform == 'win32':
265 raise Exception("This doesn't work on Windows.")
265 raise Exception("This doesn't work on Windows.")
266
266
267 # Run all sub-commands (at least those that need to be run)
267 # Run all sub-commands (at least those that need to be run)
268 for cmd_name in self.get_sub_commands():
268 for cmd_name in self.get_sub_commands():
269 self.run_command(cmd_name)
269 self.run_command(cmd_name)
270
270
271 # 'sub_commands': a list of commands this command might have to run to
271 # 'sub_commands': a list of commands this command might have to run to
272 # get its work done. See cmd.py for more info.
272 # get its work done. See cmd.py for more info.
273 sub_commands = [('install_lib_symlink', lambda self:True),
273 sub_commands = [('install_lib_symlink', lambda self:True),
274 ('install_scripts_sym', lambda self:True),
274 ('install_scripts_sym', lambda self:True),
275 ]
275 ]
276
276
277 class install_scripts_for_symlink(install_scripts):
277 class install_scripts_for_symlink(install_scripts):
278 """Redefined to get options from 'symlink' instead of 'install'.
278 """Redefined to get options from 'symlink' instead of 'install'.
279
279
280 I love distutils almost as much as I love setuptools.
280 I love distutils almost as much as I love setuptools.
281 """
281 """
282 def finalize_options(self):
282 def finalize_options(self):
283 self.set_undefined_options('build', ('build_scripts', 'build_dir'))
283 self.set_undefined_options('build', ('build_scripts', 'build_dir'))
284 self.set_undefined_options('symlink',
284 self.set_undefined_options('symlink',
285 ('install_scripts', 'install_dir'),
285 ('install_scripts', 'install_dir'),
286 ('force', 'force'),
286 ('force', 'force'),
287 ('skip_build', 'skip_build'),
287 ('skip_build', 'skip_build'),
288 )
288 )
289
289
290
290
291 #---------------------------------------------------------------------------
291 #---------------------------------------------------------------------------
292 # VCS related
292 # VCS related
293 #---------------------------------------------------------------------------
293 #---------------------------------------------------------------------------
294
294
295
295
296 def git_prebuild(pkg_dir, build_cmd=build_py):
296 def git_prebuild(pkg_dir, build_cmd=build_py):
297 """Return extended build or sdist command class for recording commit
297 """Return extended build or sdist command class for recording commit
298
298
299 records git commit in IPython.utils._sysinfo.commit
299 records git commit in IPython.utils._sysinfo.commit
300
300
301 for use in IPython.utils.sysinfo.sys_info() calls after installation.
301 for use in IPython.utils.sysinfo.sys_info() calls after installation.
302 """
302 """
303
303
304 class MyBuildPy(build_cmd):
304 class MyBuildPy(build_cmd):
305 ''' Subclass to write commit data into installation tree '''
305 ''' Subclass to write commit data into installation tree '''
306 def run(self):
306 def run(self):
307 # loose as `.dev` is suppose to be invalid
307 # loose as `.dev` is suppose to be invalid
308 print("check version number")
308 print("check version number")
309 loose_pep440re = re.compile(r'^(\d+)\.(\d+)\.(\d+((a|b|rc)\d+)?)(\.post\d+)?(\.dev\d*)?$')
309 loose_pep440re = re.compile(r'^(\d+)\.(\d+)\.(\d+((a|b|rc)\d+)?)(\.post\d+)?(\.dev\d*)?$')
310 if not loose_pep440re.match(version):
310 if not loose_pep440re.match(version):
311 raise ValueError("Version number '%s' is not valid (should match [N!]N(.N)*[{a|b|rc}N][.postN][.devN])" % version)
311 raise ValueError("Version number '%s' is not valid (should match [N!]N(.N)*[{a|b|rc}N][.postN][.devN])" % version)
312
312
313
313
314 build_cmd.run(self)
314 build_cmd.run(self)
315 # this one will only fire for build commands
315 # this one will only fire for build commands
316 if hasattr(self, 'build_lib'):
316 if hasattr(self, 'build_lib'):
317 self._record_commit(self.build_lib)
317 self._record_commit(self.build_lib)
318
318
319 def make_release_tree(self, base_dir, files):
319 def make_release_tree(self, base_dir, files):
320 # this one will fire for sdist
320 # this one will fire for sdist
321 build_cmd.make_release_tree(self, base_dir, files)
321 build_cmd.make_release_tree(self, base_dir, files)
322 self._record_commit(base_dir)
322 self._record_commit(base_dir)
323
323
324 def _record_commit(self, base_dir):
324 def _record_commit(self, base_dir):
325 import subprocess
325 import subprocess
326 proc = subprocess.Popen('git rev-parse --short HEAD',
326 proc = subprocess.Popen('git rev-parse --short HEAD',
327 stdout=subprocess.PIPE,
327 stdout=subprocess.PIPE,
328 stderr=subprocess.PIPE,
328 stderr=subprocess.PIPE,
329 shell=True)
329 shell=True)
330 repo_commit, _ = proc.communicate()
330 repo_commit, _ = proc.communicate()
331 repo_commit = repo_commit.strip().decode("ascii")
331 repo_commit = repo_commit.strip().decode("ascii")
332
332
333 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
333 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
334 if os.path.isfile(out_pth) and not repo_commit:
334 if os.path.isfile(out_pth) and not repo_commit:
335 # nothing to write, don't clobber
335 # nothing to write, don't clobber
336 return
336 return
337
337
338 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
338 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
339
339
340 # remove to avoid overwriting original via hard link
340 # remove to avoid overwriting original via hard link
341 try:
341 try:
342 os.remove(out_pth)
342 os.remove(out_pth)
343 except (IOError, OSError):
343 except (IOError, OSError):
344 pass
344 pass
345 with open(out_pth, "w", encoding="utf-8") as out_file:
345 with open(out_pth, "w", encoding="utf-8") as out_file:
346 out_file.writelines(
346 out_file.writelines(
347 [
347 [
348 "# GENERATED BY setup.py\n",
348 "# GENERATED BY setup.py\n",
349 'commit = u"%s"\n' % repo_commit,
349 'commit = "%s"\n' % repo_commit,
350 ]
350 ]
351 )
351 )
352
352
353 return MyBuildPy
353 return MyBuildPy
354
354
General Comments 0
You need to be logged in to leave comments. Login now