~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to setup.py

Add bzrlib.pyutils, which has get_named_object, a wrapper around __import__.

This is used to replace various ad hoc implementations of the same logic,
notably the version used in registry's _LazyObjectGetter which had a bug when
getting a module without also getting a member.  And of course, this new
function has unit tests, unlike the replaced code.

This also adds a KnownHooksRegistry subclass to provide a more natural home for
some other logic.

I'm not thrilled about the name of the new module or the new functions, but it's
hard to think of good names for such generic functionality.

Show diffs side-by-side

added added

removed removed

Lines of Context:
9
9
import os
10
10
import os.path
11
11
import sys
 
12
import copy
12
13
 
13
14
if sys.version_info < (2, 4):
14
15
    sys.stderr.write("[ERROR] Not a supported Python version. Need 2.4+\n")
125
126
                f = file(batch_path, "w")
126
127
                f.write(batch_str)
127
128
                f.close()
128
 
                print "Created:", batch_path
129
 
            except Exception, e:
130
 
                print "ERROR: Unable to create %s: %s" % (batch_path, e)
 
129
                print("Created: %s" % batch_path)
 
130
            except Exception:
 
131
                e = sys.exc_info()[1]
 
132
                print("ERROR: Unable to create %s: %s" % (batch_path, e))
131
133
 
132
134
    def _quoted_path(self, path):
133
135
        if ' ' in path:
171
173
        from Pyrex.Distutils import build_ext
172
174
        from Pyrex.Compiler.Version import version as pyrex_version
173
175
    except ImportError:
174
 
        print "No Pyrex, trying Cython..."
 
176
        print("No Pyrex, trying Cython...")
175
177
        from Cython.Distutils import build_ext
176
178
        from Cython.Compiler.Version import version as pyrex_version
177
179
except ImportError:
178
180
    have_pyrex = False
179
181
    # try to build the extension from the prior generated source.
180
 
    print
181
 
    print ("The python package 'Pyrex' is not available."
182
 
           " If the .c files are available,")
183
 
    print ("they will be built,"
184
 
           " but modifying the .pyx files will not rebuild them.")
185
 
    print
 
182
    print("")
 
183
    print("The python package 'Pyrex' is not available."
 
184
          " If the .c files are available,")
 
185
    print("they will be built,"
 
186
          " but modifying the .pyx files will not rebuild them.")
 
187
    print("")
186
188
    from distutils.command.build_ext import build_ext
187
189
else:
188
190
    have_pyrex = True
204
206
    def run(self):
205
207
        try:
206
208
            build_ext.run(self)
207
 
        except DistutilsPlatformError, e:
 
209
        except DistutilsPlatformError:
 
210
            e = sys.exc_info()[1]
208
211
            if not self.allow_python_fallback:
