source: orange/setup.py @ 10792:7602a3f6b71e

Revision 10792:7602a3f6b71e, 29.5 KB checked in by Ales Erjavec <ales.erjavec@…>, 2 years ago (diff)

Can now build orangeqt extension by running (optional) build_pyqt_ext command.

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