setup.py 11.6 KB
Newer Older
eric pellegrini's avatar
eric pellegrini committed
1 2 3 4 5 6 7
import fnmatch
import glob
import os
import sys

import numpy

eric pellegrini's avatar
eric pellegrini committed
8
from Cython.Distutils import build_ext as cython_build_ext
eric pellegrini's avatar
eric pellegrini committed
9 10

from distutils.command.build import build
eric pellegrini's avatar
eric pellegrini committed
11
from distutils.core import setup, Extension
eric pellegrini's avatar
eric pellegrini committed
12 13 14
from distutils.sysconfig import get_config_vars
from distutils.util import convert_path

eric pellegrini's avatar
eric pellegrini committed
15 16 17 18 19 20 21 22 23 24
try:
    import sphinx
except ImportError:
    sphinx = None

try:
    import stdeb
except ImportError:
    stdeb = None

eric pellegrini's avatar
eric pellegrini committed
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
#################################
# Modules variables
#################################
EXCLUDE = ['*.py', '*.pyc', '*$py.class', '*~', '.*', '*.bak', '*.so', '*.pyd']

EXCLUDE_DIRECTORIES = ('.*', 'CVS', '_darcs', './build','*svn','./dist', 'EGG-INFO', '*.egg-info')

EXTENSIONS_PATH = "Extensions"

INCLUDE_DIR = [numpy.get_include()]

QHULL_DIR = os.path.join("Extensions","qhull_lib")

QHULL_INCLUDE_DIR = INCLUDE_DIR + [EXTENSIONS_PATH] + [os.path.join(QHULL_DIR,"ext")] + [os.path.join(QHULL_DIR,"src")]

SCRIPTS_PATH = "Scripts"

#################################
# Helper function
#################################

def is_package(path):
    return (os.path.isdir(path) and os.path.isfile(os.path.join(path, '__init__.py')))

def find_packages(path, base="", exclude=None):

    packages = {}

    for item in os.listdir(path):
        d = os.path.join(path, item)
        if exclude is not None and (os.path.abspath(d) == os.path.abspath(exclude)):
            continue
        if is_package(d):
            if base:
                module_name = "%(base)s.%(item)s" % vars()
            else:
                module_name = item
            packages[module_name] = d
            packages.update(find_packages(d, module_name, exclude))
            
    return packages

def find_package_data(where='.', package='', exclude=EXCLUDE, exclude_directories=EXCLUDE_DIRECTORIES, only_in_packages=True, show_ignored=False):
    
    out = {}
    stack = [(convert_path(where), '', package, only_in_packages)]
    while stack:
        where, prefix, package, only_in_packages = stack.pop(0)
        for name in os.listdir(where):
            fn = os.path.join(where, name)
            if os.path.isdir(fn):
                bad_name = False
                for pattern in exclude_directories:
                    if (fnmatch.fnmatchcase(name, pattern)
                        or fn.lower() == pattern.lower()):
                        bad_name = True
                        if show_ignored:
                            print >> sys.stderr, ("Directory %s ignored by pattern %s" % (fn, pattern))
                        break
                if bad_name:
                    continue
                if (os.path.isfile(os.path.join(fn, '__init__.py')) and not prefix):
                    if not package:
                        new_package = name
                    else:
                        new_package = package + '.' + name
                    stack.append((fn, '', new_package, False))
                else:
                    stack.append((fn, prefix + name + '/', package, only_in_packages))
            elif package or not only_in_packages:
                # is a file
                bad_name = False
                for pattern in exclude:
                    if (fnmatch.fnmatchcase(name, pattern)
                        or fn.lower() == pattern.lower()):
                        bad_name = True
                        if show_ignored:
                            print >> sys.stderr, ("File %s ignored by pattern %s" % (fn, pattern))
                        break
                if bad_name:
                    continue
                out.setdefault(package, []).append(prefix+name)
    
    return out


def find_data(where=".", exclude=EXCLUDE, exclude_directories=EXCLUDE_DIRECTORIES, prefix=""):

    out = {}
    stack = [convert_path(where)]
    while stack:
        where = stack.pop(0)
        for name in os.listdir(where):
            fn = os.path.join(where, name)
            d = os.path.join(prefix,os.path.dirname(fn))
            if os.path.isdir(fn):
                stack.append(fn)
            else:
                bad_name = False
                for pattern in exclude:
                    if (fnmatch.fnmatchcase(name, pattern) or fn.lower() == pattern.lower()):
                        bad_name = True
                        break
                if bad_name:
                    continue
                out.setdefault(d, []).append(fn)
            
    out = [(k,v) for k, v in out.items()]
    
    return out


