source: coopr.misc/trunk/util/coopr_install @ 3581

Last change on this file since 3581 was 3581, checked in by wehart, 9 years ago

Another change due to an update in pyutilib.virtualenv

  • Property svn:executable set to *
File size: 171.7 KB
Line 
1#!/usr/bin/env python
2## WARNING: This file is generated
3#!/usr/bin/env python
4"""Create a "virtual" Python installation
5"""
6
7virtualenv_version = "1.5.1"
8
9import sys
10import os
11import optparse
12import re
13import shutil
14import logging
15import tempfile
16import distutils.sysconfig
17try:
18    import subprocess
19except ImportError, e:
20    if sys.version_info <= (2, 3):
21        print 'ERROR: %s' % e
22        print 'ERROR: this script requires Python 2.4 or greater; or at least the subprocess module.'
23        print 'If you copy subprocess.py from a newer version of Python this script will probably work'
24        sys.exit(101)
25    else:
26        raise
27try:
28    set
29except NameError:
30    from sets import Set as set
31
32join = os.path.join
33py_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1])
34
35is_jython = sys.platform.startswith('java')
36is_pypy = hasattr(sys, 'pypy_version_info')
37
38if is_pypy:
39    expected_exe = 'pypy-c'
40elif is_jython:
41    expected_exe = 'jython'
42else:
43    expected_exe = 'python'
44
45
46REQUIRED_MODULES = ['os', 'posix', 'posixpath', 'nt', 'ntpath', 'genericpath',
47                    'fnmatch', 'locale', 'encodings', 'codecs',
48                    'stat', 'UserDict', 'readline', 'copy_reg', 'types',
49                    're', 'sre', 'sre_parse', 'sre_constants', 'sre_compile',
50                    'zlib']
51
52REQUIRED_FILES = ['lib-dynload', 'config']
53
54if sys.version_info[:2] >= (2, 6):
55    REQUIRED_MODULES.extend(['warnings', 'linecache', '_abcoll', 'abc'])
56if sys.version_info[:2] >= (2, 7):
57    REQUIRED_MODULES.extend(['_weakrefset'])
58if sys.version_info[:2] <= (2, 3):
59    REQUIRED_MODULES.extend(['sets', '__future__'])
60if is_pypy:
61    # these are needed to correctly display the exceptions that may happen
62    # during the bootstrap
63    REQUIRED_MODULES.extend(['traceback', 'linecache'])
64
65class Logger(object):
66
67    """
68    Logging object for use in command-line script.  Allows ranges of
69    levels, to avoid some redundancy of displayed information.
70    """
71
72    DEBUG = logging.DEBUG
73    INFO = logging.INFO
74    NOTIFY = (logging.INFO+logging.WARN)/2
75    WARN = WARNING = logging.WARN
76    ERROR = logging.ERROR
77    FATAL = logging.FATAL
78
79    LEVELS = [DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL]
80
81    def __init__(self, consumers):
82        self.consumers = consumers
83        self.indent = 0
84        self.in_progress = None
85        self.in_progress_hanging = False
86
87    def debug(self, msg, *args, **kw):
88        self.log(self.DEBUG, msg, *args, **kw)
89    def info(self, msg, *args, **kw):
90        self.log(self.INFO, msg, *args, **kw)
91    def notify(self, msg, *args, **kw):
92        self.log(self.NOTIFY, msg, *args, **kw)
93    def warn(self, msg, *args, **kw):
94        self.log(self.WARN, msg, *args, **kw)
95    def error(self, msg, *args, **kw):
96        self.log(self.WARN, msg, *args, **kw)
97    def fatal(self, msg, *args, **kw):
98        self.log(self.FATAL, msg, *args, **kw)
99    def log(self, level, msg, *args, **kw):
100        if args:
101            if kw:
102                raise TypeError(
103                    "You may give positional or keyword arguments, not both")
104        args = args or kw
105        rendered = None
106        for consumer_level, consumer in self.consumers:
107            if self.level_matches(level, consumer_level):
108                if (self.in_progress_hanging
109                    and consumer in (sys.stdout, sys.stderr)):
110                    self.in_progress_hanging = False
111                    sys.stdout.write('\n')
112                    sys.stdout.flush()
113                if rendered is None:
114                    if args:
115                        rendered = msg % args
116                    else:
117                        rendered = msg
118                    rendered = ' '*self.indent + rendered
119                if hasattr(consumer, 'write'):
120                    consumer.write(rendered+'\n')
121                else:
122                    consumer(rendered)
123
124    def start_progress(self, msg):
125        assert not self.in_progress, (
126            "Tried to start_progress(%r) while in_progress %r"
127            % (msg, self.in_progress))
128        if self.level_matches(self.NOTIFY, self._stdout_level()):
129            sys.stdout.write(msg)
130            sys.stdout.flush()
131            self.in_progress_hanging = True
132        else:
133            self.in_progress_hanging = False
134        self.in_progress = msg
135
136    def end_progress(self, msg='done.'):
137        assert self.in_progress, (
138            "Tried to end_progress without start_progress")
139        if self.stdout_level_matches(self.NOTIFY):
140            if not self.in_progress_hanging:
141                # Some message has been printed out since start_progress
142                sys.stdout.write('...' + self.in_progress + msg + '\n')
143                sys.stdout.flush()
144            else:
145                sys.stdout.write(msg + '\n')
146                sys.stdout.flush()
147        self.in_progress = None
148        self.in_progress_hanging = False
149
150    def show_progress(self):
151        """If we are in a progress scope, and no log messages have been
152        shown, write out another '.'"""
153        if self.in_progress_hanging:
154            sys.stdout.write('.')
155            sys.stdout.flush()
156
157    def stdout_level_matches(self, level):
158        """Returns true if a message at this level will go to stdout"""
159        return self.level_matches(level, self._stdout_level())
160
161    def _stdout_level(self):
162        """Returns the level that stdout runs at"""
163        for level, consumer in self.consumers:
164            if consumer is sys.stdout:
165                return level
166        return self.FATAL
167
168    def level_matches(self, level, consumer_level):
169        """
170        >>> l = Logger()
171        >>> l.level_matches(3, 4)
172        False
173        >>> l.level_matches(3, 2)
174        True
175        >>> l.level_matches(slice(None, 3), 3)
176        False
177        >>> l.level_matches(slice(None, 3), 2)
178        True
179        >>> l.level_matches(slice(1, 3), 1)
180        True
181        >>> l.level_matches(slice(2, 3), 1)
182        False
183        """
184        if isinstance(level, slice):
185            start, stop = level.start, level.stop
186            if start is not None and start > consumer_level:
187                return False
188            if stop is not None or stop <= consumer_level:
189                return False
190            return True
191        else:
192            return level >= consumer_level
193
194    #@classmethod
195    def level_for_integer(cls, level):
196        levels = cls.LEVELS
197        if level < 0:
198            return levels[0]
199        if level >= len(levels):
200            return levels[-1]
201        return levels[level]
202
203    level_for_integer = classmethod(level_for_integer)
204
205def mkdir(path):
206    if not os.path.exists(path):
207        logger.info('Creating %s', path)
208        os.makedirs(path)
209    else:
210        logger.info('Directory %s already exists', path)
211
212def copyfile(src, dest, symlink=True):
213    if not os.path.exists(src):
214        # Some bad symlink in the src
215        logger.warn('Cannot find file %s (bad symlink)', src)
216        return
217    if os.path.exists(dest):
218        logger.debug('File %s already exists', dest)
219        return
220    if not os.path.exists(os.path.dirname(dest)):
221        logger.info('Creating parent directories for %s' % os.path.dirname(dest))
222        os.makedirs(os.path.dirname(dest))
223    if symlink and hasattr(os, 'symlink'):
224        logger.info('Symlinking %s', dest)
225        os.symlink(os.path.abspath(src), dest)
226    else:
227        logger.info('Copying to %s', dest)
228        if os.path.isdir(src):
229            shutil.copytree(src, dest, True)
230        else:
231            shutil.copy2(src, dest)
232
233def writefile(dest, content, overwrite=True):
234    if not os.path.exists(dest):
235        logger.info('Writing %s', dest)
236        f = open(dest, 'wb')
237        f.write(content)
238        f.close()
239        return
240    else:
241        f = open(dest, 'rb')
242        c = f.read()
243        f.close()
244        if c != content:
245            if not overwrite:
246                logger.notify('File %s exists with different content; not overwriting', dest)
247                return
248            logger.notify('Overwriting %s with new content', dest)
249            f = open(dest, 'wb')
250            f.write(content)
251            f.close()
252        else:
253            logger.info('Content %s already in place', dest)
254
255def rmtree(dir):
256    if os.path.exists(dir):
257        logger.notify('Deleting tree %s', dir)
258        shutil.rmtree(dir)
259    else:
260        logger.info('Do not need to delete %s; already gone', dir)
261
262def make_exe(fn):
263    if hasattr(os, 'chmod'):
264        oldmode = os.stat(fn).st_mode & 07777
265        newmode = (oldmode | 0555) & 07777
266        os.chmod(fn, newmode)
267        logger.info('Changed mode of %s to %s', fn, oct(newmode))
268
269def _find_file(filename, dirs):
270    for dir in dirs:
271        if os.path.exists(join(dir, filename)):
272            return join(dir, filename)
273    return filename
274
275def _install_req(py_executable, unzip=False, distribute=False):
276    if not distribute:
277        setup_fn = 'setuptools-0.6c11-py%s.egg' % sys.version[:3]
278        project_name = 'setuptools'
279        bootstrap_script = EZ_SETUP_PY
280        source = None
281    else:
282        setup_fn = None
283        source = 'distribute-0.6.14.tar.gz'
284        project_name = 'distribute'
285        bootstrap_script = DISTRIBUTE_SETUP_PY
286        try:
287            # check if the global Python has distribute installed or plain
288            # setuptools
289            import pkg_resources
290            if not hasattr(pkg_resources, '_distribute'):
291                location = os.path.dirname(pkg_resources.__file__)
292                logger.notify("A globally installed setuptools was found (in %s)" % location)
293                logger.notify("Use the --no-site-packages option to use distribute in "
294                              "the virtualenv.")
295        except ImportError:
296            pass
297
298    search_dirs = file_search_dirs()
299
300    if setup_fn is not None:
301        setup_fn = _find_file(setup_fn, search_dirs)
302
303    if source is not None:
304        source = _find_file(source, search_dirs)
305
306    if is_jython and os._name == 'nt':
307        # Jython's .bat sys.executable can't handle a command line
308        # argument with newlines
309        fd, ez_setup = tempfile.mkstemp('.py')
310        os.write(fd, bootstrap_script)
311        os.close(fd)
312        cmd = [py_executable, ez_setup]
313    else:
314        cmd = [py_executable, '-c', bootstrap_script]
315    if unzip:
316        cmd.append('--always-unzip')
317    env = {}
318    remove_from_env = []
319    if logger.stdout_level_matches(logger.DEBUG):
320        cmd.append('-v')
321
322    old_chdir = os.getcwd()
323    if setup_fn is not None and os.path.exists(setup_fn):
324        logger.info('Using existing %s egg: %s' % (project_name, setup_fn))
325        cmd.append(setup_fn)
326        if os.environ.get('PYTHONPATH'):
327            env['PYTHONPATH'] = setup_fn + os.path.pathsep + os.environ['PYTHONPATH']
328        else:
329            env['PYTHONPATH'] = setup_fn
330    else:
331        # the source is found, let's chdir
332        if source is not None and os.path.exists(source):
333            os.chdir(os.path.dirname(source))
334            # in this case, we want to be sure that PYTHONPATH is unset (not
335            # just empty, really unset), else CPython tries to import the
336            # site.py that it's in virtualenv_support
337            remove_from_env.append('PYTHONPATH')
338        else:
339            logger.info('No %s egg found; downloading' % project_name)
340        cmd.extend(['--always-copy', '-U', project_name])
341    logger.start_progress('Installing %s...' % project_name)
342    logger.indent += 2
343    cwd = None
344    if project_name == 'distribute':
345        env['DONT_PATCH_SETUPTOOLS'] = 'true'
346
347    def _filter_ez_setup(line):
348        return filter_ez_setup(line, project_name)
349
350    if not os.access(os.getcwd(), os.W_OK):
351        cwd = tempfile.mkdtemp()
352        if source is not None and os.path.exists(source):
353            # the current working dir is hostile, let's copy the
354            # tarball to a temp dir
355            target = os.path.join(cwd, os.path.split(source)[-1])
356            shutil.copy(source, target)
357    try:
358        call_subprocess(cmd, show_stdout=False,
359                        filter_stdout=_filter_ez_setup,
360                        extra_env=env,
361                        remove_from_env=remove_from_env,
362                        cwd=cwd)
363    finally:
364        logger.indent -= 2
365        logger.end_progress()
366        if os.getcwd() != old_chdir:
367            os.chdir(old_chdir)
368        if is_jython and os._name == 'nt':
369            os.remove(ez_setup)
370
371def file_search_dirs():
372    here = os.path.dirname(os.path.abspath(__file__))
373    dirs = ['.', here,
374            join(here, 'virtualenv_support')]
375    if os.path.splitext(os.path.dirname(__file__))[0] != 'virtualenv':
376        # Probably some boot script; just in case virtualenv is installed...
377        try:
378            import virtualenv
379        except ImportError:
380            pass
381        else:
382            dirs.append(os.path.join(os.path.dirname(virtualenv.__file__), 'virtualenv_support'))
383    return [d for d in dirs if os.path.isdir(d)]
384
385def install_setuptools(py_executable, unzip=False):
386    _install_req(py_executable, unzip)
387
388def install_distribute(py_executable, unzip=False):
389    _install_req(py_executable, unzip, distribute=True)
390
391_pip_re = re.compile(r'^pip-.*(zip|tar.gz|tar.bz2|tgz|tbz)$', re.I)
392def install_pip(py_executable):
393    filenames = []
394    for dir in file_search_dirs():
395        filenames.extend([join(dir, fn) for fn in os.listdir(dir)
396                          if _pip_re.search(fn)])
397    filenames = [(os.path.basename(filename).lower(), i, filename) for i, filename in enumerate(filenames)]
398    filenames.sort()
399    filenames = [filename for basename, i, filename in filenames]
400    if not filenames:
401        filename = 'pip'
402    else:
403        filename = filenames[-1]
404    easy_install_script = 'easy_install'
405    if sys.platform == 'win32':
406        easy_install_script = 'easy_install-script.py'
407    cmd = [py_executable, join(os.path.dirname(py_executable), easy_install_script), filename]
408    if filename == 'pip':
409        logger.info('Installing pip from network...')
410    else:
411        logger.info('Installing %s' % os.path.basename(filename))
412    logger.indent += 2
413    def _filter_setup(line):
414        return filter_ez_setup(line, 'pip')
415    try:
416        call_subprocess(cmd, show_stdout=False,
417                        filter_stdout=_filter_setup)
418    finally:
419        logger.indent -= 2
420
421def filter_ez_setup(line, project_name='setuptools'):
422    if not line.strip():
423        return Logger.DEBUG
424    if project_name == 'distribute':
425        for prefix in ('Extracting', 'Now working', 'Installing', 'Before',
426                       'Scanning', 'Setuptools', 'Egg', 'Already',
427                       'running', 'writing', 'reading', 'installing',
428                       'creating', 'copying', 'byte-compiling', 'removing',
429                       'Processing'):
430            if line.startswith(prefix):
431                return Logger.DEBUG
432        return Logger.DEBUG
433    for prefix in ['Reading ', 'Best match', 'Processing setuptools',
434                   'Copying setuptools', 'Adding setuptools',
435                   'Installing ', 'Installed ']:
436        if line.startswith(prefix):
437            return Logger.DEBUG
438    return Logger.INFO
439
440def main():
441    parser = optparse.OptionParser(
442        version=virtualenv_version,
443        usage="%prog [OPTIONS] DEST_DIR")
444
445    parser.add_option(
446        '-v', '--verbose',
447        action='count',
448        dest='verbose',
449        default=0,
450        help="Increase verbosity")
451
452    parser.add_option(
453        '-q', '--quiet',
454        action='count',
455        dest='quiet',
456        default=0,
457        help='Decrease verbosity')
458
459    parser.add_option(
460        '-p', '--python',
461        dest='python',
462        metavar='PYTHON_EXE',
463        help='The Python interpreter to use, e.g., --python=python2.5 will use the python2.5 '
464        'interpreter to create the new environment.  The default is the interpreter that '
465        'virtualenv was installed with (%s)' % sys.executable)
466
467    parser.add_option(
468        '--clear',
469        dest='clear',
470        action='store_true',
471        help="Clear out the non-root install and start from scratch")
472
473    parser.add_option(
474        '--no-site-packages',
475        dest='no_site_packages',
476        action='store_true',
477        help="Don't give access to the global site-packages dir to the "
478             "virtual environment")
479
480    parser.add_option(
481        '--unzip-setuptools',
482        dest='unzip_setuptools',
483        action='store_true',
484        help="Unzip Setuptools or Distribute when installing it")
485
486    parser.add_option(
487        '--relocatable',
488        dest='relocatable',
489        action='store_true',
490        help='Make an EXISTING virtualenv environment relocatable.  '
491        'This fixes up scripts and makes all .pth files relative')
492
493    parser.add_option(
494        '--distribute',
495        dest='use_distribute',
496        action='store_true',
497        help='Use Distribute instead of Setuptools. Set environ variable '
498        'VIRTUALENV_USE_DISTRIBUTE to make it the default ')
499
500    parser.add_option(
501        '--prompt=',
502        dest='prompt',
503        help='Provides an alternative prompt prefix for this environment')
504
505    if 'extend_parser' in globals():
506        extend_parser(parser)
507
508    options, args = parser.parse_args()
509
510    global logger
511
512    if 'adjust_options' in globals():
513        adjust_options(options, args)
514
515    verbosity = options.verbose - options.quiet
516    logger = Logger([(Logger.level_for_integer(2-verbosity), sys.stdout)])
517
518    if options.python and not os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'):
519        env = os.environ.copy()
520        interpreter = resolve_interpreter(options.python)
521        if interpreter == sys.executable:
522            logger.warn('Already using interpreter %s' % interpreter)
523        else:
524            logger.notify('Running virtualenv with interpreter %s' % interpreter)
525            env['VIRTUALENV_INTERPRETER_RUNNING'] = 'true'
526            file = __file__
527            if file.endswith('.pyc'):
528                file = file[:-1]
529            popen = subprocess.Popen([interpreter, file] + sys.argv[1:], env=env)
530            raise SystemExit(popen.wait())
531
532    if not args:
533        print 'You must provide a DEST_DIR'
534        parser.print_help()
535        sys.exit(2)
536    if len(args) > 1:
537        print 'There must be only one argument: DEST_DIR (you gave %s)' % (
538            ' '.join(args))
539        parser.print_help()
540        sys.exit(2)
541
542    home_dir = args[0]
543
544    if os.environ.get('WORKING_ENV'):
545        logger.fatal('ERROR: you cannot run virtualenv while in a workingenv')
546        logger.fatal('Please deactivate your workingenv, then re-run this script')
547        sys.exit(3)
548
549    if 'PYTHONHOME' in os.environ:
550        logger.warn('PYTHONHOME is set.  You *must* activate the virtualenv before using it')
551        del os.environ['PYTHONHOME']
552
553    if options.relocatable:
554        make_environment_relocatable(home_dir)
555        return
556
557    create_environment(home_dir, site_packages=not options.no_site_packages, clear=options.clear,
558                       unzip_setuptools=options.unzip_setuptools,
559                       use_distribute=options.use_distribute,
560                       prompt=options.prompt)
561    if 'after_install' in globals():
562        after_install(options, home_dir)
563
564def call_subprocess(cmd, show_stdout=True,
565                    filter_stdout=None, cwd=None,
566                    raise_on_returncode=True, extra_env=None,
567                    remove_from_env=None):
568    cmd_parts = []
569    for part in cmd:
570        if len(part) > 40:
571            part = part[:30]+"..."+part[-5:]
572        if ' ' in part or '\n' in part or '"' in part or "'" in part:
573            part = '"%s"' % part.replace('"', '\\"')
574        cmd_parts.append(part)
575    cmd_desc = ' '.join(cmd_parts)
576    if show_stdout:
577        stdout = None
578    else:
579        stdout = subprocess.PIPE
580    logger.debug("Running command %s" % cmd_desc)
581    if extra_env or remove_from_env:
582        env = os.environ.copy()
583        if extra_env:
584            env.update(extra_env)
585        if remove_from_env:
586            for varname in remove_from_env:
587                env.pop(varname, None)
588    else:
589        env = None
590    try:
591        proc = subprocess.Popen(
592            cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout,
593            cwd=cwd, env=env)
594    except Exception, e:
595        logger.fatal(
596            "Error %s while executing command %s" % (e, cmd_desc))
597        raise
598    all_output = []
599    if stdout is not None:
600        stdout = proc.stdout
601        while 1:
602            line = stdout.readline()
603            if not line:
604                break
605            line = line.rstrip()
606            all_output.append(line)
607            if filter_stdout:
608                level = filter_stdout(line)
609                if isinstance(level, tuple):
610                    level, line = level
611                logger.log(level, line)
612                if not logger.stdout_level_matches(level):
613                    logger.show_progress()
614            else:
615                logger.info(line)
616    else:
617        proc.communicate()
618    proc.wait()
619    if proc.returncode:
620        if raise_on_returncode:
621            if all_output:
622                logger.notify('Complete output from command %s:' % cmd_desc)
623                logger.notify('\n'.join(all_output) + '\n----------------------------------------')
624            raise OSError(
625                "Command %s failed with error code %s"
626                % (cmd_desc, proc.returncode))
627        else:
628            logger.warn(
629                "Command %s had error code %s"
630                % (cmd_desc, proc.returncode))
631
632
633def create_environment(home_dir, site_packages=True, clear=False,
634                       unzip_setuptools=False, use_distribute=False,
635                       prompt=None):
636    """
637    Creates a new environment in ``home_dir``.
638
639    If ``site_packages`` is true (the default) then the global
640    ``site-packages/`` directory will be on the path.
641
642    If ``clear`` is true (default False) then the environment will
643    first be cleared.
644    """
645    home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
646
647    py_executable = os.path.abspath(install_python(
648        home_dir, lib_dir, inc_dir, bin_dir,
649        site_packages=site_packages, clear=clear))
650
651    install_distutils(home_dir)
652
653    if use_distribute or os.environ.get('VIRTUALENV_USE_DISTRIBUTE'):
654        install_distribute(py_executable, unzip=unzip_setuptools)
655    else:
656        install_setuptools(py_executable, unzip=unzip_setuptools)
657
658    install_pip(py_executable)
659
660    install_activate(home_dir, bin_dir, prompt)
661
662def path_locations(home_dir):
663    """Return the path locations for the environment (where libraries are,
664    where scripts go, etc)"""
665    # XXX: We'd use distutils.sysconfig.get_python_inc/lib but its
666    # prefix arg is broken: http://bugs.python.org/issue3386
667    if sys.platform == 'win32':
668        # Windows has lots of problems with executables with spaces in
669        # the name; this function will remove them (using the ~1
670        # format):
671        mkdir(home_dir)
672        if ' ' in home_dir:
673            try:
674                pass
675            except ImportError:
676                print 'Error: the path "%s" has a space in it' % home_dir
677                pass
678                print '  http://sourceforge.net/projects/pywin32/'
679                sys.exit(3)
680            pass
681        lib_dir = join(home_dir, 'Lib')
682        inc_dir = join(home_dir, 'Include')
683        bin_dir = join(home_dir, 'Scripts')
684    elif is_jython:
685        lib_dir = join(home_dir, 'Lib')
686        inc_dir = join(home_dir, 'Include')
687        bin_dir = join(home_dir, 'bin')
688    elif is_pypy:
689        lib_dir = home_dir
690        inc_dir = join(home_dir, 'include')
691        bin_dir = join(home_dir, 'bin')
692    else:
693        lib_dir = join(home_dir, 'lib', py_version)
694        inc_dir = join(home_dir, 'include', py_version)
695        bin_dir = join(home_dir, 'bin')
696    return home_dir, lib_dir, inc_dir, bin_dir
697
698
699def change_prefix(filename, dst_prefix):
700    prefixes = [sys.prefix]
701    if hasattr(sys, 'real_prefix'):
702        prefixes.append(sys.real_prefix)
703    prefixes = map(os.path.abspath, prefixes)
704    filename = os.path.abspath(filename)
705    for src_prefix in prefixes:
706        if filename.startswith(src_prefix):
707            _, relpath = filename.split(src_prefix, 1)
708            assert relpath[0] == os.sep
709            relpath = relpath[1:]
710            return join(dst_prefix, relpath)
711    assert False, "Filename %s does not start with any of these prefixes: %s" % \
712        (filename, prefixes)
713
714def copy_required_modules(dst_prefix):
715    import imp
716    for modname in REQUIRED_MODULES:
717        if modname in sys.builtin_module_names:
718            logger.info("Ignoring built-in bootstrap module: %s" % modname)
719            continue
720        try:
721            f, filename, _ = imp.find_module(modname)
722        except ImportError:
723            logger.info("Cannot import bootstrap module: %s" % modname)
724        else:
725            if f is not None:
726                f.close()
727            dst_filename = change_prefix(filename, dst_prefix)
728            copyfile(filename, dst_filename)
729            if filename.endswith('.pyc'):
730                pyfile = filename[:-1]
731                if os.path.exists(pyfile):
732                    copyfile(pyfile, dst_filename[:-1])
733
734
735def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear):
736    """Install just the base environment, no distutils patches etc"""
737    if sys.executable.startswith(bin_dir):
738        print 'Please use the *system* python to run this script'
739        return
740
741    if clear:
742        rmtree(lib_dir)
743        # pyutilib.virtualenv: ignoring comment
744        ## Maybe it should delete everything with #!/path/to/venv/python in it
745        logger.notify('Not deleting %s', bin_dir)
746
747    if hasattr(sys, 'real_prefix'):
748        logger.notify('Using real prefix %r' % sys.real_prefix)
749        prefix = sys.real_prefix
750    else:
751        prefix = sys.prefix
752    mkdir(lib_dir)
753    fix_lib64(lib_dir)
754    stdlib_dirs = [os.path.dirname(os.__file__)]
755    if sys.platform == 'win32':
756        stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), 'DLLs'))
757    elif sys.platform == 'darwin':
758        stdlib_dirs.append(join(stdlib_dirs[0], 'site-packages'))
759    if hasattr(os, 'symlink'):
760        logger.info('Symlinking Python bootstrap modules')
761    else:
762        logger.info('Copying Python bootstrap modules')
763    logger.indent += 2
764    try:
765        # copy required files...
766        for stdlib_dir in stdlib_dirs:
767            if not os.path.isdir(stdlib_dir):
768                continue
769            for fn in os.listdir(stdlib_dir):
770                if fn != 'site-packages' and os.path.splitext(fn)[0] in REQUIRED_FILES:
771                    copyfile(join(stdlib_dir, fn), join(lib_dir, fn))
772        # ...and modules
773        copy_required_modules(home_dir)
774    finally:
775        logger.indent -= 2
776    mkdir(join(lib_dir, 'site-packages'))
777    import site
778    site_filename = site.__file__
779    if site_filename.endswith('.pyc'):
780        site_filename = site_filename[:-1]
781    elif site_filename.endswith('$py.class'):
782        site_filename = site_filename.replace('$py.class', '.py')
783    site_filename_dst = change_prefix(site_filename, home_dir)
784    site_dir = os.path.dirname(site_filename_dst)
785    writefile(site_filename_dst, SITE_PY)
786    writefile(join(site_dir, 'orig-prefix.txt'), prefix)
787    site_packages_filename = join(site_dir, 'no-global-site-packages.txt')
788    if not site_packages:
789        writefile(site_packages_filename, '')
790    else:
791        if os.path.exists(site_packages_filename):
792            logger.info('Deleting %s' % site_packages_filename)
793            os.unlink(site_packages_filename)
794
795    if is_pypy:
796        stdinc_dir = join(prefix, 'include')
797    else:
798        stdinc_dir = join(prefix, 'include', py_version)
799    if os.path.exists(stdinc_dir):
800        copyfile(stdinc_dir, inc_dir)
801    else:
802        logger.debug('No include dir %s' % stdinc_dir)
803
804    if sys.exec_prefix != prefix:
805        if sys.platform == 'win32':
806            exec_dir = join(sys.exec_prefix, 'lib')
807        elif is_jython:
808            exec_dir = join(sys.exec_prefix, 'Lib')
809        else:
810            exec_dir = join(sys.exec_prefix, 'lib', py_version)
811        for fn in os.listdir(exec_dir):
812            copyfile(join(exec_dir, fn), join(lib_dir, fn))
813
814    if is_jython:
815        # Jython has either jython-dev.jar and javalib/ dir, or just
816        # jython.jar
817        for name in 'jython-dev.jar', 'javalib', 'jython.jar':
818            src = join(prefix, name)
819            if os.path.exists(src):
820                copyfile(src, join(home_dir, name))
821        # XXX: registry should always exist after Jython 2.5rc1
822        src = join(prefix, 'registry')
823        if os.path.exists(src):
824            copyfile(src, join(home_dir, 'registry'), symlink=False)
825        copyfile(join(prefix, 'cachedir'), join(home_dir, 'cachedir'),
826                 symlink=False)
827
828    mkdir(bin_dir)
829    py_executable = join(bin_dir, os.path.basename(sys.executable))
830    if 'Python.framework' in prefix:
831        if re.search(r'/Python(?:-32|-64)*$', py_executable):
832            # The name of the python executable is not quite what
833            # we want, rename it.
834            py_executable = os.path.join(
835                    os.path.dirname(py_executable), 'python')
836
837    logger.notify('New %s executable in %s', expected_exe, py_executable)
838    if sys.executable != py_executable:
839        # pyutilib.virtualenv: ignoring comment
840        executable = sys.executable
841        if sys.platform == 'cygwin' and os.path.exists(executable + '.exe'):
842            # Cygwin misreports sys.executable sometimes
843            executable += '.exe'
844            py_executable += '.exe'
845            logger.info('Executable actually exists in %s' % executable)
846        shutil.copyfile(executable, py_executable)
847        make_exe(py_executable)
848        if sys.platform == 'win32' or sys.platform == 'cygwin':
849            pythonw = os.path.join(os.path.dirname(sys.executable), 'pythonw.exe')
850            if os.path.exists(pythonw):
851                logger.info('Also created pythonw.exe')
852                shutil.copyfile(pythonw, os.path.join(os.path.dirname(py_executable), 'pythonw.exe'))
853        if is_pypy:
854            # make a symlink python --> pypy-c
855            python_executable = os.path.join(os.path.dirname(py_executable), 'python')
856            logger.info('Also created executable %s' % python_executable)
857            copyfile(py_executable, python_executable)
858
859    if os.path.splitext(os.path.basename(py_executable))[0] != expected_exe:
860        secondary_exe = os.path.join(os.path.dirname(py_executable),
861                                     expected_exe)
862        py_executable_ext = os.path.splitext(py_executable)[1]
863        if py_executable_ext == '.exe':
864            # python2.4 gives an extension of '.4' :P
865            secondary_exe += py_executable_ext
866        if os.path.exists(secondary_exe):
867            logger.warn('Not overwriting existing %s script %s (you must use %s)'
868                        % (expected_exe, secondary_exe, py_executable))
869        else:
870            logger.notify('Also creating executable in %s' % secondary_exe)
871            shutil.copyfile(sys.executable, secondary_exe)
872            make_exe(secondary_exe)
873
874    if 'Python.framework' in prefix:
875        logger.debug('MacOSX Python framework detected')
876
877        # Make sure we use the the embedded interpreter inside
878        # the framework, even if sys.executable points to
879        # the stub executable in ${sys.prefix}/bin
880        # See http://groups.google.com/group/python-virtualenv/
881        #                              browse_thread/thread/17cab2f85da75951
882        original_python = os.path.join(
883            prefix, 'Resources/Python.app/Contents/MacOS/Python')
884        shutil.copy(original_python, py_executable)
885
886        # Copy the framework's dylib into the virtual
887        # environment
888        virtual_lib = os.path.join(home_dir, '.Python')
889
890        if os.path.exists(virtual_lib):
891            os.unlink(virtual_lib)
892        copyfile(
893            os.path.join(prefix, 'Python'),
894            virtual_lib)
895
896        # And then change the install_name of the copied python executable
897        try:
898            call_subprocess(
899                ["install_name_tool", "-change",
900                 os.path.join(prefix, 'Python'),
901                 '@executable_path/../.Python',
902                 py_executable])
903        except:
904            logger.fatal(
905                "Could not call install_name_tool -- you must have Apple's development tools installed")
906            raise
907
908        # Some tools depend on pythonX.Y being present
909        py_executable_version = '%s.%s' % (
910            sys.version_info[0], sys.version_info[1])
911        if not py_executable.endswith(py_executable_version):
912            # symlinking pythonX.Y > python
913            pth = py_executable + '%s.%s' % (
914                    sys.version_info[0], sys.version_info[1])
915            if os.path.exists(pth):
916                os.unlink(pth)
917            os.symlink('python', pth)
918        else:
919            # reverse symlinking python -> pythonX.Y (with --python)
920            pth = join(bin_dir, 'python')
921            if os.path.exists(pth):
922                os.unlink(pth)
923            os.symlink(os.path.basename(py_executable), pth)
924
925    if sys.platform == 'win32' and ' ' in py_executable:
926        # There's a bug with subprocess on Windows when using a first
927        # argument that has a space in it.  Instead we have to quote
928        # the value:
929        py_executable = '"%s"' % py_executable
930    cmd = [py_executable, '-c', 'import sys; print sys.prefix']
931    logger.info('Testing executable with %s %s "%s"' % tuple(cmd))
932    proc = subprocess.Popen(cmd,
933                            stdout=subprocess.PIPE)
934    proc_stdout, proc_stderr = proc.communicate()
935    proc_stdout = os.path.normcase(os.path.abspath(proc_stdout.strip()))
936    if proc_stdout != os.path.normcase(os.path.abspath(home_dir)):
937        logger.fatal(
938            'ERROR: The executable %s is not functioning' % py_executable)
939        logger.fatal(
940            'ERROR: It thinks sys.prefix is %r (should be %r)'
941            % (proc_stdout, os.path.normcase(os.path.abspath(home_dir))))
942        logger.fatal(
943            'ERROR: virtualenv is not compatible with this system or executable')
944        if sys.platform == 'win32':
945            logger.fatal(
946                'Note: some Windows users have reported this error when they installed Python for "Only this user".  The problem may be resolvable if you install Python "For all users".  (See https://bugs.launchpad.net/virtualenv/+bug/352844)')
947        sys.exit(100)
948    else:
949        logger.info('Got sys.prefix result: %r' % proc_stdout)
950
951    pydistutils = os.path.expanduser('~/.pydistutils.cfg')
952    if os.path.exists(pydistutils):
953        logger.notify('Please make sure you remove any previous custom paths from '
954                      'your %s file.' % pydistutils)
955    # pyutilib.virtualenv: ignoring comment
956    return py_executable
957
958def install_activate(home_dir, bin_dir, prompt=None):
959    if sys.platform == 'win32' or is_jython and os._name == 'nt':
960        files = {'activate.bat': ACTIVATE_BAT,
961                 'deactivate.bat': DEACTIVATE_BAT}
962        if os.environ.get('OS') == 'Windows_NT' and os.environ.get('OSTYPE') == 'cygwin':
963            files['activate'] = ACTIVATE_SH
964    else:
965        files = {'activate': ACTIVATE_SH}
966
967        # suppling activate.fish in addition to, not instead of, the
968        # bash script support.
969        files['activate.fish'] = ACTIVATE_FISH
970
971        # same for csh/tcsh support...
972        files['activate.csh'] = ACTIVATE_CSH
973
974
975
976    files['activate_this.py'] = ACTIVATE_THIS
977    vname = os.path.basename(os.path.abspath(home_dir))
978    for name, content in files.items():
979        content = content.replace('__VIRTUAL_PROMPT__', prompt or '')
980        content = content.replace('__VIRTUAL_WINPROMPT__', prompt or '(%s)' % vname)
981        content = content.replace('__VIRTUAL_ENV__', os.path.abspath(home_dir))
982        content = content.replace('__VIRTUAL_NAME__', vname)
983        content = content.replace('__BIN_NAME__', os.path.basename(bin_dir))
984        writefile(os.path.join(bin_dir, name), content)
985
986def install_distutils(home_dir):
987    distutils_path = change_prefix(distutils.__path__[0], home_dir)
988    mkdir(distutils_path)
989    # pyutilib.virtualenv: ignoring comment
990    ## there's a local distutils.cfg with a prefix setting?
991    home_dir = os.path.abspath(home_dir)
992    # pyutilib.virtualenv: ignoring comment
993    #distutils_cfg = DISTUTILS_CFG + "\n[install]\nprefix=%s\n" % home_dir
994    writefile(os.path.join(distutils_path, '__init__.py'), DISTUTILS_INIT)
995    writefile(os.path.join(distutils_path, 'distutils.cfg'), DISTUTILS_CFG, overwrite=False)
996
997def fix_lib64(lib_dir):
998    """
999    Some platforms (particularly Gentoo on x64) put things in lib64/pythonX.Y
1000    instead of lib/pythonX.Y.  If this is such a platform we'll just create a
1001    symlink so lib64 points to lib
1002    """
1003    if [p for p in distutils.sysconfig.get_config_vars().values()
1004        if isinstance(p, basestring) and 'lib64' in p]:
1005        logger.debug('This system uses lib64; symlinking lib64 to lib')
1006        assert os.path.basename(lib_dir) == 'python%s' % sys.version[:3], (
1007            "Unexpected python lib dir: %r" % lib_dir)
1008        lib_parent = os.path.dirname(lib_dir)
1009        assert os.path.basename(lib_parent) == 'lib', (
1010            "Unexpected parent dir: %r" % lib_parent)
1011        copyfile(lib_parent, os.path.join(os.path.dirname(lib_parent), 'lib64'))
1012
1013def resolve_interpreter(exe):
1014    """
1015    If the executable given isn't an absolute path, search $PATH for the interpreter
1016    """
1017    if os.path.abspath(exe) != exe:
1018        paths = os.environ.get('PATH', '').split(os.pathsep)
1019        for path in paths:
1020            if os.path.exists(os.path.join(path, exe)):
1021                exe = os.path.join(path, exe)
1022                break
1023    if not os.path.exists(exe):
1024        logger.fatal('The executable %s (from --python=%s) does not exist' % (exe, exe))
1025        sys.exit(3)
1026    return exe
1027
1028############################################################
1029## Relocating the environment:
1030
1031def make_environment_relocatable(home_dir):
1032    """
1033    Makes the already-existing environment use relative paths, and takes out
1034    the #!-based environment selection in scripts.
1035    """
1036    home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
1037    activate_this = os.path.join(bin_dir, 'activate_this.py')
1038    if not os.path.exists(activate_this):
1039        logger.fatal(
1040            'The environment doesn\'t have a file %s -- please re-run virtualenv '
1041            'on this environment to update it' % activate_this)
1042    fixup_scripts(home_dir)
1043    fixup_pth_and_egg_link(home_dir)
1044    # pyutilib.virtualenv: ignoring comment
1045
1046OK_ABS_SCRIPTS = ['python', 'python%s' % sys.version[:3],
1047                  'activate', 'activate.bat', 'activate_this.py']
1048
1049def fixup_scripts(home_dir):
1050    # This is what we expect at the top of scripts:
1051    shebang = '#!%s/bin/python' % os.path.normcase(os.path.abspath(home_dir))
1052    # This is what we'll put:
1053    new_shebang = '#!/usr/bin/env python%s' % sys.version[:3]
1054    activate = "import os; activate_this=os.path.join(os.path.dirname(__file__), 'activate_this.py'); execfile(activate_this, dict(__file__=activate_this)); del os, activate_this"
1055    if sys.platform == 'win32':
1056        bin_suffix = 'Scripts'
1057    else:
1058        bin_suffix = 'bin'
1059    bin_dir = os.path.join(home_dir, bin_suffix)
1060    home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
1061    for filename in os.listdir(bin_dir):
1062        filename = os.path.join(bin_dir, filename)
1063        if not os.path.isfile(filename):
1064            # ignore subdirs, e.g. .svn ones.
1065            continue
1066        f = open(filename, 'rb')
1067        lines = f.readlines()
1068        f.close()
1069        if not lines:
1070            logger.warn('Script %s is an empty file' % filename)
1071            continue
1072        if not lines[0].strip().startswith(shebang):
1073            if os.path.basename(filename) in OK_ABS_SCRIPTS:
1074                logger.debug('Cannot make script %s relative' % filename)
1075            elif lines[0].strip() == new_shebang:
1076                logger.info('Script %s has already been made relative' % filename)
1077            else:
1078                logger.warn('Script %s cannot be made relative (it\'s not a normal script that starts with %s)'
1079                            % (filename, shebang))
1080            continue
1081        logger.notify('Making script %s relative' % filename)
1082        lines = [new_shebang+'\n', activate+'\n'] + lines[1:]
1083        f = open(filename, 'wb')
1084        f.writelines(lines)
1085        f.close()
1086
1087def fixup_pth_and_egg_link(home_dir, sys_path=None):
1088    """Makes .pth and .egg-link files use relative paths"""
1089    home_dir = os.path.normcase(os.path.abspath(home_dir))
1090    if sys_path is None:
1091        sys_path = sys.path
1092    for path in sys_path:
1093        if not path:
1094            path = '.'
1095        if not os.path.isdir(path):
1096            continue
1097        path = os.path.normcase(os.path.abspath(path))
1098        if not path.startswith(home_dir):
1099            logger.debug('Skipping system (non-environment) directory %s' % path)
1100            continue
1101        for filename in os.listdir(path):
1102            filename = os.path.join(path, filename)
1103            if filename.endswith('.pth'):
1104                if not os.access(filename, os.W_OK):
1105                    logger.warn('Cannot write .pth file %s, skipping' % filename)
1106                else:
1107                    fixup_pth_file(filename)
1108            if filename.endswith('.egg-link'):
1109                if not os.access(filename, os.W_OK):
1110                    logger.warn('Cannot write .egg-link file %s, skipping' % filename)
1111                else:
1112                    fixup_egg_link(filename)
1113
1114def fixup_pth_file(filename):
1115    lines = []
1116    prev_lines = []
1117    f = open(filename)
1118    prev_lines = f.readlines()
1119    f.close()
1120    for line in prev_lines:
1121        line = line.strip()
1122        if (not line or line.startswith('#') or line.startswith('import ')
1123            or os.path.abspath(line) != line):
1124            lines.append(line)
1125        else:
1126            new_value = make_relative_path(filename, line)
1127            if line != new_value:
1128                logger.debug('Rewriting path %s as %s (in %s)' % (line, new_value, filename))
1129            lines.append(new_value)
1130    if lines == prev_lines:
1131        logger.info('No changes to .pth file %s' % filename)
1132        return
1133    logger.notify('Making paths in .pth file %s relative' % filename)
1134    f = open(filename, 'w')
1135    f.write('\n'.join(lines) + '\n')
1136    f.close()
1137
1138def fixup_egg_link(filename):
1139    f = open(filename)
1140    link = f.read().strip()
1141    f.close()
1142    if os.path.abspath(link) != link:
1143        logger.debug('Link in %s already relative' % filename)
1144        return
1145    new_link = make_relative_path(filename, link)
1146    logger.notify('Rewriting link %s in %s as %s' % (link, filename, new_link))
1147    f = open(filename, 'w')
1148    f.write(new_link)
1149    f.close()
1150
1151def make_relative_path(source, dest, dest_is_directory=True):
1152    """
1153    Make a filename relative, where the filename is dest, and it is
1154    being referred to from the filename source.
1155
1156        >>> make_relative_path('/usr/share/something/a-file.pth',
1157        ...                    '/usr/share/another-place/src/Directory')
1158        '../another-place/src/Directory'
1159        >>> make_relative_path('/usr/share/something/a-file.pth',
1160        ...                    '/home/user/src/Directory')
1161        '../../../home/user/src/Directory'
1162        >>> make_relative_path('/usr/share/a-file.pth', '/usr/share/')
1163        './'
1164    """
1165    source = os.path.dirname(source)
1166    if not dest_is_directory:
1167        dest_filename = os.path.basename(dest)
1168        dest = os.path.dirname(dest)
1169    dest = os.path.normpath(os.path.abspath(dest))
1170    source = os.path.normpath(os.path.abspath(source))
1171    dest_parts = dest.strip(os.path.sep).split(os.path.sep)
1172    source_parts = source.strip(os.path.sep).split(os.path.sep)
1173    while dest_parts and source_parts and dest_parts[0] == source_parts[0]:
1174        dest_parts.pop(0)
1175        source_parts.pop(0)
1176    full_parts = ['..']*len(source_parts) + dest_parts
1177    if not dest_is_directory:
1178        full_parts.append(dest_filename)
1179    if not full_parts:
1180        # Special case for the current directory (otherwise it'd be '')
1181        return './'
1182    return os.path.sep.join(full_parts)
1183
1184
1185
1186############################################################
1187## Bootstrap script creation:
1188
1189def create_bootstrap_script(extra_text, python_version=''):
1190    """
1191    Creates a bootstrap script, which is like this script but with
1192    extend_parser, adjust_options, and after_install hooks.
1193
1194    This returns a string that (written to disk of course) can be used
1195    as a bootstrap script with your own customizations.  The script
1196    will be the standard virtualenv.py script, with your extra text
1197    added (your extra text should be Python code).
1198
1199    If you include these functions, they will be called:
1200
1201    ``extend_parser(optparse_parser)``:
1202        You can add or remove options from the parser here.
1203
1204    ``adjust_options(options, args)``:
1205        You can change options here, or change the args (if you accept
1206        different kinds of arguments, be sure you modify ``args`` so it is
1207        only ``[DEST_DIR]``).
1208
1209    ``after_install(options, home_dir)``:
1210
1211        After everything is installed, this function is called.  This
1212        is probably the function you are most likely to use.  An
1213        example would be::
1214
1215            def after_install(options, home_dir):
1216                subprocess.call([join(home_dir, 'bin', 'easy_install'),
1217                                 'MyPackage'])
1218                subprocess.call([join(home_dir, 'bin', 'my-package-script'),
1219                                 'setup', home_dir])
1220
1221        This example immediately installs a package, and runs a setup
1222        script from that package.
1223
1224    If you provide something like ``python_version='2.4'`` then the
1225    script will start with ``#!/usr/bin/env python2.4`` instead of
1226    ``#!/usr/bin/env python``.  You can use this when the script must
1227    be run with a particular Python version.
1228    """
1229    filename = __file__
1230    if filename.endswith('.pyc'):
1231        filename = filename[:-1]
1232    f = open(filename, 'rb')
1233    content = f.read()
1234    f.close()
1235    py_exe = 'python%s' % python_version
1236    content = (('#!/usr/bin/env %s\n' % py_exe)
1237               + '## WARNING: This file is generated\n'
1238               + content)
1239    return content.replace('##EXT' 'END##', extra_text)
1240
1241
1242#
1243# Imported from odict.py
1244#
1245
1246# odict.py
1247# An Ordered Dictionary object
1248# Copyright (C) 2005 Nicola Larosa, Michael Foord
1249# E-mail: nico AT tekNico DOT net, fuzzyman AT voidspace DOT org DOT uk
1250
1251# This software is licensed under the terms of the BSD license.
1252# http://www.voidspace.org.uk/python/license.shtml
1253# Basically you're free to copy, modify, distribute and relicense it,
1254# So long as you keep a copy of the license with it.
1255
1256# Documentation at http://www.voidspace.org.uk/python/odict.html
1257# For information about bugfixes, updates and support, please join the
1258# Pythonutils mailing list:
1259# http://groups.google.com/group/pythonutils/
1260# Comments, suggestions and bug reports welcome.
1261
1262"""A dict that keeps keys in insertion order"""
1263#from __future__ import generators
1264
1265__author__ = ('Nicola Larosa <nico-NoSp@m-tekNico.net>,'
1266    'Michael Foord <fuzzyman AT voidspace DOT org DOT uk>')
1267
1268__docformat__ = "restructuredtext en"
1269
1270__revision__ = '$Id: odict.py 129 2005-09-12 18:15:28Z teknico $'
1271
1272__version__ = '0.2.2'
1273
1274__all__ = ['OrderedDict', 'SequenceOrderedDict']
1275
1276import sys
1277INTP_VER = sys.version_info[:2]
1278if INTP_VER < (2, 2):
1279    raise RuntimeError("Python v.2.2 or later required")
1280
1281import types, warnings
1282
1283class OrderedDict(dict):
1284    """
1285    A class of dictionary that keeps the insertion order of keys.
1286   
1287    All appropriate methods return keys, items, or values in an ordered way.
1288   
1289    All normal dictionary methods are available. Update and comparison is
1290    restricted to other OrderedDict objects.
1291   
1292    Various sequence methods are available, including the ability to explicitly
1293    mutate the key ordering.
1294   
1295    __contains__ tests:
1296   
1297    >>> d = OrderedDict(((1, 3),))
1298    >>> 1 in d
1299    1
1300    >>> 4 in d
1301    0
1302   
1303    __getitem__ tests:
1304   
1305    >>> OrderedDict(((1, 3), (3, 2), (2, 1)))[2]
1306    1
1307    >>> OrderedDict(((1, 3), (3, 2), (2, 1)))[4]
1308    Traceback (most recent call last):
1309    KeyError: 4
1310   
1311    __len__ tests:
1312   
1313    >>> len(OrderedDict())
1314    0
1315    >>> len(OrderedDict(((1, 3), (3, 2), (2, 1))))
1316    3
1317   
1318    get tests:
1319   
1320    >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1321    >>> d.get(1)
1322    3
1323    >>> d.get(4) is None
1324    1
1325    >>> d.get(4, 5)
1326    5
1327    >>> d
1328    OrderedDict([(1, 3), (3, 2), (2, 1)])
1329   
1330    has_key tests:
1331   
1332    >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1333    >>> d.has_key(1)
1334    1
1335    >>> d.has_key(4)
1336    0
1337    """
1338
1339    def __init__(self, init_val=(), strict=False):
1340        """
1341        Create a new ordered dictionary. Cannot init from a normal dict,
1342        nor from kwargs, since items order is undefined in those cases.
1343       
1344        If the ``strict`` keyword argument is ``True`` (``False`` is the
1345        default) then when doing slice assignment - the ``OrderedDict`` you are
1346        assigning from *must not* contain any keys in the remaining dict.
1347       
1348        >>> OrderedDict()
1349        OrderedDict([])
1350        >>> OrderedDict({1: 1})
1351        Traceback (most recent call last):
1352        TypeError: undefined order, cannot get items from dict
1353        >>> OrderedDict({1: 1}.items())
1354        OrderedDict([(1, 1)])
1355        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1356        >>> d
1357        OrderedDict([(1, 3), (3, 2), (2, 1)])
1358        >>> OrderedDict(d)
1359        OrderedDict([(1, 3), (3, 2), (2, 1)])
1360        """
1361        self.strict = strict
1362        dict.__init__(self)
1363        if isinstance(init_val, OrderedDict):
1364            self._sequence = init_val.keys()
1365            dict.update(self, init_val)
1366        elif isinstance(init_val, dict):
1367            # we lose compatibility with other ordered dict types this way
1368            raise TypeError('undefined order, cannot get items from dict')
1369        else:
1370            self._sequence = []
1371            self.update(init_val)
1372
1373### Special methods ###
1374
1375    def __delitem__(self, key):
1376        """
1377        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1378        >>> del d[3]
1379        >>> d
1380        OrderedDict([(1, 3), (2, 1)])
1381        >>> del d[3]
1382        Traceback (most recent call last):
1383        KeyError: 3
1384        >>> d[3] = 2
1385        >>> d
1386        OrderedDict([(1, 3), (2, 1), (3, 2)])
1387        >>> del d[0:1]
1388        >>> d
1389        OrderedDict([(2, 1), (3, 2)])
1390        """
1391        if isinstance(key, types.SliceType):
1392            # NOTE: efficiency?
1393            keys = self._sequence[key]
1394            for entry in keys:
1395                dict.__delitem__(self, entry)
1396            del self._sequence[key]
1397        else:
1398            # do the dict.__delitem__ *first* as it raises
1399            # the more appropriate error
1400            dict.__delitem__(self, key)
1401            self._sequence.remove(key)
1402
1403    def __eq__(self, other):
1404        """
1405        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1406        >>> d == OrderedDict(d)
1407        True
1408        >>> d == OrderedDict(((1, 3), (2, 1), (3, 2)))
1409        False
1410        >>> d == OrderedDict(((1, 0), (3, 2), (2, 1)))
1411        False
1412        >>> d == OrderedDict(((0, 3), (3, 2), (2, 1)))
1413        False
1414        >>> d == dict(d)
1415        False
1416        >>> d == False
1417        False
1418        """
1419        if isinstance(other, OrderedDict):
1420            # NOTE: efficiency?
1421            #   Generate both item lists for each compare
1422            return (self.items() == other.items())
1423        else:
1424            return False
1425
1426    def __lt__(self, other):
1427        """
1428        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1429        >>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
1430        >>> c < d
1431        True
1432        >>> d < c
1433        False
1434        >>> d < dict(c)
1435        Traceback (most recent call last):
1436        TypeError: Can only compare with other OrderedDicts
1437        """
1438        if not isinstance(other, OrderedDict):
1439            raise TypeError('Can only compare with other OrderedDicts')
1440        # NOTE: efficiency?
1441        #   Generate both item lists for each compare
1442        return (self.items() < other.items())
1443
1444    def __le__(self, other):
1445        """
1446        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1447        >>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
1448        >>> e = OrderedDict(d)
1449        >>> c <= d
1450        True
1451        >>> d <= c
1452        False
1453        >>> d <= dict(c)
1454        Traceback (most recent call last):
1455        TypeError: Can only compare with other OrderedDicts
1456        >>> d <= e
1457        True
1458        """
1459        if not isinstance(other, OrderedDict):
1460            raise TypeError('Can only compare with other OrderedDicts')
1461        # NOTE: efficiency?
1462        #   Generate both item lists for each compare
1463        return (self.items() <= other.items())
1464
1465    def __ne__(self, other):
1466        """
1467        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1468        >>> d != OrderedDict(d)
1469        False
1470        >>> d != OrderedDict(((1, 3), (2, 1), (3, 2)))
1471        True
1472        >>> d != OrderedDict(((1, 0), (3, 2), (2, 1)))
1473        True
1474        >>> d == OrderedDict(((0, 3), (3, 2), (2, 1)))
1475        False
1476        >>> d != dict(d)
1477        True
1478        >>> d != False
1479        True
1480        """
1481        if isinstance(other, OrderedDict):
1482            # NOTE: efficiency?
1483            #   Generate both item lists for each compare
1484            return not (self.items() == other.items())
1485        else:
1486            return True
1487
1488    def __gt__(self, other):
1489        """
1490        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1491        >>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
1492        >>> d > c
1493        True
1494        >>> c > d
1495        False
1496        >>> d > dict(c)
1497        Traceback (most recent call last):
1498        TypeError: Can only compare with other OrderedDicts
1499        """
1500        if not isinstance(other, OrderedDict):
1501            raise TypeError('Can only compare with other OrderedDicts')
1502        # NOTE: efficiency?
1503        #   Generate both item lists for each compare
1504        return (self.items() > other.items())
1505
1506    def __ge__(self, other):
1507        """
1508        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1509        >>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
1510        >>> e = OrderedDict(d)
1511        >>> c >= d
1512        False
1513        >>> d >= c
1514        True
1515        >>> d >= dict(c)
1516        Traceback (most recent call last):
1517        TypeError: Can only compare with other OrderedDicts
1518        >>> e >= d
1519        True
1520        """
1521        if not isinstance(other, OrderedDict):
1522            raise TypeError('Can only compare with other OrderedDicts')
1523        # NOTE: efficiency?
1524        #   Generate both item lists for each compare
1525        return (self.items() >= other.items())
1526
1527    def __repr__(self):
1528        """
1529        Used for __repr__ and __str__
1530       
1531        >>> r1 = repr(OrderedDict((('a', 'b'), ('c', 'd'), ('e', 'f'))))
1532        >>> r1
1533        "OrderedDict([('a', 'b'), ('c', 'd'), ('e', 'f')])"
1534        >>> r2 = repr(OrderedDict((('a', 'b'), ('e', 'f'), ('c', 'd'))))
1535        >>> r2
1536        "OrderedDict([('a', 'b'), ('e', 'f'), ('c', 'd')])"
1537        >>> r1 == str(OrderedDict((('a', 'b'), ('c', 'd'), ('e', 'f'))))
1538        True
1539        >>> r2 == str(OrderedDict((('a', 'b'), ('e', 'f'), ('c', 'd'))))
1540        True
1541        """
1542        return '%s([%s])' % (self.__class__.__name__, ', '.join(
1543            ['(%r, %r)' % (key, self[key]) for key in self._sequence]))
1544
1545    def __setitem__(self, key, val):
1546        """
1547        Allows slice assignment, so long as the slice is an OrderedDict
1548        >>> d = OrderedDict()
1549        >>> d['a'] = 'b'
1550        >>> d['b'] = 'a'
1551        >>> d[3] = 12
1552        >>> d
1553        OrderedDict([('a', 'b'), ('b', 'a'), (3, 12)])
1554        >>> d[:] = OrderedDict(((1, 2), (2, 3), (3, 4)))
1555        >>> d
1556        OrderedDict([(1, 2), (2, 3), (3, 4)])
1557        >>> d[::2] = OrderedDict(((7, 8), (9, 10)))
1558        >>> d
1559        OrderedDict([(7, 8), (2, 3), (9, 10)])
1560        >>> d = OrderedDict(((0, 1), (1, 2), (2, 3), (3, 4)))
1561        >>> d[1:3] = OrderedDict(((1, 2), (5, 6), (7, 8)))
1562        >>> d
1563        OrderedDict([(0, 1), (1, 2), (5, 6), (7, 8), (3, 4)])
1564        >>> d = OrderedDict(((0, 1), (1, 2), (2, 3), (3, 4)), strict=True)
1565        >>> d[1:3] = OrderedDict(((1, 2), (5, 6), (7, 8)))
1566        >>> d
1567        OrderedDict([(0, 1), (1, 2), (5, 6), (7, 8), (3, 4)])
1568       
1569        >>> a = OrderedDict(((0, 1), (1, 2), (2, 3)), strict=True)
1570        >>> a[3] = 4
1571        >>> a
1572        OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
1573        >>> a[::1] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
1574        >>> a
1575        OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
1576        >>> a[:2] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)])
1577        Traceback (most recent call last):
1578        ValueError: slice assignment must be from unique keys
1579        >>> a = OrderedDict(((0, 1), (1, 2), (2, 3)))
1580        >>> a[3] = 4
1581        >>> a
1582        OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
1583        >>> a[::1] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
1584        >>> a
1585        OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
1586        >>> a[:2] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
1587        >>> a
1588        OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
1589        >>> a[::-1] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
1590        >>> a
1591        OrderedDict([(3, 4), (2, 3), (1, 2), (0, 1)])
1592       
1593        >>> d = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
1594        >>> d[:1] = 3
1595        Traceback (most recent call last):
1596        TypeError: slice assignment requires an OrderedDict
1597       
1598        >>> d = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
1599        >>> d[:1] = OrderedDict([(9, 8)])
1600        >>> d
1601        OrderedDict([(9, 8), (1, 2), (2, 3), (3, 4)])
1602        """
1603        if isinstance(key, types.SliceType):
1604            if not isinstance(val, OrderedDict):
1605                # NOTE: allow a list of tuples?
1606                raise TypeError('slice assignment requires an OrderedDict')
1607            keys = self._sequence[key]
1608            # NOTE: Could use ``range(*key.indices(len(self._sequence)))``
1609            indexes = range(len(self._sequence))[key]
1610            if key.step is None:
1611                # NOTE: new slice may not be the same size as the one being
1612                #   overwritten !
1613                # NOTE: What is the algorithm for an impossible slice?
1614                #   e.g. d[5:3]
1615                pos = key.start or 0
1616                del self[key]
1617                newkeys = val.keys()
1618                for k in newkeys:
1619                    if k in self:
1620                        if self.strict:
1621                            raise ValueError('slice assignment must be from '
1622                                'unique keys')
1623                        else:
1624                            # NOTE: This removes duplicate keys *first*
1625                            #   so start position might have changed?
1626                            del self[k]
1627                self._sequence = (self._sequence[:pos] + newkeys +
1628                    self._sequence[pos:])
1629                dict.update(self, val)
1630            else:
1631                # extended slice - length of new slice must be the same
1632                # as the one being replaced
1633                if len(keys) != len(val):
1634                    raise ValueError('attempt to assign sequence of size %s '
1635                        'to extended slice of size %s' % (len(val), len(keys)))
1636                # NOTE: efficiency?
1637                del self[key]
1638                item_list = zip(indexes, val.items())
1639                # smallest indexes first - higher indexes not guaranteed to
1640                # exist
1641                item_list.sort()
1642                for pos, (newkey, newval) in item_list:
1643                    if self.strict and newkey in self:
1644                        raise ValueError('slice assignment must be from unique'
1645                            ' keys')
1646                    self.insert(pos, newkey, newval)
1647        else:
1648            if key not in self:
1649                self._sequence.append(key)
1650            dict.__setitem__(self, key, val)
1651
1652    def __getitem__(self, key):
1653        """
1654        Allows slicing. Returns an OrderedDict if you slice.
1655        >>> b = OrderedDict([(7, 0), (6, 1), (5, 2), (4, 3), (3, 4), (2, 5), (1, 6)])
1656        >>> b[::-1]
1657        OrderedDict([(1, 6), (2, 5), (3, 4), (4, 3), (5, 2), (6, 1), (7, 0)])
1658        >>> b[2:5]
1659        OrderedDict([(5, 2), (4, 3), (3, 4)])
1660        >>> type(b[2:4])
1661        <class '__main__.OrderedDict'>
1662        """
1663        if isinstance(key, types.SliceType):
1664            # NOTE: does this raise the error we want?
1665            keys = self._sequence[key]
1666            # NOTE: efficiency?
1667            return OrderedDict([(entry, self[entry]) for entry in keys])
1668        else:
1669            return dict.__getitem__(self, key)
1670
1671    __str__ = __repr__
1672
1673    def __setattr__(self, name, value):
1674        """
1675        Implemented so that accesses to ``sequence`` raise a warning and are
1676        diverted to the new ``setkeys`` method.
1677        """
1678        if name == 'sequence':
1679            warnings.warn('Use of the sequence attribute is deprecated.'
1680                ' Use the keys method instead.', DeprecationWarning)
1681            # NOTE: doesn't return anything
1682            self.setkeys(value)
1683        else:
1684            # NOTE: do we want to allow arbitrary setting of attributes?
1685            #   Or do we want to manage it?
1686            object.__setattr__(self, name, value)
1687
1688    def __getattr__(self, name):
1689        """
1690        Implemented so that access to ``sequence`` raises a warning.
1691       
1692        >>> d = OrderedDict()
1693        >>> d.sequence
1694        []
1695        """
1696        if name == 'sequence':
1697            warnings.warn('Use of the sequence attribute is deprecated.'
1698                ' Use the keys method instead.', DeprecationWarning)
1699            # NOTE: Still (currently) returns a direct reference. Need to
1700            #   because code that uses sequence will expect to be able to
1701            #   mutate it in place.
1702            return self._sequence
1703        else:
1704            # raise the appropriate error
1705            raise AttributeError("OrderedDict has no '%s' attribute" % name)
1706
1707    def __deepcopy__(self, memo):
1708        """
1709        To allow deepcopy to work with OrderedDict.
1710       
1711        >>> from copy import deepcopy
1712        >>> a = OrderedDict([(1, 1), (2, 2), (3, 3)])
1713        >>> a['test'] = {}
1714        >>> b = deepcopy(a)
1715        >>> b == a
1716        True
1717        >>> b is a
1718        False
1719        >>> a['test'] is b['test']
1720        False
1721        """
1722        from copy import deepcopy
1723        return self.__class__(deepcopy(self.items(), memo), self.strict)
1724
1725
1726### Read-only methods ###
1727
1728    def copy(self):
1729        """
1730        >>> OrderedDict(((1, 3), (3, 2), (2, 1))).copy()
1731        OrderedDict([(1, 3), (3, 2), (2, 1)])
1732        """
1733        return OrderedDict(self)
1734
1735    def items(self):
1736        """
1737        ``items`` returns a list of tuples representing all the
1738        ``(key, value)`` pairs in the dictionary.
1739       
1740        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1741        >>> d.items()
1742        [(1, 3), (3, 2), (2, 1)]
1743        >>> d.clear()
1744        >>> d.items()
1745        []
1746        """
1747        return zip(self._sequence, self.values())
1748
1749    def keys(self):
1750        """
1751        Return a list of keys in the ``OrderedDict``.
1752       
1753        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1754        >>> d.keys()
1755        [1, 3, 2]
1756        """
1757        return self._sequence[:]
1758
1759    def values(self, values=None):
1760        """
1761        Return a list of all the values in the OrderedDict.
1762       
1763        Optionally you can pass in a list of values, which will replace the
1764        current list. The value list must be the same len as the OrderedDict.
1765       
1766        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1767        >>> d.values()
1768        [3, 2, 1]
1769        """
1770        return [self[key] for key in self._sequence]
1771
1772    def iteritems(self):
1773        """
1774        >>> ii = OrderedDict(((1, 3), (3, 2), (2, 1))).iteritems()
1775        >>> ii.next()
1776        (1, 3)
1777        >>> ii.next()
1778        (3, 2)
1779        >>> ii.next()
1780        (2, 1)
1781        >>> ii.next()
1782        Traceback (most recent call last):
1783        StopIteration
1784        """
1785        def make_iter(self=self):
1786            keys = self.iterkeys()
1787            while True:
1788                key = keys.next()
1789                yield (key, self[key])
1790        return make_iter()
1791
1792    def iterkeys(self):
1793        """
1794        >>> ii = OrderedDict(((1, 3), (3, 2), (2, 1))).iterkeys()
1795        >>> ii.next()
1796        1
1797        >>> ii.next()
1798        3
1799        >>> ii.next()
1800        2
1801        >>> ii.next()
1802        Traceback (most recent call last):
1803        StopIteration
1804        """
1805        return iter(self._sequence)
1806
1807    __iter__ = iterkeys
1808
1809    def itervalues(self):
1810        """
1811        >>> iv = OrderedDict(((1, 3), (3, 2), (2, 1))).itervalues()
1812        >>> iv.next()
1813        3
1814        >>> iv.next()
1815        2
1816        >>> iv.next()
1817        1
1818        >>> iv.next()
1819        Traceback (most recent call last):
1820        StopIteration
1821        """
1822        def make_iter(self=self):
1823            keys = self.iterkeys()
1824            while True:
1825                yield self[keys.next()]
1826        return make_iter()
1827
1828### Read-write methods ###
1829
1830    def clear(self):
1831        """
1832        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1833        >>> d.clear()
1834        >>> d
1835        OrderedDict([])
1836        """
1837        dict.clear(self)
1838        self._sequence = []
1839
1840    def pop(self, key, *args):
1841        """
1842        No dict.pop in Python 2.2, gotta reimplement it
1843       
1844        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1845        >>> d.pop(3)
1846        2
1847        >>> d
1848        OrderedDict([(1, 3), (2, 1)])
1849        >>> d.pop(4)
1850        Traceback (most recent call last):
1851        KeyError: 4
1852        >>> d.pop(4, 0)
1853        0
1854        >>> d.pop(4, 0, 1)
1855        Traceback (most recent call last):
1856        TypeError: pop expected at most 2 arguments, got 3
1857        """
1858        if len(args) > 1:
1859            raise TypeError, ('pop expected at most 2 arguments, got %s' %
1860                (len(args) + 1))
1861        if key in self:
1862            val = self[key]
1863            del self[key]
1864        else:
1865            try:
1866                val = args[0]
1867            except IndexError:
1868                raise KeyError(key)
1869        return val
1870
1871    def popitem(self, i=-1):
1872        """
1873        Delete and return an item specified by index, not a random one as in
1874        dict. The index is -1 by default (the last item).
1875       
1876        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1877        >>> d.popitem()
1878        (2, 1)
1879        >>> d
1880        OrderedDict([(1, 3), (3, 2)])
1881        >>> d.popitem(0)
1882        (1, 3)
1883        >>> OrderedDict().popitem()
1884        Traceback (most recent call last):
1885        KeyError: 'popitem(): dictionary is empty'
1886        >>> d.popitem(2)
1887        Traceback (most recent call last):
1888        IndexError: popitem(): index 2 not valid
1889        """
1890        if not self._sequence:
1891            raise KeyError('popitem(): dictionary is empty')
1892        try:
1893            key = self._sequence[i]
1894        except IndexError:
1895            raise IndexError('popitem(): index %s not valid' % i)
1896        return (key, self.pop(key))
1897
1898    def setdefault(self, key, defval = None):
1899        """
1900        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1901        >>> d.setdefault(1)
1902        3
1903        >>> d.setdefault(4) is None
1904        True
1905        >>> d
1906        OrderedDict([(1, 3), (3, 2), (2, 1), (4, None)])
1907        >>> d.setdefault(5, 0)
1908        0
1909        >>> d
1910        OrderedDict([(1, 3), (3, 2), (2, 1), (4, None), (5, 0)])
1911        """
1912        if key in self:
1913            return self[key]
1914        else:
1915            self[key] = defval
1916            return defval
1917
1918    def update(self, from_od):
1919        """
1920        Update from another OrderedDict or sequence of (key, value) pairs
1921       
1922        >>> d = OrderedDict(((1, 0), (0, 1)))
1923        >>> d.update(OrderedDict(((1, 3), (3, 2), (2, 1))))
1924        >>> d
1925        OrderedDict([(1, 3), (0, 1), (3, 2), (2, 1)])
1926        >>> d.update({4: 4})
1927        Traceback (most recent call last):
1928        TypeError: undefined order, cannot get items from dict
1929        >>> d.update((4, 4))
1930        Traceback (most recent call last):
1931        TypeError: cannot convert dictionary update sequence element "4" to a 2-item sequence
1932        """
1933        if isinstance(from_od, OrderedDict):
1934            for key, val in from_od.items():
1935                self[key] = val
1936        elif isinstance(from_od, dict):
1937            # we lose compatibility with other ordered dict types this way
1938            raise TypeError('undefined order, cannot get items from dict')
1939        else:
1940            # NOTE: efficiency?
1941            # sequence of 2-item sequences, or error
1942            for item in from_od:
1943                try:
1944                    key, val = item
1945                except TypeError:
1946                    raise TypeError('cannot convert dictionary update'
1947                        ' sequence element "%s" to a 2-item sequence' % item)
1948                self[key] = val
1949
1950    def rename(self, old_key, new_key):
1951        """
1952        Rename the key for a given value, without modifying sequence order.
1953       
1954        For the case where new_key already exists this raise an exception,
1955        since if new_key exists, it is ambiguous as to what happens to the
1956        associated values, and the position of new_key in the sequence.
1957       
1958        >>> od = OrderedDict()
1959        >>> od['a'] = 1
1960        >>> od['b'] = 2
1961        >>> od.items()
1962        [('a', 1), ('b', 2)]
1963        >>> od.rename('b', 'c')
1964        >>> od.items()
1965        [('a', 1), ('c', 2)]
1966        >>> od.rename('c', 'a')
1967        Traceback (most recent call last):
1968        ValueError: New key already exists: 'a'
1969        >>> od.rename('d', 'b')
1970        Traceback (most recent call last):
1971        KeyError: 'd'
1972        """
1973        if new_key == old_key:
1974            # no-op
1975            return
1976        if new_key in self:
1977            raise ValueError("New key already exists: %r" % new_key)
1978        # rename sequence entry
1979        value = self[old_key] 
1980        old_idx = self._sequence.index(old_key)
1981        self._sequence[old_idx] = new_key
1982        # rename internal dict entry
1983        dict.__delitem__(self, old_key)
1984        dict.__setitem__(self, new_key, value)
1985
1986    def setitems(self, items):
1987        """
1988        This method allows you to set the items in the dict.
1989       
1990        It takes a list of tuples - of the same sort returned by the ``items``
1991        method.
1992       
1993        >>> d = OrderedDict()
1994        >>> d.setitems(((3, 1), (2, 3), (1, 2)))
1995        >>> d
1996        OrderedDict([(3, 1), (2, 3), (1, 2)])
1997        """
1998        self.clear()
1999        # NOTE: this allows you to pass in an OrderedDict as well :-)
2000        self.update(items)
2001
2002    def setkeys(self, keys):
2003        """
2004        ``setkeys`` all ows you to pass in a new list of keys which will
2005        replace the current set. This must contain the same set of keys, but
2006        need not be in the same order.
2007       
2008        If you pass in new keys that don't match, a ``KeyError`` will be
2009        raised.
2010       
2011        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
2012        >>> d.keys()
2013        [1, 3, 2]
2014        >>> d.setkeys((1, 2, 3))
2015        >>> d
2016        OrderedDict([(1, 3), (2, 1), (3, 2)])
2017        >>> d.setkeys(['a', 'b', 'c'])
2018        Traceback (most recent call last):
2019        KeyError: 'Keylist is not the same as current keylist.'
2020        """
2021        # NOTE: Efficiency? (use set for Python 2.4 :-)
2022        # NOTE: list(keys) rather than keys[:] because keys[:] returns
2023        #   a tuple, if keys is a tuple.
2024        kcopy = list(keys)
2025        kcopy.sort()
2026        self._sequence.sort()
2027        if kcopy != self._sequence:
2028            raise KeyError('Keylist is not the same as current keylist.')
2029        # NOTE: This makes the _sequence attribute a new object, instead
2030        #       of changing it in place.
2031        # NOTE: efficiency?
2032        self._sequence = list(keys)
2033
2034    def setvalues(self, values):
2035        """
2036        You can pass in a list of values, which will replace the
2037        current list. The value list must be the same len as the OrderedDict.
2038       
2039        (Or a ``ValueError`` is raised.)
2040       
2041        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
2042        >>> d.setvalues((1, 2, 3))
2043        >>> d
2044        OrderedDict([(1, 1), (3, 2), (2, 3)])
2045        >>> d.setvalues([6])
2046        Traceback (most recent call last):
2047        ValueError: Value list is not the same length as the OrderedDict.
2048        """
2049        if len(values) != len(self):
2050            # NOTE: correct error to raise?
2051            raise ValueError('Value list is not the same length as the '
2052                'OrderedDict.')
2053        self.update(zip(self, values))
2054
2055### Sequence Methods ###
2056
2057    def index(self, key):
2058        """
2059        Return the position of the specified key in the OrderedDict.
2060       
2061        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
2062        >>> d.index(3)
2063        1
2064        >>> d.index(4)
2065        Traceback (most recent call last):
2066        ValueError: list.index(x): x not in list
2067        """
2068        return self._sequence.index(key)
2069
2070    def insert(self, index, key, value):
2071        """
2072        Takes ``index``, ``key``, and ``value`` as arguments.
2073       
2074        Sets ``key`` to ``value``, so that ``key`` is at position ``index`` in
2075        the OrderedDict.
2076       
2077        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
2078        >>> d.insert(0, 4, 0)
2079        >>> d
2080        OrderedDict([(4, 0), (1, 3), (3, 2), (2, 1)])
2081        >>> d.insert(0, 2, 1)
2082        >>> d
2083        OrderedDict([(2, 1), (4, 0), (1, 3), (3, 2)])
2084        >>> d.insert(8, 8, 1)
2085        >>> d
2086        OrderedDict([(2, 1), (4, 0), (1, 3), (3, 2), (8, 1)])
2087        """
2088        if key in self:
2089            # NOTE: efficiency?
2090            del self[key]
2091        self._sequence.insert(index, key)
2092        dict.__setitem__(self, key, value)
2093
2094    def reverse(self):
2095        """
2096        Reverse the order of the OrderedDict.
2097       
2098        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
2099        >>> d.reverse()
2100        >>> d
2101        OrderedDict([(2, 1), (3, 2), (1, 3)])
2102        """
2103        self._sequence.reverse()
2104
2105    def sort(self, *args, **kwargs):
2106        """
2107        Sort the key order in the OrderedDict.
2108       
2109        This method takes the same arguments as the ``list.sort`` method on
2110        your version of Python.
2111       
2112        >>> d = OrderedDict(((4, 1), (2, 2), (3, 3), (1, 4)))
2113        >>> d.sort()
2114        >>> d
2115        OrderedDict([(1, 4), (2, 2), (3, 3), (4, 1)])
2116        """
2117        self._sequence.sort(*args, **kwargs)
2118
2119class Keys(object):
2120    # NOTE: should this object be a subclass of list?
2121    """
2122    Custom object for accessing the keys of an OrderedDict.
2123   
2124    Can be called like the normal ``OrderedDict.keys`` method, but also
2125    supports indexing and sequence methods.
2126    """
2127
2128    def __init__(self, main):
2129        self._main = main
2130
2131    def __call__(self):
2132        """Pretend to be the keys method."""
2133        return self._main._keys()
2134
2135    def __getitem__(self, index):
2136        """Fetch the key at position i."""
2137        # NOTE: this automatically supports slicing :-)
2138        return self._main._sequence[index]
2139
2140    def __setitem__(self, index, name):
2141        """
2142        You cannot assign to keys, but you can do slice assignment to re-order
2143        them.
2144       
2145        You can only do slice assignment if the new set of keys is a reordering
2146        of the original set.
2147        """
2148        if isinstance(index, types.SliceType):
2149            # NOTE: efficiency?
2150            # check length is the same
2151            indexes = range(len(self._main._sequence))[index]
2152            if len(indexes) != len(name):
2153                raise ValueError('attempt to assign sequence of size %s '
2154                    'to slice of size %s' % (len(name), len(indexes)))
2155            # check they are the same keys
2156            # NOTE: Use set
2157            old_keys = self._main._sequence[index]
2158            new_keys = list(name)
2159            old_keys.sort()
2160            new_keys.sort()
2161            if old_keys != new_keys:
2162                raise KeyError('Keylist is not the same as current keylist.')
2163            orig_vals = [self._main[k] for k in name]
2164            del self._main[index]
2165            vals = zip(indexes, name, orig_vals)
2166            vals.sort()
2167            for i, k, v in vals:
2168                if self._main.strict and k in self._main:
2169                    raise ValueError('slice assignment must be from '
2170                        'unique keys')
2171                self._main.insert(i, k, v)
2172        else:
2173            raise ValueError('Cannot assign to keys')
2174
2175    ### following methods pinched from UserList and adapted ###
2176    def __repr__(self): return repr(self._main._sequence)
2177
2178    # NOTE: do we need to check if we are comparing with another ``Keys``
2179    #   object? (like the __cast method of UserList)
2180    def __lt__(self, other): return self._main._sequence <  other
2181    def __le__(self, other): return self._main._sequence <= other
2182    def __eq__(self, other): return self._main._sequence == other
2183    def __ne__(self, other): return self._main._sequence != other
2184    def __gt__(self, other): return self._main._sequence >  other
2185    def __ge__(self, other): return self._main._sequence >= other
2186    # NOTE: do we need __cmp__ as well as rich comparisons?
2187    def __cmp__(self, other): return cmp(self._main._sequence, other)
2188
2189    def __contains__(self, item): return item in self._main._sequence
2190    def __len__(self): return len(self._main._sequence)
2191    def __iter__(self): return self._main.iterkeys()
2192    def count(self, item): return self._main._sequence.count(item)
2193    def index(self, item, *args): return self._main._sequence.index(item, *args)
2194    def reverse(self): self._main._sequence.reverse()
2195    def sort(self, *args, **kwds): self._main._sequence.sort(*args, **kwds)
2196    def __mul__(self, n): return self._main._sequence*n
2197    __rmul__ = __mul__
2198    def __add__(self, other): return self._main._sequence + other
2199    def __radd__(self, other): return other + self._main._sequence
2200
2201    ## following methods not implemented for keys ##
2202    def __delitem__(self, i): raise TypeError('Can\'t delete items from keys')
2203    def __iadd__(self, other): raise TypeError('Can\'t add in place to keys')
2204    def __imul__(self, n): raise TypeError('Can\'t multiply keys in place')
2205    def append(self, item): raise TypeError('Can\'t append items to keys')
2206    def insert(self, i, item): raise TypeError('Can\'t insert items into keys')
2207    def pop(self, i=-1): raise TypeError('Can\'t pop items from keys')
2208    def remove(self, item): raise TypeError('Can\'t remove items from keys')
2209    def extend(self, other): raise TypeError('Can\'t extend keys')
2210
2211class Items(object):
2212    """
2213    Custom object for accessing the items of an OrderedDict.
2214   
2215    Can be called like the normal ``OrderedDict.items`` method, but also
2216    supports indexing and sequence methods.
2217    """
2218
2219    def __init__(self, main):
2220        self._main = main
2221
2222    def __call__(self):
2223        """Pretend to be the items method."""
2224        return self._main._items()
2225
2226    def __getitem__(self, index):
2227        """Fetch the item at position i."""
2228        if isinstance(index, types.SliceType):
2229            # fetching a slice returns an OrderedDict
2230            return self._main[index].items()
2231        key = self._main._sequence[index]
2232        return (key, self._main[key])
2233
2234    def __setitem__(self, index, item):
2235        """Set item at position i to item."""
2236        if isinstance(index, types.SliceType):
2237            # NOTE: item must be an iterable (list of tuples)
2238            self._main[index] = OrderedDict(item)
2239        else:
2240            # NOTE: Does this raise a sensible error?
2241            orig = self._main.keys[index]
2242            key, value = item
2243            if self._main.strict and key in self and (key != orig):
2244                raise ValueError('slice assignment must be from '
2245                        'unique keys')
2246            # delete the current one
2247            del self._main[self._main._sequence[index]]
2248            self._main.insert(index, key, value)
2249
2250    def __delitem__(self, i):
2251        """Delete the item at position i."""
2252        key = self._main._sequence[i]
2253        if isinstance(i, types.SliceType):
2254            for k in key:
2255                # NOTE: efficiency?
2256                del self._main[k]
2257        else:
2258            del self._main[key]
2259
2260    ### following methods pinched from UserList and adapted ###
2261    def __repr__(self): return repr(self._main.items())
2262
2263    # NOTE: do we need to check if we are comparing with another ``Items``
2264    #   object? (like the __cast method of UserList)
2265    def __lt__(self, other): return self._main.items() <  other
2266    def __le__(self, other): return self._main.items() <= other
2267    def __eq__(self, other): return self._main.items() == other
2268    def __ne__(self, other): return self._main.items() != other
2269    def __gt__(self, other): return self._main.items() >  other
2270    def __ge__(self, other): return self._main.items() >= other
2271    def __cmp__(self, other): return cmp(self._main.items(), other)
2272
2273    def __contains__(self, item): return item in self._main.items()
2274    def __len__(self): return len(self._main._sequence) # easier :-)
2275    def __iter__(self): return self._main.iteritems()
2276    def count(self, item): return self._main.items().count(item)
2277    def index(self, item, *args): return self._main.items().index(item, *args)
2278    def reverse(self): self._main.reverse()
2279    def sort(self, *args, **kwds): self._main.sort(*args, **kwds)
2280    def __mul__(self, n): return self._main.items()*n
2281    __rmul__ = __mul__
2282    def __add__(self, other): return self._main.items() + other
2283    def __radd__(self, other): return other + self._main.items()
2284
2285    def append(self, item):
2286        """Add an item to the end."""
2287        # NOTE: this is only append if the key isn't already present
2288        key, value = item
2289        self._main[key] = value
2290
2291    def insert(self, i, item):
2292        key, value = item
2293        self._main.insert(i, key, value)
2294
2295    def pop(self, i=-1):
2296        key = self._main._sequence[i]
2297        return (key, self._main.pop(key))
2298
2299    def remove(self, item):
2300        key, value = item
2301        try:
2302            assert value == self._main[key]
2303        except (KeyError, AssertionError):
2304            raise ValueError('ValueError: list.remove(x): x not in list')
2305        else:
2306            del self._main[key]
2307
2308    def extend(self, other):
2309        # NOTE: is only a true extend if none of the keys already present
2310        for item in other:
2311            key, value = item
2312            self._main[key] = value
2313
2314    def __iadd__(self, other):
2315        self.extend(other)
2316
2317    ## following methods not implemented for items ##
2318
2319    def __imul__(self, n): raise TypeError('Can\'t multiply items in place')
2320
2321class Values(object):
2322    """
2323    Custom object for accessing the values of an OrderedDict.
2324   
2325    Can be called like the normal ``OrderedDict.values`` method, but also
2326    supports indexing and sequence methods.
2327    """
2328
2329    def __init__(self, main):
2330        self._main = main
2331
2332    def __call__(self):
2333        """Pretend to be the values method."""
2334        return self._main._values()
2335
2336    def __getitem__(self, index):
2337        """Fetch the value at position i."""
2338        if isinstance(index, types.SliceType):
2339            return [self._main[key] for key in self._main._sequence[index]]
2340        else:
2341            return self._main[self._main._sequence[index]]
2342
2343    def __setitem__(self, index, value):
2344        """
2345        Set the value at position i to value.
2346       
2347        You can only do slice assignment to values if you supply a sequence of
2348        equal length to the slice you are replacing.
2349        """
2350        if isinstance(index, types.SliceType):
2351            keys = self._main._sequence[index]
2352            if len(keys) != len(value):
2353                raise ValueError('attempt to assign sequence of size %s '
2354                    'to slice of size %s' % (len(name), len(keys)))
2355            # NOTE: efficiency?  Would be better to calculate the indexes
2356            #   directly from the slice object
2357            # NOTE: the new keys can collide with existing keys (or even
2358            #   contain duplicates) - these will overwrite
2359            for key, val in zip(keys, value):
2360                self._main[key] = val
2361        else:
2362            self._main[self._main._sequence[index]] = value
2363
2364    ### following methods pinched from UserList and adapted ###
2365    def __repr__(self): return repr(self._main.values())
2366
2367    # NOTE: do we need to check if we are comparing with another ``Values``
2368    #   object? (like the __cast method of UserList)
2369    def __lt__(self, other): return self._main.values() <  other
2370    def __le__(self, other): return self._main.values() <= other
2371    def __eq__(self, other): return self._main.values() == other
2372    def __ne__(self, other): return self._main.values() != other
2373    def __gt__(self, other): return self._main.values() >  other
2374    def __ge__(self, other): return self._main.values() >= other
2375    def __cmp__(self, other): return cmp(self._main.values(), other)
2376
2377    def __contains__(self, item): return item in self._main.values()
2378    def __len__(self): return len(self._main._sequence) # easier :-)
2379    def __iter__(self): return self._main.itervalues()
2380    def count(self, item): return self._main.values().count(item)
2381    def index(self, item, *args): return self._main.values().index(item, *args)
2382
2383    def reverse(self):
2384        """Reverse the values"""
2385        vals = self._main.values()
2386        vals.reverse()
2387        # NOTE: efficiency
2388        self[:] = vals
2389
2390    def sort(self, *args, **kwds):
2391        """Sort the values."""
2392        vals = self._main.values()
2393        vals.sort(*args, **kwds)
2394        self[:] = vals
2395
2396    def __mul__(self, n): return self._main.values()*n
2397    __rmul__ = __mul__
2398    def __add__(self, other): return self._main.values() + other
2399    def __radd__(self, other): return other + self._main.values()
2400
2401    ## following methods not implemented for values ##
2402    def __delitem__(self, i): raise TypeError('Can\'t delete items from values')
2403    def __iadd__(self, other): raise TypeError('Can\'t add in place to values')
2404    def __imul__(self, n): raise TypeError('Can\'t multiply values in place')
2405    def append(self, item): raise TypeError('Can\'t append items to values')
2406    def insert(self, i, item): raise TypeError('Can\'t insert items into values')
2407    def pop(self, i=-1): raise TypeError('Can\'t pop items from values')
2408    def remove(self, item): raise TypeError('Can\'t remove items from values')
2409    def extend(self, other): raise TypeError('Can\'t extend values')
2410
2411class SequenceOrderedDict(OrderedDict):
2412    """
2413    Experimental version of OrderedDict that has a custom object for ``keys``,
2414    ``values``, and ``items``.
2415   
2416    These are callable sequence objects that work as methods, or can be
2417    manipulated directly as sequences.
2418   
2419    Test for ``keys``, ``items`` and ``values``.
2420   
2421    >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)))
2422    >>> d
2423    SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
2424    >>> d.keys
2425    [1, 2, 3]
2426    >>> d.keys()
2427    [1, 2, 3]
2428    >>> d.setkeys((3, 2, 1))
2429    >>> d
2430    SequenceOrderedDict([(3, 4), (2, 3), (1, 2)])
2431    >>> d.setkeys((1, 2, 3))
2432    >>> d.keys[0]
2433    1
2434    >>> d.keys[:]
2435    [1, 2, 3]
2436    >>> d.keys[-1]
2437    3
2438    >>> d.keys[-2]
2439    2
2440    >>> d.keys[0:2] = [2, 1]
2441    >>> d
2442    SequenceOrderedDict([(2, 3), (1, 2), (3, 4)])
2443    >>> d.keys.reverse()
2444    >>> d.keys
2445    [3, 1, 2]
2446    >>> d.keys = [1, 2, 3]
2447    >>> d
2448    SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
2449    >>> d.keys = [3, 1, 2]
2450    >>> d
2451    SequenceOrderedDict([(3, 4), (1, 2), (2, 3)])
2452    >>> a = SequenceOrderedDict()
2453    >>> b = SequenceOrderedDict()
2454    >>> a.keys == b.keys
2455    1
2456    >>> a['a'] = 3
2457    >>> a.keys == b.keys
2458    0
2459    >>> b['a'] = 3
2460    >>> a.keys == b.keys
2461    1
2462    >>> b['b'] = 3
2463    >>> a.keys == b.keys
2464    0
2465    >>> a.keys > b.keys
2466    0
2467    >>> a.keys < b.keys
2468    1
2469    >>> 'a' in a.keys
2470    1
2471    >>> len(b.keys)
2472    2
2473    >>> 'c' in d.keys
2474    0
2475    >>> 1 in d.keys
2476    1
2477    >>> [v for v in d.keys]
2478    [3, 1, 2]
2479    >>> d.keys.sort()
2480    >>> d.keys
2481    [1, 2, 3]
2482    >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)), strict=True)
2483    >>> d.keys[::-1] = [1, 2, 3]
2484    >>> d
2485    SequenceOrderedDict([(3, 4), (2, 3), (1, 2)])
2486    >>> d.keys[:2]
2487    [3, 2]
2488    >>> d.keys[:2] = [1, 3]
2489    Traceback (most recent call last):
2490    KeyError: 'Keylist is not the same as current keylist.'
2491
2492    >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)))
2493    >>> d
2494    SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
2495    >>> d.values
2496    [2, 3, 4]
2497    >>> d.values()
2498    [2, 3, 4]
2499    >>> d.setvalues((4, 3, 2))
2500    >>> d
2501    SequenceOrderedDict([(1, 4), (2, 3), (3, 2)])
2502    >>> d.values[::-1]
2503    [2, 3, 4]
2504    >>> d.values[0]
2505    4
2506    >>> d.values[-2]
2507    3
2508    >>> del d.values[0]
2509    Traceback (most recent call last):
2510    TypeError: Can't delete items from values
2511    >>> d.values[::2] = [2, 4]
2512    >>> d
2513    SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
2514    >>> 7 in d.values
2515    0
2516    >>> len(d.values)
2517    3
2518    >>> [val for val in d.values]
2519    [2, 3, 4]
2520    >>> d.values[-1] = 2
2521    >>> d.values.count(2)
2522    2
2523    >>> d.values.index(2)
2524    0
2525    >>> d.values[-1] = 7
2526    >>> d.values
2527    [2, 3, 7]
2528    >>> d.values.reverse()
2529    >>> d.values
2530    [7, 3, 2]
2531    >>> d.values.sort()
2532    >>> d.values
2533    [2, 3, 7]
2534    >>> d.values.append('anything')
2535    Traceback (most recent call last):
2536    TypeError: Can't append items to values
2537    >>> d.values = (1, 2, 3)
2538    >>> d
2539    SequenceOrderedDict([(1, 1), (2, 2), (3, 3)])
2540   
2541    >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)))
2542    >>> d
2543    SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
2544    >>> d.items()
2545    [(1, 2), (2, 3), (3, 4)]
2546    >>> d.setitems([(3, 4), (2 ,3), (1, 2)])
2547    >>> d
2548    SequenceOrderedDict([(3, 4), (2, 3), (1, 2)])
2549    >>> d.items[0]
2550    (3, 4)
2551    >>> d.items[:-1]
2552    [(3, 4), (2, 3)]
2553    >>> d.items[1] = (6, 3)
2554    >>> d.items
2555    [(3, 4), (6, 3), (1, 2)]
2556    >>> d.items[1:2] = [(9, 9)]
2557    >>> d
2558    SequenceOrderedDict([(3, 4), (9, 9), (1, 2)])
2559    >>> del d.items[1:2]
2560    >>> d
2561    SequenceOrderedDict([(3, 4), (1, 2)])
2562    >>> (3, 4) in d.items
2563    1
2564    >>> (4, 3) in d.items
2565    0
2566    >>> len(d.items)
2567    2
2568    >>> [v for v in d.items]
2569    [(3, 4), (1, 2)]
2570    >>> d.items.count((3, 4))
2571    1
2572    >>> d.items.index((1, 2))
2573    1
2574    >>> d.items.index((2, 1))
2575    Traceback (most recent call last):
2576    ValueError: list.index(x): x not in list
2577    >>> d.items.reverse()
2578    >>> d.items
2579    [(1, 2), (3, 4)]
2580    >>> d.items.reverse()
2581    >>> d.items.sort()
2582    >>> d.items
2583    [(1, 2), (3, 4)]
2584    >>> d.items.append((5, 6))
2585    >>> d.items
2586    [(1, 2), (3, 4), (5, 6)]
2587    >>> d.items.insert(0, (0, 0))
2588    >>> d.items
2589    [(0, 0), (1, 2), (3, 4), (5, 6)]
2590    >>> d.items.insert(-1, (7, 8))
2591    >>> d.items
2592    [(0, 0), (1, 2), (3, 4), (7, 8), (5, 6)]
2593    >>> d.items.pop()
2594    (5, 6)
2595    >>> d.items
2596    [(0, 0), (1, 2), (3, 4), (7, 8)]
2597    >>> d.items.remove((1, 2))
2598    >>> d.items
2599    [(0, 0), (3, 4), (7, 8)]
2600    >>> d.items.extend([(1, 2), (5, 6)])
2601    >>> d.items
2602    [(0, 0), (3, 4), (7, 8), (1, 2), (5, 6)]
2603    """
2604
2605    def __init__(self, init_val=(), strict=True):
2606        OrderedDict.__init__(self, init_val, strict=strict)
2607        self._keys = self.keys
2608        self._values = self.values
2609        self._items = self.items
2610        self.keys = Keys(self)
2611        self.values = Values(self)
2612        self.items = Items(self)
2613        self._att_dict = {
2614            'keys': self.setkeys,
2615            'items': self.setitems,
2616            'values': self.setvalues,
2617        }
2618
2619    def __setattr__(self, name, value):
2620        """Protect keys, items, and values."""
2621        if not '_att_dict' in self.__dict__:
2622            object.__setattr__(self, name, value)
2623        else:
2624            try:
2625                fun = self._att_dict[name]
2626            except KeyError:
2627                OrderedDict.__setattr__(self, name, value)
2628            else:
2629                fun(value)
2630
2631
2632
2633
2634#
2635# Imported from OrderedConfigParser.py
2636#
2637
2638#  _________________________________________________________________________
2639#
2640#  PyUtilib: A Python utility library.
2641#  Copyright (c) 2008 Sandia Corporation.
2642#  This software is distributed under the BSD License.
2643#  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
2644#  the U.S. Government retains certain rights in this software.
2645#  _________________________________________________________________________
2646#
2647
2648import ConfigParser
2649import StringIO
2650
2651if not 'OrderedDict' in dir():
2652    from odict import OrderedDict
2653
2654
2655class OrderedConfigParser(ConfigParser.ConfigParser):
2656    """
2657    Customization of ConfigParser to (a) use an ordered dictionary and (b)
2658    keep the original case of the data keys.
2659    """
2660
2661    def __init__(self):
2662        if sys.version >= (2,6,0):
2663            ConfigParser.ConfigParser.__init__(self, dict_type=OrderedDict)
2664        else:
2665            ConfigParser.ConfigParser.__init__(self)
2666            self._defaults = OrderedDict()
2667            self._sections = OrderedDict()
2668
2669    def _get_sections(self, fp):
2670        """
2671        In old version of Python, we prefetch the sections, to
2672        ensure that the data structures we are using are OrderedDict.
2673        """
2674        if sys.version >= (2,6,0):
2675            return
2676        while True:
2677            line = fp.readline()
2678            if not line:
2679                break
2680            line.strip()
2681            mo = self.SECTCRE.match(line)
2682            if mo:
2683                sectname = mo.group('header')
2684                if not sectname in self._sections:
2685                    self._sections[sectname] = OrderedDict()
2686                    self._sections[sectname]['__name__'] = sectname
2687
2688    def _read(self, fp, fpname):
2689        """Parse a sectoned setup file.
2690
2691        This first calls _get_sections to preparse the section info,
2692        and then calls the ConfigParser._read method.
2693        """
2694        self._get_sections(fp)
2695        fp.seek(0)
2696        return ConfigParser.ConfigParser._read(self, fp, fpname)
2697
2698    def optionxform(self, option):
2699        """Do not convert to lower case"""
2700        return option
2701
2702
2703
2704#
2705# Imported from header.py
2706#
2707
2708#  _________________________________________________________________________
2709#
2710#  PyUtilib: A Python utility library.
2711#  Copyright (c) 2008 Sandia Corporation.
2712#  This software is distributed under the BSD License.
2713#  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
2714#  the U.S. Government retains certain rights in this software.
2715#  _________________________________________________________________________
2716#
2717#
2718# This script was created with the virtualenv_install script.
2719#
2720
2721import commands
2722import re
2723import urllib2
2724import zipfile
2725import shutil
2726import string
2727import textwrap
2728import sys
2729import glob
2730import errno
2731import stat
2732
2733using_subversion = True
2734
2735#
2736# Working around error with PYTHONHOME
2737#
2738if 'PYTHONHOME' in os.environ:
2739    del os.environ['PYTHONHOME']
2740    print "WARNING: ignoring the value of the PYTHONHOME environment variable!  This value can corrupt the virtual python installation."
2741
2742#
2743# The following taken from PyUtilib
2744#
2745if (sys.platform[0:3] == "win"): #pragma:nocover
2746   executable_extension=".exe"
2747else:                            #pragma:nocover
2748   executable_extension=""
2749
2750
2751def search_file(filename, search_path=None, implicitExt=executable_extension, executable=False,         isfile=True):
2752    if search_path is None:
2753        #
2754        # Use the PATH environment if it is defined and not empty
2755        #
2756        if "PATH" in os.environ and os.environ["PATH"] != "":
2757            search_path = string.split(os.environ["PATH"], os.pathsep)
2758        else:
2759            search_path = os.defpath.split(os.pathsep)
2760    for path in search_path:
2761      if os.path.exists(os.path.join(path, filename)) and \
2762         (not isfile or os.path.isfile(os.path.join(path, filename))):
2763         if not executable or os.access(os.path.join(path,filename),os.X_OK):
2764            return os.path.abspath(os.path.join(path, filename))
2765      if os.path.exists(os.path.join(path, filename+implicitExt)) and \
2766         (not isfile or os.path.isfile(os.path.join(path, filename+implicitExt))):
2767         if not executable or os.access(os.path.join(path,filename+implicitExt),os.X_OK):
2768            return os.path.abspath(os.path.join(path, filename+implicitExt))
2769    return None
2770
2771#
2772# PyUtilib Ends
2773#
2774
2775
2776#
2777# The following taken from pkg_resources
2778#
2779component_re = re.compile(r'(\d+ | [a-z]+ | \.| -)', re.VERBOSE)
2780replace = {'pre':'c', 'preview':'c','-':'final-','rc':'c','dev':'@'}.get
2781
2782def _parse_version_parts(s):
2783    for part in component_re.split(s):
2784        part = replace(part,part)
2785        if not part or part=='.':
2786            continue
2787        if part[:1] in '0123456789':
2788            yield part.zfill(8)    # pad for numeric comparison
2789        else:
2790            yield '*'+part
2791
2792    yield '*final'  # ensure that alpha/beta/candidate are before final
2793
2794def parse_version(s):
2795    parts = []
2796    for part in _parse_version_parts(s.lower()):
2797        if part.startswith('*'):
2798            if part<'*final':   # remove '-' before a prerelease tag
2799                while parts and parts[-1]=='*final-': parts.pop()
2800            # remove trailing zeros from each series of numeric parts
2801            while parts and parts[-1]=='00000000':
2802                parts.pop()
2803        parts.append(part)
2804    return tuple(parts)
2805#
2806# pkg_resources Ends
2807#
2808
2809#
2810# Use pkg_resources to guess version.
2811# This allows for parsing version with the syntax:
2812#   9.3.2
2813#   8.28.rc1
2814#
2815def guess_release(svndir):
2816    if using_subversion:
2817        output = commands.getoutput('svn ls '+svndir)
2818        if output=="":
2819            return None
2820        #print output
2821        versions = []
2822# This allows for parsing version with the syntax:
2823#   9.3.2
2824#   8.28.rc1
2825#
2826def guess_release(svndir):
2827    if using_subversion:
2828        output = commands.getoutput('svn ls '+svndir)
2829        if output=="":
2830            return None
2831        #print output
2832        versions = []
2833        for link in re.split('/',output.strip()):
2834            tmp = link.strip()
2835            if tmp != '':
2836                versions.append( tmp )
2837        #print versions
2838    else:
2839        if sys.version_info[:2] <= (2,5):
2840            output = urllib2.urlopen(svndir).read()
2841        else:
2842            output = urllib2.urlopen(svndir, timeout=30).read()
2843        if output=="":
2844            return None
2845        links = re.findall('\<li>\<a href[^>]+>[^\<]+\</a>',output)
2846        versions = []
2847        for link in links:
2848            versions.append( re.split('>', link[:-5])[-1] )
2849    latest = None
2850    latest_str = None
2851    for version in versions:
2852        if version is '.':
2853            continue
2854        v = parse_version(version)
2855        if latest is None or latest < v:
2856            latest = v
2857            latest_str = version
2858    if latest_str is None:
2859        return None
2860    if not latest_str[0] in '0123456789':
2861        return svndir
2862    return svndir+"/"+latest_str
2863
2864
2865
2866def zip_file(filename,fdlist):
2867    zf = zipfile.ZipFile(filename, 'w')
2868    for file in fdlist:
2869        if os.path.isdir(file):
2870            for root, dirs, files in os.walk(file):
2871                if root.startswith(file+os.sep+'lib') or root.startswith(file+os.sep+'bin'):
2872                    continue
2873                for fname in files:
2874                    if fname.endswith('pyc') or fname.endswith('pyo') or fname.endswith('zip'):
2875                        continue
2876                    if fname.endswith('exe'):
2877                        zf.external_attr = (0777 << 16L) | (010 << 28L)
2878                    else:
2879                        zf.external_attr = (0660 << 16L) | (010 << 28L)
2880                    zf.write(join(root,fname))
2881        else:
2882            zf.write(file)
2883    zf.close()
2884
2885
2886def unzip_file(filename, dir=None):
2887    fname = os.path.abspath(filename)
2888    zf = zipfile.ZipFile(fname, 'r')
2889    if dir is None:
2890        dir = os.getcwd()
2891    for file in zf.infolist():
2892        name = file.filename
2893        if name.endswith('/') or name.endswith('\\'):
2894            outfile = os.path.join(dir, name)
2895            if not os.path.exists(outfile):
2896                os.makedirs(outfile)
2897        else:
2898            outfile = os.path.join(dir, name)
2899            parent = os.path.dirname(outfile)
2900            if not os.path.exists(parent):
2901                os.makedirs(parent)
2902            OUTPUT = open(outfile, 'wb')
2903            OUTPUT.write(zf.read(name))
2904            OUTPUT.close()
2905    zf.close()
2906
2907
2908
2909class Repository(object):
2910
2911    svn_get='checkout'
2912    easy_install_path = ["easy_install"]
2913    python = "python"
2914    svn = "svn"
2915    dev = []
2916
2917    def __init__(self, name, root=None, trunk=None, stable=None, release=None, tag=None, pyname=None, pypi=None, dev=False, username=None, install=True, rev=None, local=None):
2918        class _TEMP_(object): pass
2919        self.config = _TEMP_()
2920        self.config.name=name
2921        self.config.root=root
2922        self.config.trunk=trunk
2923        self.config.stable=stable
2924        self.config.release=release
2925        self.config.tag=tag
2926        self.config.pyname=pyname
2927        self.config.pypi=pypi
2928        self.config.local=local
2929        if dev == 'True' or dev is True:
2930            self.config.dev=True
2931        else:
2932            self.config.dev=False
2933        self.config.username=username
2934        if install == 'False' or install is False:
2935            self.config.install=False
2936        else:
2937            self.config.install=True
2938        self.config.rev=rev
2939        self.initialize(self.config)
2940
2941    def initialize(self, config):
2942        self.name = config.name
2943        self.root = config.root
2944        self.trunk = None
2945        self.trunk_root = None
2946        self.stable = None
2947        self.stable_root = None
2948        self.release = None
2949        self.tag = None
2950        self.release_root = None
2951        #
2952        self.pypi = config.pypi
2953        self.local = config.local
2954        if not config.pypi is None:
2955            self.pyname=config.pypi
2956        else:
2957            self.pyname=config.pyname
2958        self.dev = config.dev
2959        if config.dev:
2960            Repository.dev.append(config.name)
2961        self.pkgdir = None
2962        self.pkgroot = None
2963        if config.username is None or '$' in config.username:
2964            self.svn_username = []
2965        else:
2966            self.svn_username = ['--username', config.username]
2967        if config.rev is None:
2968            self.rev=''
2969            self.revarg=[]
2970        else:
2971            self.rev='@'+config.rev
2972            self.revarg=['-r',config.rev]
2973        self.install = config.install
2974
2975    def guess_versions(self, offline=False):
2976        if not self.config.root is None:
2977            if not offline:
2978                if using_subversion:
2979                    rootdir_output = commands.getoutput('svn ls ' + self.config.root)
2980                else:
2981                    if sys.version_info[:2] <= (2,5):
2982                        rootdir_output = urllib2.urlopen(self.config.root).read()
2983                    else:
2984                        rootdir_output = urllib2.urlopen(self.config.root, timeout=30).read()
2985            self.trunk = self.config.root+'/trunk'
2986            self.trunk_root = self.trunk
2987            try:
2988                if offline or not 'stable' in rootdir_output:
2989                    raise IOError
2990                self.stable = guess_release(self.config.root+'/stable')
2991                self.stable_root = self.stable
2992            except (urllib2.HTTPError,IOError):
2993                self.stable = None
2994                self.stable_root = None
2995            try:
2996                if offline or not 'releases' in rootdir_output:
2997                    raise IOError
2998                self.release = guess_release(self.config.root+'/releases')
2999                self.tag = None
3000                self.release_root = self.release
3001            except (urllib2.HTTPError,IOError):
3002                try:
3003                    if offline or not 'tags' in rootdir_output:
3004                        raise IOError
3005                    self.release = guess_release(self.config.root+'/tags')
3006                    self.tag = self.release
3007                    self.release_root = self.release
3008                except (urllib2.HTTPError,IOError):
3009                    self.release = None
3010                    self.release_root = None
3011        if not self.config.trunk is None:
3012            if self.trunk is None:
3013                self.trunk = self.config.trunk
3014            else:
3015                self.trunk += self.config.trunk
3016        if not self.config.stable is None:
3017            if self.stable is None:
3018                self.stable = self.config.stable
3019            else:
3020                self.stable += self.config.stable
3021        if not self.config.release is None:
3022            if self.release is None:
3023                self.release = self.config.release
3024            else:
3025                self.release += self.config.release
3026        if not self.config.tag is None:
3027            if self.release is None:
3028                self.release = self.config.tag
3029            else:
3030                self.release += self.config.tag
3031
3032
3033    def write_config(self, OUTPUT):
3034        config = self.config
3035        print >>OUTPUT, '[%s]' % config.name
3036        if not config.root is None:
3037            print >>OUTPUT, 'root=%s' % config.root
3038        if not config.trunk is None:
3039            print >>OUTPUT, 'trunk=%s' % config.trunk
3040        if not config.stable is None:
3041            print >>OUTPUT, 'stable=%s' % config.stable
3042        if not config.tag is None:
3043            print >>OUTPUT, 'tag=%s' % config.tag
3044        elif not config.release is None:
3045            print >>OUTPUT, 'release=%s' % config.release
3046        if not config.local is None:
3047            print >>OUTPUT, 'local=%s' % config.local
3048        if not config.pypi is None:
3049            print >>OUTPUT, 'pypi=%s' % config.pypi
3050        elif not config.pyname is None:
3051            print >>OUTPUT, 'pypi=%s' % config.pyname
3052        print >>OUTPUT, 'dev=%s' % str(config.dev)
3053        print >>OUTPUT, 'install=%s' % str(config.install)
3054        if not config.rev is None:
3055            print >>OUTPUT, 'rev=%s' % str(config.rev)
3056        if not config.username is None:
3057            print >>OUTPUT, 'username=%s' % str(config.username)
3058
3059
3060    def find_pkgroot(self, trunk=False, stable=False, release=False):
3061        if trunk:
3062            if self.trunk is None:
3063                if not self.stable is None:
3064                    self.find_pkgroot(stable=True)
3065                elif self.pypi is None and self.local is None:
3066                    self.find_pkgroot(release=True)
3067                else:
3068                    # use easy_install
3069                    self.pkgdir = None
3070                    self.pkgroot = None
3071                    return
3072            else:
3073                self.pkgdir = self.trunk
3074                self.pkgroot = self.trunk_root
3075                return
3076
3077        elif stable:
3078            if self.stable is None: 
3079                if not self.release is None:
3080                    self.find_pkgroot(release=True)
3081                elif self.pypi is None and self.local is None:
3082                    self.find_pkgroot(trunk=True)
3083                else:
3084                    # use easy_install
3085                    self.pkgdir = None
3086                    self.pkgroot = None
3087                    return
3088            else:
3089                self.pkgdir = self.stable
3090                self.pkgroot = self.stable_root
3091                return
3092
3093        elif release:
3094            if self.release is None:
3095                if not self.stable is None:
3096                    self.find_pkgroot(stable=True)
3097                elif self.pypi is None and self.local is None:
3098                    self.find_pkgroot(trunk=True)
3099                else:
3100                    # use easy_install
3101                    self.pkgdir = None
3102                    self.pkgroot = None
3103                    return
3104            else:
3105                self.pkgdir = self.release
3106                self.pkgroot = self.release_root
3107
3108        else:
3109            raise IOError, "Must have one of trunk, stable or release specified"
3110           
3111
3112    def install_trunk(self, dir=None, install=True, preinstall=False, offline=False):
3113        self.find_pkgroot(trunk=True)
3114        self.perform_install(dir=dir, install=install, preinstall=preinstall, offline=offline)
3115       
3116    def install_stable(self, dir=None, install=True, preinstall=False, offline=False):
3117        self.find_pkgroot(stable=True)
3118        self.perform_install(dir=dir, install=install, preinstall=preinstall, offline=offline)
3119       
3120    def install_release(self, dir=None, install=True, preinstall=False, offline=False):
3121        self.find_pkgroot(release=True)
3122        self.perform_install(dir=dir, install=install, preinstall=preinstall, offline=offline)
3123       
3124    def perform_install(self, dir=None, install=True, preinstall=False, offline=False):
3125        if self.pkgdir is None and self.local is None:
3126            self.easy_install(install, preinstall, dir, offline)
3127            return
3128        if self.local:
3129            install = True
3130        print "-----------------------------------------------------------------"
3131        print "  Installing branch"
3132        print "  Checking out source for package",self.name
3133        if self.local:
3134            print "     Package dir: "+self.local
3135        else:
3136            print "     Subversion dir: "+self.pkgdir
3137        if os.path.exists(dir):
3138            print "     No checkout required"
3139            print "-----------------------------------------------------------------"
3140        elif not using_subversion:
3141                print ""
3142                print "Error: Cannot checkout software %s with subversion." % self.name
3143                print "A problem was detected executing subversion commands."
3144                sys.exit(1)
3145        else:
3146            print "-----------------------------------------------------------------"
3147            try:
3148                self.run([self.svn]+self.svn_username+[Repository.svn_get,'-q',self.pkgdir+self.rev, dir])
3149            except OSError, err:
3150                print ""
3151                print "Error checkout software %s with subversion at %s" % (self.name,self.pkgdir+self.rev)
3152                print str(err)
3153                sys.exit(1)
3154        if install:
3155            try:
3156                if self.dev:
3157                    if offline:
3158                        self.run([self.python, 'setup.py', 'develop', '--no-deps'], dir=dir)
3159                    else:
3160                        self.run([self.python, 'setup.py', 'develop'], dir=dir)
3161                else:
3162                    self.run([self.python, 'setup.py', 'install'], dir=dir)
3163            except OSError, err:
3164                print ""
3165                print "Error installing software %s from source using the setup.py file." % self.name
3166                print "This is probably due to a syntax or configuration error in this package."
3167                print str(err)
3168                sys.exit(1)
3169
3170    def update_trunk(self, dir=None):
3171        self.find_pkgroot(trunk=True)
3172        self.perform_update(dir=dir)
3173
3174    def update_stable(self, dir=None):
3175        self.find_pkgroot(stable=True)
3176        self.perform_update(dir=dir)
3177
3178    def update_release(self, dir=None):
3179        self.find_pkgroot(release=True)
3180        self.perform_update(dir=dir)
3181
3182    def perform_update(self, dir=None):
3183        if self.pkgdir is None:
3184            self.easy_upgrade()
3185            return
3186        print "-----------------------------------------------------------------"
3187        print "  Updating branch"
3188        print "  Updating source for package",self.name
3189        print "     Subversion dir: "+self.pkgdir
3190        print "     Source dir:     "+dir
3191        print "-----------------------------------------------------------------"
3192        self.run([self.svn,'update','-q']+self.revarg+[dir])
3193        if self.dev:
3194            self.run([self.python, 'setup.py', 'develop'], dir=dir)
3195        else:
3196            self.run([self.python, 'setup.py', 'install'], dir=dir)
3197
3198    def easy_install(self, install, preinstall, dir, offline):
3199        try:
3200            if install:
3201                if offline:
3202                    self.run([self.python, 'setup.py', 'install'], dir=dir)
3203                else:
3204                    self.run(self.easy_install_path + ['-q', self.pypi])
3205            elif preinstall: 
3206                if not os.path.exists(dir):
3207                    self.run(self.easy_install_path + ['-q', '--editable', '--build-directory', '.', self.pypi], dir=os.path.dirname(dir))
3208        except OSError, err:
3209            print ""
3210            print "Error installing package %s with easy_install" % self.name
3211            print str(err)
3212            sys.exit(1)
3213
3214    def easy_upgrade(self):
3215        self.run(self.easy_install_path + ['-q', '--upgrade', self.pypi])
3216
3217    def run(self, cmd, dir=None):
3218        cwd=os.getcwd()
3219        if not dir is None:
3220            os.chdir(dir)
3221            cwd=dir
3222        print "Running command '%s' in directory %s" % (" ".join(cmd), cwd)
3223        call_subprocess(cmd, filter_stdout=filter_python_develop, show_stdout=True)
3224        if not dir is None:
3225            os.chdir(cwd)
3226
3227
3228if sys.platform.startswith('win'):
3229    if not is_jython:
3230        Repository.python += 'w.exe'
3231    Repository.svn += '.exe'
3232
3233
3234def filter_python_develop(line):
3235    if not line.strip():
3236        return Logger.DEBUG
3237    for prefix in ['Searching for', 'Reading ', 'Best match: ', 'Processing ',
3238                   'Moving ', 'Adding ', 'running ', 'writing ', 'Creating ',
3239                   'creating ', 'Copying ']:
3240        if line.startswith(prefix):
3241            return Logger.DEBUG
3242    return Logger.NOTIFY
3243
3244
3245def apply_template(str, d):
3246    t = string.Template(str)
3247    return t.safe_substitute(d)
3248
3249
3250wrapper = textwrap.TextWrapper(subsequent_indent="    ")
3251
3252
3253class Installer(object):
3254
3255    def __init__(self):
3256        self.description="This script manages the installation of packages into a virtual Python installation."
3257        self.home_dir = None
3258        self.default_dirname='python'
3259        self.abshome_dir = None
3260        self.sw_packages = []
3261        self.sw_dict = {}
3262        self.cmd_files = []
3263        self.auxdir = []
3264        self.srcdir = None
3265        self.config=None
3266        self.config_file=None
3267        self.README="""
3268#
3269# Virtual Python installation generated by the %s script.
3270#
3271# This directory is managed with virtualenv, which creates a
3272# virtual Python installation.  If the 'bin' directory is put in
3273# user's PATH environment, then the bin/python command can be used
3274# without further installation.
3275#
3276# Directories:
3277#   admin      Administrative data for maintaining this distribution
3278#   bin        Scripts and executables
3279#   dist       Python packages that are not intended for development
3280#   include    Python header files
3281#   lib        Python libraries and installed packages
3282#   src        Python packages whose source files can be
3283#              modified and used directly within this virtual Python
3284#              installation.
3285#   Scripts    Python bin directory (used on MS Windows)
3286#
3287""" % sys.argv[0]
3288
3289    def add_repository(self, *args, **kwds):
3290        if not 'root' in kwds and not 'pypi' in kwds and not 'release' in kwds and not 'trunk' in kwds and not 'stable' in kwds:
3291            raise IOError, "No repository info specified for repository "+args[0]
3292        repos = Repository( *args, **kwds)
3293        self.sw_dict[repos.name] = repos
3294        self.sw_packages.append( repos )
3295
3296    def add_dos_cmd(self, file):
3297        self.cmd_files.append( file )
3298
3299    def add_auxdir(self, package, todir, fromdir):
3300        self.auxdir.append( (todir, package, fromdir) )
3301
3302    def modify_parser(self, parser):
3303        self.default_windir = 'C:\\'+self.default_dirname
3304        self.default_unixdir = './'+self.default_dirname
3305        #
3306        parser.add_option('--debug',
3307            help='Configure script to generate debugging IO and to raise exceptions.',
3308            action='store_true',
3309            dest='debug',
3310            default=False)
3311
3312        parser.add_option('--release',
3313            help='Install release branches of Python software using subversion.',
3314            action='store_true',
3315            dest='release',
3316            default=False)
3317
3318        parser.add_option('--trunk',
3319            help='Install trunk branches of Python software using subversion.',
3320            action='store_true',
3321            dest='trunk',
3322            default=False)
3323
3324        parser.add_option('--stable',
3325            help='Install stable branches of Python software using subversion.',
3326            action='store_true',
3327            dest='stable',
3328            default=False)
3329
3330        parser.add_option('--update',
3331            help='Update all Python packages.',
3332            action='store_true',
3333            dest='update',
3334            default=False)
3335
3336        parser.add_option('--proxy',
3337            help='Set the HTTP_PROXY environment with this option.',
3338            action='store',
3339            dest='proxy',
3340            default=None)
3341
3342        parser.add_option('--preinstall',
3343            help='Prepare an installation that will be used to build a MS Windows installer.',
3344            action='store_true',
3345            dest='preinstall',
3346            default=False)
3347
3348        parser.add_option('--offline',
3349            help='Perform installation offline, using source extracted from ZIP files.',
3350            action='store_true',
3351            dest='offline',
3352            default=False)
3353
3354        parser.add_option('--zip',
3355            help='Add ZIP files that are use define this installation.',
3356            action='append',
3357            dest='zip',
3358            default=[])
3359
3360        parser.add_option('--source', '--src',
3361            help='Use packages defined in the specified source directory',
3362            action='store',
3363            dest='source',
3364            default=None)
3365
3366        parser.add_option('--use-pythonpath',
3367            help="By default, the PYTHONPATH is ignored when installing.  This option allows the 'easy_install' tool to search this path for related Python packages, which are then installed.",
3368            action='store_true',
3369            dest='use_pythonpath',
3370            default=False)
3371
3372        parser.add_option(
3373            '--site-packages',
3374            dest='no_site_packages',
3375            action='store_false',
3376            help="Setup the virtual environment to use the global site-packages",
3377            default=True)
3378
3379        parser.add_option(
3380            '-a', '--add-package',
3381            dest='packages',
3382            action='append',
3383            help='Specify a package that is added to the virtual Python installation.  This option can specify a directory for the Python package source or PyPI package name that is downloaded automatically.  This option can be specified multiple times to declare multiple packages.',
3384            default=[])
3385
3386        parser.add_option('--config',
3387            help='Use an INI config file to specify the packages used in this installation.  Using this option clears the initial configuration, but multiple uses of this option will add package specifications.',
3388            action='append',
3389            dest='config_files',
3390            default=[])
3391
3392        parser.add_option('--keep-config',
3393            help='Keep the initial configuration data that was specified if the --config option is specified.',
3394            action='store_true',
3395            dest='keep_config',
3396            default=False)
3397
3398        parser.add_option('--localize',
3399            help='Force localization of DOS scripts on Linux platforms',
3400            action='store_true',
3401            dest='localize',
3402            default=False)
3403
3404        #
3405        # Change the virtualenv options
3406        #
3407        parser.remove_option("--python")
3408        parser.add_option("--python",
3409            dest='python',
3410            metavar='PYTHON_EXE',
3411            help="Specify the Python interpreter to use, e.g., --python=python2.5 will install with the python2.5 interpreter.")
3412        parser.remove_option("--relocatable")
3413        parser.remove_option("--version")
3414        parser.remove_option("--unzip-setuptools")
3415        parser.remove_option("--no-site-packages")
3416        parser.remove_option("--clear")
3417        #
3418        # Add description
3419        #
3420        parser.description=self.description
3421        parser.epilog="If DEST_DIR is not specified, then a default installation path is used:  "+self.default_windir+" on Windows and "+self.default_unixdir+" on Linux.  This command uses the Python 'setuptools' package to install Python packages.  This package installs packages by downloading files from the internet.  If you are running this from within a firewall, you may need to set the HTTP_PROXY environment variable to a value like 'http://<proxyhost>:<port>'."
3422       
3423
3424    def adjust_options(self, options, args):
3425        #
3426        # Force options.clear to be False.  This allows us to preserve the logic
3427        # associated with --clear, which we may want to use later.
3428        #
3429        options.clear=False
3430        #
3431        global vpy_main
3432        if options.debug:
3433            vpy_main.raise_exceptions=True
3434        #
3435        global logger
3436        verbosity = options.verbose - options.quiet
3437        self.logger = Logger([(Logger.level_for_integer(2-verbosity), sys.stdout)])
3438        logger = self.logger
3439        #
3440        # Determine if the subversion command is available
3441        #
3442        global using_subversion
3443        try:
3444            call_subprocess(['svn'+executable_extension,'help'], show_stdout=False)
3445        except OSError, err:
3446            print ""
3447            print "------------------------------------------------"
3448            print "WARNING: problems executing subversion commands."
3449            print "Subversion is disabled."
3450            print "------------------------------------------------"
3451            print ""
3452            using_subversion = False
3453        #
3454        if options.update and (options.stable or options.trunk):
3455            self.logger.fatal("ERROR: cannot specify --stable or --trunk when specifying the --update option.")
3456            sys.exit(1000)
3457        if options.update and len(options.config_files) > 0:
3458            self.logger.fatal("ERROR: cannot specify --config when specifying the --update option.")
3459            sys.exit(1000)
3460        if options.update and options.keep_config:
3461            self.logger.fatal("ERROR: cannot specify --keep-config when specifying the --update option.")
3462            sys.exit(1000)
3463        if len(args) > 1:
3464            self.logger.fatal("ERROR: installer script can only have one argument")
3465            sys.exit(1000)
3466        #
3467        # Error checking
3468        #
3469        if not options.preinstall and (os.path.exists(self.abshome_dir) ^ options.update):
3470            if options.update:
3471                self.logger.fatal(wrapper.fill("ERROR: The 'update' option is specified, but the installation path '%s' does not exist!" % self.home_dir))
3472                sys.exit(1000)
3473            elif os.path.exists(join(self.abshome_dir,'bin')):
3474                    self.logger.fatal(wrapper.fill("ERROR: The installation path '%s' already exists!  Use the --update option if you wish to update, or remove this directory to create a fresh installation." % self.home_dir))
3475                    sys.exit(1000)
3476        if len(args) == 0:
3477            args.append(self.abshome_dir)
3478        #
3479        # Reset the config file if no options are specified
3480        #
3481        if not self.config_file is None and not (options.trunk or options.stable or options.release):
3482            self.config_file = os.path.dirname(self.config_file)+"/pypi.ini"
3483        #
3484        # Parse config files
3485        #
3486        if options.update:
3487            self.config=None
3488            options.config_files.append( join(self.abshome_dir, 'admin', 'config.ini') )
3489        if not self.config is None and (len(options.config_files) == 0 or options.keep_config):
3490            fp = StringIO.StringIO(self.config)
3491            self.read_config_file(fp=fp)
3492            fp.close()
3493        if not self.config_file is None and (len(options.config_files) == 0 or options.keep_config):
3494            self.read_config_file(file=self.config_file)
3495        for file in options.config_files:
3496            self.read_config_file(file=file)
3497        print "-----------------------------------------------------------------"
3498        print "Finished processing configuration information."
3499        print "-----------------------------------------------------------------"
3500        print " START - Configuration summary"
3501        print "-----------------------------------------------------------------"
3502        self.write_config(stream=sys.stdout)
3503        print "-----------------------------------------------------------------"
3504        print " END - Configuration summary"
3505        print "-----------------------------------------------------------------"
3506        #
3507        # If applying preinstall, then only do subversion exports
3508        #
3509        if options.preinstall:
3510            Repository.svn_get='export'
3511
3512    def get_homedir(self, options, args):
3513        #
3514        # Figure out the installation directory
3515        #
3516        if len(args) == 0:
3517            path = self.guess_path()
3518            if path is None or options.preinstall:
3519                # Install in a default location.
3520                if sys.platform == 'win32':
3521                    home_dir = self.default_windir
3522                else:
3523                    home_dir = self.default_unixdir
3524            else:
3525                home_dir = os.path.dirname(os.path.dirname(path))
3526        else:
3527            home_dir = args[0]
3528        self.home_dir = home_dir
3529        self.abshome_dir = os.path.abspath(home_dir)
3530        if options.source is None:
3531            self.srcdir = join(self.abshome_dir,'src')
3532        else:
3533            self.srcdir = os.path.abspath(options.source)
3534            if not os.path.exists(self.srcdir):
3535                raise ValueError, "Specified source directory does not exist! %s" % self.srcdir
3536
3537    def guess_path(self):
3538        return None
3539
3540    def setup_installer(self, options):
3541        if options.preinstall:
3542            print "Creating preinstall zip file in '%s'" % self.home_dir
3543        elif options.update:
3544            print "Updating existing installation in '%s'" % self.home_dir
3545        else:
3546            print "Starting fresh installation in '%s'" % self.home_dir
3547        #
3548        # Setup HTTP proxy
3549        #
3550        if options.offline:
3551            os.environ['HTTP_PROXY'] = ''
3552            os.environ['http_proxy'] = ''
3553        else:
3554            proxy = ''
3555            if not options.proxy is None:
3556                proxy = options.proxy
3557            if proxy is '':
3558                proxy = os.environ.get('HTTP_PROXY', '')
3559            if proxy is '':
3560                proxy = os.environ.get('http_proxy', '')
3561            os.environ['HTTP_PROXY'] = proxy
3562            os.environ['http_proxy'] = proxy
3563            print "  using the HTTP_PROXY environment: %s" % proxy
3564            print ""
3565        #
3566        # Disable the PYTHONPATH, to isolate this installation from
3567        # other Python installations that a user may be working with.
3568        #
3569        if not options.use_pythonpath:
3570            try:
3571                del os.environ["PYTHONPATH"]
3572            except:
3573                pass
3574        #
3575        # If --preinstall is declared, then we remove the directory, and prepare a ZIP file
3576        # that contains the full installation.
3577        #
3578        if options.preinstall:
3579            print "-----------------------------------------------------------------"
3580            print " STARTING preinstall in directory %s" % self.home_dir
3581            print "-----------------------------------------------------------------"
3582            rmtree(self.abshome_dir)
3583            os.mkdir(self.abshome_dir)
3584        #
3585        # When preinstalling or working offline, disable the
3586        # default install_setuptools() function.
3587        #
3588        if options.offline:
3589            install_setuptools.use_default=False
3590            install_pip.use_default=False
3591        #
3592        # If we're clearing the current installation, then remove a bunch of
3593        # directories
3594        #
3595        elif options.clear and not options.source is None:
3596            if os.path.exists(self.srcdir):
3597                rmtree(self.srcdir)
3598        #
3599        # Open up zip files
3600        #
3601        for file in options.zip:
3602            unzip_file(file, dir=self.abshome_dir)
3603
3604        if options.preinstall or not options.offline:
3605            #self.get_packages(options)
3606            pass
3607        else:
3608            self.sw_packages.insert( 0, Repository('virtualenv', pypi='virtualenv') )
3609            self.sw_packages.insert( 0, Repository('pip', pypi='pip') )
3610            self.sw_packages.insert( 0, Repository('setuptools', pypi='setuptools') )
3611            #
3612            # Configure the package versions, for offline installs
3613            #
3614            for pkg in self.sw_packages:
3615                pkg.guess_versions(True)
3616
3617    def get_packages(self, options):
3618        #
3619        # Setup the 'admin' directory
3620        #
3621        if not os.path.exists(self.abshome_dir):
3622            os.mkdir(self.abshome_dir)
3623        if not os.path.exists(join(self.abshome_dir,'admin')):
3624            os.mkdir(join(self.abshome_dir,'admin'))
3625        if options.update:
3626            INPUT=open(join(self.abshome_dir,'admin',"virtualenv.cfg"),'r')
3627            options.trunk = INPUT.readline().strip() != 'False'
3628            options.stable = INPUT.readline().strip() != 'False'
3629            options.release = INPUT.readline().strip() != 'False'
3630            INPUT.close()
3631        else:
3632            OUTPUT=open(join(self.abshome_dir,'admin',"virtualenv.cfg"),'w')
3633            print >>OUTPUT, options.trunk
3634            print >>OUTPUT, options.stable
3635            print >>OUTPUT, options.release
3636            OUTPUT.close()
3637            self.write_config( join(self.abshome_dir,'admin','config.ini') )
3638        #
3639        # Setup package directories
3640        #
3641        if not os.path.exists(join(self.abshome_dir,'dist')):
3642            os.mkdir(join(self.abshome_dir,'dist'))
3643        if not os.path.exists(self.srcdir):
3644            os.mkdir(self.srcdir)
3645        if not os.path.exists(self.abshome_dir+os.sep+"bin"):
3646            os.mkdir(self.abshome_dir+os.sep+"bin")
3647        #
3648        # Get source packages
3649        #
3650        self.sw_packages.insert( 0, Repository('virtualenv', pypi='virtualenv') )
3651        self.sw_packages.insert( 0, Repository('pip', pypi='pip') )
3652        if options.preinstall:
3653            #
3654            # When preinstalling, add the setuptools package to the installation list
3655            #
3656            self.sw_packages.insert( 0, Repository('setuptools', pypi='setuptools') )
3657        for _pkg in options.packages:
3658            if os.path.exists(_pkg):
3659                self.sw_packages.append( Repository(_pkg, local=os.path.abspath(_pkg)) )
3660            else:
3661                self.sw_packages.append( Repository(_pkg, pypi=_pkg) )
3662        #
3663        # Add Coopr Forum packages
3664        #
3665        self.get_other_packages(options)
3666        #
3667        # Get package source
3668        #
3669        for pkg in self.sw_packages:
3670            pkg.guess_versions(False)
3671            if not pkg.install:
3672                pkg.find_pkgroot(trunk=options.trunk, stable=options.stable, release=options.release)
3673                continue
3674            if pkg.local:
3675                tmp = pkg.local
3676            elif pkg.dev:
3677                tmp = join(self.srcdir,pkg.name)
3678            else:
3679                tmp = join(self.abshome_dir,'dist',pkg.name)
3680            if options.trunk:
3681                if not options.update:
3682                    pkg.install_trunk(dir=tmp, install=False, preinstall=options.preinstall, offline=options.offline)
3683            elif options.stable:
3684                if not options.update:
3685                    pkg.install_stable(dir=tmp, install=False, preinstall=options.preinstall, offline=options.offline)
3686            else:
3687                if not options.update:
3688                    pkg.install_release(dir=tmp, install=False, preinstall=options.preinstall, offline=options.offline)
3689        if options.update or not os.path.exists(join(self.abshome_dir,'doc')):
3690            self.install_auxdirs(options)
3691        #
3692        # Create a README.txt file
3693        #
3694        OUTPUT=open(join(self.abshome_dir,"README.txt"),"w")
3695        print >>OUTPUT, self.README.strip()
3696        OUTPUT.close()
3697        #
3698        # Finalize preinstall
3699        #
3700        if options.preinstall:
3701            print "-----------------------------------------------------------------"
3702            print " FINISHED preinstall in directory %s" % self.home_dir
3703            print "-----------------------------------------------------------------"
3704            os.chdir(self.abshome_dir)
3705            zip_file(self.default_dirname+'.zip', ['.'])
3706            sys.exit(0)
3707
3708    def get_other_packages(self, options):
3709        #
3710        # Used by subclasses of Installer to
3711        # add packages that were requested through other means....
3712        #
3713        pass
3714       
3715    def install_packages(self, options):
3716        #
3717        # Set the bin directory
3718        #
3719        if os.path.exists(self.abshome_dir+os.sep+"Scripts"):
3720            bindir = join(self.abshome_dir,"Scripts")
3721        else:
3722            bindir = join(self.abshome_dir,"bin")
3723        if is_jython:
3724            Repository.python = os.path.abspath(join(bindir, 'jython.bat'))
3725        elif sys.platform.startswith('win'):
3726            Repository.python = os.path.abspath(join(bindir, 'pythonw'))
3727        else:
3728            Repository.python = os.path.abspath(join(bindir, 'python'))
3729        if os.path.exists(os.path.abspath(join(bindir, 'easy_install'))):
3730            Repository.easy_install_path = [Repository.python, os.path.abspath(join(bindir, 'easy_install'))]
3731        else:
3732            Repository.easy_install_path = [os.path.abspath(join(bindir, 'easy_install.exe'))]
3733        #
3734        if options.preinstall or not options.offline:
3735            self.get_packages(options)
3736        #
3737        # Install the related packages
3738        #
3739        for pkg in self.sw_packages:
3740            if not pkg.install:
3741                pkg.find_pkgroot(trunk=options.trunk, stable=options.stable, release=options.release)
3742                continue
3743            if pkg.local:
3744                srcdir = pkg.local
3745            elif pkg.dev:
3746                srcdir = join(self.srcdir,pkg.name)
3747            else:
3748                srcdir = join(self.abshome_dir,'dist',pkg.name)
3749            if options.trunk:
3750                if options.update:
3751                    pkg.update_trunk(dir=srcdir)
3752                else:
3753                    pkg.install_trunk(dir=srcdir, preinstall=options.preinstall, offline=options.offline)
3754            elif options.stable:
3755                if options.update:
3756                    pkg.update_stable(dir=srcdir)
3757                else:
3758                    pkg.install_stable(dir=srcdir, preinstall=options.preinstall, offline=options.offline)
3759            else:
3760                if options.update:
3761                    pkg.update_release(dir=srcdir)
3762                else:
3763                    pkg.install_release(dir=srcdir, preinstall=options.preinstall, offline=options.offline)
3764        #
3765        # Copy the <env>/Scripts/* files into <env>/bin
3766        #
3767        if os.path.exists(self.abshome_dir+os.sep+"Scripts"):
3768            if not os.path.exists(self.abshome_dir+os.sep+"bin"):
3769                os.mkdir(self.abshome_dir+os.sep+"bin")
3770            for file in glob.glob(self.abshome_dir+os.sep+"Scripts"+os.sep+"*"):
3771                shutil.copy(file, self.abshome_dir+os.sep+"bin")
3772        #
3773        # Localize DOS cmd files
3774        #
3775        self.localize_cmd_files(self.abshome_dir, options.localize)
3776        #
3777        # Misc notifications
3778        #
3779        if not options.update:
3780            print ""
3781            print "-----------------------------------------------------------------"
3782            print "  Add %s to the PATH environment variable" % (self.home_dir+os.sep+"bin")
3783            print "-----------------------------------------------------------------"
3784        print ""
3785        print "Finished installation in '%s'" % self.home_dir
3786
3787    def localize_cmd_files(self, dir, force_localization=False):
3788        """
3789        Hard-code the path to Python that is used in the Python CMD files that
3790        are installed.
3791        """
3792        if not (sys.platform.startswith('win') or force_localization):
3793            return
3794        for file in self.cmd_files:
3795            INPUT = open(join(dir,'bin',file), 'r')
3796            content = "".join(INPUT.readlines())
3797            INPUT.close()
3798            content = content.replace('__VIRTUAL_ENV__',dir)
3799            OUTPUT = open(join(dir,'bin',file), 'w')
3800            OUTPUT.write(content)
3801            OUTPUT.close()
3802
3803    def svnjoin(*args):
3804        return '/'.join(args[1:])
3805
3806    def install_auxdirs(self, options):
3807        for todir,pkg,fromdir in self.auxdir:
3808            pkgroot = self.sw_dict[pkg].pkgroot
3809            if options.update:
3810                cmd = [Repository.svn,'update','-q',self.svnjoin(self.abshome_dir, todir)]
3811            else:
3812                if options.clear:
3813                    rmtree( join(self.abshome_dir,todir) )
3814                cmd = [Repository.svn,Repository.svn_get,'-q',self.svnjoin(pkgroot,fromdir),join(self.abshome_dir,todir)]
3815            print "Running command '%s'" % " ".join(cmd)
3816            call_subprocess(cmd, filter_stdout=filter_python_develop,show_stdout=True)
3817
3818    def read_config_file(self, file=None, fp=None):
3819        """
3820        Read a config file.
3821        """
3822        parser = OrderedConfigParser()
3823        if not fp is None:
3824            parser.readfp(fp, '<default configuration>')
3825        elif not os.path.exists(file):
3826            if not '/' in file and not self.config_file is None:
3827                file = os.path.dirname(self.config_file)+"/"+file
3828            try:
3829                if sys.version_info[:2] <= (2,5):
3830                    output = urllib2.urlopen(file).read()
3831                else:
3832                    output = urllib2.urlopen(file, timeout=30).read()
3833            except Exception, err:
3834                print "Problems opening configuration url:",file
3835                raise
3836            fp = StringIO.StringIO(output)
3837            parser.readfp(fp, file)
3838            fp.close()
3839        else:
3840            if not file in parser.read(file):
3841                raise IOError, "Error while parsing file %s." % file
3842        sections = parser.sections()
3843        if 'installer' in sections:
3844            for option, value in parser.items('installer'):
3845                setattr(self, option, apply_template(value, os.environ) )
3846        if 'localize' in sections:
3847            for option, value in parser.items('localize'):
3848                self.add_dos_cmd(option)
3849        for sec in sections:
3850            if sec in ['installer', 'localize']:
3851                continue
3852            if sec.endswith(':auxdir'):
3853                auxdir = sec[:-7]
3854                for option, value in parser.items(sec):
3855                    self.add_auxdir(auxdir, option, apply_template(value, os.environ) )
3856            else:
3857                options = {}
3858                for option, value in parser.items(sec):
3859                    options[option] = apply_template(value, os.environ)
3860                self.add_repository(sec, **options)
3861
3862    def write_config(self, filename=None, stream=None):
3863        if not filename is None:
3864            OUTPUT=open(filename,'w')
3865            self.write_config(stream=OUTPUT)
3866            OUTPUT.close()
3867        else: 
3868            for repos in self.sw_packages:
3869                repos.write_config(stream)
3870                print >>stream, ""
3871            if len(self.cmd_files) > 0:
3872                print >>stream, "[localize]"
3873                for file in self.cmd_files:
3874                    print >>stream, file+"="
3875                print >>stream, "\n"
3876       
3877
3878
3879def configure(installer):
3880    """
3881    A dummy configuration function.
3882    """
3883    return installer
3884
3885def create_installer():
3886    return Installer()
3887
3888def get_installer():
3889    """
3890    Return an instance of the installer object.  If this object
3891    does not already exist, then create the object and use the
3892    configure() function to customize it based on the end-user's
3893    needs.
3894
3895    The argument to this function is the class type that will be
3896    constructed if needed.
3897    """
3898    try:
3899        return get_installer.installer
3900    except:
3901        get_installer.installer = configure( create_installer() )
3902        return get_installer.installer
3903
3904#
3905# Override the default definition of rmtree, to better handle MSWindows errors
3906# that are associated with read-only files
3907#
3908def handleRemoveReadonly(func, path, exc):
3909  excvalue = exc[1]
3910  if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
3911      os.chmod(path, stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO) # 0777
3912      func(path)
3913  else:
3914      raise
3915
3916def rmtree(dir):
3917    if os.path.exists(dir):
3918        logger.notify('Deleting tree %s', dir)
3919        shutil.rmtree(dir, ignore_errors=False, onerror=handleRemoveReadonly)
3920    else:
3921        logger.info('Do not need to delete %s; already gone', dir)
3922
3923#
3924# This is a monkey patch, to add control for exception management.
3925#
3926vpy_main = main
3927vpy_main.raise_exceptions=False
3928def main():
3929    if sys.platform != 'win32':
3930        if os.environ.get('TMPDIR','') == '.':
3931            os.environ['TMPDIR'] = '/tmp'
3932        elif os.environ.get('TEMPDIR','') == '.':
3933            os.environ['TEMPDIR'] = '/tmp'
3934    try:
3935        vpy_main()
3936    except Exception, err:
3937        if vpy_main.raise_exceptions:
3938            raise
3939        print ""
3940        print "ERROR:",str(err)
3941
3942#
3943# This is a monkey patch, to control the execution of the install_setuptools()
3944# function that is defined by virtualenv.
3945#
3946default_install_setuptools = install_setuptools
3947
3948def install_setuptools(py_executable, unzip=False):
3949    try:
3950        if install_setuptools.use_default:
3951            default_install_setuptools(py_executable, unzip)
3952    except OSError, err:
3953        print "-----------------------------------------------------------------"
3954        print "Error installing the 'setuptools' package!"
3955        if os.environ['HTTP_PROXY'] == '':
3956            print ""
3957            print "WARNING: you may need to set your HTTP_PROXY environment variable!"
3958        print "-----------------------------------------------------------------"
3959        sys.exit(1)
3960
3961install_setuptools.use_default=True
3962
3963
3964#
3965# This is a monkey patch, to control the execution of the install_pip()
3966# function that is defined by virtualenv.
3967#
3968default_install_pip = install_pip
3969
3970def install_pip(*args, **kwds):
3971    try:
3972        if install_pip.use_default:
3973            default_install_pip(*args, **kwds)
3974    except OSError, err:
3975        print "-----------------------------------------------------------------"
3976        print "Error installing the 'pip' package!"
3977        if os.environ['HTTP_PROXY'] == '':
3978            print ""
3979            print "WARNING: you may need to set your HTTP_PROXY environment variable!"
3980        print "-----------------------------------------------------------------"
3981        sys.exit(1)
3982
3983install_pip.use_default=True
3984
3985
3986#
3987# This is a monkey patch, to catch errors when a directory cannot be created
3988# by virtualenv.
3989#
3990def mkdir(path):
3991    if not os.path.exists(path):
3992        logger.info('Creating %s', path)
3993        try:
3994            os.makedirs(path)
3995        except Exception, e:
3996            print "Cannot create directory '%s'!" % path
3997            print "Verify that you have write permissions to this directory."
3998            sys.exit(1)
3999    else:
4000        logger.info('Directory %s already exists', path)
4001
4002#
4003# The following methods will be called by virtualenv
4004#
4005def extend_parser(parser):
4006    installer = get_installer()
4007    installer.modify_parser(parser)
4008
4009def adjust_options(options, args):
4010    installer = get_installer()
4011    installer.get_homedir(options, args)
4012    installer.adjust_options(options, args)
4013    installer.setup_installer(options)
4014   
4015def after_install(options, home_dir):
4016    installer = get_installer()
4017    installer.install_packages(options)
4018
4019
4020
4021#
4022# Imported from coopr.py
4023#
4024
4025#  _________________________________________________________________________
4026#
4027#  Coopr: A COmmon Optimization Python Repository
4028#  Copyright (c) 2008 Sandia Corporation.
4029#  This software is distributed under the BSD License.
4030#  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
4031#  the U.S. Government retains certain rights in this software.
4032#  _________________________________________________________________________
4033
4034# Revision: $Revision$
4035# Date:     $Date$
4036
4037import sys
4038
4039class CooprInstaller(Installer):
4040
4041    def __init__(self):
4042        Installer.__init__(self)
4043        self.default_dirname='coopr'
4044        self.config_file='https://software.sandia.gov/svn/public/coopr/vpy/installer.ini'
4045        if sys.version_info[:2] < (2,5) or sys.version_info[:2] >= (3,0):
4046            print ""
4047            print "------------------------------------------------------------------"
4048            print "WARNING: Most Coopr packages will only work with Python 2.5 - 2.7."
4049            print "         You attempted to installed Coopr with:"
4050            print sys.version
4051            print "------------------------------------------------------------------"
4052            print ""
4053            sys.exit(1)
4054
4055    def modify_parser(self, parser):
4056        Installer.modify_parser(self, parser)
4057
4058        parser.add_option('--coin',
4059            help='Use one or more packages from the Coin Bazaar software repository.  Multiple packages are specified with a comma-separated list.',
4060            action='store',
4061            dest='coin',
4062            default=None)
4063
4064    def get_other_packages(self, options):
4065        if options.coin is None:
4066            return
4067        for pkg in options.coin.split(','):
4068            if pkg is '':
4069                continue
4070            self.add_repository('coopr.'+pkg, root='https://projects.coin-or.org/svn/CoinBazaar/projects/coopr.'+pkg, dev=True, username=os.environ.get('COINOR_USERNAME',None))
4071
4072def create_installer():
4073    return CooprInstaller()
4074
4075
4076##file site.py
4077SITE_PY = """
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
4211""".decode("base64").decode("zlib")
4212
4213##file ez_setup.py
4214EZ_SETUP_PY = """
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
4281178BYnMUkw==
4282""".decode("base64").decode("zlib")
4283
4284##file distribute_setup.py
4285DISTRIBUTE_SETUP_PY = """
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
4365""".decode("base64").decode("zlib")
4366
4367##file activate.sh
4368ACTIVATE_SH = """
4369eJytVU1v4jAQPW9+xTT0ANVS1GsrDlRFAqmFqmG72m0rY5IJsRRslDiktNr/vuMQ8tFQpNU2B4I9
4370H36eeW/SglkgYvBFiLBKYg0LhCRGD1KhA7BjlUQuwkLIHne12HCNNpz5kVrBgsfBmdWCrUrA5VIq
4371DVEiQWjwRISuDreW5eE+CtodeLeAnhZEGKMGFXqAciMiJVcoNWx4JPgixDjzEj48QVeCfcqmtzfs
4372cfww+zG4ZfeD2ciGF7gCHaDMPM1jtvuHXAsPfF2rSGeOxV4iDY5GUGb3xVEYv2aj6WQ0vRseAlMY
4373G5DKsAawwnQUXt2LQOYlzZoYByqhonqoqfxZf4BLD97i4DukgXADCPgGgdOLTK5arYxZB1xnrc9T
4374EQFcHoZEAa1gSQioo/TPV5FZrDlxJA+NzwF+Ek1UonOzFnKZp6k5mgLBqSkuuAGXS4whJb5xz/xs
4375wXCHjiVerAk5eh9Kfz1wqOldtVv9dkbscfjgjKeTA8XPrtaNauX5rInOxaHuOReNtpFjo1/OxdFG
43765eY9hJ3L3jqcPJbATggXAemDLZX0MNZRYjSDH7C1wMHQh73DyYfTu8a0F9v+6D8W6XNnF1GEIXW/
4377JrSKPOtnW1YFat9mrLJkzLbyIlTvYzV0RGXcaTBfVLx7jF2PJ2wyuBsydpm7VSVa4C4Zb6pFO2TR
4378huypCEPwuQjNftUrNl6GsYZzuFrrLdC9iJjQ3omAPBbcI2lsU77tUD43kw1NPZhTrnZWzuQKLomx
4379Rd4OXM1ByExVVkmoTwfBJ7Lt10Iq1Kgo23Bmd8Ib1KrGbsbO4Pp2yO4fpnf3s6MnZiwuiJuls1/L
4380Pu4yUCvhpA+vZaJvWWDTr0yFYYyVnHMqCEq+QniuYX225xmnzRENjbXACF3wkCYNVZ1mBwxoR9Iw
4381WAo3/36oSOTfgjwEEQKt15e9Xpqm52+oaXxszmnE9GLl65RH2OMmS6+u5acKxDmlPgj2eT5/gQOX
4382LLK0j1y0Uwbmn438VZkVpqlfNKa/YET/53j+99G8H8tUhr9ZSXs2
4383""".decode("base64").decode("zlib")
4384
4385##file activate.fish
4386ACTIVATE_FISH = """
4387eJydVm1v4jgQ/s6vmA1wBxUE7X2stJVYlVWR2lK13d6d9laRk0yIr8HmbIe0++tvnIQQB9pbXT5A
4388Ys/LM55nZtyHx5RrSHiGsMm1gRAh1xhDwU0Kng8hFzMWGb5jBv2E69SDs0TJDdj3MxilxmzPZzP7
4389pVPMMl+q9bjXh1eZQ8SEkAZULoAbiLnCyGSvvV6SC7IoBcS4Nw0wjcFbvJDcjiuTswzFDpiIQaHJ
4390lQAjQUi1YRmUboC2uZJig8J4PaCnT5IaDcgsbm/CjinOwgx1KcUTMEhhTgV4g2B1fRk8Le8fv86v
4391g7v545UHpZB9rKnp+gXsMhxLunIIpwVQxP/l9c/Hq9Xt1epm4R27bva6AJqN92G4YhbMG2i+LB+u
4392grv71c3dY7B6WtzfLy9bePbp0taDTXSwJQJszUnnp0y57mvpPcrF7ZODyhswtd59+/jdgw+fwBNS
4393xLSscksUPIDqwwNmCez3PpxGeyBYg6HE0YdcWBxcKczYzuVJi5Wu915vn5oWePCCoPUZBN5B7IgV
4394MCi54ZDLG7TUZ0HweXkb3M5vFmSpFm/gthhBx0UrveoPpv9AJ9unIbQYdUoe21bKg2q48sPFGVwu
4395H+afrxd1qvclaNlRFyh1EQ2sSccEuNAGWQwysfVpz1tPajUqbqJUnEcIJkWo6OXDaodK8ZiLdbmM
4396L1wb+9H0D+pcyPSrX5u5kgWSygRYXCnJUi/KKcuU4cqsAyTKZBiissLc7NFwizvjxtieKBVCIdWz
4397fzilzPaYyljZN0cGN1v7NnaIPNCGmVy3GKuJaQ6iVjE1Qfm+36hglErwmnAD8hu0dDy4uICBA8ZV
4398pQr/q/+O0KFW2kjelu9Dgb9SDBsWV4F4x5CswgS0zBVlk5tDMP5bVtUGpslbm81Lu2sdKq7uNMGh
4399MVQ4fy9xhogC1lS5guhISa0DlBWv0O8odT6/LP+4WZzDV6FzIkEqC0uolGZSZoMnlpxplmD2euaT
4400O4hkTpPnbztDccey0bhjDaBIqaWQa0uwEtQEwtyU56i4fq54F9IE3ORR6mKriODM4XOYZwaVYLYz
44017SPbKkz4i7VkB6/Ot1upDE3znNqYKpM8raa0Bx8vfvntJ32UENsM4aI6gJL+jJwhxhh3jVIDOcpi
4402m0r2hmEtS8XXXNBk71QCDXTBNhhPiHX2LtHkrVIlhoEshH/EZgdq53Eirqs5iFKMnkOmqZTtr3Xq
4403djvPTWZT4S3NT5aVLgurMPUWI07BRVYqkQrmtCKohNY8qu9EdACoT6ki0a66XxVF4f9AQ3W38yO5
4404mWmZmIIpnDFrbXakvKWeZhLwhvrbUH8fahhqD0YUcBDJjEBMQwiznE4y5QbHrbhHBOnUAYzb2tVN
4405jJa65e+eE2Ya30E2GurxUP8ssA6e/wOnvo3V78d3vTcvMB3n7l3iX1JXWqk=
4406""".decode("base64").decode("zlib")
4407
4408##file activate.csh
4409ACTIVATE_CSH = """
4410eJx9U11vmzAUffevOCVRu+UB9pws29Kl0iq1aVWllaZlcgxciiViItsQdb9+xiQp+dh4QOB7Pu49
4411XHqY59IgkwVhVRmLmFAZSrGRNkdgykonhFiqSCRW1sJSmJg8wCDT5QrucRCyHn6WFRKhVGmhKwVp
4412kUpNiS3emup3TY6XIn7DVNQyJUwlrgthJD6n/iCNv72uhCzCpFx9CRkThRQGKe08cWXJ9db/yh/u
4413pvzl9mn+PLnjj5P5D1yM8QmXlzBkSdXwZ0H/BBc0mEo5FE5qI2jKhclHOOvy9HD/OO/6YO1mX9vx
4414sY0H/tPIV0dtqel0V7iZvWyNg8XFcBA0ToEqVeqOdNUEQFvN41SumAv32VtJrakQNSmLWmgp4oJM
4415yDoBHgoydtoEAs47r5wHHnUal5vbJ8oOI+9wI86vb2d8Nrm/4Xy4RZ8R85E4uTZPB5EZPnTaaAGu
4416E59J8BE2J8XgrkbLeXMlVoQxznEYFYY8uFFdxsKQRx90Giwx9vSueHP1YNaUSFG4vTaErNSYuBOF
4417lXiVyXa9Sy3JdClEyK1dD6Nos9mEf8iKlOpmqSNTZnYjNEWiUYn2pKNB3ttcLJ3HmYYXy6Un76f7
4418r8rRsC1TpTJj7f19m5sUf/V3Ir+x/yjtLu8KjLX/CmN/AcVGUUo=
4419""".decode("base64").decode("zlib")
4420
4421##file activate.bat
4422ACTIVATE_BAT = """
4423eJyFUkEKgzAQvAfyhz0YaL9QEWpRqlSjWGspFPZQTevFHOr/adQaU1GaUzI7Mzu7ZF89XhKkEJS8
4424qxaKMMsvboQ+LxxE44VICSW1gEa2UFaibqoS0iyJ0xw2lIA6nX5AHCu1jpRsv5KRjknkac9VLVug
4425sX9mtzxIeJDE/mg4OGp47qoLo3NHX2jsMB3AiDht5hryAUOEifoTdCXbSh7V0My2NMq/Xbh5MEjU
4426ZT63gpgNT9lKOJ/CtHsvT99re3pX303kydn4HeyOeAg5cjf2EW1D6HOPkg9NGKhu
4427""".decode("base64").decode("zlib")
4428
4429##file deactivate.bat
4430DEACTIVATE_BAT = """
4431eJxzSE3OyFfIT0vj4spMU0hJTcvMS01RiPf3cYkP8wwKCXX0iQ8I8vcNCFHQ4FIAguLUEgWIgK0q
4432FlWqXJpcICVYpGzx2BAZ4uHv5+Hv6wq1BWINXBTdKriEKkI1DhW2QAfhttcxxANiFZCBbglQSJUL
4433i2dASrm4rFz9XLgAwJNbyQ==
4434""".decode("base64").decode("zlib")
4435
4436##file distutils-init.py
4437DISTUTILS_INIT = """
4438eJytV92L4zYQf9dfMU0ottuse/TeFkKh3MvC0Ydy0IdlMVpbTtR1JCMpm+T++s5Y/pBs53oPZ1hQ
4439pPnSb34zo5WnVhsH2jLpV/Y2Li/cKKkOFoYN3Za6ErAdFtKC0g44vEvjzrwR6h1Oujo3YgdWw0VA
4440yRWcLUo6cBpqqSpwRwHWVY18ZRB9W3jq3HDlfoIvqK7NG2gF7a297VANvZ3O1sGrQI/eDe5yB0ZY
4441WQkLUpHxhVX09NDe3FGr31BL1lJUD9f8ln+FShpROm1ujOFS8ZOAPUKRt9wd836Hjqw7O9nYgvYD
4442iX+1VOlMPPXQ5EVRy0YURbaDZDSQZEzWo7rS5kSLNHaQwX4RRLrQGe1nj92Fh1zltEhHDDZfEO0g
4443O6MraHn5xg8IpYOfLfC2FdxYShLC64EES4A0uuROYhq49Zs368RpMvTHJmOiscKHUXRXKIpcKiuM
4444Sz/sYHa7TkxcRYkkEhN8HZaxKCJXFFJJh+baW5JluRG8SjM20JHEA9qWWtXywBjbbvF2rjzC61k2
4445VSGuDibTUGlhVeLgTekLHPEP73wQrrscUsUGrPCGjkTCC1JXXyw8EJWP3FSUZY8IiSCCRp97dnfO
4446RUUx5a0RtbxSzLX/3XBXYxIpyQka/fh74pGrjQ5QzUt9OnFV5dMV+otOG5gQjctxozNTNtzaSSiN
4447JHqu0FeJmsqRN/KrKHRLGbaQWtHUgRB9FDfu5giN4eZWIDqWCv8vrcTjrNZgRXQPzy+RmGjQpLRI
4448EKz0UqQLlR28ciusM8jn7PtcLPZy2zbSDeyyos0iO+ybBgPyRvSk/CEFm8IndQebz8iXTRbbjhDP
44495xh7iJfBrKd/Nenjj6Jvgp2B+W7AnP102BXH5IZWPV3tI2MUOvXowpdS12IIXhLLP0lKyeuZrpEv
4450pFhPqHg3JFTd1cceVp0EsPgGU0wFO2u4iyYRoFYfEm9kG/RZcUUBm87t9mFtx9iCtC9kx4Rt4R8a
4451OdgzSt40vtyFecAZZ8BfCOhCrC8djMGPFaz2Vlt5TSZCk053+37wbLDLRXfZ+F45NtdVpVWdudSC
4452xgODI8EsiLoTl5aO0lhoigX7GHZDHAY4LxoMIu1gXPYPksmFquxF4uRKZhEnKzXu82HESb+LlNQz
4453Fh/RvFJVuhK+Ee5slBdj30FcRGdJ5rhKxtkyKxWcGoV/WOCYKqkNDYJ5fNQVx3g400tpJBS2FSU+
4454Tco9ss8nZ08dtscGQfSby87b73fOw+4UgrEMNnY6uMzYvSDxPVPpsij6+l0/ZPfuH0Iz010giY34
4455HpL0ZLyLJB4ukaQRU+GwptO7yIZCQE33B0K9iCqO6X+AR4n7wAeH68DPkJzpTsD3x+/cj9LIVHC2
4456An1wmv7CzWHoqR02vb0VL73siP+3nkX0YbQ0l9f6WDyOm24cj3rxO2MMip6kpcu6VCefn/789PR3
44570v0fg21sFIp70rj9PCi8YDRDXFucym/43qN+iENh1Jy/dIIIqF3OIkDvBMsdx+huWv8Kz73vl8g5
4458WQ3JOGqwu3lb4dfKKbvLigXDQsb8B/xt39Q=
4459""".decode("base64").decode("zlib")
4460
4461##file distutils.cfg
4462DISTUTILS_CFG = """
4463eJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH
4464xJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg
44659FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q=
4466""".decode("base64").decode("zlib")
4467
4468##file activate_this.py
4469ACTIVATE_THIS = """
4470eJyNUlGL2zAMfvevEBlHEujSsXsL9GGDvW1jD3sZpQQ3Ua7aJXawnbT595Ocpe0dO5ghseVP+vRJ
4471VpIkn2cYPZknwAvWLXWYhRP5Sk4baKgOWRWNqtpdgTyH2Y5wpq5Tug406YAgKEzkwqg7NBPwR86a
4472Hk0olPopaK0NHJHzYQPnE5rI0o8+yBUwiBfyQcT8mMPJGiAT0A0O+b8BY4MKJ7zPcSSzHaKrSpJE
4473qeDmUgGvVbPCS41DgO+6xy/OWbfAThMn/OQ9ukDWRCSLiKzk1yrLjWapq6NnvHUoHXQ4bYPdrsVX
44744lQMc/q6ZW975nmSK+oH6wL42a9H65U6aha342Mh0UVDzrD87C1bH73s16R5zsStkBZDp0NrXQ+7
4475HaRnMo8f06UBnljKoOtn/YT+LtdvSyaT/BtIv9KR60nF9f3qmuYKO4//T9ItJMsjPfgUHqKwCZ3n
4476xu/Lx8M/UvCLTxW7VULHxB1PRRbrYfvWNY5S8it008jOjcleaMqVBDnUXcWULV2YK9JEQ92OfC96
44771Tv4ZicZZZ7GpuEpZbbeQ7DxquVx5hdqoyFSSmXwfC90f1Dc7hjFs/tK99I0fpkI8zSLy4tSy+sI
44783vMWehjQNJmE5VePlZbL61nzX3S93ZcfDqznnkb9AZ3GWJU=
4479""".decode("base64").decode("zlib")
4480
4481if __name__ == '__main__':
4482    main()
4483
4484# pyutilib.virtualenv: ignoring comment
4485## Copy python.exe.manifest
4486## Monkeypatch distutils.sysconfig
Note: See TracBrowser for help on using the repository browser.