forked from nose-devs/nose
-
Notifications
You must be signed in to change notification settings - Fork 1
/
setup3lib.py
140 lines (128 loc) · 5.27 KB
/
setup3lib.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
import sys
from setuptools import setup as _setup
py3_args = ['use_2to3', 'convert_2to3_doctests', 'use_2to3_fixers', 'test_dirs', 'test_build_dir', 'doctest_exts', 'pyversion_patching']
if sys.version_info < (3,):
# Remove any Python-3.x-only arguments (so they don't generate complaints
# from 2.x setuptools) and then just pass through to the regular setup
# routine.
def setup(*args, **kwargs):
for a in py3_args:
if a in kwargs:
del kwargs[a]
return _setup(*args, **kwargs)
else:
import os
import re
import logging
from setuptools import Distribution as _Distribution
from distutils.core import Command
from setuptools.command.build_py import Mixin2to3
from distutils import dir_util, file_util, log
import setuptools.command.test
from pkg_resources import normalize_path
try:
import patch
patch.logger.setLevel(logging.WARN)
except ImportError:
patch = None
patchfile_re = re.compile(r'(.*)\.py([0-9.]+)\.patch$')
def pyversion_patch(filename):
'''Find the best pyversion-fixup patch for a given filename and apply
it.
'''
dir, file = os.path.split(filename)
best_ver = (0,)
patchfile = None
for dirfile in os.listdir(dir):
m = patchfile_re.match(dirfile)
if not m:
continue
base, ver = m.groups()
if base != file:
continue
ver = tuple([int(v) for v in ver.split('.')])
if sys.version_info >= ver and ver > best_ver:
best_ver = ver
patchfile = dirfile
if not patchfile:
return False
log.info("Applying %s to %s..." % (patchfile, filename))
cwd = os.getcwd()
os.chdir(dir)
try:
p = patch.fromfile(patchfile)
p.apply()
finally:
os.chdir(cwd)
return True
class Distribution (_Distribution):
def __init__(self, attrs=None):
self.test_dirs = []
self.test_build_dir = None
self.doctest_exts = ['.py', '.rst']
self.pyversion_patching = False
_Distribution.__init__(self, attrs)
class BuildTestsCommand (Command, Mixin2to3):
# Create mirror copy of tests, convert all .py files using 2to3
user_options = []
def initialize_options(self):
self.test_base = None
def finalize_options(self):
test_base = self.distribution.test_build_dir
if not test_base:
bcmd = self.get_finalized_command('build')
test_base = bcmd.build_base
self.test_base = test_base
def run(self):
use_2to3 = getattr(self.distribution, 'use_2to3', False)
test_dirs = getattr(self.distribution, 'test_dirs', [])
test_base = self.test_base
bpy_cmd = self.get_finalized_command("build_py")
lib_base = normalize_path(bpy_cmd.build_lib)
modified = []
py_modified = []
doc_modified = []
dir_util.mkpath(test_base)
for testdir in test_dirs:
for srcdir, dirnames, filenames in os.walk(testdir):
destdir = os.path.join(test_base, srcdir)
dir_util.mkpath(destdir)
for fn in filenames:
if fn.startswith("."):
# Skip .svn folders and such
continue
dstfile, copied = file_util.copy_file(
os.path.join(srcdir, fn),
os.path.join(destdir, fn),
update=True)
if copied:
modified.append(dstfile)
if fn.endswith('.py'):
py_modified.append(dstfile)
for ext in self.distribution.doctest_exts:
if fn.endswith(ext):
doc_modified.append(dstfile)
break
if use_2to3:
self.run_2to3(py_modified)
self.run_2to3(doc_modified, True)
if self.distribution.pyversion_patching:
if patch is not None:
for file in modified:
pyversion_patch(file)
else:
log.warn("Warning: pyversion_patching specified in setup config but patch module not found. Patching will not be performed.")
dir_util.mkpath(lib_base)
self.reinitialize_command('egg_info', egg_base=lib_base)
self.run_command('egg_info')
class TestCommand (setuptools.command.test.test):
# Override 'test' command to make sure 'build_tests' gets run first.
def run(self):
self.run_command('build_tests')
setuptools.command.test.test.run(self)
def setup(*args, **kwargs):
kwargs.setdefault('distclass', Distribution)
cmdclass = kwargs.setdefault('cmdclass', {})
cmdclass.setdefault('build_tests', BuildTestsCommand)
cmdclass.setdefault('test', TestCommand)
return _setup(*args, **kwargs)