parameters: (name, req, wheeldir, user=False, home=None, root=None,
                       pycompile=True, scheme=None, isolated=False)
docstring: Install a wheel
docstring_summary: Install a wheel
docstring_tokens: Install a wheel
function: def move_wheel_files(name, req, wheeldir, user=False, home=None, root=None,
                       pycompile=True, scheme=None, isolated=False):
      """Install a wheel"""
  
      if not scheme:
          scheme = distutils_scheme(
              name, user=user, home=home, root=root, isolated=isolated
          )
  
      if root_is_purelib(name, wheeldir):
          lib_dir = scheme['purelib']
      else:
          lib_dir = scheme['platlib']
  
      info_dir = []
      data_dirs = []
      source = wheeldir.rstrip(os.path.sep) + os.path.sep
  
      # Record details of the files moved
      #   installed = files copied from the wheel to the destination
      #   changed = files changed while installing (scripts #! line typically)
      #   generated = files newly generated during the install (script wrappers)
      installed = {}
      changed = set()
      generated = []
  
      # Compile all of the pyc files that we're going to be installing
      if pycompile:
          with captured_stdout() as stdout:
              with warnings.catch_warnings():
                  warnings.filterwarnings('ignore')
                  compileall.compile_dir(source, force=True, quiet=True)
          logger.debug(stdout.getvalue())
  
      def normpath(src, p):
          return make_path_relative(src, p).replace(os.path.sep, '/')
  
      def record_installed(srcfile, destfile, modified=False):
          """Map archive RECORD paths to installation RECORD paths."""
          oldpath = normpath(srcfile, wheeldir)
          newpath = normpath(destfile, lib_dir)
          installed[oldpath] = newpath
          if modified:
              changed.add(destfile)
  
      def clobber(source, dest, is_base, fixer=None, filter=None):
          ensure_dir(dest)  # common for the 'include' path
  
          for dir, subdirs, files in os.walk(source):
              basedir = dir[len(source):].lstrip(os.path.sep)
              destdir = os.path.join(dest, basedir)
              if is_base and basedir.split(os.path.sep, 1)[0].endswith('.data'):
                  continue
              for s in subdirs:
                  destsubdir = os.path.join(dest, basedir, s)
                  if is_base and basedir == '' and destsubdir.endswith('.data'):
                      data_dirs.append(s)
                      continue
                  elif (is_base and
                          s.endswith('.dist-info') and
                          # is self.req.project_name case preserving?
                          s.lower().startswith(
                              req.project_name.replace('-', '_').lower())):
                      assert not info_dir, 'Multiple .dist-info directories'
                      info_dir.append(destsubdir)
              for f in files:
                  # Skip unwanted files
                  if filter and filter(f):
                      continue
                  srcfile = os.path.join(dir, f)
                  destfile = os.path.join(dest, basedir, f)
                  # directory creation is lazy and after the file filtering above
                  # to ensure we don't install empty dirs; empty dirs can't be
                  # uninstalled.
                  ensure_dir(destdir)
  
                  # We use copyfile (not move, copy, or copy2) to be extra sure
                  # that we are not moving directories over (copyfile fails for
                  # directories) as well as to ensure that we are not copying
                  # over any metadata because we want more control over what
                  # metadata we actually copy over.
                  shutil.copyfile(srcfile, destfile)
  
                  # Copy over the metadata for the file, currently this only
                  # includes the atime and mtime.
                  st = os.stat(srcfile)
                  if hasattr(os, "utime"):
                      os.utime(destfile, (st.st_atime, st.st_mtime))
  
                  # If our file is executable, then make our destination file
                  # executable.
                  if os.access(srcfile, os.X_OK):
                      st = os.stat(srcfile)
                      permissions = (
                          st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
                      )
                      os.chmod(destfile, permissions)
  
                  changed = False
                  if fixer:
                      changed = fixer(destfile)
                  record_installed(srcfile, destfile, changed)
  
      clobber(source, lib_dir, True)
  
      assert info_dir, "%s .dist-info directory not found" % req
  
      # Get the defined entry points
      ep_file = os.path.join(info_dir[0], 'entry_points.txt')
      console, gui = get_entrypoints(ep_file)
  
      def is_entrypoint_wrapper(name):
          # EP, EP.exe and EP-script.py are scripts generated for
          # entry point EP by setuptools
          if name.lower().endswith('.exe'):
              matchname = name[:-4]
          elif name.lower().endswith('-script.py'):
              matchname = name[:-10]
          elif name.lower().endswith(".pya"):
              matchname = name[:-4]
          else:
              matchname = name
          # Ignore setuptools-generated scripts
          return (matchname in console or matchname in gui)
  
      for datadir in data_dirs:
          fixer = None
          filter = None
          for subdir in os.listdir(os.path.join(wheeldir, datadir)):
              fixer = None
              if subdir == 'scripts':
                  fixer = fix_script
                  filter = is_entrypoint_wrapper
              source = os.path.join(wheeldir, datadir, subdir)
              dest = scheme[subdir]
              clobber(source, dest, False, fixer=fixer, filter=filter)
  
      maker = ScriptMaker(None, scheme['scripts'])
  
      # Ensure old scripts are overwritten.
      # See https://github.com/pypa/pip/issues/1800
      maker.clobber = True
  
      # Ensure we don't generate any variants for scripts because this is almost
      # never what somebody wants.
      # See https://bitbucket.org/pypa/distlib/issue/35/
      maker.variants = set(('', ))
  
      # This is required because otherwise distlib creates scripts that are not
      # executable.
      # See https://bitbucket.org/pypa/distlib/issue/32/
      maker.set_mode = True
  
      # Simplify the script and fix the fact that the default script swallows
      # every single stack trace.
      # See https://bitbucket.org/pypa/distlib/issue/34/
      # See https://bitbucket.org/pypa/distlib/issue/33/
      def _get_script_text(entry):
          return maker.script_template % {
              "module": entry.prefix,
              "import_name": entry.suffix.split(".")[0],
              "func": entry.suffix,
          }
  
      maker._get_script_text = _get_script_text
      maker.script_template = """# -*- coding: utf-8 -*-
  import re
  import sys
  
  from %(module)s import %(import_name)s
  
  if __name__ == '__main__':
      sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
      sys.exit(%(func)s())
  """
  
      # Special case pip and setuptools to generate versioned wrappers
      #
      # The issue is that some projects (specifically, pip and setuptools) use
      # code in setup.py to create "versioned" entry points - pip2.7 on Python
      # 2.7, pip3.3 on Python 3.3, etc. But these entry points are baked into
      # the wheel metadata at build time, and so if the wheel is installed with
      # a *different* version of Python the entry points will be wrong. The
      # correct fix for this is to enhance the metadata to be able to describe
      # such versioned entry points, but that won't happen till Metadata 2.0 is
      # available.
      # In the meantime, projects using versioned entry points will either have
      # incorrect versioned entry points, or they will not be able to distribute
      # "universal" wheels (i.e., they will need a wheel per Python version).
      #
      # Because setuptools and pip are bundled with _ensurepip and virtualenv,
      # we need to use universal wheels. So, as a stopgap until Metadata 2.0, we
      # override the versioned entry points in the wheel and generate the
      # correct ones. This code is purely a short-term measure until Metadat 2.0
      # is available.
      #
      # To add the level of hack in this section of code, in order to support
      # ensurepip this code will look for an ``ENSUREPIP_OPTIONS`` environment
      # variable which will control which version scripts get installed.
      #
      # ENSUREPIP_OPTIONS=altinstall
      #   - Only pipX.Y and easy_install-X.Y will be generated and installed
      # ENSUREPIP_OPTIONS=install
      #   - pipX.Y, pipX, easy_install-X.Y will be generated and installed. Note
      #     that this option is technically if ENSUREPIP_OPTIONS is set and is
      #     not altinstall
      # DEFAULT
      #   - The default behavior is to install pip, pipX, pipX.Y, easy_install
      #     and easy_install-X.Y.
      pip_script = console.pop('pip', None)
      if pip_script:
          if "ENSUREPIP_OPTIONS" not in os.environ:
              spec = 'pip = ' + pip_script
              generated.extend(maker.make(spec))
  
          if os.environ.get("ENSUREPIP_OPTIONS", "") != "altinstall":
              spec = 'pip%s = %s' % (sys.version[:1], pip_script)
              generated.extend(maker.make(spec))
  
          spec = 'pip%s = %s' % (sys.version[:3], pip_script)
          generated.extend(maker.make(spec))
          # Delete any other versioned pip entry points
          pip_ep = [k for k in console if re.match(r'pip(\d(\.\d)?)?$', k)]
          for k in pip_ep:
              del console[k]
      easy_install_script = console.pop('easy_install', None)
      if easy_install_script:
          if "ENSUREPIP_OPTIONS" not in os.environ:
              spec = 'easy_install = ' + easy_install_script
              generated.extend(maker.make(spec))
  
          spec = 'easy_install-%s = %s' % (sys.version[:3], easy_install_script)
          generated.extend(maker.make(spec))
          # Delete any other versioned easy_install entry points
          easy_install_ep = [
              k for k in console if re.match(r'easy_install(-\d\.\d)?$', k)
          ]
          for k in easy_install_ep:
              del console[k]
  
      # Generate the console and GUI entry points specified in the wheel
      if len(console) > 0:
          generated.extend(
              maker.make_multiple(['%s = %s' % kv for kv in console.items()])
          )
      if len(gui) > 0:
          generated.extend(
              maker.make_multiple(
                  ['%s = %s' % kv for kv in gui.items()],
                  {'gui': True}
              )
          )
  
      record = os.path.join(info_dir[0], 'RECORD')
      temp_record = os.path.join(info_dir[0], 'RECORD.pip')
      with open_for_csv(record, 'r') as record_in:
          with open_for_csv(temp_record, 'w+') as record_out:
              reader = csv.reader(record_in)
              writer = csv.writer(record_out)
              for row in reader:
                  row[0] = installed.pop(row[0], row[0])
                  if row[0] in changed:
                      row[1], row[2] = rehash(row[0])
                  writer.writerow(row)
              for f in generated:
                  h, l = rehash(f)
                  writer.writerow((f, h, l))
              for f in installed:
                  writer.writerow((installed[f], '', ''))
      shutil.move(temp_record, record)
