6
6
BSD license. Parts are from lxml (https://github.com/lxml/lxml)
7
7
"""
8
8
9
+ import glob
9
10
import os
11
+ import os .path as osp
10
12
import sys
11
13
import shutil
12
- import warnings
13
14
import re
14
15
import platform
15
16
from distutils .version import LooseVersion
17
+ from distutils import sysconfig
18
+
19
+ from os .path import join as pjoin
16
20
17
21
# versioning
18
22
import versioneer
26
30
except ImportError :
27
31
_CYTHON_INSTALLED = False
28
32
33
+
29
34
try :
30
35
import pkg_resources
31
36
from setuptools import setup , Command
35
40
from distutils .core import setup , Command
36
41
_have_setuptools = False
37
42
43
+
38
44
setuptools_kwargs = {}
39
45
min_numpy_ver = '1.7.0'
40
46
if sys .version_info [0 ] >= 3 :
53
59
else :
54
60
setuptools_kwargs = {
55
61
'install_requires' : ['python-dateutil' ,
56
- 'pytz >= 2011k' ,
62
+ 'pytz >= 2011k' ,
57
63
'numpy >= %s' % min_numpy_ver ],
58
64
'setup_requires' : ['numpy >= %s' % min_numpy_ver ],
59
65
'zip_safe' : False ,
60
66
}
61
67
62
68
if not _have_setuptools :
63
69
try :
64
- import numpy
65
- import dateutil
70
+ import numpy # noqa
71
+ import dateutil # noqa
66
72
setuptools_kwargs = {}
67
73
except ImportError :
68
74
sys .exit ("install requires: 'python-dateutil < 2','numpy'."
69
75
" use pip or easy_install."
70
76
"\n $ pip install 'python-dateutil < 2' 'numpy'" )
71
77
78
+
79
+ # Check if we're running 64-bit Python
80
+ is_64_bit = sys .maxsize > 2 ** 32
81
+
82
+ # Check if this is a debug build of Python.
83
+ if hasattr (sys , 'gettotalrefcount' ):
84
+ build_type = 'Debug'
85
+ else :
86
+ build_type = 'Release'
87
+
88
+
72
89
from distutils .extension import Extension
73
90
from distutils .command .build import build
74
91
from distutils .command .build_ext import build_ext as _build_ext
75
92
76
93
try :
77
94
if not _CYTHON_INSTALLED :
78
95
raise ImportError ('No supported version of Cython installed.' )
79
- from Cython .Distutils import build_ext as _build_ext
96
+ from Cython .Distutils import build_ext as _build_ext # noqa
80
97
cython = True
81
98
except ImportError :
82
99
cython = False
83
100
84
- from os .path import join as pjoin
85
-
86
101
87
102
class build_ext (_build_ext ):
103
+
88
104
def build_extensions (self ):
89
105
numpy_incl = pkg_resources .resource_filename ('numpy' , 'core/include' )
90
106
91
107
for ext in self .extensions :
92
- if hasattr (ext , 'include_dirs' ) and not numpy_incl in ext .include_dirs :
108
+ if (hasattr (ext , 'include_dirs' ) and
109
+ numpy_incl not in ext .include_dirs ):
93
110
ext .include_dirs .append (numpy_incl )
94
111
_build_ext .build_extensions (self )
95
112
113
+ def run (self ):
114
+ self ._run_cmake ()
115
+ _build_ext .run (self )
116
+
117
+ # adapted from cmake_build_ext in dynd-python
118
+ # github.com/libdynd/dynd-python
119
+
120
+ description = "Build the C-extension for libpandas and regular pandas"
121
+ user_options = ([('extra-cmake-args=' , None ,
122
+ 'extra arguments for CMake' )] +
123
+ _build_ext .user_options )
124
+
125
+ def initialize_options (self ):
126
+ _build_ext .initialize_options (self )
127
+ self .extra_cmake_args = ''
128
+
129
+ def _run_cmake (self ):
130
+ # The directory containing this setup.py
131
+ source = osp .dirname (osp .abspath (__file__ ))
132
+
133
+ # The staging directory for the module being built
134
+ build_temp = pjoin (os .getcwd (), self .build_temp )
135
+
136
+ # Change to the build directory
137
+ saved_cwd = os .getcwd ()
138
+ if not os .path .isdir (self .build_temp ):
139
+ self .mkpath (self .build_temp )
140
+ os .chdir (self .build_temp )
141
+
142
+ # Detect if we built elsewhere
143
+ if os .path .isfile ('CMakeCache.txt' ):
144
+ cachefile = open ('CMakeCache.txt' , 'r' )
145
+ cachedir = re .search ('CMAKE_CACHEFILE_DIR:INTERNAL=(.*)' ,
146
+ cachefile .read ()).group (1 )
147
+ cachefile .close ()
148
+ if (cachedir != build_temp ):
149
+ return
150
+
151
+ pyexe_option = '-DPYTHON_EXECUTABLE=%s' % sys .executable
152
+ static_lib_option = ''
153
+ build_tests_option = ''
154
+
155
+ if sys .platform != 'win32' :
156
+ cmake_command = ['cmake' , self .extra_cmake_args , pyexe_option ,
157
+ build_tests_option ,
158
+ static_lib_option , source ]
159
+
160
+ self .spawn (cmake_command )
161
+ self .spawn (['make' ])
162
+ else :
163
+ import shlex
164
+ cmake_generator = 'Visual Studio 14 2015'
165
+ if is_64_bit :
166
+ cmake_generator += ' Win64'
167
+ # Generate the build files
168
+ extra_cmake_args = shlex .split (self .extra_cmake_args )
169
+ cmake_command = (['cmake' ] + extra_cmake_args +
170
+ [source , pyexe_option ,
171
+ static_lib_option ,
172
+ build_tests_option ,
173
+ '-G' , cmake_generator ])
174
+ if "-G" in self .extra_cmake_args :
175
+ cmake_command = cmake_command [:- 2 ]
176
+
177
+ self .spawn (cmake_command )
178
+ # Do the build
179
+ self .spawn (['cmake' , '--build' , '.' , '--config' , build_type ])
180
+
181
+ if self .inplace :
182
+ # a bit hacky
183
+ build_lib = saved_cwd
184
+ else :
185
+ build_lib = pjoin (os .getcwd (), self .build_lib )
186
+
187
+ # Move the built libpandas library to the place expected by the Python
188
+ # build
189
+ if sys .platform != 'win32' :
190
+ name , = glob .glob ('libpandas.*' )
191
+ try :
192
+ os .makedirs (pjoin (build_lib , 'pandas' ))
193
+ except OSError :
194
+ pass
195
+ shutil .move (name , pjoin (build_lib , 'pandas' , name ))
196
+ else :
197
+ shutil .move (pjoin (build_type , 'pandas.dll' ),
198
+ pjoin (build_lib , 'pandas' , 'pandas.dll' ))
199
+
200
+ # Move the built C-extension to the place expected by the Python build
201
+ self ._found_names = []
202
+ for name in self .get_cmake_cython_names ():
203
+ built_path = self .get_ext_built (name )
204
+ if not os .path .exists (built_path ):
205
+ raise RuntimeError ('libpandas C-extension failed to build:' ,
206
+ os .path .abspath (built_path ))
207
+
208
+ ext_path = pjoin (build_lib , self ._get_cmake_ext_path (name ))
209
+ if os .path .exists (ext_path ):
210
+ os .remove (ext_path )
211
+ self .mkpath (os .path .dirname (ext_path ))
212
+ print ('Moving built libpandas C-extension' , built_path ,
213
+ 'to build path' , ext_path )
214
+ shutil .move (self .get_ext_built (name ), ext_path )
215
+ self ._found_names .append (name )
216
+
217
+ os .chdir (saved_cwd )
218
+
219
+ def _get_inplace_dir (self ):
220
+ pass
221
+
222
+ def _get_cmake_ext_path (self , name ):
223
+ # Get the package directory from build_py
224
+ build_py = self .get_finalized_command ('build_py' )
225
+ package_dir = build_py .get_package_dir ('pandas' )
226
+ # This is the name of the pandas C-extension
227
+ suffix = sysconfig .get_config_var ('EXT_SUFFIX' )
228
+ if suffix is None :
229
+ suffix = sysconfig .get_config_var ('SO' )
230
+ filename = name + suffix
231
+ return pjoin (package_dir , filename )
232
+
233
+ def get_ext_built (self , name ):
234
+ if sys .platform == 'win32' :
235
+ head , tail = os .path .split (name )
236
+ suffix = sysconfig .get_config_var ('SO' )
237
+ return pjoin (head , build_type , tail + suffix )
238
+ else :
239
+ suffix = sysconfig .get_config_var ('SO' )
240
+ return name + suffix
241
+
242
+ def get_cmake_cython_names (self ):
243
+ return ['native' ]
244
+
245
+ def get_names (self ):
246
+ return self ._found_names
247
+
248
+ def get_outputs (self ):
249
+ # Just the C extensions
250
+ cmake_exts = [self ._get_cmake_ext_path (name )
251
+ for name in self .get_names ()]
252
+ regular_exts = _build_ext .get_outputs (self )
253
+ return regular_exts + cmake_exts
254
+
96
255
97
256
DESCRIPTION = ("Powerful data structures for data analysis, time series,"
98
257
"and statistics" )
@@ -186,6 +345,7 @@ def build_extensions(self):
186
345
'Topic :: Scientific/Engineering' ,
187
346
]
188
347
348
+
189
349
class CleanCommand (Command ):
190
350
"""Custom distutils command to clean the .so and .pyc files."""
191
351
@@ -196,22 +356,22 @@ def initialize_options(self):
196
356
self ._clean_me = []
197
357
self ._clean_trees = []
198
358
199
- base = pjoin ('pandas' ,'src' )
200
- dt = pjoin (base ,'datetime' )
359
+ base = pjoin ('pandas' , 'src' )
360
+ dt = pjoin (base , 'datetime' )
201
361
src = base
202
- parser = pjoin (base ,'parser' )
203
- ujson_python = pjoin (base ,'ujson' ,'python' )
204
- ujson_lib = pjoin (base ,'ujson' ,'lib' )
205
- self ._clean_exclude = [pjoin (dt ,'np_datetime.c' ),
206
- pjoin (dt ,'np_datetime_strings.c' ),
207
- pjoin (src ,'period_helper.c' ),
208
- pjoin (parser ,'tokenizer.c' ),
209
- pjoin (parser ,'io.c' ),
210
- pjoin (ujson_python ,'ujson.c' ),
211
- pjoin (ujson_python ,'objToJSON.c' ),
212
- pjoin (ujson_python ,'JSONtoObj.c' ),
213
- pjoin (ujson_lib ,'ultrajsonenc.c' ),
214
- pjoin (ujson_lib ,'ultrajsondec.c' ),
362
+ parser = pjoin (base , 'parser' )
363
+ ujson_python = pjoin (base , 'ujson' , 'python' )
364
+ ujson_lib = pjoin (base , 'ujson' , 'lib' )
365
+ self ._clean_exclude = [pjoin (dt , 'np_datetime.c' ),
366
+ pjoin (dt , 'np_datetime_strings.c' ),
367
+ pjoin (src , 'period_helper.c' ),
368
+ pjoin (parser , 'tokenizer.c' ),
369
+ pjoin (parser , 'io.c' ),
370
+ pjoin (ujson_python , 'ujson.c' ),
371
+ pjoin (ujson_python , 'objToJSON.c' ),
372
+ pjoin (ujson_python , 'JSONtoObj.c' ),
373
+ pjoin (ujson_lib , 'ultrajsonenc.c' ),
374
+ pjoin (ujson_lib , 'ultrajsondec.c' ),
215
375
]
216
376
217
377
for root , dirs , files in os .walk ('pandas' ):
@@ -252,6 +412,7 @@ def run(self):
252
412
# class as it encodes the version info
253
413
sdist_class = cmdclass ['sdist' ]
254
414
415
+
255
416
class CheckSDist (sdist_class ):
256
417
"""Custom sdist that ensures Cython has compiled all pyx files to c."""
257
418
@@ -469,13 +630,13 @@ def pxd(name):
469
630
extensions .extend ([sparse_ext ])
470
631
471
632
testing_ext = Extension ('pandas._testing' ,
472
- sources = [srcpath ('testing' , suffix = suffix )],
473
- include_dirs = [],
474
- libraries = libraries )
633
+ sources = [srcpath ('testing' , suffix = suffix )],
634
+ include_dirs = [],
635
+ libraries = libraries )
475
636
476
637
extensions .extend ([testing_ext ])
477
638
478
- #- ---------------------------------------------------------------------
639
+ # ---------------------------------------------------------------------
479
640
# msgpack stuff here
480
641
481
642
if sys .byteorder == 'big' :
@@ -484,31 +645,35 @@ def pxd(name):
484
645
macros = [('__LITTLE_ENDIAN__' , '1' )]
485
646
486
647
packer_ext = Extension ('pandas.msgpack._packer' ,
487
- depends = ['pandas/src/msgpack/pack.h' ,
488
- 'pandas/src/msgpack/pack_template.h' ],
489
- sources = [srcpath ('_packer' ,
490
- suffix = suffix if suffix == '.pyx' else '.cpp' ,
648
+ depends = ['pandas/src/msgpack/pack.h' ,
649
+ 'pandas/src/msgpack/pack_template.h' ],
650
+ sources = [
651
+ srcpath ('_packer' , suffix = suffix
652
+ if suffix == '.pyx' else '.cpp' ,
491
653
subdir = 'msgpack' )],
492
- language = 'c++' ,
493
- include_dirs = ['pandas/src/msgpack' ] + common_include ,
494
- define_macros = macros )
654
+ language = 'c++' ,
655
+ include_dirs = ['pandas/src/msgpack' ] + common_include ,
656
+ define_macros = macros )
657
+
495
658
unpacker_ext = Extension ('pandas.msgpack._unpacker' ,
496
- depends = ['pandas/src/msgpack/unpack.h' ,
497
- 'pandas/src/msgpack/unpack_define.h' ,
498
- 'pandas/src/msgpack/unpack_template.h' ],
499
- sources = [srcpath ('_unpacker' ,
500
- suffix = suffix if suffix == '.pyx' else '.cpp' ,
501
- subdir = 'msgpack' )],
502
- language = 'c++' ,
503
- include_dirs = ['pandas/src/msgpack' ] + common_include ,
504
- define_macros = macros )
659
+ depends = ['pandas/src/msgpack/unpack.h' ,
660
+ 'pandas/src/msgpack/unpack_define.h' ,
661
+ 'pandas/src/msgpack/unpack_template.h' ],
662
+ sources = [
663
+ srcpath ('_unpacker' ,
664
+ suffix = suffix
665
+ if suffix == '.pyx' else '.cpp' ,
666
+ subdir = 'msgpack' )],
667
+ language = 'c++' ,
668
+ include_dirs = ['pandas/src/msgpack' ] + common_include ,
669
+ define_macros = macros )
505
670
extensions .append (packer_ext )
506
671
extensions .append (unpacker_ext )
507
672
508
673
if suffix == '.pyx' and 'setuptools' in sys .modules :
509
674
# undo dumb setuptools bug clobbering .pyx sources back to .c
510
675
for ext in extensions :
511
- if ext .sources [0 ].endswith (('.c' ,'.cpp' )):
676
+ if ext .sources [0 ].endswith (('.c' , '.cpp' )):
512
677
root , _ = os .path .splitext (ext .sources [0 ])
513
678
ext .sources [0 ] = root + suffix
514
679
0 commit comments