##// END OF EJS Templates
setupbase.py: Remove duplication of package_data
Matthias Koeppe -
Show More
@@ -1,48 +1,47 b''
1 include README.rst
1 include README.rst
2 include COPYING.rst
2 include COPYING.rst
3 include LICENSE
3 include LICENSE
4 include setupbase.py
4 include setupbase.py
5 include _build_meta.py
5 include _build_meta.py
6 include MANIFEST.in
6 include MANIFEST.in
7 include py.typed
8 include .mailmap
7 include .mailmap
9 include .flake8
8 include .flake8
10 include .pre-commit-config.yaml
9 include .pre-commit-config.yaml
11 include long_description.rst
10 include long_description.rst
12
11
13 recursive-exclude tools *
12 recursive-exclude tools *
14 exclude tools
13 exclude tools
15 exclude CONTRIBUTING.md
14 exclude CONTRIBUTING.md
16 exclude .editorconfig
15 exclude .editorconfig
17 exclude SECURITY.md
16 exclude SECURITY.md
18 exclude .readthedocs.yaml
17 exclude .readthedocs.yaml
19
18
20 graft scripts
19 graft scripts
21
20
22 # Load main dir but exclude things we don't want in the distro
21 # Load main dir but exclude things we don't want in the distro
23 graft IPython
22 graft IPython
24
23
25 # Documentation
24 # Documentation
26 graft docs
25 graft docs
27 exclude docs/\#*
26 exclude docs/\#*
28 exclude docs/man/*.1.gz
27 exclude docs/man/*.1.gz
29
28
30 exclude .git-blame-ignore-revs
29 exclude .git-blame-ignore-revs
31
30
32 # Examples
31 # Examples
33 graft examples
32 graft examples
34
33
35 # docs subdirs we want to skip
34 # docs subdirs we want to skip
36 prune docs/build
35 prune docs/build
37 prune docs/gh-pages
36 prune docs/gh-pages
38 prune docs/dist
37 prune docs/dist
39
38
40 # Patterns to exclude from any directory
39 # Patterns to exclude from any directory
41 global-exclude *~
40 global-exclude *~
42 global-exclude *.flc
41 global-exclude *.flc
43 global-exclude *.yml
42 global-exclude *.yml
44 global-exclude *.pyc
43 global-exclude *.pyc
45 global-exclude *.pyo
44 global-exclude *.pyo
46 global-exclude .dircopy.log
45 global-exclude .dircopy.log
47 global-exclude .git
46 global-exclude .git
48 global-exclude .ipynb_checkpoints
47 global-exclude .ipynb_checkpoints
@@ -1,205 +1,204 b''
1 [build-system]
1 [build-system]
2 requires = ["setuptools>=61.2"]
2 requires = ["setuptools>=61.2"]
3 # We need access to the 'setupbase' module at build time.
3 # We need access to the 'setupbase' module at build time.
4 # Hence we declare a custom build backend.
4 # Hence we declare a custom build backend.
5 build-backend = "_build_meta" # just re-exports setuptools.build_meta definitions
5 build-backend = "_build_meta" # just re-exports setuptools.build_meta definitions
6 backend-path = ["."]
6 backend-path = ["."]
7
7
8 [project]
8 [project]
9 name = "ipython"
9 name = "ipython"
10 description = "IPython: Productive Interactive Computing"
10 description = "IPython: Productive Interactive Computing"
11 keywords = ["Interactive", "Interpreter", "Shell", "Embedding"]
11 keywords = ["Interactive", "Interpreter", "Shell", "Embedding"]
12 classifiers = [
12 classifiers = [
13 "Framework :: IPython",
13 "Framework :: IPython",
14 "Framework :: Jupyter",
14 "Framework :: Jupyter",
15 "Intended Audience :: Developers",
15 "Intended Audience :: Developers",
16 "Intended Audience :: Science/Research",
16 "Intended Audience :: Science/Research",
17 "License :: OSI Approved :: BSD License",
17 "License :: OSI Approved :: BSD License",
18 "Programming Language :: Python",
18 "Programming Language :: Python",
19 "Programming Language :: Python :: 3",
19 "Programming Language :: Python :: 3",
20 "Programming Language :: Python :: 3 :: Only",
20 "Programming Language :: Python :: 3 :: Only",
21 "Topic :: System :: Shells",
21 "Topic :: System :: Shells",
22 ]
22 ]
23 requires-python = ">=3.10"
23 requires-python = ">=3.10"
24 dependencies = [
24 dependencies = [
25 'colorama; sys_platform == "win32"',
25 'colorama; sys_platform == "win32"',
26 "decorator",
26 "decorator",
27 "exceptiongroup; python_version<'3.11'",
27 "exceptiongroup; python_version<'3.11'",
28 "jedi>=0.16",
28 "jedi>=0.16",
29 "matplotlib-inline",
29 "matplotlib-inline",
30 'pexpect>4.3; sys_platform != "win32" and sys_platform != "emscripten"',
30 'pexpect>4.3; sys_platform != "win32" and sys_platform != "emscripten"',
31 "prompt_toolkit>=3.0.41,<3.1.0",
31 "prompt_toolkit>=3.0.41,<3.1.0",
32 "pygments>=2.4.0",
32 "pygments>=2.4.0",
33 "stack_data",
33 "stack_data",
34 "traitlets>=5",
34 "traitlets>=5",
35 "typing_extensions; python_version<'3.10'",
35 "typing_extensions; python_version<'3.10'",
36 ]
36 ]
37 dynamic = ["authors", "entry-points", "license", "scripts", "version"]
37 dynamic = ["authors", "entry-points", "license", "scripts", "version"]
38
38
39 [project.readme]
39 [project.readme]
40 file = "long_description.rst"
40 file = "long_description.rst"
41 content-type = "text/x-rst"
41 content-type = "text/x-rst"
42
42
43 [project.urls]
43 [project.urls]
44 Homepage = "https://ipython.org"
44 Homepage = "https://ipython.org"
45 Documentation = "https://ipython.readthedocs.io/"
45 Documentation = "https://ipython.readthedocs.io/"
46 Funding = "https://numfocus.org/"
46 Funding = "https://numfocus.org/"
47 Source = "https://github.com/ipython/ipython"
47 Source = "https://github.com/ipython/ipython"
48 Tracker = "https://github.com/ipython/ipython/issues"
48 Tracker = "https://github.com/ipython/ipython/issues"
49
49
50 [project.optional-dependencies]
50 [project.optional-dependencies]
51 black = [
51 black = [
52 "black",
52 "black",
53 ]
53 ]
54 doc = [
54 doc = [
55 "ipykernel",
55 "ipykernel",
56 "setuptools>=18.5",
56 "setuptools>=18.5",
57 "sphinx>=1.3",
57 "sphinx>=1.3",
58 "sphinx-rtd-theme",
58 "sphinx-rtd-theme",
59 "docrepr",
59 "docrepr",
60 "matplotlib",
60 "matplotlib",
61 "stack_data",
61 "stack_data",
62 "typing_extensions",
62 "typing_extensions",
63 "exceptiongroup",
63 "exceptiongroup",
64 "ipython[test]",
64 "ipython[test]",
65 ]
65 ]
66 kernel = [
66 kernel = [
67 "ipykernel",
67 "ipykernel",
68 ]
68 ]
69 nbconvert = [
69 nbconvert = [
70 "nbconvert",
70 "nbconvert",
71 ]
71 ]
72 nbformat = [
72 nbformat = [
73 "nbformat",
73 "nbformat",
74 ]
74 ]
75 notebook = [
75 notebook = [
76 "ipywidgets",
76 "ipywidgets",
77 "notebook",
77 "notebook",
78 ]
78 ]
79 parallel = [
79 parallel = [
80 "ipyparallel",
80 "ipyparallel",
81 ]
81 ]
82 qtconsole = [
82 qtconsole = [
83 "qtconsole",
83 "qtconsole",
84 ]
84 ]
85 terminal = []
85 terminal = []
86 test = [
86 test = [
87 "pytest<8",
87 "pytest<8",
88 "pytest-asyncio<0.22",
88 "pytest-asyncio<0.22",
89 "testpath",
89 "testpath",
90 "pickleshare",
90 "pickleshare",
91 ]
91 ]
92 test_extra = [
92 test_extra = [
93 "ipython[test]",
93 "ipython[test]",
94 "curio",
94 "curio",
95 "matplotlib!=3.2.0",
95 "matplotlib!=3.2.0",
96 "nbformat",
96 "nbformat",
97 "numpy>=1.23",
97 "numpy>=1.23",
98 "pandas",
98 "pandas",
99 "trio",
99 "trio",
100 ]
100 ]
101 all = [
101 all = [
102 "ipython[black,doc,kernel,nbconvert,nbformat,notebook,parallel,qtconsole,terminal]",
102 "ipython[black,doc,kernel,nbconvert,nbformat,notebook,parallel,qtconsole,terminal]",
103 "ipython[test,test_extra]",
103 "ipython[test,test_extra]",
104 ]
104 ]
105
105
106 [tool.mypy]
106 [tool.mypy]
107 python_version = "3.10"
107 python_version = "3.10"
108 ignore_missing_imports = true
108 ignore_missing_imports = true
109 follow_imports = 'silent'
109 follow_imports = 'silent'
110 exclude = [
110 exclude = [
111 'test_\.+\.py',
111 'test_\.+\.py',
112 'IPython.utils.tests.test_wildcard',
112 'IPython.utils.tests.test_wildcard',
113 'testing',
113 'testing',
114 'tests',
114 'tests',
115 'PyColorize.py',
115 'PyColorize.py',
116 '_process_win32_controller.py',
116 '_process_win32_controller.py',
117 'IPython/core/application.py',
117 'IPython/core/application.py',
118 'IPython/core/completerlib.py',
118 'IPython/core/completerlib.py',
119 'IPython/core/displaypub.py',
119 'IPython/core/displaypub.py',
120 'IPython/core/historyapp.py',
120 'IPython/core/historyapp.py',
121 #'IPython/core/interactiveshell.py',
121 #'IPython/core/interactiveshell.py',
122 'IPython/core/magic.py',
122 'IPython/core/magic.py',
123 'IPython/core/profileapp.py',
123 'IPython/core/profileapp.py',
124 # 'IPython/core/ultratb.py',
124 # 'IPython/core/ultratb.py',
125 'IPython/lib/deepreload.py',
125 'IPython/lib/deepreload.py',
126 'IPython/lib/pretty.py',
126 'IPython/lib/pretty.py',
127 'IPython/sphinxext/ipython_directive.py',
127 'IPython/sphinxext/ipython_directive.py',
128 'IPython/terminal/ipapp.py',
128 'IPython/terminal/ipapp.py',
129 'IPython/utils/_process_win32.py',
129 'IPython/utils/_process_win32.py',
130 'IPython/utils/path.py',
130 'IPython/utils/path.py',
131 'IPython/utils/timing.py',
131 'IPython/utils/timing.py',
132 'IPython/utils/text.py'
132 'IPython/utils/text.py'
133 ]
133 ]
134
134
135 [tool.pytest.ini_options]
135 [tool.pytest.ini_options]
136 addopts = [
136 addopts = [
137 "--durations=10",
137 "--durations=10",
138 "-pIPython.testing.plugin.pytest_ipdoctest",
138 "-pIPython.testing.plugin.pytest_ipdoctest",
139 "--ipdoctest-modules",
139 "--ipdoctest-modules",
140 "--ignore=docs",
140 "--ignore=docs",
141 "--ignore=examples",
141 "--ignore=examples",
142 "--ignore=htmlcov",
142 "--ignore=htmlcov",
143 "--ignore=ipython_kernel",
143 "--ignore=ipython_kernel",
144 "--ignore=ipython_parallel",
144 "--ignore=ipython_parallel",
145 "--ignore=results",
145 "--ignore=results",
146 "--ignore=tmp",
146 "--ignore=tmp",
147 "--ignore=tools",
147 "--ignore=tools",
148 "--ignore=traitlets",
148 "--ignore=traitlets",
149 "--ignore=IPython/core/tests/daft_extension",
149 "--ignore=IPython/core/tests/daft_extension",
150 "--ignore=IPython/sphinxext",
150 "--ignore=IPython/sphinxext",
151 "--ignore=IPython/terminal/pt_inputhooks",
151 "--ignore=IPython/terminal/pt_inputhooks",
152 "--ignore=IPython/__main__.py",
152 "--ignore=IPython/__main__.py",
153 "--ignore=IPython/external/qt_for_kernel.py",
153 "--ignore=IPython/external/qt_for_kernel.py",
154 "--ignore=IPython/html/widgets/widget_link.py",
154 "--ignore=IPython/html/widgets/widget_link.py",
155 "--ignore=IPython/html/widgets/widget_output.py",
155 "--ignore=IPython/html/widgets/widget_output.py",
156 "--ignore=IPython/terminal/console.py",
156 "--ignore=IPython/terminal/console.py",
157 "--ignore=IPython/utils/_process_cli.py",
157 "--ignore=IPython/utils/_process_cli.py",
158 "--ignore=IPython/utils/_process_posix.py",
158 "--ignore=IPython/utils/_process_posix.py",
159 "--ignore=IPython/utils/_process_win32.py",
159 "--ignore=IPython/utils/_process_win32.py",
160 "--ignore=IPython/utils/_process_win32_controller.py",
160 "--ignore=IPython/utils/_process_win32_controller.py",
161 "--ignore=IPython/utils/daemonize.py",
161 "--ignore=IPython/utils/daemonize.py",
162 "--ignore=IPython/utils/eventful.py",
162 "--ignore=IPython/utils/eventful.py",
163 "--ignore=IPython/kernel",
163 "--ignore=IPython/kernel",
164 "--ignore=IPython/consoleapp.py",
164 "--ignore=IPython/consoleapp.py",
165 "--ignore=IPython/core/inputsplitter.py",
165 "--ignore=IPython/core/inputsplitter.py",
166 "--ignore=IPython/lib/kernel.py",
166 "--ignore=IPython/lib/kernel.py",
167 "--ignore=IPython/utils/jsonutil.py",
167 "--ignore=IPython/utils/jsonutil.py",
168 "--ignore=IPython/utils/localinterfaces.py",
168 "--ignore=IPython/utils/localinterfaces.py",
169 "--ignore=IPython/utils/log.py",
169 "--ignore=IPython/utils/log.py",
170 "--ignore=IPython/utils/signatures.py",
170 "--ignore=IPython/utils/signatures.py",
171 "--ignore=IPython/utils/traitlets.py",
171 "--ignore=IPython/utils/traitlets.py",
172 "--ignore=IPython/utils/version.py"
172 "--ignore=IPython/utils/version.py"
173 ]
173 ]
174 doctest_optionflags = [
174 doctest_optionflags = [
175 "NORMALIZE_WHITESPACE",
175 "NORMALIZE_WHITESPACE",
176 "ELLIPSIS"
176 "ELLIPSIS"
177 ]
177 ]
178 ipdoctest_optionflags = [
178 ipdoctest_optionflags = [
179 "NORMALIZE_WHITESPACE",
179 "NORMALIZE_WHITESPACE",
180 "ELLIPSIS"
180 "ELLIPSIS"
181 ]
181 ]
182 asyncio_mode = "strict"
182 asyncio_mode = "strict"
183
183
184 [tool.pyright]
184 [tool.pyright]
185 pythonPlatform="All"
185 pythonPlatform="All"
186
186
187 [tool.setuptools]
187 [tool.setuptools]
188 zip-safe = false
188 zip-safe = false
189 platforms = ["Linux", "Mac OSX", "Windows"]
189 platforms = ["Linux", "Mac OSX", "Windows"]
190 license-files = ["LICENSE"]
190 license-files = ["LICENSE"]
191 include-package-data = false
192
191
193 [tool.setuptools.packages.find]
192 [tool.setuptools.packages.find]
194 exclude = ["setupext"]
193 exclude = ["setupext"]
195 namespaces = false
194 namespaces = false
196
195
197 [tool.setuptools.package-data]
196 [tool.setuptools.package-data]
198 ipython = ["py.typed"]
197 ipython = ["py.typed"]
199 "ipython.core" = ["profile/README*"]
198 "ipython.core" = ["profile/README*"]
200 "ipython.core.tests" = ["*.png", "*.jpg", "daft_extension/*.py"]
199 "ipython.core.tests" = ["*.png", "*.jpg", "daft_extension/*.py"]
201 "ipython.lib.tests" = ["*.wav"]
200 "ipython.lib.tests" = ["*.wav"]
202 "ipython.testing.plugin" = ["*.txt"]
201 "ipython.testing.plugin" = ["*.txt"]
203
202
204 [tool.setuptools.dynamic]
203 [tool.setuptools.dynamic]
205 version = {attr = "IPython.core.release.__version__"}
204 version = {attr = "IPython.core.release.__version__"}
@@ -1,349 +1,332 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 # Check package data
93 #---------------------------------------------------------------------------
93 #---------------------------------------------------------------------------
94
94
95 def find_package_data():
96 """
97 Find IPython's package_data.
98 """
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
101
102 package_data = {
103 'IPython.core' : ['profile/README*'],
104 'IPython.core.tests' : ['*.png', '*.jpg', 'daft_extension/*.py'],
105 'IPython.lib.tests' : ['*.wav'],
106 'IPython.testing.plugin' : ['*.txt'],
107 }
108
109 return package_data
110
111
112 def check_package_data(package_data):
95 def check_package_data(package_data):
113 """verify that package_data globs make sense"""
96 """verify that package_data globs make sense"""
114 print("checking package data")
97 print("checking package data")
115 for pkg, data in package_data.items():
98 for pkg, data in package_data.items():
116 pkg_root = pjoin(*pkg.split('.'))
99 pkg_root = pjoin(*pkg.split('.'))
117 for d in data:
100 for d in data:
118 path = pjoin(pkg_root, d)
101 path = pjoin(pkg_root, d)
119 if '*' in path:
102 if '*' in path:
120 assert len(glob(path)) > 0, "No files match pattern %s" % path
103 assert len(glob(path)) > 0, "No files match pattern %s" % path
121 else:
104 else:
122 assert os.path.exists(path), "Missing package data: %s" % path
105 assert os.path.exists(path), "Missing package data: %s" % path
123
106
124
107
125 def check_package_data_first(command):
108 def check_package_data_first(command):
126 """decorator for checking package_data before running a given command
109 """decorator for checking package_data before running a given command
127
110
128 Probably only needs to wrap build_py
111 Probably only needs to wrap build_py
129 """
112 """
130 class DecoratedCommand(command):
113 class DecoratedCommand(command):
131 def run(self):
114 def run(self):
132 check_package_data(self.package_data)
115 check_package_data(self.package_data)
133 command.run(self)
116 command.run(self)
134 return DecoratedCommand
117 return DecoratedCommand
135
118
136
119
137 #---------------------------------------------------------------------------
120 #---------------------------------------------------------------------------
138 # Find data files
121 # Find data files
139 #---------------------------------------------------------------------------
122 #---------------------------------------------------------------------------
140
123
141 def find_data_files():
124 def find_data_files():
142 """
125 """
143 Find IPython's data_files.
126 Find IPython's data_files.
144
127
145 Just man pages at this point.
128 Just man pages at this point.
146 """
129 """
147
130
148 if "freebsd" in sys.platform:
131 if "freebsd" in sys.platform:
149 manpagebase = pjoin('man', 'man1')
132 manpagebase = pjoin('man', 'man1')
150 else:
133 else:
151 manpagebase = pjoin('share', 'man', 'man1')
134 manpagebase = pjoin('share', 'man', 'man1')
152
135
153 # Simple file lists can be made by hand
136 # Simple file lists can be made by hand
154 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
137 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
155 if not manpages:
138 if not manpages:
156 # When running from a source tree, the manpages aren't gzipped
139 # 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)]
140 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
158
141
159 # And assemble the entire output list
142 # And assemble the entire output list
160 data_files = [ (manpagebase, manpages) ]
143 data_files = [ (manpagebase, manpages) ]
161
144
162 return data_files
145 return data_files
163
146
164
147
165 # The two functions below are copied from IPython.utils.path, so we don't need
148 # 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.
149 # to import IPython during setup, which fails on Python 3.
167
150
168 def target_outdated(target,deps):
151 def target_outdated(target,deps):
169 """Determine whether a target is out of date.
152 """Determine whether a target is out of date.
170
153
171 target_outdated(target,deps) -> 1/0
154 target_outdated(target,deps) -> 1/0
172
155
173 deps: list of filenames which MUST exist.
156 deps: list of filenames which MUST exist.
174 target: single filename which may or may not exist.
157 target: single filename which may or may not exist.
175
158
176 If target doesn't exist or is older than any file listed in deps, return
159 If target doesn't exist or is older than any file listed in deps, return
177 true, otherwise return false.
160 true, otherwise return false.
178 """
161 """
179 try:
162 try:
180 target_time = os.path.getmtime(target)
163 target_time = os.path.getmtime(target)
181 except os.error:
164 except os.error:
182 return 1
165 return 1
183 for dep in deps:
166 for dep in deps:
184 dep_time = os.path.getmtime(dep)
167 dep_time = os.path.getmtime(dep)
185 if dep_time > target_time:
168 if dep_time > target_time:
186 #print "For target",target,"Dep failed:",dep # dbg
169 #print "For target",target,"Dep failed:",dep # dbg
187 #print "times (dep,tar):",dep_time,target_time # dbg
170 #print "times (dep,tar):",dep_time,target_time # dbg
188 return 1
171 return 1
189 return 0
172 return 0
190
173
191
174
192 def target_update(target,deps,cmd):
175 def target_update(target,deps,cmd):
193 """Update a target with a given command given a list of dependencies.
176 """Update a target with a given command given a list of dependencies.
194
177
195 target_update(target,deps,cmd) -> runs cmd if target is outdated.
178 target_update(target,deps,cmd) -> runs cmd if target is outdated.
196
179
197 This is just a wrapper around target_outdated() which calls the given
180 This is just a wrapper around target_outdated() which calls the given
198 command if target is outdated."""
181 command if target is outdated."""
199
182
200 if target_outdated(target,deps):
183 if target_outdated(target,deps):
201 os.system(cmd)
184 os.system(cmd)
202
185
203 #---------------------------------------------------------------------------
186 #---------------------------------------------------------------------------
204 # Find scripts
187 # Find scripts
205 #---------------------------------------------------------------------------
188 #---------------------------------------------------------------------------
206
189
207 def find_entry_points():
190 def find_entry_points():
208 """Defines the command line entry points for IPython
191 """Defines the command line entry points for IPython
209
192
210 This always uses setuptools-style entry points. When setuptools is not in
193 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
194 use, our own build_scripts_entrypt class below parses these and builds
212 command line scripts.
195 command line scripts.
213
196
214 Each of our entry points gets a plain name, e.g. ipython, and a name
197 Each of our entry points gets a plain name, e.g. ipython, and a name
215 suffixed with the Python major version number, e.g. ipython3.
198 suffixed with the Python major version number, e.g. ipython3.
216 """
199 """
217 ep = [
200 ep = [
218 'ipython%s = IPython:start_ipython',
201 'ipython%s = IPython:start_ipython',
219 ]
202 ]
220 major_suffix = str(sys.version_info[0])
203 major_suffix = str(sys.version_info[0])
221 return [e % "" for e in ep] + [e % major_suffix for e in ep]
204 return [e % "" for e in ep] + [e % major_suffix for e in ep]
222
205
223
206
224 class install_lib_symlink(Command):
207 class install_lib_symlink(Command):
225 user_options = [
208 user_options = [
226 ('install-dir=', 'd', "directory to install to"),
209 ('install-dir=', 'd', "directory to install to"),
227 ]
210 ]
228
211
229 def initialize_options(self):
212 def initialize_options(self):
230 self.install_dir = None
213 self.install_dir = None
231
214
232 def finalize_options(self):
215 def finalize_options(self):
233 self.set_undefined_options('symlink',
216 self.set_undefined_options('symlink',
234 ('install_lib', 'install_dir'),
217 ('install_lib', 'install_dir'),
235 )
218 )
236
219
237 def run(self):
220 def run(self):
238 if sys.platform == 'win32':
221 if sys.platform == 'win32':
239 raise Exception("This doesn't work on Windows.")
222 raise Exception("This doesn't work on Windows.")
240 pkg = os.path.join(os.getcwd(), 'IPython')
223 pkg = os.path.join(os.getcwd(), 'IPython')
241 dest = os.path.join(self.install_dir, 'IPython')
224 dest = os.path.join(self.install_dir, 'IPython')
242 if os.path.islink(dest):
225 if os.path.islink(dest):
243 print('removing existing symlink at %s' % dest)
226 print('removing existing symlink at %s' % dest)
244 os.unlink(dest)
227 os.unlink(dest)
245 print('symlinking %s -> %s' % (pkg, dest))
228 print('symlinking %s -> %s' % (pkg, dest))
246 os.symlink(pkg, dest)
229 os.symlink(pkg, dest)
247
230
248 class unsymlink(install):
231 class unsymlink(install):
249 def run(self):
232 def run(self):
250 dest = os.path.join(self.install_lib, 'IPython')
233 dest = os.path.join(self.install_lib, 'IPython')
251 if os.path.islink(dest):
234 if os.path.islink(dest):
252 print('removing symlink at %s' % dest)
235 print('removing symlink at %s' % dest)
253 os.unlink(dest)
236 os.unlink(dest)
254 else:
237 else:
255 print('No symlink exists at %s' % dest)
238 print('No symlink exists at %s' % dest)
256
239
257 class install_symlinked(install):
240 class install_symlinked(install):
258 def run(self):
241 def run(self):
259 if sys.platform == 'win32':
242 if sys.platform == 'win32':
260 raise Exception("This doesn't work on Windows.")
243 raise Exception("This doesn't work on Windows.")
261
244
262 # Run all sub-commands (at least those that need to be run)
245 # Run all sub-commands (at least those that need to be run)
263 for cmd_name in self.get_sub_commands():
246 for cmd_name in self.get_sub_commands():
264 self.run_command(cmd_name)
247 self.run_command(cmd_name)
265
248
266 # 'sub_commands': a list of commands this command might have to run to
249 # 'sub_commands': a list of commands this command might have to run to
267 # get its work done. See cmd.py for more info.
250 # get its work done. See cmd.py for more info.
268 sub_commands = [('install_lib_symlink', lambda self:True),
251 sub_commands = [('install_lib_symlink', lambda self:True),
269 ('install_scripts_sym', lambda self:True),
252 ('install_scripts_sym', lambda self:True),
270 ]
253 ]
271
254
272 class install_scripts_for_symlink(install_scripts):
255 class install_scripts_for_symlink(install_scripts):
273 """Redefined to get options from 'symlink' instead of 'install'.
256 """Redefined to get options from 'symlink' instead of 'install'.
274
257
275 I love distutils almost as much as I love setuptools.
258 I love distutils almost as much as I love setuptools.
276 """
259 """
277 def finalize_options(self):
260 def finalize_options(self):
278 self.set_undefined_options('build', ('build_scripts', 'build_dir'))
261 self.set_undefined_options('build', ('build_scripts', 'build_dir'))
279 self.set_undefined_options('symlink',
262 self.set_undefined_options('symlink',
280 ('install_scripts', 'install_dir'),
263 ('install_scripts', 'install_dir'),
281 ('force', 'force'),
264 ('force', 'force'),
282 ('skip_build', 'skip_build'),
265 ('skip_build', 'skip_build'),
283 )
266 )
284
267
285
268
286 #---------------------------------------------------------------------------
269 #---------------------------------------------------------------------------
287 # VCS related
270 # VCS related
288 #---------------------------------------------------------------------------
271 #---------------------------------------------------------------------------
289
272
290
273
291 def git_prebuild(pkg_dir, build_cmd=build_py):
274 def git_prebuild(pkg_dir, build_cmd=build_py):
292 """Return extended build or sdist command class for recording commit
275 """Return extended build or sdist command class for recording commit
293
276
294 records git commit in IPython.utils._sysinfo.commit
277 records git commit in IPython.utils._sysinfo.commit
295
278
296 for use in IPython.utils.sysinfo.sys_info() calls after installation.
279 for use in IPython.utils.sysinfo.sys_info() calls after installation.
297 """
280 """
298
281
299 class MyBuildPy(build_cmd):
282 class MyBuildPy(build_cmd):
300 ''' Subclass to write commit data into installation tree '''
283 ''' Subclass to write commit data into installation tree '''
301 def run(self):
284 def run(self):
302 # loose as `.dev` is suppose to be invalid
285 # loose as `.dev` is suppose to be invalid
303 print("check version number")
286 print("check version number")
304 loose_pep440re = re.compile(r'^(\d+)\.(\d+)\.(\d+((a|b|rc)\d+)?)(\.post\d+)?(\.dev\d*)?$')
287 loose_pep440re = re.compile(r'^(\d+)\.(\d+)\.(\d+((a|b|rc)\d+)?)(\.post\d+)?(\.dev\d*)?$')
305 if not loose_pep440re.match(version):
288 if not loose_pep440re.match(version):
306 raise ValueError("Version number '%s' is not valid (should match [N!]N(.N)*[{a|b|rc}N][.postN][.devN])" % version)
289 raise ValueError("Version number '%s' is not valid (should match [N!]N(.N)*[{a|b|rc}N][.postN][.devN])" % version)
307
290
308
291
309 build_cmd.run(self)
292 build_cmd.run(self)
310 # this one will only fire for build commands
293 # this one will only fire for build commands
311 if hasattr(self, 'build_lib'):
294 if hasattr(self, 'build_lib'):
312 self._record_commit(self.build_lib)
295 self._record_commit(self.build_lib)
313
296
314 def make_release_tree(self, base_dir, files):
297 def make_release_tree(self, base_dir, files):
315 # this one will fire for sdist
298 # this one will fire for sdist
316 build_cmd.make_release_tree(self, base_dir, files)
299 build_cmd.make_release_tree(self, base_dir, files)
317 self._record_commit(base_dir)
300 self._record_commit(base_dir)
318
301
319 def _record_commit(self, base_dir):
302 def _record_commit(self, base_dir):
320 import subprocess
303 import subprocess
321 proc = subprocess.Popen('git rev-parse --short HEAD',
304 proc = subprocess.Popen('git rev-parse --short HEAD',
322 stdout=subprocess.PIPE,
305 stdout=subprocess.PIPE,
323 stderr=subprocess.PIPE,
306 stderr=subprocess.PIPE,
324 shell=True)
307 shell=True)
325 repo_commit, _ = proc.communicate()
308 repo_commit, _ = proc.communicate()
326 repo_commit = repo_commit.strip().decode("ascii")
309 repo_commit = repo_commit.strip().decode("ascii")
327
310
328 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
311 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
329 if os.path.isfile(out_pth) and not repo_commit:
312 if os.path.isfile(out_pth) and not repo_commit:
330 # nothing to write, don't clobber
313 # nothing to write, don't clobber
331 return
314 return
332
315
333 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
316 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
334
317
335 # remove to avoid overwriting original via hard link
318 # remove to avoid overwriting original via hard link
336 try:
319 try:
337 os.remove(out_pth)
320 os.remove(out_pth)
338 except (IOError, OSError):
321 except (IOError, OSError):
339 pass
322 pass
340 with open(out_pth, "w", encoding="utf-8") as out_file:
323 with open(out_pth, "w", encoding="utf-8") as out_file:
341 out_file.writelines(
324 out_file.writelines(
342 [
325 [
343 "# GENERATED BY setup.py\n",
326 "# GENERATED BY setup.py\n",
344 'commit = "%s"\n' % repo_commit,
327 'commit = "%s"\n' % repo_commit,
345 ]
328 ]
346 )
329 )
347
330
348 return MyBuildPy
331 return MyBuildPy
349
332
General Comments 0
You need to be logged in to leave comments. Login now