function_tokens: def move_wheel_files ( name , req , wheeldir , user = False , home = None , root = None , pycompile = True , scheme = None , isolated = False ) : if not scheme : scheme = distutils_scheme ( name , user = user , home = home , root = root , isolated = isolated ) if root_is_purelib ( name , wheeldir ) : lib_dir = scheme [ 'purelib' ] else : lib_dir = scheme [ 'platlib' ] info_dir = [ ] data_dirs = [ ] source = wheeldir . rstrip ( os . path . sep ) + os . path . sep # Record details of the files moved #   installed = files copied from the wheel to the destination #   changed = files changed while installing (scripts #! line typically) #   generated = files newly generated during the install (script wrappers) installed = { } changed = set ( ) generated = [ ] # Compile all of the pyc files that we're going to be installing if pycompile : with captured_stdout ( ) as stdout : with warnings . catch_warnings ( ) : warnings . filterwarnings ( 'ignore' ) compileall . compile_dir ( source , force = True , quiet = True ) logger . debug ( stdout . getvalue ( ) ) def normpath ( src , p ) : return make_path_relative ( src , p ) . replace ( os . path . sep , '/' ) def record_installed ( srcfile , destfile , modified = False ) : """Map archive RECORD paths to installation RECORD paths.""" oldpath = normpath ( srcfile , wheeldir ) newpath = normpath ( destfile , lib_dir ) installed [ oldpath ] = newpath if modified : changed . add ( destfile ) def clobber ( source , dest , is_base , fixer = None , filter = None ) : ensure_dir ( dest ) # common for the 'include' path for dir , subdirs , files in os . walk ( source ) : basedir = dir [ len ( source ) : ] . lstrip ( os . path . sep ) destdir = os . path . join ( dest , basedir ) if is_base and basedir . split ( os . path . sep , 1 ) [ 0 ] . endswith ( '.data' ) : continue for s in subdirs : destsubdir = os . path . join ( dest , basedir , s ) if is_base and basedir == '' and destsubdir . endswith ( '.data' ) : data_dirs . append ( s ) continue elif ( is_base and s . endswith ( '.dist-info' ) and # is self.req.project_name case preserving? s . lower ( ) . startswith ( req . project_name . replace ( '-' , '_' ) . lower ( ) ) ) : assert not info_dir , 'Multiple .dist-info directories' info_dir . append ( destsubdir ) for f in files : # Skip unwanted files if filter and filter ( f ) : continue srcfile = os . path . join ( dir , f ) destfile = os . path . join ( dest , basedir , f ) # directory creation is lazy and after the file filtering above # to ensure we don't install empty dirs; empty dirs can't be # uninstalled. ensure_dir ( destdir ) # We use copyfile (not move, copy, or copy2) to be extra sure # that we are not moving directories over (copyfile fails for # directories) as well as to ensure that we are not copying # over any metadata because we want more control over what # metadata we actually copy over. shutil . copyfile ( srcfile , destfile ) # Copy over the metadata for the file, currently this only # includes the atime and mtime. st = os . stat ( srcfile ) if hasattr ( os , "utime" ) : os . utime ( destfile , ( st . st_atime , st . st_mtime ) ) # If our file is executable, then make our destination file # executable. if os . access ( srcfile , os . X_OK ) : st = os . stat ( srcfile ) permissions = ( st . st_mode | stat . S_IXUSR | stat . S_IXGRP | stat . S_IXOTH ) os . chmod ( destfile , permissions ) changed = False if fixer : changed = fixer ( destfile ) record_installed ( srcfile , destfile , changed ) clobber ( source , lib_dir , True ) assert info_dir , "%s .dist-info directory not found" % req # Get the defined entry points ep_file = os . path . join ( info_dir [ 0 ] , 'entry_points.txt' ) console , gui = get_entrypoints ( ep_file ) def is_entrypoint_wrapper ( name ) : # EP, EP.exe and EP-script.py are scripts generated for # entry point EP by setuptools if name . lower ( ) . endswith ( '.exe' ) : matchname = name [ : - 4 ] elif name . lower ( ) . endswith ( '-script.py' ) : matchname = name [ : - 10 ] elif name . lower ( ) . endswith ( ".pya" ) : matchname = name [ : - 4 ] else : matchname = name # Ignore setuptools-generated scripts return ( matchname in console or matchname in gui ) for datadir in data_dirs : fixer = None filter = None for subdir in os . listdir ( os . path . join ( wheeldir , datadir ) ) : fixer = None if subdir == 'scripts' : fixer = fix_script filter = is_entrypoint_wrapper source = os . path . join ( wheeldir , datadir , subdir ) dest = scheme [ subdir ] clobber ( source , dest , False , fixer = fixer , filter = filter ) maker = ScriptMaker ( None , scheme [ 'scripts' ] ) # Ensure old scripts are overwritten. # See https://github.com/pypa/pip/issues/1800 maker . clobber = True # Ensure we don't generate any variants for scripts because this is almost # never what somebody wants. # See https://bitbucket.org/pypa/distlib/issue/35/ maker . variants = set ( ( '' , ) ) # This is required because otherwise distlib creates scripts that are not # executable. # See https://bitbucket.org/pypa/distlib/issue/32/ maker . set_mode = True # Simplify the script and fix the fact that the default script swallows # every single stack trace. # See https://bitbucket.org/pypa/distlib/issue/34/ # See https://bitbucket.org/pypa/distlib/issue/33/ def _get_script_text ( entry ) : return maker . script_template % { "module" : entry . prefix , "import_name" : entry . suffix . split ( "." ) [ 0 ] , "func" : entry . suffix , } maker . _get_script_text = _get_script_text maker . script_template = """# -*- coding: utf-8 -*-
  import re
  import sys
  
  from %(module)s import %(import_name)s
  
  if __name__ == '__main__':
      sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
      sys.exit(%(func)s())
  """ # Special case pip and setuptools to generate versioned wrappers # # The issue is that some projects (specifically, pip and setuptools) use # code in setup.py to create "versioned" entry points - pip2.7 on Python # 2.7, pip3.3 on Python 3.3, etc. But these entry points are baked into # the wheel metadata at build time, and so if the wheel is installed with # a *different* version of Python the entry points will be wrong. The # correct fix for this is to enhance the metadata to be able to describe # such versioned entry points, but that won't happen till Metadata 2.0 is # available. # In the meantime, projects using versioned entry points will either have # incorrect versioned entry points, or they will not be able to distribute # "universal" wheels (i.e., they will need a wheel per Python version). # # Because setuptools and pip are bundled with _ensurepip and virtualenv, # we need to use universal wheels. So, as a stopgap until Metadata 2.0, we # override the versioned entry points in the wheel and generate the # correct ones. This code is purely a short-term measure until Metadat 2.0 # is available. # # To add the level of hack in this section of code, in order to support # ensurepip this code will look for an ``ENSUREPIP_OPTIONS`` environment # variable which will control which version scripts get installed. # # ENSUREPIP_OPTIONS=altinstall #   - Only pipX.Y and easy_install-X.Y will be generated and installed # ENSUREPIP_OPTIONS=install #   - pipX.Y, pipX, easy_install-X.Y will be generated and installed. Note #     that this option is technically if ENSUREPIP_OPTIONS is set and is #     not altinstall # DEFAULT #   - The default behavior is to install pip, pipX, pipX.Y, easy_install #     and easy_install-X.Y. pip_script = console . pop ( 'pip' , None ) if pip_script : if "ENSUREPIP_OPTIONS" not in os . environ : spec = 'pip = ' + pip_script generated . extend ( maker . make ( spec ) ) if os . environ . get ( "ENSUREPIP_OPTIONS" , "" ) != "altinstall" : spec = 'pip%s = %s' % ( sys . version [ : 1 ] , pip_script ) generated . extend ( maker . make ( spec ) ) spec = 'pip%s = %s' % ( sys . version [ : 3 ] , pip_script ) generated . extend ( maker . make ( spec ) ) # Delete any other versioned pip entry points pip_ep = [ k for k in console if re . match ( r'pip(\d(\.\d)?)?$' , k ) ] for k in pip_ep : del console [ k ] easy_install_script = console . pop ( 'easy_install' , None ) if easy_install_script : if "ENSUREPIP_OPTIONS" not in os . environ : spec = 'easy_install = ' + easy_install_script generated . extend ( maker . make ( spec ) ) spec = 'easy_install-%s = %s' % ( sys . version [ : 3 ] , easy_install_script ) generated . extend ( maker . make ( spec ) ) # Delete any other versioned easy_install entry points easy_install_ep = [ k for k in console if re . match ( r'easy_install(-\d\.\d)?$' , k ) ] for k in easy_install_ep : del console [ k ] # Generate the console and GUI entry points specified in the wheel if len ( console ) > 0 : generated . extend ( maker . make_multiple ( [ '%s = %s' % kv for kv in console . items ( ) ] ) ) if len ( gui ) > 0 : generated . extend ( maker . make_multiple ( [ '%s = %s' % kv for kv in gui . items ( ) ] , { 'gui' : True } ) ) record = os . path . join ( info_dir [ 0 ] , 'RECORD' ) temp_record = os . path . join ( info_dir [ 0 ] , 'RECORD.pip' ) with open_for_csv ( record , 'r' ) as record_in : with open_for_csv ( temp_record , 'w+' ) as record_out : reader = csv . reader ( record_in ) writer = csv . writer ( record_out ) for row in reader : row [ 0 ] = installed . pop ( row [ 0 ] , row [ 0 ] ) if row [ 0 ] in changed : row [ 1 ] , row [ 2 ] = rehash ( row [ 0 ] ) writer . writerow ( row ) for f in generated : h , l = rehash ( f ) writer . writerow ( ( f , h , l ) ) for f in installed : writer . writerow ( ( installed [ f ] , '' , '' ) ) shutil . move ( temp_record , record )