Skip to content

Commit ce1da9b

Browse files
committed
Fix infinite process recursion on Windows
1 parent 5f41835 commit ce1da9b

File tree

2 files changed

+158
-133
lines changed

2 files changed

+158
-133
lines changed

setup.py

Lines changed: 137 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,19 @@
2020
except AttributeError:
2121
pass
2222

23-
# BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
24-
# update it when the contents of directories change.
25-
if os.path.exists('MANIFEST'):
26-
os.remove('MANIFEST')
23+
# This 'if' statement is needed to prevent spawning infinite processes
24+
# on Windows
25+
if __name__ == '__main__':
26+
# BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
27+
# update it when the contents of directories change.
28+
if os.path.exists('MANIFEST'):
29+
os.remove('MANIFEST')
2730

2831
try:
2932
from setuptools.core import setup
3033
except ImportError:
3134
from distutils.core import setup
3235

33-
3436
import setupext
3537
from setupext import print_line, print_raw, print_message, print_status
3638

@@ -48,6 +50,7 @@
4850
'Required dependencies and extensions',
4951
setupext.Numpy(),
5052
setupext.Dateutil(),
53+
setupext.Tornado(),
5154
setupext.Pyparsing(),
5255
setupext.CXX(),
5356
setupext.LibAgg(),
@@ -87,90 +90,6 @@
8790
]
8891

8992

90-
# These are distutils.setup parameters that the various packages add
91-
# things to.
92-
packages = []
93-
py_modules = []
94-
ext_modules = []
95-
package_data = {}
96-
package_dir = {'': 'lib'}
97-
install_requires = []
98-
default_backend = None
99-
100-
101-
# Go through all of the packages and figure out which ones we are
102-
# going to build/install.
103-
print_line()
104-
print_raw("Edit setup.cfg to change the build options")
105-
106-
107-
required_failed = []
108-
good_packages = []
109-
for package in mpl_packages:
110-
if isinstance(package, str):
111-
print_raw('')
112-
print_raw(package.upper())
113-
else:
114-
try:
115-
result = package.check()
116-
if result is not None:
117-
message = 'yes [%s]' % result
118-
print_status(package.name, message)
119-
except setupext.CheckFailed as e:
120-
print_status(package.name, 'no [%s]' % str(e))
121-
if not package.optional:
122-
required_failed.append(package)
123-
else:
124-
good_packages.append(package)
125-
if isinstance(package, setupext.OptionalBackendPackage):
126-
if default_backend is None:
127-
default_backend = package.name
128-
print_raw('')
129-
130-
131-
# Abort if any of the required packages can not be built.
132-
if required_failed:
133-
print_line()
134-
print_message(
135-
"The following required packages can not "
136-
"be built: %s" %
137-
', '.join(x.name for x in required_failed))
138-
sys.exit(1)
139-
140-
141-
# Now collect all of the information we need to build all of the
142-
# packages.
143-
for package in good_packages:
144-
if isinstance(package, str):
145-
continue
146-
packages.extend(package.get_packages())
147-
py_modules.extend(package.get_py_modules())
148-
ext = package.get_extension()
149-
if ext is not None:
150-
ext_modules.append(ext)
151-
data = package.get_package_data()
152-
for key, val in data.items():
153-
package_data.setdefault(key, [])
154-
package_data[key] = list(set(val + package_data[key]))
155-
install_requires.extend(package.get_install_requires())
156-
157-
# Write the default matplotlibrc file
158-
if default_backend is None:
159-
default_backend = 'svg'
160-
if setupext.options['backend']:
161-
default_backend = setupext.options['backend']
162-
with open('matplotlibrc.template') as fd:
163-
template = fd.read()
164-
with open('lib/matplotlib/mpl-data/matplotlibrc', 'w') as fd:
165-
fd.write(template % {'backend': default_backend})
166-
167-
168-
# Build in verbose mode if requested
169-
if setupext.options['verbose']:
170-
for mod in ext_modules:
171-
mod.extra_compile_args.append('-DVERBOSE')
172-
173-
17493
classifiers = [
17594
'Development Status :: 5 - Production/Stable',
17695
'Intended Audience :: Science/Research',
@@ -181,47 +100,132 @@
181100
'Topic :: Scientific/Engineering :: Visualization',
182101
]
183102