#################################
# Packages section
#################################

PACKAGE_INFO = {}
142
execfile('MDANSE/__pkginfo__.py', PACKAGE_INFO)
eric pellegrini's avatar
eric pellegrini committed
143

144
PACKAGES = find_packages(path=".", exclude=os.path.join("MDANSE","App","GUI"))
eric pellegrini's avatar
eric pellegrini committed
145 146 147 148 149 150
PACKAGES = PACKAGES.keys()

#################################
# Package data section
#################################

151 152
# Retrieve all the data related to the MDANSE package.
PACKAGE_DATA = find_package_data(where='MDANSE', package='MDANSE', show_ignored=False)
eric pellegrini's avatar
eric pellegrini committed
153 154 155 156 157 158

#################################
# User data section
#################################

DATA_FILES = []
eric pellegrini's avatar
eric pellegrini committed
159
DATA_FILES.extend(find_data('Doc',exclude=[],prefix='conf_'))
eric pellegrini's avatar
eric pellegrini committed
160 161 162 163 164 165

#################################
# Scripts section
#################################

SCRIPTS = []
166
SCRIPTS.append(os.path.join(SCRIPTS_PATH,'mdanse'))
eric pellegrini's avatar
eric pellegrini committed
167
SCRIPTS.append(os.path.join(SCRIPTS_PATH,'mdanse_gui'))
eric pellegrini's avatar
eric pellegrini committed
168

169 170 171 172
#################################
# Documentation
#################################

eric pellegrini's avatar
eric pellegrini committed
173 174 175
if sphinx:
    import sphinx.apidoc
    import sphinx.setup_command
176

eric pellegrini's avatar
eric pellegrini committed
177 178 179 180 181 182 183
    class mdanse_build_doc(sphinx.setup_command.BuildDoc):
                              
        def run(self):
            
            build = self.get_finalized_command('build')
                    
            buildDir = os.path.abspath(build.build_lib)
184

eric pellegrini's avatar
eric pellegrini committed
185
            sys.path.insert(0,buildDir)
186

eric pellegrini's avatar
eric pellegrini committed
187 188 189
            sphinxDir = os.path.join(build.build_base,'sphinx',self.doctype)
                                 
            metadata = self.distribution.metadata
190
     
eric pellegrini's avatar
eric pellegrini committed
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
            sphinx.apidoc.main(['',
                                '-F',
                                '--separate',
                                '-H', metadata.name,
                                '-A', metadata.author,
                                '-V', metadata.version,
                                '-R', metadata.version,
                                '-o', sphinxDir,
                                os.path.join(buildDir,'MDANSE'),
                                os.path.join(buildDir,'MDANSE','Externals')])
                 
            curDir = os.getcwd()
                 
            import shutil
            shutil.copy(os.path.join(curDir,'Doc','conf_%s.py' % self.doctype),os.path.join(sphinxDir,'conf.py'))
            shutil.copy(os.path.join(curDir,'Doc','mdanse_logo.png'),os.path.join(sphinxDir,'_static'))
            shutil.copy(os.path.join(curDir,'Doc','layout.html'),os.path.join(sphinxDir,'_templates'))
     
            # The directory where the rst files are located.
            self.source_dir = sphinxDir
            # The directory where the conf.py file is located.
            self.config_dir = self.source_dir
     
            # The directory where the documentation will be built
            self.build_dir = os.path.join(buildDir,'MDANSE','Doc',self.doctype)
            
            self.finalize_options()
                                                     
            sphinx.setup_command.BuildDoc.run(self)
                 
            sys.path.pop(0)
            
    class mdanse_build_help(mdanse_build_doc):
224
        
eric pellegrini's avatar
eric pellegrini committed
225
        doctype = 'help'
226

eric pellegrini's avatar
eric pellegrini committed
227
    class mdanse_build_api(mdanse_build_doc):
228
        
eric pellegrini's avatar
eric pellegrini committed
229
        doctype = 'api'
230

eric pellegrini's avatar
eric pellegrini committed
231 232 233
#################################
# Debian packaging
#################################
234

eric pellegrini's avatar
eric pellegrini committed
235
class mdanse_build(build):
236

eric pellegrini's avatar
eric pellegrini committed
237 238 239 240 241 242 243 244
    def has_sphinx(self):
        if sphinx is None:
            return False
        setup_dir = os.path.dirname(os.path.abspath(__file__))
        return os.path.isdir(os.path.join(setup_dir, 'Doc'))
    
    sub_commands = build.sub_commands + [('build_api', has_sphinx),('build_help',has_sphinx)]
                        
