source: orange/setup.py @ 10815:425fac56a06c

Revision 10815:425fac56a06c, 29.9 KB checked in by mitar, 2 years ago (diff)

Updated setup.py.

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