209
212
                log.warn('\n  Cannot build extensions.\n'
210
213
                         '  Use "build_ext --allow-python-fallback" to use'
281
284
    add_pyrex_extension('bzrlib._dirstate_helpers_pyx',
282
285
                        libraries=['Ws2_32'])
283
286
    add_pyrex_extension('bzrlib._walkdirs_win32')
284
 
    z_lib = 'zdll'
285
287
else:
286
288
    if have_pyrex and pyrex_version_info[:3] == (0,9,4):
287
289
        # Pyrex 0.9.4.1 fails to compile this extension correctly
290
292
        # which is NULL safe with PY_DECREF which is not.)
291
293
        # <https://bugs.edge.launchpad.net/bzr/+bug/449372>
292
294
        # <https://bugs.edge.launchpad.net/bzr/+bug/276868>
293
 
        print 'Cannot build extension "bzrlib._dirstate_helpers_pyx" using'
294
 
        print 'your version of pyrex "%s". Please upgrade your pyrex' % (
295
 
            pyrex_version,)
296
 
        print 'install. For now, the non-compiled (python) version will'
297
 
        print 'be used instead.'
 
295
        print('Cannot build extension "bzrlib._dirstate_helpers_pyx" using')
 
296
        print('your version of pyrex "%s". Please upgrade your pyrex' % (
 
297
            pyrex_version,))
 
298
        print('install. For now, the non-compiled (python) version will')
 
299
        print('be used instead.')
298
300
    else:
299
301
        add_pyrex_extension('bzrlib._dirstate_helpers_pyx')
300
302
    add_pyrex_extension('bzrlib._readdir_pyx')
301
 
    z_lib = 'z'
302
 
add_pyrex_extension('bzrlib._chk_map_pyx', libraries=[z_lib])
 
303
add_pyrex_extension('bzrlib._chk_map_pyx')
303
304
ext_modules.append(Extension('bzrlib._patiencediff_c',
304
305
                             ['bzrlib/_patiencediff_c.c']))
305
306
if have_pyrex and pyrex_version_info < (0, 9, 6, 3):
306
 
    print
307
 
    print 'Your Pyrex/Cython version %s is too old to build the simple_set' % (
308
 
        pyrex_version)
309
 
    print 'and static_tuple extensions.'
310
 
    print 'Please upgrade to at least Pyrex 0.9.6.3'
311
 
    print
 
307
    print("")
 
308
    print('Your Pyrex/Cython version %s is too old to build the simple_set' % (
 
309
        pyrex_version))
 
310
    print('and static_tuple extensions.')
 
311
    print('Please upgrade to at least Pyrex 0.9.6.3')
 
312
    print("")
312
313
    # TODO: Should this be a fatal error?
313
314
else:
314
315
    # We only need 0.9.6.3 to build _simple_set_pyx, but static_tuple depends
320
321
 
321
322
 
322
323
if unavailable_files:
323
 
    print 'C extension(s) not found:'
324
 
    print '   %s' % ('\n  '.join(unavailable_files),)
325
 
    print 'The python versions will be used instead.'
326
 
    print
 
324
    print('C extension(s) not found:')
 
325
    print('   %s' % ('\n  '.join(unavailable_files),))
 
326
    print('The python versions will be used instead.')
 
327
    print("")
327
328
 
328
329
 
329
330
def get_tbzr_py2exe_info(includes, excludes, packages, console_targets,
413
414
 
414
415
def get_qbzr_py2exe_info(includes, excludes, packages, data_files):
415
416
    # PyQt4 itself still escapes the plugin detection code for some reason...
416
 
    packages.append('PyQt4')
417
 
    excludes.append('PyQt4.elementtree.ElementTree')
418
 
    excludes.append('PyQt4.uic.port_v3')
 
417
    includes.append('PyQt4.QtCore')
 
418
    includes.append('PyQt4.QtGui')
419
419
    includes.append('sip') # extension module required for Qt.
420
420
    packages.append('pygments') # colorizer for qbzr
421
421
    packages.append('docutils') # html formatting
422
422
    includes.append('win32event')  # for qsubprocess stuff
423
 
    # but we can avoid many Qt4 Dlls.
424
 
    dll_excludes.extend(
425
 
        """QtAssistantClient4.dll QtCLucene4.dll QtDesigner4.dll
426
 
        QtHelp4.dll QtNetwork4.dll QtOpenGL4.dll QtScript4.dll
427
 
        QtSql4.dll QtTest4.dll QtWebKit4.dll QtXml4.dll
428
 
        qscintilla2.dll""".split())
429
423
    # the qt binaries might not be on PATH...
430
424
    # They seem to install to a place like C:\Python25\PyQt4\*
431
425
    # Which is not the same as C:\Python25\Lib\site-packages\PyQt4
534
528
            install_data.run(self)
535
529
 
536
530
            py2exe = self.distribution.get_command_obj('py2exe', False)
537
 
            optimize = py2exe.optimize
 
531
            # GZ 2010-04-19: Setup has py2exe.optimize as 2, but give plugins
 
532
            #                time before living with docstring stripping
 
533
            optimize = 1
538
534
            compile_names = [f for f in self.outfiles if f.endswith('.py')]
 
535
            # Round mtime to nearest even second so that installing on a FAT
 
536
            # filesystem bytecode internal and script timestamps will match
 
537
            for f in compile_names:
 
538
                mtime = os.stat(f).st_mtime
 
539
                remainder = mtime % 2
 
540
                if remainder:
 
541
                    mtime -= remainder
 
542
                    os.utime(f, (mtime, mtime))
539
543
            byte_compile(compile_names,
540
544
                         optimize=optimize,
541
545
                         force=self.force, prefix=self.install_dir,
542
546
                         dry_run=self.dry_run)
543
 
            if optimize:
544
 
                suffix = 'o'
545
 
            else:
546
 
                suffix = 'c'
547
 
            self.outfiles.extend([f + suffix for f in compile_names])
 
547
            self.outfiles.extend([f + 'o' for f in compile_names])
548
548
    # end of class install_data_with_bytecompile
549
549
 
550
550
    target = py2exe.build_exe.Target(script = "bzr",
558
558
                                     company_name = "Canonical Ltd.",
559
559
                                     comments = META_INFO['description'],
560
560
                                    )
 
561
    gui_target = copy.copy(target)
 
562
    gui_target.dest_base = "bzrw"
561
563
 
562
564
    packages = BZRLIB['packages']
563
565
    packages.remove('bzrlib')
648
650
    console_targets = [target,
649
651
                       'tools/win32/bzr_postinstall.py',
650
652
                       ]
651
 
    gui_targets = []
 
653
    gui_targets = [gui_target]
652
654
    data_files = topics_files + plugins_files
653
655
 
654
656
    if 'qbzr' in plugins:
681
683
        # print this warning to stderr as output is redirected, so it is seen
682
684
        # at build time.  Also to stdout so it appears in the log
683
685
        for f in (sys.stderr, sys.stdout):
684
 
            print >> f, \
685
 
                "Skipping TBZR binaries - please set TBZR to a directory to enable"
 
686
            f.write("Skipping TBZR binaries - "
 
687
                "please set TBZR to a directory to enable\n")
686
688
 
687
689
    # MSWSOCK.dll is a system-specific library, which py2exe accidentally pulls
688
690
    # in on Vista.
692
694
                               "excludes": excludes,
693
695
                               "dll_excludes": dll_excludes,
694
696
                               "dist_dir": "win32_bzr.exe",
695
 
                               "optimize": 1,
 
697
                               "optimize": 2,
 
698
                               "custom_boot_script":
 
699
                                        "tools/win32/py2exe_boot_common.py",
696
700
                              },
697
701
                   }
