##// END OF EJS Templates
pyproject.toml (project.entrypoints, project.scripts): Move here from setup.py, setupbase.py
Matthias Koeppe -
Show More
@@ -1,196 +1,205 b''
1 1 [build-system]
2 2 requires = ["setuptools>=61.2"]
3 3 # We need access to the 'setupbase' module at build time.
4 4 # Hence we declare a custom build backend.
5 5 build-backend = "_build_meta" # just re-exports setuptools.build_meta definitions
6 6 backend-path = ["."]
7 7
8 8 [project]
9 9 name = "ipython"
10 10 description = "IPython: Productive Interactive Computing"
11 11 keywords = ["Interactive", "Interpreter", "Shell", "Embedding"]
12 12 classifiers = [
13 13 "Framework :: IPython",
14 14 "Framework :: Jupyter",
15 15 "Intended Audience :: Developers",
16 16 "Intended Audience :: Science/Research",
17 17 "License :: OSI Approved :: BSD License",
18 18 "Programming Language :: Python",
19 19 "Programming Language :: Python :: 3",
20 20 "Programming Language :: Python :: 3 :: Only",
21 21 "Topic :: System :: Shells",
22 22 ]
23 23 requires-python = ">=3.10"
24 24 dependencies = [
25 25 'colorama; sys_platform == "win32"',
26 26 "decorator",
27 27 "exceptiongroup; python_version<'3.11'",
28 28 "jedi>=0.16",
29 29 "matplotlib-inline",
30 30 'pexpect>4.3; sys_platform != "win32" and sys_platform != "emscripten"',
31 31 "prompt_toolkit>=3.0.41,<3.1.0",
32 32 "pygments>=2.4.0",
33 33 "stack_data",
34 34 "traitlets>=5",
35 35 "typing_extensions; python_version<'3.10'",
36 36 ]
37 dynamic = ["authors", "entry-points", "license", "scripts", "version"]
37 dynamic = ["authors", "license", "version"]
38
39 [project.entry-points."pygments.lexers"]
40 ipythonconsole = "IPython.lib.lexers:IPythonConsoleLexer"
41 ipython = "IPython.lib.lexers:IPythonLexer"
42 ipython3 = "IPython.lib.lexers:IPython3Lexer"
43
44 [project.scripts]
45 ipython = "IPython:start_ipython"
46 ipython3 = "IPython:start_ipython"
38 47
39 48 [project.readme]
40 49 file = "long_description.rst"
41 50 content-type = "text/x-rst"
42 51
43 52 [project.urls]
44 53 Homepage = "https://ipython.org"
45 54 Documentation = "https://ipython.readthedocs.io/"
46 55 Funding = "https://numfocus.org/"
47 56 Source = "https://github.com/ipython/ipython"
48 57 Tracker = "https://github.com/ipython/ipython/issues"
49 58
50 59 [project.optional-dependencies]
51 60 black = [
52 61 "black",
53 62 ]
54 63 doc = [
55 64 "ipykernel",
56 65 "setuptools>=18.5",
57 66 "sphinx>=1.3",
58 67 "sphinx-rtd-theme",
59 68 "docrepr",
60 69 "matplotlib",
61 70 "stack_data",
62 71 "typing_extensions",
63 72 "exceptiongroup",
64 73 "ipython[test]",
65 74 ]
66 75 kernel = [
67 76 "ipykernel",
68 77 ]
69 78 nbconvert = [
70 79 "nbconvert",
71 80 ]
72 81 nbformat = [
73 82 "nbformat",
74 83 ]
75 84 notebook = [
76 85 "ipywidgets",
77 86 "notebook",
78 87 ]
79 88 parallel = [
80 89 "ipyparallel",
81 90 ]
82 91 qtconsole = [
83 92 "qtconsole",
84 93 ]
85 94 terminal = []
86 95 test = [
87 96 "pytest<8",
88 97 "pytest-asyncio<0.22",
89 98 "testpath",
90 99 "pickleshare",
91 100 ]
92 101 test_extra = [
93 102 "ipython[test]",
94 103 "curio",
95 104 "matplotlib!=3.2.0",
96 105 "nbformat",
97 106 "numpy>=1.23",
98 107 "pandas",
99 108 "trio",
100 109 ]
101 110 all = [
102 111 "ipython[black,doc,kernel,nbconvert,nbformat,notebook,parallel,qtconsole,terminal]",
103 112 "ipython[test,test_extra]",
104 113 ]
105 114
106 115 [tool.mypy]
107 116 python_version = "3.10"
108 117 ignore_missing_imports = true
109 118 follow_imports = 'silent'
110 119 exclude = [
111 120 'test_\.+\.py',
112 121 'IPython.utils.tests.test_wildcard',
113 122 'testing',
114 123 'tests',
115 124 'PyColorize.py',
116 125 '_process_win32_controller.py',
117 126 'IPython/core/application.py',
118 127 'IPython/core/profileapp.py',
119 128 'IPython/lib/deepreload.py',
120 129 'IPython/sphinxext/ipython_directive.py',
121 130 'IPython/terminal/ipapp.py',
122 131 'IPython/utils/_process_win32.py',
123 132 'IPython/utils/path.py',
124 133 ]
125 134
126 135 [tool.pytest.ini_options]
127 136 addopts = [
128 137 "--durations=10",
129 138 "-pIPython.testing.plugin.pytest_ipdoctest",
130 139 "--ipdoctest-modules",
131 140 "--ignore=docs",
132 141 "--ignore=examples",
133 142 "--ignore=htmlcov",
134 143 "--ignore=ipython_kernel",
135 144 "--ignore=ipython_parallel",
136 145 "--ignore=results",
137 146 "--ignore=tmp",
138 147 "--ignore=tools",
139 148 "--ignore=traitlets",
140 149 "--ignore=IPython/core/tests/daft_extension",
141 150 "--ignore=IPython/sphinxext",
142 151 "--ignore=IPython/terminal/pt_inputhooks",
143 152 "--ignore=IPython/__main__.py",
144 153 "--ignore=IPython/external/qt_for_kernel.py",
145 154 "--ignore=IPython/html/widgets/widget_link.py",
146 155 "--ignore=IPython/html/widgets/widget_output.py",
147 156 "--ignore=IPython/terminal/console.py",
148 157 "--ignore=IPython/utils/_process_cli.py",
149 158 "--ignore=IPython/utils/_process_posix.py",
150 159 "--ignore=IPython/utils/_process_win32.py",
151 160 "--ignore=IPython/utils/_process_win32_controller.py",
152 161 "--ignore=IPython/utils/daemonize.py",
153 162 "--ignore=IPython/utils/eventful.py",
154 163 "--ignore=IPython/kernel",
155 164 "--ignore=IPython/consoleapp.py",
156 165 "--ignore=IPython/core/inputsplitter.py",
157 166 "--ignore=IPython/lib/kernel.py",
158 167 "--ignore=IPython/utils/jsonutil.py",
159 168 "--ignore=IPython/utils/localinterfaces.py",
160 169 "--ignore=IPython/utils/log.py",
161 170 "--ignore=IPython/utils/signatures.py",
162 171 "--ignore=IPython/utils/traitlets.py",
163 172 "--ignore=IPython/utils/version.py"
164 173 ]
165 174 doctest_optionflags = [
166 175 "NORMALIZE_WHITESPACE",
167 176 "ELLIPSIS"
168 177 ]
169 178 ipdoctest_optionflags = [
170 179 "NORMALIZE_WHITESPACE",
171 180 "ELLIPSIS"
172 181 ]
173 182 asyncio_mode = "strict"
174 183
175 184 [tool.pyright]
176 185 pythonPlatform="All"
177 186
178 187 [tool.setuptools]
179 188 zip-safe = false
180 189 platforms = ["Linux", "Mac OSX", "Windows"]
181 190 license-files = ["LICENSE"]
182 191 include-package-data = false
183 192
184 193 [tool.setuptools.packages.find]
185 194 exclude = ["setupext"]
186 195 namespaces = false
187 196
188 197 [tool.setuptools.package-data]
189 198 "IPython" = ["py.typed"]
190 199 "IPython.core" = ["profile/README*"]
191 200 "IPython.core.tests" = ["*.png", "*.jpg", "daft_extension/*.py"]
192 201 "IPython.lib.tests" = ["*.wav"]
193 202 "IPython.testing.plugin" = ["*.txt"]
194 203
195 204 [tool.setuptools.dynamic]
196 205 version = {attr = "IPython.core.release.__version__"}
@@ -1,150 +1,141 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Setup script for IPython.
3 3
4 4 Under Posix environments it works like a typical setup.py script.
5 5 Under Windows, the command sdist is not supported, since IPython
6 6 requires utilities which are not available under Windows."""
7 7
8 8 #-----------------------------------------------------------------------------
9 9 # Copyright (c) 2008-2011, IPython Development Team.
10 10 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
11 11 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
12 12 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
13 13 #
14 14 # Distributed under the terms of the Modified BSD License.
15 15 #
16 16 # The full license is in the file COPYING.rst, distributed with this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 import os
20 20 import sys
21 21
22 22 # **Python version check**
23 23 #
24 24 # This check is also made in IPython/__init__, don't forget to update both when
25 25 # changing Python version requirements.
26 26 if sys.version_info < (3, 10):
27 27 pip_message = 'This may be due to an out of date pip. Make sure you have pip >= 9.0.1.'
28 28 try:
29 29 import pip
30 30 pip_version = tuple([int(x) for x in pip.__version__.split('.')[:3]])
31 31 if pip_version < (9, 0, 1) :
32 32 pip_message = 'Your pip version is out of date, please install pip >= 9.0.1. '\
33 33 'pip {} detected.'.format(pip.__version__)
34 34 else:
35 35 # pip is new enough - it must be something else
36 36 pip_message = ''
37 37 except Exception:
38 38 pass
39 39
40 40
41 41 error = """
42 42 IPython 8.19+ supports Python 3.10 and above, following SPEC0
43 43 IPython 8.13+ supports Python 3.9 and above, following NEP 29.
44 44 IPython 8.0-8.12 supports Python 3.8 and above, following NEP 29.
45 45 When using Python 2.7, please install IPython 5.x LTS Long Term Support version.
46 46 Python 3.3 and 3.4 were supported up to IPython 6.x.
47 47 Python 3.5 was supported with IPython 7.0 to 7.9.
48 48 Python 3.6 was supported with IPython up to 7.16.
49 49 Python 3.7 was still supported with the 7.x branch.
50 50
51 51 See IPython `README.rst` file for more information:
52 52
53 53 https://github.com/ipython/ipython/blob/main/README.rst
54 54
55 55 Python {py} detected.
56 56 {pip}
57 57 """.format(
58 58 py=sys.version_info, pip=pip_message
59 59 )
60 60
61 61 print(error, file=sys.stderr)
62 62 sys.exit(1)
63 63
64 64 # At least we're on the python version we need, move on.
65 65
66 66 from setuptools import setup
67 67
68 68 # Our own imports
69 69
70 from setupbase import target_update, find_entry_points
70 from setupbase import target_update
71 71
72 72 from setupbase import (
73 73 setup_args,
74 74 check_package_data_first,
75 75 find_data_files,
76 76 git_prebuild,
77 77 )
78 78
79 79 #-------------------------------------------------------------------------------
80 80 # Handle OS specific things
81 81 #-------------------------------------------------------------------------------
82 82
83 83 if os.name in ('nt','dos'):
84 84 os_name = 'windows'
85 85 else:
86 86 os_name = os.name
87 87
88 88 # Under Windows, 'sdist' has not been supported. Now that the docs build with
89 89 # Sphinx it might work, but let's not turn it on until someone confirms that it
90 90 # actually works.
91 91 if os_name == 'windows' and 'sdist' in sys.argv:
92 92 print('The sdist command is not available under Windows. Exiting.')
93 93 sys.exit(1)
94 94
95 95
96 96 #-------------------------------------------------------------------------------
97 97 # Things related to the IPython documentation
98 98 #-------------------------------------------------------------------------------
99 99
100 100 # update the manuals when building a source dist
101 101 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
102 102
103 103 # List of things to be updated. Each entry is a triplet of args for
104 104 # target_update()
105 105 to_update = [
106 106 (
107 107 "docs/man/ipython.1.gz",
108 108 ["docs/man/ipython.1"],
109 109 "cd docs/man && python -m gzip --best ipython.1",
110 110 ),
111 111 ]
112 112
113 113
114 114 [ target_update(*t) for t in to_update ]
115 115
116 116 #---------------------------------------------------------------------------
117 117 # Find all the packages, package data, and data_files
118 118 #---------------------------------------------------------------------------
119 119
120 120 data_files = find_data_files()
121 121
122 122 setup_args['data_files'] = data_files
123 123
124 124 #---------------------------------------------------------------------------
125 125 # custom distutils commands
126 126 #---------------------------------------------------------------------------
127 127 # imports here, so they are after setuptools import if there was one
128 128 from setuptools.command.sdist import sdist
129 129
130 130 setup_args['cmdclass'] = {
131 131 'build_py': \
132 132 check_package_data_first(git_prebuild('IPython')),
133 133 'sdist' : git_prebuild('IPython', sdist),
134 134 }
135 135
136 setup_args["entry_points"] = {
137 "console_scripts": find_entry_points(),
138 "pygments.lexers": [
139 "ipythonconsole = IPython.lib.lexers:IPythonConsoleLexer",
140 "ipython = IPython.lib.lexers:IPythonLexer",
141 "ipython3 = IPython.lib.lexers:IPython3Lexer",
142 ],
143 }
144
145 136 #---------------------------------------------------------------------------
146 137 # Do the actual setup now
147 138 #---------------------------------------------------------------------------
148 139
149 140 if __name__ == "__main__":
150 141 setup(**setup_args)
@@ -1,246 +1,226 b''
1 1 # encoding: utf-8
2 2 """
3 3 This module defines the things that are used in setup.py for building IPython
4 4
5 5 This includes:
6 6
7 7 * The basic arguments to setup
8 8 * Functions for finding things like packages, package data, etc.
9 9 * A function for checking dependencies.
10 10 """
11 11
12 12 # Copyright (c) IPython Development Team.
13 13 # Distributed under the terms of the Modified BSD License.
14 14
15 15 import os
16 16 import re
17 17 import sys
18 18 from glob import glob
19 19 from logging import log
20 20
21 21 from setuptools import Command
22 22 from setuptools.command.build_py import build_py
23 23
24 24 from setuptools.command.install import install
25 25 from setuptools.command.install_scripts import install_scripts
26 26
27 27
28 28 #-------------------------------------------------------------------------------
29 29 # Useful globals and utility functions
30 30 #-------------------------------------------------------------------------------
31 31
32 32 # A few handy globals
33 33 isfile = os.path.isfile
34 34 pjoin = os.path.join
35 35 repo_root = os.path.dirname(os.path.abspath(__file__))
36 36
37 37 def execfile(fname, globs, locs=None):
38 38 locs = locs or globs
39 39 with open(fname, encoding="utf-8") as f:
40 40 exec(compile(f.read(), fname, "exec"), globs, locs)
41 41
42 42 # A little utility we'll need below, since glob() does NOT allow you to do
43 43 # exclusion on multiple endings!
44 44 def file_doesnt_endwith(test,endings):
45 45 """Return true if test is a file and its name does NOT end with any
46 46 of the strings listed in endings."""
47 47 if not isfile(test):
48 48 return False
49 49 for e in endings:
50 50 if test.endswith(e):
51 51 return False
52 52 return True
53 53
54 54 #---------------------------------------------------------------------------
55 55 # Basic project information
56 56 #---------------------------------------------------------------------------
57 57
58 58 # release.py contains version, authors, license, url, keywords, etc.
59 59 execfile(pjoin(repo_root, 'IPython','core','release.py'), globals())
60 60
61 61 # Create a dict with the basic information
62 62 # This dict is eventually passed to setup after additional keys are added.
63 63 setup_args = dict(
64 64 author = author,
65 65 author_email = author_email,
66 66 license = license,
67 67 )
68 68
69 69 #---------------------------------------------------------------------------
70 70 # Check package data
71 71 #---------------------------------------------------------------------------
72 72
73 73 def check_package_data(package_data):
74 74 """verify that package_data globs make sense"""
75 75 print("checking package data")
76 76 for pkg, data in package_data.items():
77 77 pkg_root = pjoin(*pkg.split('.'))
78 78 for d in data:
79 79 path = pjoin(pkg_root, d)
80 80 if '*' in path:
81 81 assert len(glob(path)) > 0, "No files match pattern %s" % path
82 82 else:
83 83 assert os.path.exists(path), "Missing package data: %s" % path
84 84
85 85
86 86 def check_package_data_first(command):
87 87 """decorator for checking package_data before running a given command
88 88
89 89 Probably only needs to wrap build_py
90 90 """
91 91 class DecoratedCommand(command):
92 92 def run(self):
93 93 check_package_data(self.package_data)
94 94 command.run(self)
95 95 return DecoratedCommand
96 96
97 97
98 98 #---------------------------------------------------------------------------
99 99 # Find data files
100 100 #---------------------------------------------------------------------------
101 101
102 102 def find_data_files():
103 103 """
104 104 Find IPython's data_files.
105 105
106 106 Just man pages at this point.
107 107 """
108 108
109 109 if "freebsd" in sys.platform:
110 110 manpagebase = pjoin('man', 'man1')
111 111 else:
112 112 manpagebase = pjoin('share', 'man', 'man1')
113 113
114 114 # Simple file lists can be made by hand
115 115 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
116 116 if not manpages:
117 117 # When running from a source tree, the manpages aren't gzipped
118 118 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
119 119
120 120 # And assemble the entire output list
121 121 data_files = [ (manpagebase, manpages) ]
122 122
123 123 return data_files
124 124
125 125
126 126 # The two functions below are copied from IPython.utils.path, so we don't need
127 127 # to import IPython during setup, which fails on Python 3.
128 128
129 129 def target_outdated(target,deps):
130 130 """Determine whether a target is out of date.
131 131
132 132 target_outdated(target,deps) -> 1/0
133 133
134 134 deps: list of filenames which MUST exist.
135 135 target: single filename which may or may not exist.
136 136
137 137 If target doesn't exist or is older than any file listed in deps, return
138 138 true, otherwise return false.
139 139 """
140 140 try:
141 141 target_time = os.path.getmtime(target)
142 142 except os.error:
143 143 return 1
144 144 for dep in deps:
145 145 dep_time = os.path.getmtime(dep)
146 146 if dep_time > target_time:
147 147 #print "For target",target,"Dep failed:",dep # dbg
148 148 #print "times (dep,tar):",dep_time,target_time # dbg
149 149 return 1
150 150 return 0
151 151
152 152
153 153 def target_update(target,deps,cmd):
154 154 """Update a target with a given command given a list of dependencies.
155 155
156 156 target_update(target,deps,cmd) -> runs cmd if target is outdated.
157 157
158 158 This is just a wrapper around target_outdated() which calls the given
159 159 command if target is outdated."""
160 160
161 161 if target_outdated(target,deps):
162 162 os.system(cmd)
163 163
164 164 #---------------------------------------------------------------------------
165 # Find scripts
166 #---------------------------------------------------------------------------
167
168 def find_entry_points():
169 """Defines the command line entry points for IPython
170
171 This always uses setuptools-style entry points. When setuptools is not in
172 use, our own build_scripts_entrypt class below parses these and builds
173 command line scripts.
174
175 Each of our entry points gets a plain name, e.g. ipython, and a name
176 suffixed with the Python major version number, e.g. ipython3.
177 """
178 ep = [
179 'ipython%s = IPython:start_ipython',
180 ]
181 major_suffix = str(sys.version_info[0])
182 return [e % "" for e in ep] + [e % major_suffix for e in ep]
183
184 #---------------------------------------------------------------------------
185 165 # VCS related
186 166 #---------------------------------------------------------------------------
187 167
188 168 def git_prebuild(pkg_dir, build_cmd=build_py):
189 169 """Return extended build or sdist command class for recording commit
190 170
191 171 records git commit in IPython.utils._sysinfo.commit
192 172
193 173 for use in IPython.utils.sysinfo.sys_info() calls after installation.
194 174 """
195 175
196 176 class MyBuildPy(build_cmd):
197 177 ''' Subclass to write commit data into installation tree '''
198 178 def run(self):
199 179 # loose as `.dev` is suppose to be invalid
200 180 print("check version number")
201 181 loose_pep440re = re.compile(r'^(\d+)\.(\d+)\.(\d+((a|b|rc)\d+)?)(\.post\d+)?(\.dev\d*)?$')
202 182 if not loose_pep440re.match(version):
203 183 raise ValueError("Version number '%s' is not valid (should match [N!]N(.N)*[{a|b|rc}N][.postN][.devN])" % version)
204 184
205 185
206 186 build_cmd.run(self)
207 187 # this one will only fire for build commands
208 188 if hasattr(self, 'build_lib'):
209 189 self._record_commit(self.build_lib)
210 190
211 191 def make_release_tree(self, base_dir, files):
212 192 # this one will fire for sdist
213 193 build_cmd.make_release_tree(self, base_dir, files)
214 194 self._record_commit(base_dir)
215 195
216 196 def _record_commit(self, base_dir):
217 197 import subprocess
218 198 proc = subprocess.Popen('git rev-parse --short HEAD',
219 199 stdout=subprocess.PIPE,
220 200 stderr=subprocess.PIPE,
221 201 shell=True)
222 202 repo_commit, _ = proc.communicate()
223 203 repo_commit = repo_commit.strip().decode("ascii")
224 204
225 205 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
226 206 if os.path.isfile(out_pth) and not repo_commit:
227 207 # nothing to write, don't clobber
228 208 return
229 209
230 210 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
231 211
232 212 # remove to avoid overwriting original via hard link
233 213 try:
234 214 os.remove(out_pth)
235 215 except (IOError, OSError):
236 216 pass
237 217 with open(out_pth, "w", encoding="utf-8") as out_file:
238 218 out_file.writelines(
239 219 [
240 220 "# GENERATED BY setup.py\n",
241 221 'commit = "%s"\n' % repo_commit,
242 222 ]
243 223 )
244 224
245 225 return MyBuildPy
246 226
General Comments 0
You need to be logged in to leave comments. Login now