1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3"""Setup script for IPython.
4
5Under Posix environments it works like a typical setup.py script.
6Under Windows, the command sdist is not supported, since IPython
7requires utilities which are not available under Windows."""
8
9#-----------------------------------------------------------------------------
10#  Copyright (c) 2008-2011, IPython Development Team.
11#  Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
12#  Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
13#  Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
14#
15#  Distributed under the terms of the Modified BSD License.
16#
17#  The full license is in the file COPYING.rst, distributed with this software.
18#-----------------------------------------------------------------------------
19
20from __future__ import print_function
21
22import os
23import sys
24
25# **Python version check**
26#
27# This check is also made in IPython/__init__, don't forget to update both when
28# changing Python version requirements.
29if sys.version_info < (3, 7):
30    pip_message = 'This may be due to an out of date pip. Make sure you have pip >= 9.0.1.'
31    try:
32        import pip
33        pip_version = tuple([int(x) for x in pip.__version__.split('.')[:3]])
34        if pip_version < (9, 0, 1) :
35            pip_message = 'Your pip version is out of date, please install pip >= 9.0.1. '\
36            'pip {} detected.'.format(pip.__version__)
37        else:
38            # pip is new enough - it must be something else
39            pip_message = ''
40    except Exception:
41        pass
42
43
44    error = """
45IPython 7.17+ supports Python 3.7 and above, following NEP 29.
46When using Python 2.7, please install IPython 5.x LTS Long Term Support version.
47Python 3.3 and 3.4 were supported up to IPython 6.x.
48Python 3.5 was supported with IPython 7.0 to 7.9.
49Python 3.6 was supported with IPython up to 7.16.
50
51See IPython `README.rst` file for more information:
52
53    https://github.com/ipython/ipython/blob/master/README.rst
54
55Python {py} detected.
56{pip}
57""".format(py=sys.version_info, pip=pip_message )
58
59    print(error, file=sys.stderr)
60    sys.exit(1)
61
62# At least we're on the python version we need, move on.
63
64# BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
65# update it when the contents of directories change.
66if os.path.exists('MANIFEST'): os.remove('MANIFEST')
67
68from distutils.core import setup
69
70# Our own imports
71from setupbase import target_update
72
73from setupbase import (
74    setup_args,
75    find_packages,
76    find_package_data,
77    check_package_data_first,
78    find_entry_points,
79    build_scripts_entrypt,
80    find_data_files,
81    git_prebuild,
82    install_symlinked,
83    install_lib_symlink,
84    install_scripts_for_symlink,
85    unsymlink,
86)
87
88isfile = os.path.isfile
89pjoin = os.path.join
90
91#-------------------------------------------------------------------------------
92# Handle OS specific things
93#-------------------------------------------------------------------------------
94
95if os.name in ('nt','dos'):
96    os_name = 'windows'
97else:
98    os_name = os.name
99
100# Under Windows, 'sdist' has not been supported.  Now that the docs build with
101# Sphinx it might work, but let's not turn it on until someone confirms that it
102# actually works.
103if os_name == 'windows' and 'sdist' in sys.argv:
104    print('The sdist command is not available under Windows.  Exiting.')
105    sys.exit(1)
106
107
108#-------------------------------------------------------------------------------
109# Things related to the IPython documentation
110#-------------------------------------------------------------------------------
111
112# update the manuals when building a source dist
113if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
114
115    # List of things to be updated. Each entry is a triplet of args for
116    # target_update()
117    to_update = [
118                 ('docs/man/ipython.1.gz',
119                  ['docs/man/ipython.1'],
120                  'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
121                 ]
122
123
124    [ target_update(*t) for t in to_update ]
125
126#---------------------------------------------------------------------------
127# Find all the packages, package data, and data_files
128#---------------------------------------------------------------------------
129
130packages = find_packages()
131package_data = find_package_data()
132
133data_files = find_data_files()
134
135setup_args['packages'] = packages
136setup_args['package_data'] = package_data
137setup_args['data_files'] = data_files
138
139#---------------------------------------------------------------------------
140# custom distutils commands
141#---------------------------------------------------------------------------
142# imports here, so they are after setuptools import if there was one
143from distutils.command.sdist import sdist
144
145setup_args['cmdclass'] = {
146    'build_py': \
147            check_package_data_first(git_prebuild('IPython')),
148    'sdist' : git_prebuild('IPython', sdist),
149    'symlink': install_symlinked,
150    'install_lib_symlink': install_lib_symlink,
151    'install_scripts_sym': install_scripts_for_symlink,
152    'unsymlink': unsymlink,
153}
154
155
156#---------------------------------------------------------------------------
157# Handle scripts, dependencies, and setuptools specific things
158#---------------------------------------------------------------------------
159
160# For some commands, use setuptools.  Note that we do NOT list install here!
161# If you want a setuptools-enhanced install, just run 'setupegg.py install'
162needs_setuptools = {'develop', 'release', 'bdist_egg', 'bdist_rpm',
163           'bdist', 'bdist_dumb', 'bdist_wininst', 'bdist_wheel',
164           'egg_info', 'easy_install', 'upload', 'install_egg_info',
165          }
166
167if len(needs_setuptools.intersection(sys.argv)) > 0:
168    import setuptools
169
170# This dict is used for passing extra arguments that are setuptools
171# specific to setup
172setuptools_extra_args = {}
173
174# setuptools requirements
175
176extras_require = dict(
177    parallel=["ipyparallel"],
178    qtconsole=["qtconsole"],
179    doc=["Sphinx>=1.3"],
180    test=[
181        "nose>=0.10.1",
182        "requests",
183        "testpath",
184        "pygments",
185        "nbformat",
186        "ipykernel",
187        "numpy>=1.17",
188    ],
189    terminal=[],
190    kernel=["ipykernel"],
191    nbformat=["nbformat"],
192    notebook=["notebook", "ipywidgets"],
193    nbconvert=["nbconvert"],
194)
195
196install_requires = [
197    "setuptools>=18.5",
198    "jedi>=0.16",
199    "decorator",
200    "pickleshare",
201    "traitlets>=4.2",
202    "prompt_toolkit>=2.0.0,<3.1.0,!=3.0.0,!=3.0.1",
203    "pygments",
204    "backcall",
205    "matplotlib-inline",
206]
207
208# Platform-specific dependencies:
209# This is the correct way to specify these,
210# but requires pip >= 6. pip < 6 ignores these.
211
212extras_require.update(
213    {
214        ':sys_platform != "win32"': ["pexpect>4.3"],
215        ':sys_platform == "darwin"': ["appnope"],
216        ':sys_platform == "win32"': ["colorama"],
217    }
218)
219# FIXME: re-specify above platform dependencies for pip < 6
220# These would result in non-portable bdists.
221if not any(arg.startswith('bdist') for arg in sys.argv):
222    if sys.platform == 'darwin':
223        install_requires.extend(['appnope'])
224
225    if not sys.platform.startswith("win"):
226        install_requires.append("pexpect>4.3")
227
228    # workaround pypa/setuptools#147, where setuptools misspells
229    # platform_python_implementation as python_implementation
230    if 'setuptools' in sys.modules:
231        for key in list(extras_require):
232            if 'platform_python_implementation' in key:
233                new_key = key.replace('platform_python_implementation', 'python_implementation')
234                extras_require[new_key] = extras_require.pop(key)
235
236everything = set()
237for key, deps in extras_require.items():
238    if ':' not in key:
239        everything.update(deps)
240extras_require['all'] = list(sorted(everything))
241
242if 'setuptools' in sys.modules:
243    setuptools_extra_args['python_requires'] = '>=3.7'
244    setuptools_extra_args['zip_safe'] = False
245    setuptools_extra_args['entry_points'] = {
246        'console_scripts': find_entry_points(),
247        'pygments.lexers': [
248            'ipythonconsole = IPython.lib.lexers:IPythonConsoleLexer',
249            'ipython = IPython.lib.lexers:IPythonLexer',
250            'ipython3 = IPython.lib.lexers:IPython3Lexer',
251        ],
252    }
253    setup_args['extras_require'] = extras_require
254    setup_args['install_requires'] = install_requires
255
256else:
257    # scripts has to be a non-empty list, or install_scripts isn't called
258    setup_args['scripts'] = [e.split('=')[0].strip() for e in find_entry_points()]
259
260    setup_args['cmdclass']['build_scripts'] = build_scripts_entrypt
261
262#---------------------------------------------------------------------------
263# Do the actual setup now
264#---------------------------------------------------------------------------
265
266setup_args.update(setuptools_extra_args)
267
268
269
270def main():
271    setup(**setup_args)
272
273if __name__ == '__main__':
274    main()
275