-
Notifications
You must be signed in to change notification settings - Fork 15
/
setupinfo.py
438 lines (315 loc) · 11.5 KB
/
setupinfo.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
# Copyright the RTMPy Project
#
# RTMPy is free software: you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, either version 2.1 of the License, or (at your option)
# any later version.
#
# RTMPy is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with RTMPy. If not, see <http://www.gnu.org/licenses/>.
"""
Meta data and helper functions for setup
"""
import sys
import os.path
import fnmatch
try:
from Cython.Distutils import build_ext
have_cython = True
except ImportError:
from setuptools.command.build_ext import build_ext
have_cython = False
if have_cython:
# may need to work around setuptools bug by providing a fake Pyrex
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "fake_pyrex"))
from setuptools.command import test, sdist
from setuptools import Extension
from distutils.core import Distribution
_version = None
jython = sys.platform.startswith('java')
can_compile_extensions = not jython
class MyDistribution(Distribution):
"""
This seems to be is the only obvious way to add a global option to
distutils.
Provide the ability to disable building the extensions for any called
command.
"""
global_options = Distribution.global_options + [
('disable-ext', None, 'Disable building extensions.')
]
def finalize_options(self):
Distribution.finalize_options(self)
try:
i = self.script_args.index('--disable-ext')
except ValueError:
self.disable_ext = False
else:
self.disable_ext = True
self.script_args.pop(i)
class MyBuildExt(build_ext):
"""
The companion to L{MyDistribution} that checks to see if building the
extensions are disabled.
"""
def build_extension(self, ext):
if self.distribution.disable_ext:
return
return build_ext.build_extension(self, ext)
def build_extensions(self):
if self.distribution.disable_ext:
return
return build_ext.build_extensions(self)
class MySDist(sdist.sdist):
"""
We generate the Cython code for a source distribution
"""
def cythonise(self):
ext = MyBuildExt(self.distribution)
ext.initialize_options()
ext.finalize_options()
ext.check_extensions_list(ext.extensions)
for e in ext.extensions:
e.sources = ext.cython_sources(e.sources, e)
def run(self):
if not have_cython:
print('ERROR - Cython is required to build source distributions')
raise SystemExit(1)
self.cythonise()
return sdist.sdist.run(self)
class TrialTest(test.test):
"""
Twisted Trial setuptools command
Stolen from setuptools_trial.
"""
user_options = test.test.user_options + [
('rterrors', 'e', "Realtime errors: print out tracebacks as soon as they occur."),
('debug-stacktraces', 'B', "Report Deferred creation and callback stack traces."),
('coverage','c', "Report coverage data."),
('reactor=','r', "which reactor to use"),
('reporter=', None, "Customize Trial's output with a Reporter plugin."),
('until-failure','u', "Repeat test until it fails."),
]
boolean_options = ['coverage', 'debug-stacktraces', 'rterrors']
def initialize_options(self):
test.test.initialize_options(self)
self.coverage = None
self.debug_stacktraces = None
self.reactor = None
self.reporter = None
self.rterrors = None
self.until_failure = None
def finalize_options(self):
if self.test_suite is None:
if self.test_module is None:
self.test_suite = self.distribution.test_suite
else:
self.test_suite = self.test_module
elif self.test_module:
raise DistutilsOptionError(
"You may specify a module or a suite, but not both"
)
self.test_args = self.test_suite
def run_tests(self):
# We do the import from Twisted inside the function instead of the top
# of the file because since Twisted is a setup_requires, we can't
# assume that Twisted will be installed on the user's system prior
# to using Tahoe, so if we don't do the import here, then importing
# from this plugin will fail.
from twisted.scripts import trial
# Handle parsing the trial options passed through the setuptools
# trial command.
cmd_options = []
if self.reactor is not None:
cmd_options.extend(['--reactor', self.reactor])
else:
# Cygwin requires the poll reactor to work at all. Linux requires the poll reactor
# to avoid twisted bug #3218. In general, the poll reactor is better than the
# select reactor, but it is not available on all platforms. According to exarkun on
# IRC, it is available but buggy on some versions of Mac OS X, so just because you
# can install it doesn't mean we want to use it on every platform.
# Unfortunately this leads to this error with some combinations of tools:
# twisted.python.usage.UsageError: The specified reactor cannot be used, failed with error: reactor already installed.
if sys.platform in ("cygwin"):
cmd_options.extend(['--reactor', 'poll'])
if self.reporter is not None:
cmd_options.extend(['--reporter', self.reporter])
if self.rterrors is not None:
cmd_options.append('--rterrors')
if self.debug_stacktraces is not None:
cmd_options.append('--debug-stacktraces')
config = trial.Options()
config.parseOptions(cmd_options)
args = self.test_args
if type(args) == str:
args = [args,]
config['tests'] = args
if self.coverage:
config.opt_coverage()
trial._initialDebugSetup(config)
trialRunner = trial._makeRunner(config)
suite = trial._getSuite(config)
# run the tests
if self.until_failure:
test_result = trialRunner.runUntilFailure(suite)
else:
test_result = trialRunner.run(suite)
# write coverage data
if config.tracer:
sys.settrace(None)
results = config.tracer.results()
results.write_results(show_missing=1, summary=False,
coverdir=config.coverdir)
if test_result.wasSuccessful():
sys.exit(0) # success
else:
sys.exit(1) # failure
def set_version(version):
global _version
_version = version
def get_version():
v = ''
prev = None
for x in _version:
if prev is not None:
if isinstance(x, int):
v += '.'
prev = x
v += str(x)
return v.strip('.')
def extra_setup_args():
"""
Extra kwargs to supply in the call to C{setup}.
This is used to supply custom commands, not metadata - that should live in
setup.py itself.
"""
return {
'distclass': MyDistribution,
'cmdclass': {
'test': TrialTest,
'build_ext': MyBuildExt,
'sdist': MySDist
}
}
def get_test_requirements():
"""
Returns a list of required packages to run the test suite.
"""
return []
def write_version_py(filename='rtmpy/_version.py'):
"""
"""
if os.path.exists(filename):
os.remove(filename)
content = """\
# THIS FILE IS GENERATED BY RTMPY SETUP.PY
from pyamf.versions import Version
version = Version(*%(version)r)
"""
a = open(filename, 'wt')
try:
a.write(content % {'version': _version})
finally:
a.close()
def get_extras_require():
return {}
def make_extension(mod_name, **extra_options):
"""
Tries is best to return an Extension instance based on the mod_name
"""
include_dirs = extra_options.setdefault('include_dirs', [])
base_name = os.path.join(mod_name.replace('.', os.path.sep))
if have_cython:
cpd = get_cpyamf_pxd_dir()
if cpd and cpd not in include_dirs:
include_dirs.append(cpd)
for ext in ['.pyx', '.py']:
source = base_name + ext
if os.path.exists(source):
return Extension(mod_name, [source], **extra_options)
print('WARNING: Could not find Cython source for %r' % (mod_name,))
else:
source = base_name + '.c'
if os.path.exists(source):
return Extension(mod_name, [source], **extra_options)
print('WARNING: Could not build extension for %r, no source found' % (
mod_name,))
def read(fname):
return open(os.path.join(os.path.dirname(__file__), fname)).read()
def get_extensions():
"""
Return a list of Extension instances that can be compiled.
"""
if not can_compile_extensions:
print(80 * '*')
print('WARNING:')
print('\tAn optional code optimization (C extension) could not be compiled.\n\n')
print('\tOptimizations for this package will not be available!\n\n')
print('Compiling extensions is not supported on %r' % (sys.platform,))
print(80 * '*')
return []
extensions = []
mods = [
'rtmpy.protocol.rtmp.header'
]
for m in mods:
e = make_extension(m)
if e:
extensions.append(e)
return extensions
def get_trove_classifiers():
"""
Return a list of trove classifiers that are setup dependent.
"""
classifiers = []
def dev_status():
version = get_version()
if 'dev' in version:
return 'Development Status :: 2 - Pre-Alpha'
elif 'alpha' in version:
return 'Development Status :: 3 - Alpha'
elif 'beta' in version:
return 'Development Status :: 4 - Beta'
else:
return 'Development Status :: 5 - Production/Stable'
return classifiers + [dev_status()]
def recursive_glob(path, pattern):
matches = []
for root, dirnames, filenames in os.walk(path):
for filename in fnmatch.filter(filenames, pattern):
matches.append(os.path.normpath(os.path.join(root, filename)))
return matches
def get_install_requirements():
"""
Returns a list of dependencies for RTMPy to function correctly on the
target platform.
"""
install_requires = ['Twisted>=2.5.0', 'PyAMF>=0.6']
if sys.platform.startswith('win'):
install_requires.append('PyWin32')
if 'dev' in get_version():
if can_compile_extensions:
install_requires.extend(['Cython>=0.13'])
return install_requires
def get_test_requirements():
"""
Returns a list of required packages to run the test suite.
"""
return []
def get_cpyamf_pxd_dir():
"""
Return the directory that will be included to allow Cython to find
cpyamf/*.pxd files (if cpyamf is installed)
"""
try:
import cpyamf
except ImportError:
print ("WARNING: cpyamf is not installed")
return
# TODO: what to do about pyamf in an egg here?
return os.path.dirname(os.path.dirname(cpyamf.__file__))