##// END OF EJS Templates
Merge pull request #13729 from jarrodmillman/master2main...
Matthias Bussonnier -
r27714:57eaa12c merge
parent child Browse files
Show More
@@ -1,34 +1,34 b''
1 1 name: Run MyPy
2 2
3 3 on:
4 4 push:
5 branches: [ master, 7.x]
5 branches: [ main, 7.x]
6 6 pull_request:
7 branches: [ master, 7.x]
7 branches: [ main, 7.x]
8 8
9 9 jobs:
10 10 build:
11 11
12 12 runs-on: ubuntu-latest
13 13 strategy:
14 14 matrix:
15 15 python-version: [3.8]
16 16
17 17 steps:
18 18 - uses: actions/checkout@v2
19 19 - name: Set up Python ${{ matrix.python-version }}
20 20 uses: actions/setup-python@v2
21 21 with:
22 22 python-version: ${{ matrix.python-version }}
23 23 - name: Install dependencies
24 24 run: |
25 25 python -m pip install --upgrade pip
26 26 pip install mypy pyflakes flake8
27 27 - name: Lint with mypy
28 28 run: |
29 29 mypy -p IPython.terminal
30 30 mypy -p IPython.core.magics
31 31 - name: Lint with pyflakes
32 32 run: |
33 33 flake8 IPython/core/magics/script.py
34 34 flake8 IPython/core/magics/packaging.py
@@ -1,40 +1,40 b''
1 1 # This workflow will install Python dependencies, run tests and lint with a variety of Python versions
2 2 # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
3 3
4 4 name: Python package
5 5
6 6 on:
7 7 push:
8 branches: [ master, 7.x ]
8 branches: [ main, 7.x ]
9 9 pull_request:
10 branches: [ master, 7.x ]
10 branches: [ main, 7.x ]
11 11
12 12 jobs:
13 13 formatting:
14 14
15 15 runs-on: ubuntu-latest
16 16 timeout-minutes: 5
17 17 strategy:
18 18 matrix:
19 19 python-version: [3.8]
20 20
21 21 steps:
22 22 - uses: actions/checkout@v2
23 23 with:
24 24 fetch-depth: 0
25 25 - name: Set up Python ${{ matrix.python-version }}
26 26 uses: actions/setup-python@v2
27 27 with:
28 28 python-version: ${{ matrix.python-version }}
29 29 - name: Install dependencies
30 30 run: |
31 31 python -m pip install --upgrade pip
32 32 pip install darker black==21.12b0
33 33 - name: Lint with darker
34 34 run: |
35 35 darker -r 60625f241f298b5039cb2debc365db38aa7bb522 --check --diff . || (
36 36 echo "Changes need auto-formatting. Run:"
37 37 echo " darker -r 60625f241f298b5039cb2debc365db38aa7bb522"
38 38 echo "then commit and push changes to fix."
39 39 exit 1
40 40 )
@@ -1,81 +1,80 b''
1 1 name: Run tests
2 2
3 3 on:
4 4 push:
5 5 branches:
6 6 - main
7 - master
8 7 - '*.x'
9 8 pull_request:
10 9 # Run weekly on Monday at 1:23 UTC
11 10 schedule:
12 11 - cron: '23 1 * * 1'
13 12 workflow_dispatch:
14 13
15 14
16 15 jobs:
17 16 test:
18 17 runs-on: ${{ matrix.os }}
19 18 strategy:
20 19 fail-fast: false
21 20 matrix:
22 21 os: [ubuntu-latest, windows-latest]
23 22 python-version: ["3.8", "3.9", "3.10"]
24 23 deps: [test_extra]
25 24 # Test all on ubuntu, test ends on macos
26 25 include:
27 26 - os: macos-latest
28 27 python-version: "3.8"
29 28 deps: test_extra
30 29 - os: macos-latest
31 30 python-version: "3.10"
32 31 deps: test_extra
33 32 # Tests minimal dependencies set
34 33 - os: ubuntu-latest
35 34 python-version: "3.10"
36 35 deps: test
37 36 # Tests latest development Python version
38 37 - os: ubuntu-latest
39 38 python-version: "3.11-dev"
40 39 deps: test
41 40 # Installing optional dependencies stuff takes ages on PyPy
42 41 - os: ubuntu-latest
43 42 python-version: "pypy-3.8"
44 43 deps: test
45 44 - os: windows-latest
46 45 python-version: "pypy-3.8"
47 46 deps: test
48 47 - os: macos-latest
49 48 python-version: "pypy-3.8"
50 49 deps: test
51 50
52 51 steps:
53 52 - uses: actions/checkout@v2
54 53 - name: Set up Python ${{ matrix.python-version }}
55 54 uses: actions/setup-python@v2
56 55 with:
57 56 python-version: ${{ matrix.python-version }}
58 57 cache: pip
59 58 - name: Install latex
60 59 if: runner.os == 'Linux' && matrix.deps == 'test_extra'
61 60 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 61 - name: Install and update Python dependencies
63 62 run: |
64 63 python -m pip install --upgrade pip setuptools wheel build
65 64 python -m pip install --upgrade -e .[${{ matrix.deps }}]
66 65 python -m pip install --upgrade check-manifest pytest-cov
67 66 - name: Try building with Python build
68 67 if: runner.os != 'Windows' # setup.py does not support sdist on Windows
69 68 run: |
70 69 python -m build
71 70 shasum -a 256 dist/*
72 71 - name: Check manifest
73 72 if: runner.os != 'Windows' # setup.py does not support sdist on Windows
74 73 run: check-manifest
75 74 - name: pytest
76 75 env:
77 76 COLUMNS: 120
78 77 run: |
79 78 pytest --color=yes -raXxs ${{ startsWith(matrix.python-version, 'pypy') && ' ' || '--cov --cov-report=xml' }}
80 79 - name: Upload coverage to Codecov
81 80 uses: codecov/codecov-action@v2
@@ -1,90 +1,90 b''
1 1 ## Triaging Issues
2 2
3 3 On the IPython repository, we strive to trust users and give them responsibility.
4 4 By using one of our bots, any user can close issues or add/remove
5 5 labels by mentioning the bot and asking it to do things on your behalf.
6 6
7 7 To close an issue (or PR), even if you did not create it, use the following:
8 8
9 9 > @meeseeksdev close
10 10
11 11 This command can be in the middle of another comment, but must start on its
12 12 own line.
13 13
14 14 To add labels to an issue, ask the bot to `tag` with a comma-separated list of
15 15 tags to add:
16 16
17 17 > @meeseeksdev tag windows, documentation
18 18
19 19 Only already pre-created tags can be added. So far, the list is limited to:
20 20 `async/await`, `backported`, `help wanted`, `documentation`, `notebook`,
21 21 `tab-completion`, `windows`
22 22
23 23 To remove a label, use the `untag` command:
24 24
25 25 > @meeseeksdev untag windows, documentation
26 26
27 27 We'll be adding additional capabilities for the bot and will share them here
28 28 when they are ready to be used.
29 29
30 30 ## Opening an Issue
31 31
32 32 When opening a new Issue, please take the following steps:
33 33
34 34 1. Search GitHub and/or Google for your issue to avoid duplicate reports.
35 35 Keyword searches for your error messages are most helpful.
36 2. If possible, try updating to master and reproducing your issue,
36 2. If possible, try updating to main and reproducing your issue,
37 37 because we may have already fixed it.
38 38 3. Try to include a minimal reproducible test case.
39 39 4. Include relevant system information. Start with the output of:
40 40
41 41 python -c "import IPython; print(IPython.sys_info())"
42 42
43 43 And include any relevant package versions, depending on the issue, such as
44 44 matplotlib, numpy, Qt, Qt bindings (PyQt/PySide), tornado, web browser, etc.
45 45
46 46 ## Pull Requests
47 47
48 48 Some guidelines on contributing to IPython:
49 49
50 50 * All work is submitted via Pull Requests.
51 51 * Pull Requests can be submitted as soon as there is code worth discussing.
52 52 Pull Requests track the branch, so you can continue to work after the PR is submitted.
53 53 Review and discussion can begin well before the work is complete,
54 54 and the more discussion the better.
55 55 The worst case is that the PR is closed.
56 * Pull Requests should generally be made against master
56 * Pull Requests should generally be made against main
57 57 * Pull Requests should be tested, if feasible:
58 58 - bugfixes should include regression tests.
59 59 - new behavior should at least get minimal exercise.
60 60 * New features and backwards-incompatible changes should be documented by adding
61 61 a new file to the [pr](docs/source/whatsnew/pr) directory, see [the README.md
62 62 there](docs/source/whatsnew/pr/README.md) for details.
63 63 * Don't make 'cleanup' pull requests just to change code style.
64 64 We don't follow any style guide strictly, and we consider formatting changes
65 65 unnecessary noise.
66 66 If you're making functional changes, you can clean up the specific pieces of
67 67 code you're working on.
68 68
69 69 [Travis](http://travis-ci.org/#!/ipython/ipython) does a pretty good job testing
70 70 IPython and Pull Requests, but it may make sense to manually perform tests,
71 71 particularly for PRs that affect `IPython.parallel` or Windows.
72 72
73 73 For more detailed information, see our [GitHub Workflow](https://github.com/ipython/ipython/wiki/Dev:-GitHub-workflow).
74 74
75 75 ## Running Tests
76 76
77 77 All the tests can be run by using
78 78 ```shell
79 79 pytest
80 80 ```
81 81
82 82 All the tests for a single module (for example **test_alias**) can be run by using the fully qualified path to the module.
83 83 ```shell
84 84 pytest IPython/core/tests/test_alias.py
85 85 ```
86 86
87 87 Only a single test (for example **test_alias_lifecycle**) within a single file can be run by adding the specific test after a `::` at the end:
88 88 ```shell
89 89 pytest IPython/core/tests/test_alias.py::test_alias_lifecycle
90 90 ```
@@ -1,156 +1,156 b''
1 1 """
2 2 IPython: tools for interactive and parallel computing in Python.
3 3
4 4 https://ipython.org
5 5 """
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (c) 2008-2011, IPython Development Team.
8 8 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
9 9 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
10 10 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
11 11 #
12 12 # Distributed under the terms of the Modified BSD License.
13 13 #
14 14 # The full license is in the file COPYING.txt, distributed with this software.
15 15 #-----------------------------------------------------------------------------
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Imports
19 19 #-----------------------------------------------------------------------------
20 20
21 21 import os
22 22 import sys
23 23
24 24 #-----------------------------------------------------------------------------
25 25 # Setup everything
26 26 #-----------------------------------------------------------------------------
27 27
28 28 # Don't forget to also update setup.py when this changes!
29 29 if sys.version_info < (3, 8):
30 30 raise ImportError(
31 31 """
32 32 IPython 8+ supports Python 3.8 and above, following NEP 29.
33 33 When using Python 2.7, please install IPython 5.x LTS Long Term Support version.
34 34 Python 3.3 and 3.4 were supported up to IPython 6.x.
35 35 Python 3.5 was supported with IPython 7.0 to 7.9.
36 36 Python 3.6 was supported with IPython up to 7.16.
37 37 Python 3.7 was still supported with the 7.x branch.
38 38
39 39 See IPython `README.rst` file for more information:
40 40
41 https://github.com/ipython/ipython/blob/master/README.rst
41 https://github.com/ipython/ipython/blob/main/README.rst
42 42
43 43 """
44 44 )
45 45
46 46 #-----------------------------------------------------------------------------
47 47 # Setup the top level names
48 48 #-----------------------------------------------------------------------------
49 49
50 50 from .core.getipython import get_ipython
51 51 from .core import release
52 52 from .core.application import Application
53 53 from .terminal.embed import embed
54 54
55 55 from .core.interactiveshell import InteractiveShell
56 56 from .utils.sysinfo import sys_info
57 57 from .utils.frame import extract_module_locals
58 58
59 59 # Release data
60 60 __author__ = '%s <%s>' % (release.author, release.author_email)
61 61 __license__ = release.license
62 62 __version__ = release.version
63 63 version_info = release.version_info
64 64 # list of CVEs that should have been patched in this release.
65 65 # this is informational and should not be relied upon.
66 66 __patched_cves__ = {"CVE-2022-21699"}
67 67
68 68
69 69 def embed_kernel(module=None, local_ns=None, **kwargs):
70 70 """Embed and start an IPython kernel in a given scope.
71 71
72 72 If you don't want the kernel to initialize the namespace
73 73 from the scope of the surrounding function,
74 74 and/or you want to load full IPython configuration,
75 75 you probably want `IPython.start_kernel()` instead.
76 76
77 77 Parameters
78 78 ----------
79 79 module : types.ModuleType, optional
80 80 The module to load into IPython globals (default: caller)
81 81 local_ns : dict, optional
82 82 The namespace to load into IPython user namespace (default: caller)
83 83 **kwargs : various, optional
84 84 Further keyword args are relayed to the IPKernelApp constructor,
85 85 allowing configuration of the Kernel. Will only have an effect
86 86 on the first embed_kernel call for a given process.
87 87 """
88 88
89 89 (caller_module, caller_locals) = extract_module_locals(1)
90 90 if module is None:
91 91 module = caller_module
92 92 if local_ns is None:
93 93 local_ns = caller_locals
94 94
95 95 # Only import .zmq when we really need it
96 96 from ipykernel.embed import embed_kernel as real_embed_kernel
97 97 real_embed_kernel(module=module, local_ns=local_ns, **kwargs)
98 98
99 99 def start_ipython(argv=None, **kwargs):
100 100 """Launch a normal IPython instance (as opposed to embedded)
101 101
102 102 `IPython.embed()` puts a shell in a particular calling scope,
103 103 such as a function or method for debugging purposes,
104 104 which is often not desirable.
105 105
106 106 `start_ipython()` does full, regular IPython initialization,
107 107 including loading startup files, configuration, etc.
108 108 much of which is skipped by `embed()`.
109 109
110 110 This is a public API method, and will survive implementation changes.
111 111
112 112 Parameters
113 113 ----------
114 114 argv : list or None, optional
115 115 If unspecified or None, IPython will parse command-line options from sys.argv.
116 116 To prevent any command-line parsing, pass an empty list: `argv=[]`.
117 117 user_ns : dict, optional
118 118 specify this dictionary to initialize the IPython user namespace with particular values.
119 119 **kwargs : various, optional
120 120 Any other kwargs will be passed to the Application constructor,
121 121 such as `config`.
122 122 """
123 123 from IPython.terminal.ipapp import launch_new_instance
124 124 return launch_new_instance(argv=argv, **kwargs)
125 125
126 126 def start_kernel(argv=None, **kwargs):
127 127 """Launch a normal IPython kernel instance (as opposed to embedded)
128 128
129 129 `IPython.embed_kernel()` puts a shell in a particular calling scope,
130 130 such as a function or method for debugging purposes,
131 131 which is often not desirable.
132 132
133 133 `start_kernel()` does full, regular IPython initialization,
134 134 including loading startup files, configuration, etc.
135 135 much of which is skipped by `embed()`.
136 136
137 137 Parameters
138 138 ----------
139 139 argv : list or None, optional
140 140 If unspecified or None, IPython will parse command-line options from sys.argv.
141 141 To prevent any command-line parsing, pass an empty list: `argv=[]`.
142 142 user_ns : dict, optional
143 143 specify this dictionary to initialize the IPython user namespace with particular values.
144 144 **kwargs : various, optional
145 145 Any other kwargs will be passed to the Application constructor,
146 146 such as `config`.
147 147 """
148 148 import warnings
149 149
150 150 warnings.warn(
151 151 "start_kernel is deprecated since IPython 8.0, use from `ipykernel.kernelapp.launch_new_instance`",
152 152 DeprecationWarning,
153 153 stacklevel=2,
154 154 )
155 155 from ipykernel.kernelapp import launch_new_instance
156 156 return launch_new_instance(argv=argv, **kwargs)
@@ -1,171 +1,171 b''
1 .. image:: https://codecov.io/github/ipython/ipython/coverage.svg?branch=master
2 :target: https://codecov.io/github/ipython/ipython?branch=master
1 .. image:: https://codecov.io/github/ipython/ipython/coverage.svg?branch=main
2 :target: https://codecov.io/github/ipython/ipython?branch=main
3 3
4 4 .. image:: https://img.shields.io/pypi/v/IPython.svg
5 5 :target: https://pypi.python.org/pypi/ipython
6 6
7 7 .. image:: https://github.com/ipython/ipython/actions/workflows/test.yml/badge.svg
8 8 :target: https://github.com/ipython/ipython/actions/workflows/test.yml)
9 9
10 10 .. image:: https://www.codetriage.com/ipython/ipython/badges/users.svg
11 11 :target: https://www.codetriage.com/ipython/ipython/
12 12
13 13 .. image:: https://raster.shields.io/badge/Follows-NEP29-brightgreen.png
14 14 :target: https://numpy.org/neps/nep-0029-deprecation_policy.html
15 15
16 16
17 17 ===========================================
18 18 IPython: Productive Interactive Computing
19 19 ===========================================
20 20
21 21 Overview
22 22 ========
23 23
24 24 Welcome to IPython. Our full documentation is available on `ipython.readthedocs.io
25 25 <https://ipython.readthedocs.io/en/stable/>`_ and contains information on how to install, use, and
26 26 contribute to the project.
27 27 IPython (Interactive Python) is a command shell for interactive computing in multiple programming languages, originally developed for the Python programming language, that offers introspection, rich media, shell syntax, tab completion, and history.
28 28
29 29 **IPython versions and Python Support**
30 30
31 31 Starting with IPython 7.10, IPython follows `NEP 29 <https://numpy.org/neps/nep-0029-deprecation_policy.html>`_
32 32
33 33 **IPython 7.17+** requires Python version 3.7 and above.
34 34
35 35 **IPython 7.10+** requires Python version 3.6 and above.
36 36
37 37 **IPython 7.0** requires Python version 3.5 and above.
38 38
39 39 **IPython 6.x** requires Python version 3.3 and above.
40 40
41 41 **IPython 5.x LTS** is the compatible release for Python 2.7.
42 42 If you require Python 2 support, you **must** use IPython 5.x LTS. Please
43 43 update your project configurations and requirements as necessary.
44 44
45 45
46 46 The Notebook, Qt console and a number of other pieces are now parts of *Jupyter*.
47 47 See the `Jupyter installation docs <https://jupyter.readthedocs.io/en/latest/install.html>`__
48 48 if you want to use these.
49 49
50 50 Main features of IPython
51 51 ========================
52 52 Comprehensive object introspection.
53 53
54 54 Input history, persistent across sessions.
55 55
56 56 Caching of output results during a session with automatically generated references.
57 57
58 58 Extensible tab completion, with support by default for completion of python variables and keywords, filenames and function keywords.
59 59
60 60 Extensible system of β€˜magic’ commands for controlling the environment and performing many tasks related to IPython or the operating system.
61 61
62 62 A rich configuration system with easy switching between different setups (simpler than changing $PYTHONSTARTUP environment variables every time).
63 63
64 64 Session logging and reloading.
65 65
66 66 Extensible syntax processing for special purpose situations.
67 67
68 68 Access to the system shell with user-extensible alias system.
69 69
70 70 Easily embeddable in other Python programs and GUIs.
71 71
72 72 Integrated access to the pdb debugger and the Python profiler.
73 73
74 74
75 75 Development and Instant running
76 76 ===============================
77 77
78 78 You can find the latest version of the development documentation on `readthedocs
79 79 <https://ipython.readthedocs.io/en/latest/>`_.
80 80
81 81 You can run IPython from this directory without even installing it system-wide
82 82 by typing at the terminal::
83 83
84 84 $ python -m IPython
85 85
86 86 Or see the `development installation docs
87 87 <https://ipython.readthedocs.io/en/latest/install/install.html#installing-the-development-version>`_
88 88 for the latest revision on read the docs.
89 89
90 90 Documentation and installation instructions for older version of IPython can be
91 91 found on the `IPython website <https://ipython.org/documentation.html>`_
92 92
93 93
94 94
95 95 IPython requires Python version 3 or above
96 96 ==========================================
97 97
98 98 Starting with version 6.0, IPython does not support Python 2.7, 3.0, 3.1, or
99 99 3.2.
100 100
101 101 For a version compatible with Python 2.7, please install the 5.x LTS Long Term
102 102 Support version.
103 103
104 104 If you are encountering this error message you are likely trying to install or
105 105 use IPython from source. You need to checkout the remote 5.x branch. If you are
106 106 using git the following should work::
107 107
108 108 $ git fetch origin
109 109 $ git checkout 5.x
110 110
111 111 If you encounter this error message with a regular install of IPython, then you
112 112 likely need to update your package manager, for example if you are using `pip`
113 113 check the version of pip with::
114 114
115 115 $ pip --version
116 116
117 117 You will need to update pip to the version 9.0.1 or greater. If you are not using
118 118 pip, please inquiry with the maintainers of the package for your package
119 119 manager.
120 120
121 121 For more information see one of our blog posts:
122 122
123 123 https://blog.jupyter.org/release-of-ipython-5-0-8ce60b8d2e8e
124 124
125 125 As well as the following Pull-Request for discussion:
126 126
127 127 https://github.com/ipython/ipython/pull/9900
128 128
129 129 This error does also occur if you are invoking ``setup.py`` directly – which you
130 130 should not – or are using ``easy_install`` If this is the case, use ``pip
131 131 install .`` instead of ``setup.py install`` , and ``pip install -e .`` instead
132 132 of ``setup.py develop`` If you are depending on IPython as a dependency you may
133 133 also want to have a conditional dependency on IPython depending on the Python
134 134 version::
135 135
136 136 install_req = ['ipython']
137 137 if sys.version_info[0] < 3 and 'bdist_wheel' not in sys.argv:
138 138 install_req.remove('ipython')
139 139 install_req.append('ipython<6')
140 140
141 141 setup(
142 142 ...
143 143 install_requires=install_req
144 144 )
145 145
146 146 Alternatives to IPython
147 147 =======================
148 148
149 149 IPython may not be to your taste; if that's the case there might be similar
150 150 project that you might want to use:
151 151
152 152 - The classic Python REPL.
153 153 - `bpython <https://bpython-interpreter.org/>`_
154 154 - `mypython <https://www.asmeurer.com/mypython/>`_
155 155 - `ptpython and ptipython <https://pypi.org/project/ptpython/>`_
156 156 - `Xonsh <https://xon.sh/>`_
157 157
158 158 Ignoring commits with git blame.ignoreRevsFile
159 159 ==============================================
160 160
161 161 As of git 2.23, it is possible to make formatting changes without breaking
162 162 ``git blame``. See the `git documentation
163 163 <https://git-scm.com/docs/git-config#Documentation/git-config.txt-blameignoreRevsFile>`_
164 164 for more details.
165 165
166 166 To use this feature you must:
167 167
168 168 - Install git >= 2.23
169 169 - Configure your local git repo by running:
170 170 - POSIX: ``tools\configure-git-blame-ignore-revs.sh``
171 171 - Windows: ``tools\configure-git-blame-ignore-revs.bat``
@@ -1,320 +1,320 b''
1 1 .. _core_developer_guide:
2 2
3 3 =================================
4 4 Guide for IPython core Developers
5 5 =================================
6 6
7 7 This guide documents the development of IPython itself. Alternatively,
8 8 developers of third party tools and libraries that use IPython should see the
9 9 :doc:`../development/index`.
10 10
11 11
12 12 For instructions on how to make a developer install see :ref:`devinstall`.
13 13
14 14 Backporting Pull requests
15 15 =========================
16 16
17 All pull requests should usually be made against ``master``, if a Pull Request
17 All pull requests should usually be made against ``main``, if a Pull Request
18 18 need to be backported to an earlier release; then it should be tagged with the
19 19 correct ``milestone``.
20 20
21 21 If you tag a pull request with a milestone **before** merging the pull request,
22 and the base ref is ``master``, then our backport bot should automatically create
22 and the base ref is ``main``, then our backport bot should automatically create
23 23 a corresponding pull-request that backport on the correct branch.
24 24
25 25 If you have write access to the IPython repository you can also just mention the
26 26 **backport bot** to do the work for you. The bot is evolving so instructions may
27 27 be different. At the time of this writing you can use::
28 28
29 29 @meeseeksdev[bot] backport [to] <branchname>
30 30
31 31 The bot will attempt to backport the current pull-request and issue a PR if
32 32 possible.
33 33
34 34 .. note::
35 35
36 36 The ``@`` and ``[bot]`` when mentioning the bot should be optional and can
37 37 be omitted.
38 38
39 39 If the pull request cannot be automatically backported, the bot should tell you
40 40 so on the PR and apply a "Need manual backport" tag to the origin PR.
41 41
42 42 .. _release_process:
43 43
44 44 IPython release process
45 45 =======================
46 46
47 47 This document contains the process that is used to create an IPython release.
48 48
49 49 Conveniently, the ``release`` script in the ``tools`` directory of the ``IPython``
50 50 repository automates most of the release process. This document serves as a
51 51 handy reminder and checklist for the release manager.
52 52
53 53 During the release process, you might need the extra following dependencies:
54 54
55 55 - ``keyring`` to access your GitHub authentication tokens
56 56 - ``graphviz`` to generate some graphs in the documentation
57 57 - ``ghpro`` to generate the stats
58 58
59 59 Make sure you have all the required dependencies to run the tests as well.
60 60
61 61 You can try to ``source tools/release_helper.sh`` when releasing via bash, it
62 62 should guide you through most of the process.
63 63
64 64
65 65 1. Set Environment variables
66 66 ----------------------------
67 67
68 68 Set environment variables to document previous release tag, current
69 69 release milestone, current release version, and git tag.
70 70
71 71 These variables may be used later to copy/paste as answers to the script
72 72 questions instead of typing the appropriate command when the time comes. These
73 73 variables are not used by the scripts directly; therefore, there is no need to
74 74 ``export`` them. The format for bash is as follows, but note that these values
75 75 are just an example valid only for the 5.0 release; you'll need to update them
76 76 for the release you are actually making::
77 77
78 78 PREV_RELEASE=4.2.1
79 79 MILESTONE=5.0
80 80 VERSION=5.0.0
81 BRANCH=master
81 BRANCH=main
82 82
83 83 For `reproducibility of builds <https://reproducible-builds.org/specs/source-date-epoch/>`_,
84 84 we recommend setting ``SOURCE_DATE_EPOCH`` prior to running the build; record the used value
85 85 of ``SOURCE_DATE_EPOCH`` as it may not be available from build artifact. You
86 86 should be able to use ``date +%s`` to get a formatted timestamp::
87 87
88 88 SOURCE_DATE_EPOCH=$(date +%s)
89 89
90 90
91 91 2. Create GitHub stats and finish release note
92 92 ----------------------------------------------
93 93
94 94 .. note::
95 95
96 96 This step is optional if making a Beta or RC release.
97 97
98 98 .. note::
99 99
100 100 Before generating the GitHub stats, verify that all closed issues and pull
101 101 requests have `appropriate milestones
102 102 <https://github.com/ipython/ipython/wiki/Dev:-GitHub-workflow#milestones>`_.
103 103 `This search
104 104 <https://github.com/ipython/ipython/issues?q=is%3Aclosed+no%3Amilestone+is%3Aissue>`_
105 105 should return no results before creating the GitHub stats.
106 106
107 107 If a major release:
108 108
109 109 - merge any pull request notes into what's new::
110 110
111 111 python tools/update_whatsnew.py
112 112
113 113 - update ``docs/source/whatsnew/development.rst``, to ensure it covers
114 114 the major release features
115 115
116 116 - move the contents of ``development.rst`` to ``versionX.rst`` where ``X`` is
117 117 the numerical release version
118 118
119 119 - generate summary of GitHub contributions, which can be done with::
120 120
121 121 python tools/github_stats.py --milestone $MILESTONE > stats.rst
122 122
123 123 which may need some manual cleanup of ``stats.rst``. Add the cleaned
124 124 ``stats.rst`` results to ``docs/source/whatsnew/github-stats-X.rst``
125 125 where ``X`` is the numerical release version (don't forget to add it to
126 126 the git repository as well). If creating a major release, make a new
127 127 ``github-stats-X.rst`` file; if creating a minor release, the content
128 128 from ``stats.rst`` may simply be added to the top of an existing
129 129 ``github-stats-X.rst`` file.
130 130
131 131 - Edit ``docs/source/whatsnew/index.rst`` to list the new ``github-stats-X``
132 132 file you just created.
133 133
134 134 - You do not need to temporarily remove the first entry called
135 135 ``development``, nor re-add it after the release, it will automatically be
136 136 hidden when releasing a stable version of IPython (if ``_version_extra``
137 137 in ``release.py`` is an empty string.
138 138
139 139 Make sure that the stats file has a header or it won't be rendered in
140 140 the final documentation.
141 141
142 142 To find duplicates and update `.mailmap`, use::
143 143
144 144 git log --format="%aN <%aE>" $PREV_RELEASE... | sort -u -f
145 145
146 146 If a minor release you might need to do some of the above points manually, and
147 147 forward port the changes.
148 148
149 149 3. Make sure the repository is clean
150 150 ------------------------------------
151 151
152 152 of any file that could be problematic.
153 153 Remove all non-tracked files with:
154 154
155 155 .. code::
156 156
157 157 git clean -xfdi
158 158
159 159 This will ask for confirmation before removing all untracked files. Make
160 160 sure the ``dist/`` folder is clean to avoid any stale builds from
161 161 previous build attempts.
162 162
163 163
164 164 4. Update the release version number
165 165 ------------------------------------
166 166
167 167 Edit ``IPython/core/release.py`` to have the current version.
168 168
169 169 in particular, update version number and ``_version_extra`` content in
170 170 ``IPython/core/release.py``.
171 171
172 172 Step 5 will validate your changes automatically, but you might still want to
173 173 make sure the version number matches pep440.
174 174
175 175 In particular, ``rc`` and ``beta`` are not separated by ``.`` or the ``sdist``
176 176 and ``bdist`` will appear as different releases. For example, a valid version
177 177 number for a release candidate (rc) release is: ``1.3rc1``. Notice that there
178 178 is no separator between the '3' and the 'r'. Check the environment variable
179 179 ``$VERSION`` as well.
180 180
181 181 You will likely just have to modify/comment/uncomment one of the lines setting
182 182 ``_version_extra``
183 183
184 184
185 185 5. Run the `tools/build_release` script
186 186 ---------------------------------------
187 187
188 188 Running ``tools/build_release`` does all the file checking and building that
189 189 the real release script will do. This makes test installations, checks that
190 190 the build procedure runs OK, and tests other steps in the release process.
191 191
192 192 The ``build_release`` script will in particular verify that the version number
193 193 match PEP 440, in order to avoid surprise at the time of build upload.
194 194
195 195 We encourage creating a test build of the docs as well.
196 196
197 197 6. Create and push the new tag
198 198 ------------------------------
199 199
200 200 Commit the changes to release.py::
201 201
202 202 git commit -am "release $VERSION" -S
203 203 git push origin $BRANCH
204 204
205 205 (omit the ``-S`` if you are no signing the package)
206 206
207 207 Create and push the tag::
208 208
209 209 git tag -am "release $VERSION" "$VERSION" -s
210 210 git push origin $VERSION
211 211
212 212 (omit the ``-s`` if you are no signing the package)
213 213
214 214 Update release.py back to ``x.y-dev`` or ``x.y-maint`` commit and push::
215 215
216 216 git commit -am "back to development" -S
217 217 git push origin $BRANCH
218 218
219 219 (omit the ``-S`` if you are no signing the package)
220 220
221 221 Now checkout the tag we just made::
222 222
223 223 git checkout $VERSION
224 224
225 225 7. Run the release script
226 226 -------------------------
227 227
228 228 Run the ``release`` script, this step requires having a current wheel, Python
229 229 >=3.4 and Python 2.7.::
230 230
231 231 ./tools/release
232 232
233 233 This makes the tarballs and wheels, and puts them under the ``dist/``
234 234 folder. Be sure to test the ``wheels`` and the ``sdist`` locally before
235 235 uploading them to PyPI. We do not use an universal wheel as each wheel
236 236 installs an ``ipython2`` or ``ipython3`` script, depending on the version of
237 237 Python it is built for. Using an universal wheel would prevent this.
238 238
239 239 Check the shasum of files with::
240 240
241 241 shasum -a 256 dist/*
242 242
243 243 and takes notes of them you might need them to update the conda-forge recipes.
244 244 Rerun the command and check the hash have not changed::
245 245
246 246 ./tools/release
247 247 shasum -a 256 dist/*
248 248
249 249 Use the following to actually upload the result of the build::
250 250
251 251 ./tools/release upload
252 252
253 253 It should posts them to ``archive.ipython.org`` and to PyPI.
254 254
255 255 PyPI/Warehouse will automatically hide previous releases. If you are uploading
256 256 a non-stable version, make sure to log-in to PyPI and un-hide previous version.
257 257
258 258
259 259 8. Draft a short release announcement
260 260 -------------------------------------
261 261
262 262 The announcement should include:
263 263
264 264 - release highlights
265 265 - a link to the html version of the *What's new* section of the documentation
266 266 - a link to upgrade or installation tips (if necessary)
267 267
268 268 Post the announcement to the mailing list and or blog, and link from Twitter.
269 269
270 270 .. note::
271 271
272 272 If you are doing a RC or Beta, you can likely skip the next steps.
273 273
274 274 9. Update milestones on GitHub
275 275 -------------------------------
276 276
277 277 These steps will bring milestones up to date:
278 278
279 279 - close the just released milestone
280 280 - open a new milestone for the next release (x, y+1), if the milestone doesn't
281 281 exist already
282 282
283 283 10. Update the IPython website
284 284 ------------------------------
285 285
286 286 The IPython website should document the new release:
287 287
288 288 - add release announcement (news, announcements)
289 289 - update current version and download links
290 290 - update links on the documentation page (especially if a major release)
291 291
292 292 11. Update readthedocs
293 293 ----------------------
294 294
295 295 Make sure to update readthedocs and set the latest tag as stable, as well as
296 296 checking that previous release is still building under its own tag.
297 297
298 298 12. Update the Conda-Forge feedstock
299 299 ------------------------------------
300 300
301 301 Follow the instructions on `the repository <https://github.com/conda-forge/ipython-feedstock>`_
302 302
303 303 13. Celebrate!
304 304 --------------
305 305
306 306 Celebrate the release and please thank the contributors for their work. Great
307 307 job!
308 308
309 309
310 310
311 311 Old Documentation
312 312 =================
313 313
314 314 Out of date documentation is still available and have been kept for archival purposes.
315 315
316 316 .. note::
317 317
318 318 Developers documentation used to be on the IPython wiki, but are now out of
319 319 date. The wiki is though still available for historical reasons: `Old IPython
320 320 GitHub Wiki. <https://github.com/ipython/ipython/wiki/Dev:-Index>`_
@@ -1,285 +1,285 b''
1 1 {
2 2 "cells": [
3 3 {
4 4 "cell_type": "markdown",
5 5 "metadata": {},
6 6 "source": [
7 7 "# A few things that work best/only at the IPython terminal or Qt console clients"
8 8 ]
9 9 },
10 10 {
11 11 "cell_type": "markdown",
12 12 "metadata": {},
13 13 "source": [
14 14 "## Running code with `%run`"
15 15 ]
16 16 },
17 17 {
18 18 "cell_type": "code",
19 19 "execution_count": 1,
20 20 "metadata": {
21 21 "collapsed": false
22 22 },
23 23 "outputs": [
24 24 {
25 25 "name": "stdout",
26 26 "output_type": "stream",
27 27 "text": [
28 28 "Writing script.py\n"
29 29 ]
30 30 }
31 31 ],
32 32 "source": [
33 33 "%%writefile script.py\n",
34 34 "x = 10\n",
35 35 "y = 20\n",
36 36 "z = x+y\n",
37 37 "print('z is: %s' % z)"
38 38 ]
39 39 },
40 40 {
41 41 "cell_type": "code",
42 42 "execution_count": 2,
43 43 "metadata": {
44 44 "collapsed": false
45 45 },
46 46 "outputs": [
47 47 {
48 48 "name": "stdout",
49 49 "output_type": "stream",
50 50 "text": [
51 51 "z is: 30\n"
52 52 ]
53 53 }
54 54 ],
55 55 "source": [
56 56 "%run script"
57 57 ]
58 58 },
59 59 {
60 60 "cell_type": "code",
61 61 "execution_count": 3,
62 62 "metadata": {
63 63 "collapsed": false
64 64 },
65 65 "outputs": [
66 66 {
67 67 "data": {
68 68 "text/plain": [
69 69 "10"
70 70 ]
71 71 },
72 72 "execution_count": 3,
73 73 "metadata": {},
74 74 "output_type": "execute_result"
75 75 }
76 76 ],
77 77 "source": [
78 78 "x"
79 79 ]
80 80 },
81 81 {
82 82 "cell_type": "markdown",
83 83 "metadata": {},
84 84 "source": [
85 85 "## Event loop and GUI integration"
86 86 ]
87 87 },
88 88 {
89 89 "cell_type": "markdown",
90 90 "metadata": {},
91 91 "source": [
92 92 "The `%gui` magic enables the integration of GUI event loops with the interactive execution loop, allowing you to run GUI code without blocking IPython.\n",
93 93 "\n",
94 94 "Consider for example the execution of Qt-based code. Once we enable the Qt gui support:"
95 95 ]
96 96 },
97 97 {
98 98 "cell_type": "code",
99 99 "execution_count": 4,
100 100 "metadata": {
101 101 "collapsed": false
102 102 },
103 103 "outputs": [],
104 104 "source": [
105 105 "%gui qt"
106 106 ]
107 107 },
108 108 {
109 109 "cell_type": "markdown",
110 110 "metadata": {},
111 111 "source": [
112 112 "We can define a simple Qt application class (simplified version from [this Qt tutorial](http://zetcode.com/tutorials/pyqt4/firstprograms)):"
113 113 ]
114 114 },
115 115 {
116 116 "cell_type": "code",
117 117 "execution_count": 5,
118 118 "metadata": {
119 119 "collapsed": false
120 120 },
121 121 "outputs": [],
122 122 "source": [
123 123 "import sys\n",
124 124 "from PyQt4 import QtGui, QtCore\n",
125 125 "\n",
126 126 "class SimpleWindow(QtGui.QWidget):\n",
127 127 " def __init__(self, parent=None):\n",
128 128 " QtGui.QWidget.__init__(self, parent)\n",
129 129 "\n",
130 130 " self.setGeometry(300, 300, 200, 80)\n",
131 131 " self.setWindowTitle('Hello World')\n",
132 132 "\n",
133 133 " quit = QtGui.QPushButton('Close', self)\n",
134 134 " quit.setGeometry(10, 10, 60, 35)\n",
135 135 "\n",
136 136 " self.connect(quit, QtCore.SIGNAL('clicked()'),\n",
137 137 " self, QtCore.SLOT('close()'))"
138 138 ]
139 139 },
140 140 {
141 141 "cell_type": "markdown",
142 142 "metadata": {},
143 143 "source": [
144 144 "And now we can instantiate it:"
145 145 ]
146 146 },
147 147 {
148 148 "cell_type": "code",
149 149 "execution_count": 6,
150 150 "metadata": {
151 151 "collapsed": false
152 152 },
153 153 "outputs": [],
154 154 "source": [
155 155 "app = QtCore.QCoreApplication.instance()\n",
156 156 "if app is None:\n",
157 157 " app = QtGui.QApplication([])\n",
158 158 "\n",
159 159 "sw = SimpleWindow()\n",
160 160 "sw.show()\n",
161 161 "\n",
162 162 "from IPython.lib.guisupport import start_event_loop_qt4\n",
163 163 "start_event_loop_qt4(app)"
164 164 ]
165 165 },
166 166 {
167 167 "cell_type": "markdown",
168 168 "metadata": {},
169 169 "source": [
170 170 "But IPython still remains responsive:"
171 171 ]
172 172 },
173 173 {
174 174 "cell_type": "code",
175 175 "execution_count": 7,
176 176 "metadata": {
177 177 "collapsed": false
178 178 },
179 179 "outputs": [
180 180 {
181 181 "data": {
182 182 "text/plain": [
183 183 "12"
184 184 ]
185 185 },
186 186 "execution_count": 7,
187 187 "metadata": {},
188 188 "output_type": "execute_result"
189 189 }
190 190 ],
191 191 "source": [
192 192 "10+2"
193 193 ]
194 194 },
195 195 {
196 196 "cell_type": "markdown",
197 197 "metadata": {},
198 198 "source": [
199 "The `%gui` magic can be similarly used to control Wx, Tk, glut and pyglet applications, [as can be seen in our examples](https://github.com/ipython/ipython/tree/master/examples/lib)."
199 "The `%gui` magic can be similarly used to control Wx, Tk, glut and pyglet applications, [as can be seen in our examples](https://github.com/ipython/ipython/tree/main/examples/lib)."
200 200 ]
201 201 },
202 202 {
203 203 "cell_type": "markdown",
204 204 "metadata": {},
205 205 "source": [
206 206 "## Embedding IPython in a terminal application"
207 207 ]
208 208 },
209 209 {
210 210 "cell_type": "code",
211 211 "execution_count": 8,
212 212 "metadata": {
213 213 "collapsed": false
214 214 },
215 215 "outputs": [
216 216 {
217 217 "name": "stdout",
218 218 "output_type": "stream",
219 219 "text": [
220 220 "Writing simple-embed.py\n"
221 221 ]
222 222 }
223 223 ],
224 224 "source": [
225 225 "%%writefile simple-embed.py\n",
226 226 "# This shows how to use the new top-level embed function. It is a simpler\n",
227 227 "# API that manages the creation of the embedded shell.\n",
228 228 "\n",
229 229 "from IPython import embed\n",
230 230 "\n",
231 231 "a = 10\n",
232 232 "b = 20\n",
233 233 "\n",
234 234 "embed(header='First time', banner1='')\n",
235 235 "\n",
236 236 "c = 30\n",
237 237 "d = 40\n",
238 238 "\n",
239 239 "embed(header='The second time')"
240 240 ]
241 241 },
242 242 {
243 243 "cell_type": "markdown",
244 244 "metadata": {},
245 245 "source": [
246 246 "The example in kernel-embedding shows how to embed a full kernel into an application and how to connect to this kernel from an external process."
247 247 ]
248 248 },
249 249 {
250 250 "cell_type": "markdown",
251 251 "metadata": {},
252 252 "source": [
253 253 "## Logging terminal sessions and transitioning to a notebook"
254 254 ]
255 255 },
256 256 {
257 257 "cell_type": "markdown",
258 258 "metadata": {},
259 259 "source": [
260 260 "The `%logstart` magic lets you log a terminal session with various degrees of control, and the `%notebook` one will convert an interactive console session into a notebook with all input cells already created for you (but no output)."
261 261 ]
262 262 }
263 263 ],
264 264 "metadata": {
265 265 "kernelspec": {
266 266 "display_name": "Python 3",
267 267 "language": "python",
268 268 "name": "python3"
269 269 },
270 270 "language_info": {
271 271 "codemirror_mode": {
272 272 "name": "ipython",
273 273 "version": 3
274 274 },
275 275 "file_extension": ".py",
276 276 "mimetype": "text/x-python",
277 277 "name": "python",
278 278 "nbconvert_exporter": "python",
279 279 "pygments_lexer": "ipython3",
280 280 "version": "3.4.2"
281 281 }
282 282 },
283 283 "nbformat": 4,
284 284 "nbformat_minor": 0
285 285 }
@@ -1,148 +1,148 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, 8):
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+ supports Python 3.8 and above, following NEP 29.
43 43 When using Python 2.7, please install IPython 5.x LTS Long Term Support version.
44 44 Python 3.3 and 3.4 were supported up to IPython 6.x.
45 45 Python 3.5 was supported with IPython 7.0 to 7.9.
46 46 Python 3.6 was supported with IPython up to 7.16.
47 47 Python 3.7 was still supported with the 7.x branch.
48 48
49 49 See IPython `README.rst` file for more information:
50 50
51 https://github.com/ipython/ipython/blob/master/README.rst
51 https://github.com/ipython/ipython/blob/main/README.rst
52 52
53 53 Python {py} detected.
54 54 {pip}
55 55 """.format(
56 56 py=sys.version_info, pip=pip_message
57 57 )
58 58
59 59 print(error, file=sys.stderr)
60 60 sys.exit(1)
61 61
62 62 # At least we're on the python version we need, move on.
63 63
64 64 from setuptools import setup
65 65
66 66 # Our own imports
67 67 sys.path.insert(0, ".")
68 68
69 69 from setupbase import target_update
70 70
71 71 from setupbase import (
72 72 setup_args,
73 73 check_package_data_first,
74 74 find_data_files,
75 75 git_prebuild,
76 76 install_symlinked,
77 77 install_lib_symlink,
78 78 install_scripts_for_symlink,
79 79 unsymlink,
80 80 )
81 81
82 82 #-------------------------------------------------------------------------------
83 83 # Handle OS specific things
84 84 #-------------------------------------------------------------------------------
85 85
86 86 if os.name in ('nt','dos'):
87 87 os_name = 'windows'
88 88 else:
89 89 os_name = os.name
90 90
91 91 # Under Windows, 'sdist' has not been supported. Now that the docs build with
92 92 # Sphinx it might work, but let's not turn it on until someone confirms that it
93 93 # actually works.
94 94 if os_name == 'windows' and 'sdist' in sys.argv:
95 95 print('The sdist command is not available under Windows. Exiting.')
96 96 sys.exit(1)
97 97
98 98
99 99 #-------------------------------------------------------------------------------
100 100 # Things related to the IPython documentation
101 101 #-------------------------------------------------------------------------------
102 102
103 103 # update the manuals when building a source dist
104 104 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
105 105
106 106 # List of things to be updated. Each entry is a triplet of args for
107 107 # target_update()
108 108 to_update = [
109 109 (
110 110 "docs/man/ipython.1.gz",
111 111 ["docs/man/ipython.1"],
112 112 "cd docs/man && python -m gzip --best ipython.1",
113 113 ),
114 114 ]
115 115
116 116
117 117 [ target_update(*t) for t in to_update ]
118 118
119 119 #---------------------------------------------------------------------------
120 120 # Find all the packages, package data, and data_files
121 121 #---------------------------------------------------------------------------
122 122
123 123 data_files = find_data_files()
124 124
125 125 setup_args['data_files'] = data_files
126 126
127 127 #---------------------------------------------------------------------------
128 128 # custom distutils commands
129 129 #---------------------------------------------------------------------------
130 130 # imports here, so they are after setuptools import if there was one
131 131 from setuptools.command.sdist import sdist
132 132
133 133 setup_args['cmdclass'] = {
134 134 'build_py': \
135 135 check_package_data_first(git_prebuild('IPython')),
136 136 'sdist' : git_prebuild('IPython', sdist),
137 137 'symlink': install_symlinked,
138 138 'install_lib_symlink': install_lib_symlink,
139 139 'install_scripts_sym': install_scripts_for_symlink,
140 140 'unsymlink': unsymlink,
141 141 }
142 142
143 143 #---------------------------------------------------------------------------
144 144 # Do the actual setup now
145 145 #---------------------------------------------------------------------------
146 146
147 147 if __name__ == "__main__":
148 148 setup(**setup_args)
@@ -1,230 +1,230 b''
1 1 #!/usr/bin/env python
2 2 """Simple tools to query github.com and gather stats about issues.
3 3
4 4 To generate a report for IPython 2.0, run:
5 5
6 6 python github_stats.py --milestone 2.0 --since-tag rel-1.0.0
7 7 """
8 8 #-----------------------------------------------------------------------------
9 9 # Imports
10 10 #-----------------------------------------------------------------------------
11 11
12 12
13 13 import sys
14 14
15 15 from argparse import ArgumentParser
16 16 from datetime import datetime, timedelta
17 17 from subprocess import check_output
18 18
19 19 from gh_api import (
20 20 get_paged_request, make_auth_header, get_pull_request, is_pull_request,
21 21 get_milestone_id, get_issues_list, get_authors,
22 22 )
23 23 #-----------------------------------------------------------------------------
24 24 # Globals
25 25 #-----------------------------------------------------------------------------
26 26
27 27 ISO8601 = "%Y-%m-%dT%H:%M:%SZ"
28 28 PER_PAGE = 100
29 29
30 30 #-----------------------------------------------------------------------------
31 31 # Functions
32 32 #-----------------------------------------------------------------------------
33 33
34 34 def round_hour(dt):
35 35 return dt.replace(minute=0,second=0,microsecond=0)
36 36
37 37 def _parse_datetime(s):
38 38 """Parse dates in the format returned by the Github API."""
39 39 if s:
40 40 return datetime.strptime(s, ISO8601)
41 41 else:
42 42 return datetime.fromtimestamp(0)
43 43
44 44 def issues2dict(issues):
45 45 """Convert a list of issues to a dict, keyed by issue number."""
46 46 idict = {}
47 47 for i in issues:
48 48 idict[i['number']] = i
49 49 return idict
50 50
51 51 def split_pulls(all_issues, project="ipython/ipython"):
52 52 """split a list of closed issues into non-PR Issues and Pull Requests"""
53 53 pulls = []
54 54 issues = []
55 55 for i in all_issues:
56 56 if is_pull_request(i):
57 57 pull = get_pull_request(project, i['number'], auth=True)
58 58 pulls.append(pull)
59 59 else:
60 60 issues.append(i)
61 61 return issues, pulls
62 62
63 63
64 64 def issues_closed_since(period=timedelta(days=365), project="ipython/ipython", pulls=False):
65 65 """Get all issues closed since a particular point in time. period
66 66 can either be a datetime object, or a timedelta object. In the
67 67 latter case, it is used as a time before the present.
68 68 """
69 69
70 70 which = 'pulls' if pulls else 'issues'
71 71
72 72 if isinstance(period, timedelta):
73 73 since = round_hour(datetime.utcnow() - period)
74 74 else:
75 75 since = period
76 76 url = "https://api.github.com/repos/%s/%s?state=closed&sort=updated&since=%s&per_page=%i" % (project, which, since.strftime(ISO8601), PER_PAGE)
77 77 allclosed = get_paged_request(url, headers=make_auth_header())
78 78
79 79 filtered = [ i for i in allclosed if _parse_datetime(i['closed_at']) > since ]
80 80 if pulls:
81 81 filtered = [ i for i in filtered if _parse_datetime(i['merged_at']) > since ]
82 # filter out PRs not against master (backports)
83 filtered = [ i for i in filtered if i['base']['ref'] == 'master' ]
82 # filter out PRs not against main (backports)
83 filtered = [ i for i in filtered if i['base']['ref'] == 'main' ]
84 84 else:
85 85 filtered = [ i for i in filtered if not is_pull_request(i) ]
86 86
87 87 return filtered
88 88
89 89
90 90 def sorted_by_field(issues, field='closed_at', reverse=False):
91 91 """Return a list of issues sorted by closing date date."""
92 92 return sorted(issues, key = lambda i:i[field], reverse=reverse)
93 93
94 94
95 95 def report(issues, show_urls=False):
96 96 """Summary report about a list of issues, printing number and title."""
97 97 if show_urls:
98 98 for i in issues:
99 99 role = 'ghpull' if 'merged_at' in i else 'ghissue'
100 100 print(u'* :%s:`%d`: %s' % (role, i['number'],
101 101 i['title'].replace(u'`', u'``')))
102 102 else:
103 103 for i in issues:
104 104 print(u'* %d: %s' % (i['number'], i['title'].replace(u'`', u'``')))
105 105
106 106 #-----------------------------------------------------------------------------
107 107 # Main script
108 108 #-----------------------------------------------------------------------------
109 109
110 110 if __name__ == "__main__":
111 111
112 112 print("DEPRECATE: backport_pr.py is deprecated and it is now recommended"
113 113 "to install `ghpro` from PyPI.", file=sys.stderr)
114 114
115 115
116 116 # Whether to add reST urls for all issues in printout.
117 117 show_urls = True
118 118
119 119 parser = ArgumentParser()
120 120 parser.add_argument('--since-tag', type=str,
121 121 help="The git tag to use for the starting point (typically the last major release)."
122 122 )
123 123 parser.add_argument('--milestone', type=str,
124 124 help="The GitHub milestone to use for filtering issues [optional]."
125 125 )
126 126 parser.add_argument('--days', type=int,
127 127 help="The number of days of data to summarize (use this or --since-tag)."
128 128 )
129 129 parser.add_argument('--project', type=str, default="ipython/ipython",
130 130 help="The project to summarize."
131 131 )
132 132 parser.add_argument('--links', action='store_true', default=False,
133 133 help="Include links to all closed Issues and PRs in the output."
134 134 )
135 135
136 136 opts = parser.parse_args()
137 137 tag = opts.since_tag
138 138
139 139 # set `since` from days or git tag
140 140 if opts.days:
141 141 since = datetime.utcnow() - timedelta(days=opts.days)
142 142 else:
143 143 if not tag:
144 144 tag = check_output(['git', 'describe', '--abbrev=0']).strip().decode('utf8')
145 145 cmd = ['git', 'log', '-1', '--format=%ai', tag]
146 146 tagday, tz = check_output(cmd).strip().decode('utf8').rsplit(' ', 1)
147 147 since = datetime.strptime(tagday, "%Y-%m-%d %H:%M:%S")
148 148 h = int(tz[1:3])
149 149 m = int(tz[3:])
150 150 td = timedelta(hours=h, minutes=m)
151 151 if tz[0] == '-':
152 152 since += td
153 153 else:
154 154 since -= td
155 155
156 156 since = round_hour(since)
157 157
158 158 milestone = opts.milestone
159 159 project = opts.project
160 160
161 161 print("fetching GitHub stats since %s (tag: %s, milestone: %s)" % (since, tag, milestone), file=sys.stderr)
162 162 if milestone:
163 163 milestone_id = get_milestone_id(project=project, milestone=milestone,
164 164 auth=True)
165 165 issues_and_pulls = get_issues_list(project=project,
166 166 milestone=milestone_id,
167 167 state='closed',
168 168 auth=True,
169 169 )
170 170 issues, pulls = split_pulls(issues_and_pulls, project=project)
171 171 else:
172 172 issues = issues_closed_since(since, project=project, pulls=False)
173 173 pulls = issues_closed_since(since, project=project, pulls=True)
174 174
175 175 # For regular reports, it's nice to show them in reverse chronological order
176 176 issues = sorted_by_field(issues, reverse=True)
177 177 pulls = sorted_by_field(pulls, reverse=True)
178 178
179 179 n_issues, n_pulls = map(len, (issues, pulls))
180 180 n_total = n_issues + n_pulls
181 181
182 182 # Print summary report we can directly include into release notes.
183 183
184 184 print()
185 185 since_day = since.strftime("%Y/%m/%d")
186 186 today = datetime.today().strftime("%Y/%m/%d")
187 187 print("GitHub stats for %s - %s (tag: %s)" % (since_day, today, tag))
188 188 print()
189 189 print("These lists are automatically generated, and may be incomplete or contain duplicates.")
190 190 print()
191 191
192 192 ncommits = 0
193 193 all_authors = []
194 194 if tag:
195 195 # print git info, in addition to GitHub info:
196 196 since_tag = tag+'..'
197 197 cmd = ['git', 'log', '--oneline', since_tag]
198 198 ncommits += len(check_output(cmd).splitlines())
199 199
200 200 author_cmd = ['git', 'log', '--use-mailmap', "--format=* %aN", since_tag]
201 201 all_authors.extend(check_output(author_cmd).decode('utf-8', 'replace').splitlines())
202 202
203 203 pr_authors = []
204 204 for pr in pulls:
205 205 pr_authors.extend(get_authors(pr))
206 206 ncommits = len(pr_authors) + ncommits - len(pulls)
207 207 author_cmd = ['git', 'check-mailmap'] + pr_authors
208 208 with_email = check_output(author_cmd).decode('utf-8', 'replace').splitlines()
209 209 all_authors.extend([ u'* ' + a.split(' <')[0] for a in with_email ])
210 210 unique_authors = sorted(set(all_authors), key=lambda s: s.lower())
211 211
212 212 print("We closed %d issues and merged %d pull requests." % (n_issues, n_pulls))
213 213 if milestone:
214 214 print("The full list can be seen `on GitHub <https://github.com/{project}/issues?q=milestone%3A{milestone}>`__".format(project=project,milestone=milestone)
215 215 )
216 216
217 217 print()
218 218 print("The following %i authors contributed %i commits." % (len(unique_authors), ncommits))
219 219 print()
220 220 print('\n'.join(unique_authors))
221 221
222 222 if opts.links:
223 223 print()
224 224 print("GitHub issues and pull requests:")
225 225 print()
226 226 print('Pull Requests (%d):\n' % n_pulls)
227 227 report(pulls, show_urls)
228 228 print()
229 229 print('Issues (%d):\n' % n_issues)
230 230 report(issues, show_urls)
@@ -1,251 +1,251 b''
1 1 # Simple tool to help for release
2 2 # when releasing with bash, simple source it to get asked questions.
3 3
4 4 # misc check before starting
5 5
6 6 python -c 'import keyring'
7 7 python -c 'import twine'
8 8 python -c 'import sphinx'
9 9 python -c 'import sphinx_rtd_theme'
10 10 python -c 'import pytest'
11 11
12 12
13 13 BLACK=$(tput setaf 1)
14 14 RED=$(tput setaf 1)
15 15 GREEN=$(tput setaf 2)
16 16 YELLOW=$(tput setaf 3)
17 17 BLUE=$(tput setaf 4)
18 18 MAGENTA=$(tput setaf 5)
19 19 CYAN=$(tput setaf 6)
20 20 WHITE=$(tput setaf 7)
21 21 NOR=$(tput sgr0)
22 22
23 23
24 24 echo "Will use $BLUE'$EDITOR'$NOR to edit files when necessary"
25 25 echo -n "PREV_RELEASE (X.y.z) [$PREV_RELEASE]: "
26 26 read input
27 27 PREV_RELEASE=${input:-$PREV_RELEASE}
28 28 echo -n "MILESTONE (X.y) [$MILESTONE]: "
29 29 read input
30 30 MILESTONE=${input:-$MILESTONE}
31 31 echo -n "VERSION (X.y.z) [$VERSION]:"
32 32 read input
33 33 VERSION=${input:-$VERSION}
34 echo -n "BRANCH (master|X.y) [$BRANCH]:"
34 echo -n "BRANCH (main|X.y) [$BRANCH]:"
35 35 read input
36 36 BRANCH=${input:-$BRANCH}
37 37
38 38 ask_section(){
39 39 echo
40 40 echo $BLUE"$1"$NOR
41 41 echo -n $GREEN"Press Enter to continue, S to skip: "$NOR
42 42 if [ "$ZSH_NAME" = "zsh" ] ; then
43 43 read -k1 value
44 44 value=${value%$'\n'}
45 45 else
46 46 read -n1 value
47 47 fi
48 48 if [ -z "$value" ] || [ $value = 'y' ]; then
49 49 return 0
50 50 fi
51 51 return 1
52 52 }
53 53
54 54
55 55 maybe_edit(){
56 56 echo
57 57 echo $BLUE"$1"$NOR
58 58 echo -n $GREEN"Press ${BLUE}e$GREEN to Edit ${BLUE}$1$GREEN, any other keys to skip: "$NOR
59 59 if [ "$ZSH_NAME" = "zsh" ] ; then
60 60 read -k1 value
61 61 value=${value%$'\n'}
62 62 else
63 63 read -n1 value
64 64 fi
65 65
66 66 echo
67 67 if [ $value = 'e' ] ; then
68 68 $=EDITOR $1
69 69 fi
70 70 }
71 71
72 72
73 73
74 74 echo
75 75 if ask_section "Updating what's new with information from docs/source/whatsnew/pr"
76 76 then
77 77 python tools/update_whatsnew.py
78 78
79 79 echo
80 80 echo $BLUE"please move the contents of "docs/source/whatsnew/development.rst" to version-X.rst"$NOR
81 81 echo $GREEN"Press enter to continue"$NOR
82 82 read
83 83 fi
84 84
85 85 if ask_section "Gen Stats, and authors"
86 86 then
87 87
88 88 echo
89 89 echo $BLUE"here are all the authors that contributed to this release:"$NOR
90 90 git log --format="%aN <%aE>" $PREV_RELEASE... | sort -u -f
91 91
92 92 echo
93 93 echo $BLUE"If you see any duplicates cancel (Ctrl-C), then edit .mailmap."
94 94 echo $GREEN"Press enter to continue:"$NOR
95 95 read
96 96
97 97 echo $BLUE"generating stats"$NOR
98 98 python tools/github_stats.py --milestone $MILESTONE > stats.rst
99 99
100 100 echo $BLUE"stats.rst files generated."$NOR
101 101 echo $GREEN"Please merge it with the right file (github-stats-X.rst) and commit."$NOR
102 102 echo $GREEN"press enter to continue."$NOR
103 103 read
104 104
105 105 fi
106 106
107 107 if ask_section "Generate API difference (using frapuccino)"
108 108 then
109 109 echo $BLUE"Checking out $PREV_RELEASE"$NOR
110 110 git checkout $PREV_RELEASE
111 111 sleep 1
112 112 echo $BLUE"Saving API to file $PREV_RELEASE"$NOR
113 113 frappuccino IPython IPython.kernel IPython.lib IPython.qt IPython.lib.kernel IPython.html IPython.frontend IPython.external --save IPython-$PREV_RELEASE.json
114 114 echo $BLUE"coming back to $BRANCH"$NOR
115 115 git checkout $BRANCH
116 116 sleep 1
117 117 echo $BLUE"comparing ..."$NOR
118 118 frappuccino IPython IPython.kernel IPython.lib --compare IPython-$PREV_RELEASE.json
119 119 echo $GREEN"Use the above guideline to write an API changelog ..."$NOR
120 120 echo $GREEN"Press any keys to continue"$NOR
121 121 read
122 122 fi
123 123
124 124 echo "Cleaning repository"
125 125 git clean -xfdi
126 126
127 127 echo $GREEN"please update version number in ${RED}IPython/core/release.py${NOR} , Do not commit yet – we'll do it later."$NOR
128 128 echo $GREEN"I tried ${RED}sed -i bkp -e '/Uncomment/s/^# //g' IPython/core/release.py${NOR}"
129 129 sed -i bkp -e '/Uncomment/s/^# //g' IPython/core/release.py
130 130 rm IPython/core/release.pybkp
131 131 git diff | cat
132 132 maybe_edit IPython/core/release.py
133 133
134 134 echo $GREEN"Press enter to continue"$NOR
135 135 read
136 136
137 137 if ask_section "Build the documentation ?"
138 138 then
139 139 make html -C docs
140 140 echo
141 141 echo $GREEN"Check the docs, press enter to continue"$NOR
142 142 read
143 143
144 144 fi
145 145
146 146 if ask_section "Should we commit, tag, push... etc ? "
147 147 then
148 148 echo
149 149 echo $BLUE"Let's commit : git commit -am \"release $VERSION\" -S"
150 150 echo $GREEN"Press enter to commit"$NOR
151 151 read
152 152 git commit -am "release $VERSION" -S
153 153
154 154 echo
155 155 echo $BLUE"git push origin \$BRANCH ($BRANCH)?"$NOR
156 156 echo $GREEN"Make sure you can push"$NOR
157 157 echo $GREEN"Press enter to continue"$NOR
158 158 read
159 159 git push origin $BRANCH
160 160
161 161 echo
162 162 echo "Let's tag : git tag -am \"release $VERSION\" \"$VERSION\" -s"
163 163 echo $GREEN"Press enter to tag commit"$NOR
164 164 read
165 165 git tag -am "release $VERSION" "$VERSION" -s
166 166
167 167 echo
168 168 echo $BLUE"And push the tag: git push origin \$VERSION ?"$NOR
169 169 echo $GREEN"Press enter to continue"$NOR
170 170 read
171 171 git push origin $VERSION
172 172
173 173
174 174 echo $GREEN"please update version number and back to .dev in ${RED}IPython/core/release.py"
175 175 echo $GREEN"I tried ${RED}sed -i bkp -e '/Uncomment/s/^/# /g' IPython/core/release.py${NOR}"
176 176 sed -i bkp -e '/Uncomment/s/^/# /g' IPython/core/release.py
177 177 rm IPython/core/release.pybkp
178 178 git diff | cat
179 179 echo $GREEN"Please bump ${RED}the minor version number${NOR}"
180 180 maybe_edit IPython/core/release.py
181 181 echo ${BLUE}"Do not commit yet – we'll do it later."$NOR
182 182
183 183
184 184 echo $GREEN"Press enter to continue"$NOR
185 185 read
186 186
187 187 echo
188 188 echo "Let's commit : "$BLUE"git commit -am \"back to dev\""$NOR
189 189 echo $GREEN"Press enter to commit"$NOR
190 190 read
191 191 git commit -am "back to dev"
192 192
193 193 echo
194 194 echo $BLUE"git push origin \$BRANCH ($BRANCH)?"$NOR
195 195 echo $GREEN"Press enter to continue"$NOR
196 196 read
197 197 git push origin $BRANCH
198 198
199 199
200 200 echo
201 201 echo $BLUE"let's : git checkout $VERSION"$NOR
202 202 echo $GREEN"Press enter to continue"$NOR
203 203 read
204 204 git checkout $VERSION
205 205 fi
206 206
207 207 if ask_section "Should we build and release ?"
208 208 then
209 209
210 210 echo $BLUE"going to set SOURCE_DATE_EPOCH"$NOR
211 211 echo $BLUE'export SOURCE_DATE_EPOCH=$(git show -s --format=%ct HEAD)'$NOR
212 212 echo $GREEN"Press enter to continue"$NOR
213 213 read
214 214
215 215 export SOURCE_DATE_EPOCH=$(git show -s --format=%ct HEAD)
216 216
217 217 echo $BLUE"SOURCE_DATE_EPOCH set to $SOURCE_DATE_EPOCH"$NOR
218 218 echo $GREEN"Press enter to continue"$NOR
219 219 read
220 220
221 221
222 222
223 223 echo
224 224 echo $BLUE"Attempting to build package..."$NOR
225 225
226 226 tools/release
227 227
228 228
229 229 echo $RED'$ shasum -a 256 dist/*'
230 230 shasum -a 256 dist/*
231 231 echo $NOR
232 232
233 233 echo $BLUE"We are going to rebuild, node the hash above, and compare them to the rebuild"$NOR
234 234 echo $GREEN"Press enter to continue"$NOR
235 235 read
236 236
237 237 echo
238 238 echo $BLUE"Attempting to build package..."$NOR
239 239
240 240 tools/release
241 241
242 242 echo $RED"Check the shasum for SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH"
243 243 echo $RED'$ shasum -a 256 dist/*'
244 244 shasum -a 256 dist/*
245 245 echo $NOR
246 246
247 247 if ask_section "upload packages ?"
248 248 then
249 249 tools/release upload
250 250 fi
251 251 fi
General Comments 0
You need to be logged in to leave comments. Login now