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