source: orange/setup.py @ 10818:86a5e8a0cfb1

Revision 10818:86a5e8a0cfb1, 29.9 KB checked in by mitar, 2 years ago (diff)

Automatically install setuptools if not present.

Line 
1#!usr/bin/env python
2
3import distribute_setup
4distribute_setup.use_setuptools()
5
6"""Orange: Machine learning and interactive data mining toolbox.
7
8Orange is a scriptable environment for fast prototyping of new
9algorithms and testing schemes. It is a collection of Python packages
10that sit over the core library and implement some functionality for
11which execution time is not crucial and which is easier done in Python
12than in C++. This includes a variety of tasks such as attribute subset,
13bagging and boosting, and alike.
14
15Orange also includes a set of graphical widgets that use methods from
16core library and Orange modules. Through visual programming, widgets
17can be assembled together into an application by a visual programming
18tool called Orange Canvas.
19"""
20
21DOCLINES = __doc__.splitlines()
22
23import os, sys
24try:
25    from setuptools import setup
26    from setuptools.command.install import install
27    have_setuptools = True
28except ImportError:
29    from distutils.core import setup
30    from distutils.command.install import install
31    have_setuptools = False
32
33from distutils.core import Extension
34from distutils.command.build import build
35from distutils.command.build_ext import build_ext
36from distutils.command.install_lib import install_lib
37from distutils.util import convert_path
38from distutils.errors import DistutilsSetupError
39from distutils.msvccompiler import MSVCCompiler
40from distutils.unixccompiler import UnixCCompiler
41import subprocess
42
43CLASSIFIERS = """\
44Development Status :: 4 - Beta
45Environment :: X11 Applications :: Qt
46Environment :: Console
47Environment :: Plugins
48Programming Language :: Python
49Framework :: Orange
50License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
51Operating System :: POSIX
52Operating System :: Microsoft :: Windows
53Topic :: Scientific/Engineering :: Artificial Intelligence
54Topic :: Scientific/Engineering :: Visualization
55Topic :: Software Development :: Libraries :: Python Modules
56Intended Audience :: Education
57Intended Audience :: Science/Research
58Intended Audience :: Developers
59"""
60
61KEYWORDS = """\
62data mining
63machine learning
64artificial intelligence
65"""
66
67NAME                = 'Orange'
68DESCRIPTION         = DOCLINES[0]
69LONG_DESCRIPTION    = "\n".join(DOCLINES[2:])
70URL                 = "http://orange.biolab.si/"
71DOWNLOAD_URL        = "https://bitbucket.org/biolab/orange/downloads"
72LICENSE             = 'GPLv3'
73CLASSIFIERS         = filter(None, CLASSIFIERS.splitlines())
74AUTHOR              = "Bioinformatics Laboratory, FRI UL"
75AUTHOR_EMAIL        = "contact@orange.biolab.si"
76KEYWORDS            = filter(None, KEYWORDS.splitlines())
77MAJOR               = 2
78MINOR               = 5
79MICRO               = 0
80ISRELEASED          = False
81VERSION             = '%d.%d.%da5' % (MAJOR, MINOR, MICRO)
82
83if have_setuptools:
84    setuptools_args = {"zip_safe": False,
85                       "install_requires": ["numpy"],
86                       "extras_require": {"GUI": ["PyQt4", "PyQwt"],
87                                          "NETWORK": ["networkx"]}
88                      }
89else:
90    setuptools_args = {}
91
92import glob
93from subprocess import check_call
94
95import types
96
97from distutils.dep_util import newer_group
98from distutils.file_util import copy_file
99from distutils import log
100
101from distutils.sysconfig import get_python_inc, get_config_var
102
103try:
104    import numpy
105    numpy_include_dir = numpy.get_include()
106except ImportError:
107    # When setup.py is first run to install orange, numpy can still be missing
108    pass
109    numpy_include_dir = None
110
111python_include_dir = get_python_inc(plat_specific=1)
112
113include_dirs = [python_include_dir, numpy_include_dir, "source/include"]
114
115if sys.platform == "darwin":
116    extra_compile_args = "-fPIC -fpermissive -fno-common -w -DDARWIN".split()
117    extra_link_args = "-headerpad_max_install_names -undefined dynamic_lookup".split()
118elif sys.platform == "win32":
119    extra_compile_args = ["-EHsc"]
120    extra_link_args = []
121elif sys.platform.startswith("linux"):
122    extra_compile_args = "-fPIC -fpermissive -w -DLINUX".split()
123    extra_link_args = ["-Wl,-R$ORIGIN"]
124else:
125    extra_compile_args = []
126    extra_link_args = []
127
128
129# Get the command for building orangeqt extension from
130# source/orangeqt/setup.py file.
131# Fails  without PyQt4.
132import imp
133try:
134    orangeqt_setup = imp.load_source("orangeqt_setup", "source/orangeqt/setup.py")
135    build_pyqt_ext = orangeqt_setup.build_pyqt_ext
136except ImportError:
137    orangeqt_setup = None
138    build_pyqt_ext = None
139
140class LibStatic(Extension):
141    pass
142
143class PyXtractExtension(Extension):
144    def __init__(self, *args, **kwargs):
145        for name, default in [("extra_pyxtract_cmds", []), ("lib_type", "dynamic")]:
146            setattr(self, name, kwargs.get(name, default))
147            if name in kwargs:
148                del kwargs[name]
149
150        Extension.__init__(self, *args, **kwargs)
151
152class PyXtractSharedExtension(PyXtractExtension):
153    pass
154
155class pyxtract_build_ext(build_ext):
156    def run_pyxtract(self, ext, dir):
157        original_dir = os.path.realpath(os.path.curdir)
158        log.info("running pyxtract for %s" % ext.name)
159        try:
160            os.chdir(dir)
161            ## we use the commands which are used for building under windows
162            pyxtract_cmds = [cmd.split() for cmd in getattr(ext, "extra_pyxtract_cmds", [])]
163            if os.path.exists("_pyxtract.bat"):
164                pyxtract_cmds.extend([cmd.split()[1:] for cmd in open("_pyxtract.bat").read().strip().splitlines()])
165            for cmd in pyxtract_cmds:
166                log.info(" ".join([sys.executable] + cmd))
167                check_call([sys.executable] + cmd)
168            if pyxtract_cmds:
169                ext.include_dirs.append(os.path.join(dir, "ppp"))
170                ext.include_dirs.append(os.path.join(dir, "px"))
171
172        finally:
173            os.chdir(original_dir)
174
175    def finalize_options(self):
176        build_ext.finalize_options(self)
177        # add the build_lib dir and build_temp (for
178        # liborange_include and liborange linking)
179        if not self.inplace:
180            # for linking with liborange.so (it is in Orange package)
181            self.library_dirs.append(os.path.join(self.build_lib, "Orange"))
182            # for linking with liborange_include.a
183            self.library_dirs.append(self.build_temp)
184        else:
185            # for linking with liborange.so
186            self.library_dirs.append("./Orange") 
187            # for linking with liborange_include.a
188            self.library_dirs.append(self.build_temp)
189
190    def build_extension(self, ext):
191        if isinstance(ext, LibStatic):
192            # Build static library
193            self.build_static(ext)
194        elif isinstance(ext, PyXtractExtension):
195            # Build pyextract extension
196            self.build_pyxtract(ext)
197        elif orangeqt_setup and isinstance(ext, orangeqt_setup.PyQt4Extension):
198            # Skip the build (will be handled by build_pyqt_ext command)
199            return
200        else:
201            build_ext.build_extension(self, ext)
202
203        if isinstance(ext, PyXtractSharedExtension):
204            # Fix extension modules so they can be linked
205            # by other modules
206            if isinstance(self.compiler, MSVCCompiler):
207                # Copy ${TEMP}/orange/orange.lib to ${BUILD}/orange.lib
208                ext_fullpath = self.get_ext_fullpath(ext.name)
209                # Get the last component of the name
210                ext_name = ext.name.rsplit(".", 1)[-1]
211                libs = glob.glob(os.path.join(self.build_temp, 
212                                              "*", "*", ext_name + ".lib"))
213                if not libs:
214                    log.info("Could not locate library %r in directory %r" \
215                             %(ext_name, self.build_temp))
216                else:
217                    lib = libs[0]
218                    copy_file(lib, os.path.splitext(ext_fullpath)[0] + ".lib")
219            else:
220                # Make lib{name}.so link to {name}.so
221                ext_path = self.get_ext_fullpath(ext.name)
222                ext_path, ext_filename = os.path.split(ext_path)
223                realpath = os.path.realpath(os.curdir)
224                try:
225                    os.chdir(ext_path)
226                    # Get the shared library name
227                    _, name = ext.name.rsplit(".", 1)
228                    lib_filename = self.compiler.library_filename(name, lib_type="shared")
229                    # Create the link
230                    copy_file(ext_filename, lib_filename, link="sym")
231                except OSError, ex:
232                    log.info("failed to create shared library for %s: %s" % (ext.name, str(ex)))
233                finally:
234                    os.chdir(realpath)
235
236    def build_pyxtract(self, ext):
237        ## mostly copied from build_extension
238        sources = ext.sources
239        if sources is None or type(sources) not in (types.ListType, types.TupleType):
240            raise DistutilsSetupError, \
241                  ("in 'ext_modules' option (extension '%s'), " +
242                   "'sources' must be present and must be " +
243                   "a list of source filenames") % ext.name
244        sources = list(sources)
245
246        ext_path = self.get_ext_fullpath(ext.name)
247
248        depends = sources + ext.depends
249        if not (self.force or newer_group(depends, ext_path, 'newer')):
250            log.debug("skipping '%s' extension (up-to-date)", ext.name)
251            return
252        else:
253            log.info("building '%s' extension", ext.name)
254
255        # First, scan the sources for SWIG definition files (.i), run
256        # SWIG on 'em to create .c files, and modify the sources list
257        # accordingly.
258        sources = self.swig_sources(sources, ext)
259
260        # Run pyxtract in dir this adds ppp and px dirs to include_dirs
261        dir = os.path.commonprefix([os.path.split(s)[0] for s in ext.sources])
262        self.run_pyxtract(ext, dir)
263
264        # Next, compile the source code to object files.
265
266        # XXX not honouring 'define_macros' or 'undef_macros' -- the
267        # CCompiler API needs to change to accommodate this, and I
268        # want to do one thing at a time!
269
270        # Two possible sources for extra compiler arguments:
271        #   - 'extra_compile_args' in Extension object
272        #   - CFLAGS environment variable (not particularly
273        #     elegant, but people seem to expect it and I
274        #     guess it's useful)
275        # The environment variable should take precedence, and
276        # any sensible compiler will give precedence to later
277        # command line args.  Hence we combine them in order:
278        extra_args = ext.extra_compile_args or []
279
280        macros = ext.define_macros[:]
281        for undef in ext.undef_macros:
282            macros.append((undef,))
283
284        objects = self.compiler.compile(sources,
285                                         output_dir=self.build_temp,
286                                         macros=macros,
287                                         include_dirs=ext.include_dirs,
288                                         debug=self.debug,
289                                         extra_postargs=extra_args,
290                                         depends=ext.depends)
291
292        # XXX -- this is a Vile HACK!
293        #
294        # The setup.py script for Python on Unix needs to be able to
295        # get this list so it can perform all the clean up needed to
296        # avoid keeping object files around when cleaning out a failed
297        # build of an extension module.  Since Distutils does not
298        # track dependencies, we have to get rid of intermediates to
299        # ensure all the intermediates will be properly re-built.
300        #
301        self._built_objects = objects[:]
302
303        # Now link the object files together into a "shared object" --
304        # of course, first we have to figure out all the other things
305        # that go into the mix.
306        if ext.extra_objects:
307            objects.extend(ext.extra_objects)
308        extra_args = ext.extra_link_args or []
309
310        # Detect target language, if not provided
311        language = ext.language or self.compiler.detect_language(sources)
312
313        self.compiler.link_shared_object(
314            objects, ext_path,
315            libraries=self.get_libraries(ext),
316            library_dirs=ext.library_dirs,
317            runtime_library_dirs=ext.runtime_library_dirs,
318            extra_postargs=extra_args,
319            export_symbols=self.get_export_symbols(ext),
320            debug=self.debug,
321            build_temp=self.build_temp,
322            target_lang=language)
323
324
325    def build_static(self, ext):
326        ## mostly copied from build_extension, changed
327        sources = ext.sources
328        if sources is None or type(sources) not in (types.ListType, types.TupleType):
329            raise DistutilsSetupError, \
330                  ("in 'ext_modules' option (extension '%s'), " +
331                   "'sources' must be present and must be " +
332                   "a list of source filenames") % ext.name
333        sources = list(sources)
334
335        # Static libs get build in the build_temp directory
336        output_dir = self.build_temp
337        if not os.path.exists(output_dir): #VSC fails if the dir does not exist
338            os.makedirs(output_dir)
339
340        lib_filename = self.compiler.library_filename(ext.name, lib_type='static', output_dir=output_dir)
341
342        depends = sources + ext.depends
343        if not (self.force or newer_group(depends, lib_filename, 'newer')):
344            log.debug("skipping '%s' extension (up-to-date)", ext.name)
345            return
346        else:
347            log.info("building '%s' extension", ext.name)
348
349        # First, scan the sources for SWIG definition files (.i), run
350        # SWIG on 'em to create .c files, and modify the sources list
351        # accordingly.
352        sources = self.swig_sources(sources, ext)
353
354        # Next, compile the source code to object files.
355
356        # XXX not honouring 'define_macros' or 'undef_macros' -- the
357        # CCompiler API needs to change to accommodate this, and I
358        # want to do one thing at a time!
359
360        # Two possible sources for extra compiler arguments:
361        #   - 'extra_compile_args' in Extension object
362        #   - CFLAGS environment variable (not particularly
363        #     elegant, but people seem to expect it and I
364        #     guess it's useful)
365        # The environment variable should take precedence, and
366        # any sensible compiler will give precedence to later
367        # command line args.  Hence we combine them in order:
368        extra_args = ext.extra_compile_args or []
369
370        macros = ext.define_macros[:]
371        for undef in ext.undef_macros:
372            macros.append((undef,))
373
374        objects = self.compiler.compile(sources,
375                                         output_dir=self.build_temp,
376                                         macros=macros,
377                                         include_dirs=ext.include_dirs,
378                                         debug=self.debug,
379                                         extra_postargs=extra_args,
380                                         depends=ext.depends)
381
382        # XXX -- this is a Vile HACK!
383        #
384        # The setup.py script for Python on Unix needs to be able to
385        # get this list so it can perform all the clean up needed to
386        # avoid keeping object files around when cleaning out a failed
387        # build of an extension module.  Since Distutils does not
388        # track dependencies, we have to get rid of intermediates to
389        # ensure all the intermediates will be properly re-built.
390        #
391        self._built_objects = objects[:]
392
393        # Now link the object files together into a "shared object" --
394        # of course, first we have to figure out all the other things
395        # that go into the mix.
396        if ext.extra_objects:
397            objects.extend(ext.extra_objects)
398        extra_args = ext.extra_link_args or []
399
400        # Detect target language, if not provided
401        language = ext.language or self.compiler.detect_language(sources)
402       
403        #first remove old library (ar only appends the contents if archive already exists)
404        try:
405            os.remove(lib_filename)
406        except OSError, ex:
407            log.debug("failed to remove obsolete static library %s: %s" %(ext.name, str(ex)))
408
409        # The static library is created in the temp dir, it is used during the compile step only
410        # it should not be included in the final install
411        self.compiler.create_static_lib(
412            objects, ext.name, output_dir,
413            debug=self.debug,
414            target_lang=language)
415
416    def get_libraries(self, ext):
417        """ Change the 'orange' library name to 'orange_d' if
418        building in debug mode. Using ``get_ext_filename`` to discover if
419        _d postfix is required.
420       
421        """
422        libraries = build_ext.get_libraries(self, ext)
423        if "orange" in libraries and self.debug:
424            filename = self.get_ext_filename("orange")
425            basename = os.path.basename(filename)
426            name, ext = os.path.splitext(basename)
427            if name.endswith("_d"):
428                index = libraries.index("orange")
429                libraries[index] = "orange_d"
430
431        return libraries
432
433    if not hasattr(build_ext, "get_ext_fullpath"):
434        #On mac OS X python 2.6.1 distutils does not have this method
435        def get_ext_fullpath(self, ext_name):
436            """Returns the path of the filename for a given extension.
437           
438            The file is located in `build_lib` or directly in the package
439            (inplace option).
440            """
441            import string
442            # makes sure the extension name is only using dots
443            all_dots = string.maketrans('/' + os.sep, '..')
444            ext_name = ext_name.translate(all_dots)
445            fullname = self.get_ext_fullname(ext_name)
446            modpath = fullname.split('.')
447            filename = self.get_ext_filename(ext_name)
448            filename = os.path.split(filename)[-1]
449            if not self.inplace:
450                # no further work needed
451                # returning :
452                #   build_dir/package/path/filename
453                filename = os.path.join(*modpath[:-1] + [filename])
454                return os.path.join(self.build_lib, filename)
455            # the inplace option requires to find the package directory
456            # using the build_py command for that
457            package = '.'.join(modpath[0:-1])
458            build_py = self.get_finalized_command('build_py')
459            package_dir = os.path.abspath(build_py.get_package_dir(package))
460            # returning
461            #   package_dir/filename
462            return os.path.join(package_dir, filename)
463
464
465# Add build_pyqt_ext to build subcommands
466class orange_build(build):
467    def has_pyqt_extensions(self):
468        # For now this is disabled unless specifically requested
469        # using build_pyqt_ext command
470        return False
471#        return any([isinstance(ext, orangeqt_setup.PyQt4Extension) \
472#                   for ext in self.distribution.ext_modules]
473#                   )
474
475    sub_commands = build.sub_commands
476    if orangeqt_setup:
477        sub_commands += [("build_pyqt_ext", has_pyqt_extensions)]
478
479
480class orange_install_lib(install_lib):
481    """ An command to install orange (preserves liborange.so -> orange.so symlink)
482    """
483    def run(self):
484        install_lib.run(self)
485
486    def copy_tree(self, infile, outfile, preserve_mode=1, preserve_times=1, preserve_symlinks=1, level=1):
487        """ Run copy_tree with preserve_symlinks=1 as default
488        """ 
489        install_lib.copy_tree(self, infile, outfile, preserve_mode, preserve_times, preserve_symlinks, level)
490
491    def install(self):
492        """ Copy build_dir to install_dir
493        """
494        # A Hack to unlink liborange.so -> orange.so if it already exists,
495        # because copy_tree fails to overwrite it
496        #
497        liborange = os.path.join(self.install_dir, "Orange", "liborange.so")
498        if os.path.exists(liborange) and os.path.islink(liborange):
499            log.info("unlinking %s -> %s", liborange, os.path.join(self.install_dir, "orange.so"))
500            os.unlink(liborange)
501
502        return install_lib.install(self)
503
504
505class orange_install(install):
506    """ A command to install orange while also creating
507    a .pth path to access the old orng* modules and orange,
508    orangeom etc.
509   
510    """
511    def run(self):
512        install.run(self)
513        # Create a .pth file with a path inside the Orange/orng directory
514        # so the old modules are importable
515        self.path_file, self.extra_dirs = ("Orange-orng-modules", "Orange/orng")
516        self.extra_dirs = convert_path(self.extra_dirs)
517        log.info("creating portal path for orange compatibility.")
518        self.create_path_file()
519        self.path_file, self.extra_dirs = None, None
520
521
522def get_source_files(path, ext="cpp", exclude=[]):
523    files = glob.glob(os.path.join(path, "*." + ext))
524    files = [file for file in files if os.path.basename(file) not in exclude]
525    return files
526
527
528include_ext = LibStatic("orange_include",
529                        get_source_files("source/include/"),
530                        include_dirs=include_dirs)
531
532
533if sys.platform == "win32": # ?? mingw/cygwin
534    libraries = ["orange_include"]
535else:
536    libraries = ["stdc++", "orange_include"]
537
538
539import ConfigParser
540config = ConfigParser.RawConfigParser()
541
542config.read(["setup-site.cfg",
543             os.path.expanduser("~/.orange-site.cfg")]
544            )
545
546orange_sources = get_source_files("source/orange/")
547orange_include_dirs = list(include_dirs)
548orange_libraries = list(libraries)
549
550if config.has_option("blas", "library"):
551    # Link external blas library
552    orange_libraries += [config.get("blas", "library")]
553else:
554    orange_sources += get_source_files("source/orange/blas/", "c")
555
556if config.has_option("R", "library"):
557    # Link external R library (for linpack)
558    orange_libraries += [config.get("R", "library")]
559else:
560    orange_sources += get_source_files("source/orange/linpack/", "c")
561
562if config.has_option("liblinear", "library"):
563    # Link external LIBLINEAR library
564    orange_libraries += [config.get("liblinear", "library")]
565else:
566    orange_sources += get_source_files("source/orange/liblinear/", "cpp")
567    orange_include_dirs += ["source/orange/liblinear"]
568
569if config.has_option("libsvm", "library"):
570    # Link external LibSVM library
571    orange_libraries += [config.get("libsvm", "library")]
572else:
573    orange_sources += get_source_files("source/orange/libsvm/", "cpp")
574
575
576orange_ext = PyXtractSharedExtension("Orange.orange", orange_sources,
577                                      include_dirs=orange_include_dirs,
578                                      extra_compile_args = extra_compile_args + ["-DORANGE_EXPORTS"],
579                                      extra_link_args = extra_link_args,
580                                      libraries=orange_libraries,
581                                      extra_pyxtract_cmds = ["../pyxtract/defvectors.py"],
582                                      )
583
584if sys.platform == "darwin":
585    build_shared_cmd = get_config_var("BLDSHARED")
586    # Dont link liborange.so with orangeom and orangene - MacOS X treats
587    # loadable modules and shared libraries different
588    if "-bundle" in build_shared_cmd.split():
589        shared_libs = libraries
590    else:
591        shared_libs = libraries + ["orange"]
592else:
593    shared_libs = libraries + ["orange"]
594
595orangeom_sources = get_source_files("source/orangeom/", exclude=["lib_vectors.cpp"])
596orangeom_libraries = list(shared_libs)
597orangeom_include_dirs = list(include_dirs)
598
599if config.has_option("qhull", "library"):
600    # Link external qhull library
601    orangeom_libraries += [config.get("qhull", "library")]
602else:
603    orangeom_sources += get_source_files("source/orangeom/qhull/", "c")
604    orangeom_include_dirs += ["source/orangeom"]
605
606
607orangeom_ext = PyXtractExtension("Orange.orangeom", orangeom_sources,
608                                  include_dirs=orangeom_include_dirs + ["source/orange/"],
609                                  extra_compile_args = extra_compile_args + ["-DORANGEOM_EXPORTS"],
610                                  extra_link_args = extra_link_args,
611                                  libraries=orangeom_libraries,
612                                  )
613
614orangene_ext = PyXtractExtension("Orange.orangene",
615    get_source_files("source/orangene/", exclude=["lib_vectors.cpp"]),
616                                  include_dirs=include_dirs + ["source/orange/"], 
617                                  extra_compile_args = extra_compile_args + ["-DORANGENE_EXPORTS"],
618                                  extra_link_args = extra_link_args,
619                                  libraries=shared_libs,
620                                  )
621
622corn_ext = Extension("Orange.corn", get_source_files("source/corn/"),
623                     include_dirs=include_dirs + ["source/orange/"], 
624                     extra_compile_args = extra_compile_args + ["-DCORN_EXPORTS"],
625                     extra_link_args = extra_link_args,
626                     libraries=libraries
627                     )
628
629statc_ext = Extension("Orange.statc", get_source_files("source/statc/"),
630                      include_dirs=include_dirs + ["source/orange/"], 
631                      extra_compile_args = extra_compile_args + ["-DSTATC_EXPORTS"],
632                      extra_link_args = extra_link_args,
633                      libraries=libraries
634                      )
635
636
637ext_modules = [include_ext, orange_ext, orangeom_ext,
638               orangene_ext, corn_ext, statc_ext]
639
640cmdclass = {"build": orange_build,
641            "build_ext": pyxtract_build_ext,
642            "install_lib": orange_install_lib,
643            "install": orange_install}
644                   
645if orangeqt_setup:
646    orangeqt_ext = orangeqt_setup.orangeqt_ext
647    # Fix relative paths, name etc.
648    orangeqt_ext.name = "Orange.orangeqt"
649    orangeqt_ext.sources = ["source/orangeqt/orangeqt.sip"] + \
650                           get_source_files("source/orangeqt", "cpp",
651                                exclude=["canvas3d.cpp", "plot3d.cpp", 
652                                         "glextensions.cpp"]
653                                            )
654
655    orangeqt_ext.include_dirs += ["source/orangeqt"]
656
657    ext_modules += [orangeqt_ext]
658
659    cmdclass["build_pyqt_ext"] = build_pyqt_ext
660
661
662def get_packages():
663    import fnmatch
664    matches = []
665
666    #Recursively find '__init__.py's
667    for root, dirnames, filenames in os.walk('Orange'):
668        # Add packages for Orange
669        for filename in fnmatch.filter(filenames, '__init__.py'):
670            matches.append(os.path.join(root, filename))
671    return [os.path.dirname(pkg).replace(os.path.sep, '.') for pkg in matches]
672
673
674def get_package_data():
675    package_data = {
676        "Orange":
677            ["orangerc.cfg", "doc/style.css", "doc/widgets/*/*.*"] +\
678             all_with_extension(path="doc/datasets", extensions=("tab", "csv", "basket")) +\
679             all_with_extension(path="doc/networks", extensions=("net", "tab")) +\
680             all_with_extension(path="testing/regression/tests_20", extensions=("net", "tab", "basket", "csv")),
681        "Orange.OrangeCanvas": ["icons/*.png", "orngCanvas.pyw", "WidgetTabs.txt"],
682        "Orange.OrangeWidgets": ["icons/*.png", "icons/backgrounds/*.png", "report/index.html"],
683        "Orange.OrangeWidgets.Associate": ["icons/*.png"],
684        "Orange.OrangeWidgets.Classify": ["icons/*.png"],
685        "Orange.OrangeWidgets.Data": ["icons/*.png"],
686        "Orange.OrangeWidgets.Evaluate": ["icons/*.png"],
687        "Orange.OrangeWidgets.Prototypes": ["icons/*.png"],
688        "Orange.OrangeWidgets.Regression": ["icons/*.png"],
689        "Orange.OrangeWidgets.Unsupervised": ["icons/*.png"],
690        "Orange.OrangeWidgets.Visualize": ["icons/*.png"],
691        "Orange.OrangeWidgets.Visualize Qt": ["icons/*.png"],
692        "Orange.OrangeWidgets.plot": ["*.gs", "*.vs"],
693        "Orange.OrangeWidgets.plot.primitives": ["*.obj"],
694    }
695
696    return package_data
697
698def all_with_extension(path, extensions):
699    return [os.path.join(path, "*.%s"%extension) for extension in extensions]
700
701def hg_revision():
702    # Copied from numpy setup.py and modified to work with hg
703    def _minimal_ext_cmd(cmd):
704        # construct minimal environment
705        env = {}
706        for k in ['SYSTEMROOT', 'PATH']:
707            v = os.environ.get(k)
708            if v is not None:
709                env[k] = v
710        # LANGUAGE is used on win32
711        env['LANGUAGE'] = 'C'
712        env['LANG'] = 'C'
713        env['LC_ALL'] = 'C'
714        out = subprocess.Popen(cmd, stdout = subprocess.PIPE, env=env).communicate()[0]
715        return out
716
717    try:
718        out = _minimal_ext_cmd(['hg', 'ide', '-i'])
719        HG_REVISION = str(out.strip().decode('ascii'))
720    except OSError:
721        HG_REVISION = "Unknown"
722
723    return HG_REVISION
724
725def write_version_py(filename='Orange/version.py'):
726    # Copied from numpy setup.py
727    cnt = """
728# THIS FILE IS GENERATED FROM ORANGE SETUP.PY
729short_version = '%(version)s'
730version = '%(version)s'
731full_version = '%(full_version)s'
732hg_revision = '%(hg_revision)s'
733release = %(isrelease)s
734
735if not release:
736    version = full_version
737"""
738    FULLVERSION = VERSION
739    if os.path.exists('.hg'):
740        HG_REVISION = hg_revision()
741    elif os.path.exists('Orange/version.py'):
742        # must be a source distribution, use existing version file
743        version = imp.load_source("Orange.version", "Orange/version.py")
744        HG_REVISION = version.hg_revision
745    else:
746        HG_REVISION = "Unknown"
747
748    if not ISRELEASED:
749        FULLVERSION += '.dev-' + HG_REVISION[:7]
750
751    a = open(filename, 'w')
752    try:
753        a.write(cnt % {'version': VERSION,
754                       'full_version' : FULLVERSION,
755                       'hg_revision' : HG_REVISION,
756                       'isrelease': str(ISRELEASED)})
757    finally:
758        a.close()
759
760
761def setup_package():
762    write_version_py()
763    setup(name = NAME,
764          description = DESCRIPTION,
765          version = VERSION,
766          author = AUTHOR,
767          author_email = AUTHOR_EMAIL,
768          url = URL,
769          download_url = DOWNLOAD_URL,
770          classifiers = CLASSIFIERS,
771          long_description=LONG_DESCRIPTION,
772          license = LICENSE,
773          keywords = KEYWORDS,
774          cmdclass=cmdclass,
775          packages = get_packages(),
776          package_data = get_package_data(),
777          ext_modules = ext_modules,
778          scripts = ["bin/orange-canvas"],
779          **setuptools_args)
780
781if __name__ == '__main__':
782    setup_package()
Note: See TracBrowser for help on using the repository browser.