184-
185-
# Finally, pass this all along to distutils to do the heavy lifting.
186-
distrib = setup(name="matplotlib",
187-
version=__version__,
188-
description="Python plotting package",
189-
author="John D. Hunter, Michael Droettboom",
190-
author_email="mdroe@stsci.edu",
191-
url="http://matplotlib.org",
192-
long_description="""
193-
matplotlib strives to produce publication quality 2D graphics
194-
for interactive graphing, scientific publishing, user interface
195-
development and web application servers targeting multiple user
196-
interfaces and hardcopy output formats. There is a 'pylab' mode
197-
which emulates matlab graphics.
198-
""",
199-
download_url="https://downloads.sourceforge.net/project/matplotlib/matplotlib/matplotlib-{0}/matplotlib-{0}.tar.gz".format(__version__),
200-
install_requires=['dateutils', 'tornado'],
201-
license="BSD",
202-
packages=packages,
203-
platforms='any',
204-
py_modules=py_modules,
205-
ext_modules=ext_modules,
206-
package_dir=package_dir,
207-
package_data=package_data,
208-
classifiers=classifiers,
209-
210-
# List third-party Python packages that we require
211-
install_requires=install_requires,
212-
213-
# Automatically 2to3 source on Python 3.x
214-
use_2to3=True,
215-
216-
# matplotlib has C/C++ extensions, so it's not zip safe.
217-
# Telling setuptools this prevents it from doing an automatic
218-
# check for zip safety.
219-
zip_safe=False,
220-
221-
# Install our nose plugin so it will always be found
222-
entry_points={
223-
'nose.plugins.0.10': [
224-
'KnownFailure = matplotlib.testing.noseclasses:KnownFailure'
225-
]
226-
},
227-
)
103+
# One doesn't normally see `if __name__ == '__main__'` blocks in a setup.py,
104+
# however, this is needed on Windows to avoid creating infinite subprocesses
105+
# when using multiprocessing.
106+
if __name__ == '__main__':
107+
# These are distutils.setup parameters that the various packages add
108+
# things to.
109+
packages = []
110+
py_modules = []
111+
ext_modules = []
112+
package_data = {}
113+
package_dir = {'': 'lib'}
114+
install_requires = []
115+
default_backend = None
116+
117+
118+
# Go through all of the packages and figure out which ones we are
119+
# going to build/install.
120+
print_line()
121+
print_raw("Edit setup.cfg to change the build options")
122+
123+
required_failed = []
124+
good_packages = []
125+
for package in mpl_packages:
126+
if isinstance(package, str):
127+
print_raw('')
128+
print_raw(package.upper())
129+
else:
130+
try:
131+
result = package.check()
132+
if result is not None:
133+
message = 'yes [%s]' % result
134+
print_status(package.name, message)
135+
except setupext.CheckFailed as e:
136+
print_status(package.name, 'no [%s]' % str(e))
137+
if not package.optional:
138+
required_failed.append(package)
139+
else:
140+
good_packages.append(package)
141+
if isinstance(package, setupext.OptionalBackendPackage):
142+
if default_backend is None:
143+
default_backend = package.name
144+
print_raw('')
145+
146+
147+
# Abort if any of the required packages can not be built.
148+
if required_failed:
149+
print_line()
150+
print_message(
151+
"The following required packages can not "
152+
"be built: %s" %
153+
', '.join(x.name for x in required_failed))
154+
sys.exit(1)
155+
156+
157+
# Now collect all of the information we need to build all of the
158+
# packages.
159+
for package in good_packages:
160+
if isinstance(package, str):
161+
continue
162+
packages.extend(package.get_packages())
163+
py_modules.extend(package.get_py_modules())
164+
ext = package.get_extension()
165+
if ext is not None:
166+
ext_modules.append(ext)
167+
data = package.get_package_data()
168+
for key, val in data.items():
169+
package_data.setdefault(key, [])
170+
package_data[key] = list(set(val + package_data[key]))
171+
install_requires.extend(package.get_install_requires())
172+
173+
# Write the default matplotlibrc file
174+
if default_backend is None:
175+
default_backend = 'svg'
176+
if setupext.options['backend']:
177+
default_backend = setupext.options['backend']
178+
with open('matplotlibrc.template') as fd:
179+
template = fd.read()
180+
with open('lib/matplotlib/mpl-data/matplotlibrc', 'w') as fd:
181+
fd.write(template % {'backend': default_backend})
182+
183+
184+
# Build in verbose mode if requested
185+
if setupext.options['verbose']:
186+
for mod in ext_modules:
187+
mod.extra_compile_args.append('-DVERBOSE')
188+
189+
190+
# Finally, pass this all along to distutils to do the heavy lifting.
191+
distrib = setup(name="matplotlib",
192+
version=__version__,
193+
description="Python plotting package",
194+
author="John D. Hunter, Michael Droettboom",
195+
author_email="mdroe@stsci.edu",
196+
url="http://matplotlib.org",
197+
long_description="""
198+
matplotlib strives to produce publication quality 2D graphics
199+
for interactive graphing, scientific publishing, user interface
200+
development and web application servers targeting multiple user
201+
interfaces and hardcopy output formats. There is a 'pylab' mode
202+
which emulates matlab graphics.
203+
""",
204+
license="BSD",
205+
packages=packages,
206+
platforms='any',
207+
py_modules=py_modules,
208+
ext_modules=ext_modules,
209+
package_dir=package_dir,
210+
package_data=package_data,
211+
classifiers=classifiers,
212+
download_url="https://downloads.sourceforge.net/project/matplotlib/matplotlib/matplotlib-{0}/matplotlib-{0}.tar.gz".format(__version__),
213+
214+
# List third-party Python packages that we require
215+
install_requires=install_requires,
216+
217+
# Automatically 2to3 source on Python 3.x
218+
use_2to3=True,
219+
220+
# matplotlib has C/C++ extensions, so it's not zip safe.
221+
# Telling setuptools this prevents it from doing an automatic
222+
# check for zip safety.
223+
zip_safe=False,
224+
225+
# Install our nose plugin so it will always be found
226+
entry_points={
227+
'nose.plugins.0.10': [
228+
'KnownFailure = matplotlib.testing.noseclasses:KnownFailure'
229+
]
230+
},
231+
)

setupext.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,9 @@ class FreeType(SetupPackage):
723723
name = "freetype"
724724

725725
def check(self):
726+
if sys.platform == 'win32':
727+
return "Unknown version"
728+
726729
status, output = getstatusoutput("freetype-config --version")
727730
if status == 0:
728731
version = output
@@ -885,6 +888,24 @@ def get_install_requires(self):
885888
return ['python_dateutil']
886889

887890

891+
class Tornado(SetupPackage):
892+
name = "tornado"
893+
894+
def check(self):
895+
try:
896+
import tornado
897+
except ImportError:
898+
return (
899+
"tornado was not found. It is required for the WebAgg "
900+
"backend. pip/easy_install may attempt to install it "
901+
"after matplotlib.")
902+
903+
return "using tornado version %s" % tornado.__version__
904+
905+
def get_install_requires(self):
906+
return ['tornado']
907+
908+
888909
class Pyparsing(SetupPackage):
889910
name = "pyparsing"
890911

0 commit comments

Comments
 (0)