698
702
 
699
 
    setup(options=options_list,
700
 
          console=console_targets,
701
 
          windows=gui_targets,
702
 
          zipfile='lib/library.zip',
703
 
          data_files=data_files,
704
 
          cmdclass={'install_data': install_data_with_bytecompile},
705
 
          )
 
703
    # We want the libaray.zip to have optimize = 2, but the exe to have
 
704
    # optimize = 1, so that .py files that get compilied at run time
 
705
    # (e.g. user installed plugins) dont have their doc strings removed.
 
706
    class py2exe_no_oo_exe(py2exe.build_exe.py2exe):
 
707
        def build_executable(self, *args, **kwargs):
 
708
            self.optimize = 1
 
709
            py2exe.build_exe.py2exe.build_executable(self, *args, **kwargs)
 
710
            self.optimize = 2
 
711
 
 
712
    if __name__ == '__main__':
 
713
        setup(options=options_list,
 
714
              console=console_targets,
 
715
              windows=gui_targets,
 
716
              zipfile='lib/library.zip',
 
717
              data_files=data_files,
 
718
              cmdclass={'install_data': install_data_with_bytecompile,
 
719
                        'py2exe': py2exe_no_oo_exe},
 
720
              )
706
721
 
707
722
else:
708
723
    # ad-hoc for easy_install
736
751
    ARGS.update(BZRLIB)
737
752
    ARGS.update(PKG_DATA)
738
753
 
739
 
    setup(**ARGS)
 
754
    if __name__ == '__main__':
 
755
        setup(**ARGS)