eric pellegrini's avatar
eric pellegrini committed
245 246 247 248 249 250 251 252
#################################
# Extensions section
#################################

if 'linux' in sys.platform:
    (opt,) = get_config_vars('OPT')
    os.environ['OPT'] = " ".join(flag for flag in opt.split() if flag != '-Wstrict-prototypes')

253
EXTENSIONS = [Extension('MDANSE.Extensions.distance_histogram',
eric pellegrini's avatar
eric pellegrini committed
254 255
                        include_dirs=INCLUDE_DIR,
                        sources = [os.path.join("Extensions",'distance_histogram.pyx')]),
256
              Extension('MDANSE.Extensions.fast_calculation',
eric pellegrini's avatar
eric pellegrini committed
257 258
                        include_dirs=INCLUDE_DIR,
                        sources = [os.path.join("Extensions",'fast_calculation.pyx')]),
259
              Extension('MDANSE.Extensions.sas_fast_calc',
eric pellegrini's avatar
eric pellegrini committed
260 261
                        include_dirs=INCLUDE_DIR,
                        sources = [os.path.join("Extensions",'sas_fast_calc.pyx')]),
262
              Extension('MDANSE.Extensions.mt_fast_calc',
eric pellegrini's avatar
eric pellegrini committed
263 264
                        include_dirs=INCLUDE_DIR,
                        sources = [os.path.join("Extensions",'mt_fast_calc.pyx')]),
265
              Extension('MDANSE.Extensions.sd_fast_calc',
eric pellegrini's avatar
eric pellegrini committed
266 267
                        include_dirs=INCLUDE_DIR,
                        sources = [os.path.join("Extensions",'sd_fast_calc.pyx')]),
268
              Extension('MDANSE.Extensions.mic_fast_calc', 
eric pellegrini's avatar
eric pellegrini committed
269 270 271
                        include_dirs=INCLUDE_DIR,
                        sources = [os.path.join("Extensions",'mic_fast_calc.pyx')],
                        language="c++"),
272
              Extension('MDANSE.Extensions.qhull',
eric pellegrini's avatar
eric pellegrini committed
273 274 275 276 277
                        include_dirs  = QHULL_INCLUDE_DIR,
                        sources =  glob.glob(os.path.join(QHULL_DIR, 'src','*.c')) + [os.path.join("Extensions",'qhull.pyx')],
                        define_macros = [('qh_QHpointer','1')])
              ]

eric pellegrini's avatar
eric pellegrini committed
278 279
CMDCLASS = {'build'     : mdanse_build,
            'build_ext' : cython_build_ext}
eric pellegrini's avatar
eric pellegrini committed
280

eric pellegrini's avatar
eric pellegrini committed
281 282 283
if sphinx:
    CMDCLASS['build_api'] = mdanse_build_api
    CMDCLASS['build_help'] = mdanse_build_help
eric pellegrini's avatar
eric pellegrini committed
284 285 286 287 288
             
#################################
# The setup section
#################################

289
setup (name             = "MDANSE",
eric pellegrini's avatar
eric pellegrini committed
290 291 292
       version          = PACKAGE_INFO["__version__"],
       description      = "Analysis of Molecular Dynamics trajectories",
       long_description =
293
"""MDANSE is an interactive program for the analysis of Molecular
eric pellegrini's avatar
eric pellegrini committed
294 295 296 297 298 299 300
Dynamics simulations. It is especially designed for the computation
and decomposition of neutron scattering spectra. The structure and
dynamics of the simulated systems can be characterized in terms of
various space and time correlation functions. To analyze the dynamics
of complex systems, rigid-body motions of arbitrarily chosen molecular
subunits can be studied.
""",
301 302
       author           = "B. Aoun & G. Goret & E. Pellegrini",
       author_email     = "aoun.ill.fr, goretg@ill.fr, pellegrini@ill.fr",
eric pellegrini's avatar
eric pellegrini committed
303 304
       maintainer       = "B. Aoun, G. Goret, E. Pellegrini",
       maintainer_email = "aoun.ill.fr, goretg.ill.fr, pellegrini@ill.fr",
305
       url              = "https://github.com/eurydyce/MDANSE/tree/master/MDANSE",
eric pellegrini's avatar
eric pellegrini committed
306 307 308 309 310 311 312
       license          = "CeCILL",
       packages         = PACKAGES,
       package_data     = PACKAGE_DATA,
       data_files       = DATA_FILES,
       platforms        = ['Unix','Windows'],
       ext_modules      = EXTENSIONS,
       scripts          = SCRIPTS,
313
       cmdclass         = CMDCLASS,
eric pellegrini's avatar
eric pellegrini committed
314
       install_requires = ['Jinja2'])